--- /dev/null
+/*
+ *
+ * OBEX library with GLib integration
+ *
+ * Copyright (C) 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __GOBEX_DEFS_H
+#define __GOBEX_DEFS_H
+
+typedef enum {
+ G_OBEX_DATA_INHERIT,
+ G_OBEX_DATA_COPY,
+ G_OBEX_DATA_REF,
+} GObexDataPolicy;
+
+#endif /* __GOBEX_DEFS_H */
--- /dev/null
+/*
+ *
+ * OBEX library with GLib integration
+ *
+ * Copyright (C) 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <string.h>
+
+#include "gobex-header.h"
+
+/* Header types */
+#define G_OBEX_HDR_TYPE_UNICODE (0 << 6)
+#define G_OBEX_HDR_TYPE_BYTES (1 << 6)
+#define G_OBEX_HDR_TYPE_UINT8 (2 << 6)
+#define G_OBEX_HDR_TYPE_UINT32 (3 << 6)
+
+#define G_OBEX_HDR_TYPE(id) ((id) & 0xc0)
+
+struct _GObexHeader {
+ guint8 id;
+ gboolean extdata;
+ size_t vlen; /* Length of value */
+ size_t hlen; /* Length of full encoded header */
+ union {
+ char *string; /* UTF-8 converted from UTF-16 */
+ guint8 *data; /* Own buffer */
+ const guint8 *extdata; /* Reference to external buffer */
+ guint8 u8;
+ guint32 u32;
+ } v;
+};
+
+static glong utf8_to_utf16(gunichar2 **utf16, const char *utf8) {
+ glong utf16_len;
+ int i;
+
+ if (*utf8 == '\0') {
+ *utf16 = NULL;
+ return 0;
+ }
+
+ *utf16 = g_utf8_to_utf16(utf8, -1, NULL, &utf16_len, NULL);
+ if (*utf16 == NULL)
+ return -1;
+
+ /* g_utf8_to_utf16 produces host-byteorder UTF-16,
+ * but OBEX requires network byteorder (big endian) */
+ for (i = 0; i < utf16_len; i++)
+ (*utf16)[i] = g_htons((*utf16)[i]);
+
+ utf16_len = (utf16_len + 1) << 1;
+
+ return utf16_len;
+}
+
+static guint8 *put_bytes(guint8 *to, const void *from, size_t count)
+{
+ memcpy(to, from, count);
+ return (to + count);
+}
+
+static const guint8 *get_bytes(void *to, const guint8 *from, size_t count)
+{
+ memcpy(to, from, count);
+ return (from + count);
+}
+
+size_t g_obex_header_encode(GObexHeader *header, void *buf, size_t buf_len)
+{
+ guint8 *ptr = buf;
+ guint16 u16;
+ guint32 u32;
+ gunichar2 *utf16;
+ glong utf16_len;
+
+ if (buf_len < header->hlen)
+ return 0;
+
+ ptr = put_bytes(ptr, &header->id, sizeof(header->id));
+
+ switch (G_OBEX_HDR_TYPE(header->id)) {
+ case G_OBEX_HDR_TYPE_UNICODE:
+ utf16_len = utf8_to_utf16(&utf16, header->v.string);
+ if (utf16_len < 0 || (guint16) utf16_len > buf_len)
+ return 0;
+ g_assert_cmpuint(utf16_len + 3, ==, header->hlen);
+ u16 = g_htons(utf16_len + 3);
+ ptr = put_bytes(ptr, &u16, sizeof(u16));
+ ptr = put_bytes(ptr, utf16, utf16_len);
+ g_free(utf16);
+ break;
+ case G_OBEX_HDR_TYPE_BYTES:
+ u16 = g_htons(header->hlen);
+ ptr = put_bytes(ptr, &u16, sizeof(u16));
+ if (header->extdata)
+ ptr = put_bytes(ptr, header->v.extdata, header->vlen);
+ else
+ ptr = put_bytes(ptr, header->v.data, header->vlen);
+ break;
+ case G_OBEX_HDR_TYPE_UINT8:
+ *ptr = header->v.u8;
+ break;
+ case G_OBEX_HDR_TYPE_UINT32:
+ u32 = g_htonl(header->v.u32);
+ ptr = put_bytes(ptr, &u32, sizeof(u32));
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ return header->hlen;
+}
+
+GObexHeader *g_obex_header_decode(const void *data, size_t len,
+ GObexDataPolicy data_policy, size_t *parsed)
+{
+ GObexHeader *header;
+ const guint8 *ptr = data;
+ guint16 hdr_len;
+ size_t str_len;
+
+ if (len < 2)
+ return NULL;
+
+ header = g_new0(GObexHeader, 1);
+
+ ptr = get_bytes(&header->id, ptr, sizeof(header->id));
+
+ switch (G_OBEX_HDR_TYPE(header->id)) {
+ case G_OBEX_HDR_TYPE_UNICODE:
+ if (len < 3)
+ goto failed;
+ ptr = get_bytes(&hdr_len, ptr, sizeof(hdr_len));
+ hdr_len = g_ntohs(hdr_len);
+ if (hdr_len > len || hdr_len < 5)
+ goto failed;
+
+ header->v.string = g_convert((const char *) ptr, hdr_len - 5,
+ "UTF8", "UTF16BE",
+ NULL, &str_len, NULL);
+ if (header->v.string == NULL)
+ goto failed;
+
+ header->vlen = (size_t) str_len;
+ header->hlen = hdr_len;
+
+ *parsed = hdr_len;
+
+ break;
+ case G_OBEX_HDR_TYPE_BYTES:
+ if (len < 3)
+ goto failed;
+ ptr = get_bytes(&hdr_len, ptr, sizeof(hdr_len));
+ hdr_len = g_ntohs(hdr_len);
+ if (hdr_len > len)
+ goto failed;
+
+ header->vlen = hdr_len - 3;
+ header->hlen = hdr_len;
+
+ switch (data_policy) {
+ case G_OBEX_DATA_COPY:
+ header->v.data = g_memdup(ptr, header->vlen);
+ break;
+ case G_OBEX_DATA_REF:
+ header->extdata = TRUE;
+ header->v.extdata = ptr;
+ break;
+ default:
+ goto failed;
+ }
+
+ *parsed = hdr_len;
+
+ break;
+ case G_OBEX_HDR_TYPE_UINT8:
+ header->vlen = 1;
+ header->hlen = 2;
+ header->v.u8 = *ptr;
+ *parsed = 2;
+ break;
+ case G_OBEX_HDR_TYPE_UINT32:
+ if (len < 5)
+ goto failed;
+ header->vlen = 4;
+ header->hlen = 5;
+ ptr = get_bytes(&header->v.u32, ptr, sizeof(header->v.u32));
+ header->v.u32 = g_ntohl(header->v.u32);
+ *parsed = 5;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ return header;
+
+failed:
+ g_obex_header_free(header);
+ return NULL;
+}
+
+void g_obex_header_free(GObexHeader *header)
+{
+ switch (G_OBEX_HDR_TYPE(header->id)) {
+ case G_OBEX_HDR_TYPE_UNICODE:
+ g_free(header->v.string);
+ break;
+ case G_OBEX_HDR_TYPE_BYTES:
+ if (!header->extdata)
+ g_free(header->v.data);
+ break;
+ case G_OBEX_HDR_TYPE_UINT8:
+ case G_OBEX_HDR_TYPE_UINT32:
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ g_free(header);
+}
+
+gboolean g_obex_header_get_unicode(GObexHeader *header, const char **str)
+{
+ if (G_OBEX_HDR_TYPE(header->id) != G_OBEX_HDR_TYPE_UNICODE)
+ return FALSE;
+
+ *str = header->v.string;
+
+ return TRUE;
+}
+
+gboolean g_obex_header_get_bytes(GObexHeader *header, const guint8 **val,
+ size_t *len)
+{
+ if (G_OBEX_HDR_TYPE(header->id) != G_OBEX_HDR_TYPE_BYTES)
+ return FALSE;
+
+ *len = header->vlen;
+
+ if (header->extdata)
+ *val = header->v.extdata;
+ else
+ *val = header->v.data;
+
+ return TRUE;
+}
+
+gboolean g_obex_header_get_uint8(GObexHeader *header, guint8 *val)
+{
+ if (G_OBEX_HDR_TYPE(header->id) != G_OBEX_HDR_TYPE_UINT8)
+ return FALSE;
+
+ *val = header->v.u8;
+
+ return TRUE;
+}
+
+gboolean g_obex_header_get_uint32(GObexHeader *header, guint32 *val)
+{
+ if (G_OBEX_HDR_TYPE(header->id) != G_OBEX_HDR_TYPE_UINT32)
+ return FALSE;
+
+ *val = header->v.u32;
+
+ return TRUE;
+}
+
+GObexHeader *g_obex_header_new_unicode(guint8 id, const char *str)
+{
+ GObexHeader *header;
+ size_t len;
+
+ if (G_OBEX_HDR_TYPE(id) != G_OBEX_HDR_TYPE_UNICODE)
+ return NULL;
+
+ header = g_new0(GObexHeader, 1);
+
+ header->id = id;
+
+ len = g_utf8_strlen(str, -1);
+
+ header->vlen = len;
+ header->hlen = 3 + ((len + 1) * 2);
+ header->v.string = g_strdup(str);
+
+ return header;
+}
+
+GObexHeader *g_obex_header_new_bytes(guint8 id, void *data, size_t len,
+ GObexDataPolicy data_policy)
+{
+ GObexHeader *header;
+
+ if (G_OBEX_HDR_TYPE(id) != G_OBEX_HDR_TYPE_BYTES)
+ return NULL;
+
+ header = g_new0(GObexHeader, 1);
+
+ header->id = id;
+ header->vlen = len;
+ header->hlen = len + 3;
+
+ switch (data_policy) {
+ case G_OBEX_DATA_INHERIT:
+ header->v.data = data;
+ break;
+ case G_OBEX_DATA_COPY:
+ header->v.data = g_memdup(data, len);
+ break;
+ case G_OBEX_DATA_REF:
+ header->extdata = TRUE;
+ header->v.extdata = data;
+ break;
+ }
+
+ return header;
+}
+
+GObexHeader *g_obex_header_new_uint8(guint8 id, guint8 val)
+{
+ GObexHeader *header;
+
+ if (G_OBEX_HDR_TYPE(id) != G_OBEX_HDR_TYPE_UINT8)
+ return NULL;
+
+ header = g_new0(GObexHeader, 1);
+
+ header->id = id;
+ header->vlen = 1;
+ header->hlen = 2;
+ header->v.u8 = val;
+
+ return header;
+}
+
+GObexHeader *g_obex_header_new_uint32(guint8 id, guint32 val)
+{
+ GObexHeader *header;
+
+ if (G_OBEX_HDR_TYPE(id) != G_OBEX_HDR_TYPE_UINT32)
+ return NULL;
+
+ header = g_new0(GObexHeader, 1);
+
+ header->id = id;
+ header->vlen = 4;
+ header->hlen = 5;
+ header->v.u32 = val;
+
+ return header;
+}
+
+guint8 g_obex_header_get_id(GObexHeader *header)
+{
+ return header->id;
+}
+
+guint16 g_obex_header_get_length(GObexHeader *header)
+{
+ return header->hlen;
+}
--- /dev/null
+/*
+ *
+ * OBEX library with GLib integration
+ *
+ * Copyright (C) 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __GOBEX_HEADER_H
+#define __GOBEX_HEADER_H
+
+#include <glib.h>
+
+#include <gobex/gobex-defs.h>
+
+/* Header ID's */
+#define G_OBEX_HDR_ID_COUNT 0xc0
+#define G_OBEX_HDR_ID_NAME 0x01
+#define G_OBEX_HDR_ID_TYPE 0x42
+#define G_OBEX_HDR_ID_LENGTH 0xc3
+#define G_OBEX_HDR_ID_TIME 0x44
+#define G_OBEX_HDR_ID_DESCRIPTION 0x05
+#define G_OBEX_HDR_ID_TARGET 0x46
+#define G_OBEX_HDR_ID_HTTP 0x47
+#define G_OBEX_HDR_ID_BODY 0x48
+#define G_OBEX_HDR_ID_BODY_END 0x49
+#define G_OBEX_HDR_ID_WHO 0x4a
+#define G_OBEX_HDR_ID_CONNECTION 0xcb
+#define G_OBEX_HDR_ID_APPARAM 0x4c
+#define G_OBEX_HDR_ID_AUTHCHAL 0x4d
+#define G_OBEX_HDR_ID_AUTHRESP 0x4e
+#define G_OBEX_HDR_ID_CREATOR 0xcf
+#define G_OBEX_HDR_ID_WANUUID 0x50
+#define G_OBEX_HDR_ID_OBJECTCLASS 0x51
+#define G_OBEX_HDR_ID_SESSIONPARAM 0x52
+#define G_OBEX_HDR_ID_SESSIONSEQ 0x93
+#define G_OBEX_HDR_ID_ACTION 0x94
+#define G_OBEX_HDR_ID_DESTNAME 0x15
+#define G_OBEX_HDR_ID_PERMISSIONS 0xd6
+#define G_OBEX_HDR_ID_SRM 0x97
+#define G_OBEX_HDR_ID_SRM_FLAGS 0x98
+
+typedef struct _GObexHeader GObexHeader;
+
+gboolean g_obex_header_get_unicode(GObexHeader *header, const char **str);
+gboolean g_obex_header_get_bytes(GObexHeader *header, const guint8 **val,
+ size_t *len);
+gboolean g_obex_header_get_uint8(GObexHeader *header, guint8 *val);
+gboolean g_obex_header_get_uint32(GObexHeader *header, guint32 *val);
+
+GObexHeader *g_obex_header_new_unicode(guint8 id, const char *str);
+GObexHeader *g_obex_header_new_bytes(guint8 id, void *data, size_t len,
+ GObexDataPolicy data_policy);
+GObexHeader *g_obex_header_new_uint8(guint8 id, guint8 val);
+GObexHeader *g_obex_header_new_uint32(guint8 id, guint32 val);
+
+guint8 g_obex_header_get_id(GObexHeader *header);
+guint16 g_obex_header_get_length(GObexHeader *header);
+
+size_t g_obex_header_encode(GObexHeader *header, void *hdr_ptr, size_t buf_len);
+GObexHeader *g_obex_header_decode(const void *data, size_t len,
+ GObexDataPolicy data_policy, size_t *parsed);
+void g_obex_header_free(GObexHeader *header);
+
+#endif /* __GOBEX_HEADER_H */
--- /dev/null
+/*
+ *
+ * OBEX library with GLib integration
+ *
+ * Copyright (C) 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <string.h>
+#include <errno.h>
+
+#include "gobex-packet.h"
+
+struct _GObexPacket {
+ guint8 opcode;
+ gboolean final;
+
+ GObexDataPolicy data_policy;
+
+ union {
+ void *buf; /* Non-header data */
+ const void *buf_ref; /* Reference to non-header data */
+ } data;
+ size_t data_len;
+
+ size_t hlen; /* Length of all encoded headers */
+ GSList *headers;
+};
+
+GObexHeader *g_obex_packet_get_header(GObexPacket *pkt, guint8 id)
+{
+ GSList *l;
+
+ for (l = pkt->headers; l != NULL; l = g_slist_next(l)) {
+ GObexHeader *hdr = l->data;
+
+ if (g_obex_header_get_id(hdr) == id)
+ return hdr;
+ }
+
+ return NULL;
+}
+
+guint8 g_obex_packet_get_operation(GObexPacket *pkt, gboolean *final)
+{
+ if (final)
+ *final = pkt->final;
+
+ return pkt->opcode;
+}
+
+gboolean g_obex_packet_add_header(GObexPacket *pkt, GObexHeader *header)
+{
+ pkt->headers = g_slist_append(pkt->headers, header);
+ pkt->hlen += g_obex_header_get_length(header);
+
+ return TRUE;
+}
+
+const void *g_obex_packet_get_data(GObexPacket *pkt, size_t *len)
+{
+ if (pkt->data_len == 0) {
+ *len = 0;
+ return NULL;
+ }
+
+ *len = pkt->data_len;
+
+ switch (pkt->data_policy) {
+ case G_OBEX_DATA_INHERIT:
+ case G_OBEX_DATA_COPY:
+ return pkt->data.buf;
+ case G_OBEX_DATA_REF:
+ return pkt->data.buf_ref;
+ }
+
+ g_assert_not_reached();
+}
+
+gboolean g_obex_packet_set_data(GObexPacket *pkt, const void *data, size_t len,
+ GObexDataPolicy data_policy)
+{
+ if (pkt->data.buf || pkt->data.buf_ref)
+ return FALSE;
+
+ pkt->data_policy = data_policy;
+ pkt->data_len = len;
+
+ switch (data_policy) {
+ case G_OBEX_DATA_COPY:
+ pkt->data.buf = g_memdup(data, len);
+ break;
+ case G_OBEX_DATA_REF:
+ pkt->data.buf_ref = data;
+ break;
+ case G_OBEX_DATA_INHERIT:
+ pkt->data.buf = (void *) data;
+ break;
+ }
+
+ return TRUE;
+}
+
+GObexPacket *g_obex_packet_new(guint8 opcode, gboolean final)
+{
+ GObexPacket *pkt;
+
+ pkt = g_new0(GObexPacket, 1);
+
+ pkt->opcode = opcode;
+ pkt->final = final;
+
+ pkt->data_policy = G_OBEX_DATA_COPY;
+
+ return pkt;
+}
+
+void g_obex_packet_free(GObexPacket *pkt)
+{
+ switch (pkt->data_policy) {
+ case G_OBEX_DATA_INHERIT:
+ case G_OBEX_DATA_COPY:
+ g_free(pkt->data.buf);
+ break;
+ case G_OBEX_DATA_REF:
+ break;
+ }
+
+ g_slist_foreach(pkt->headers, (GFunc) g_obex_header_free, NULL);
+ g_slist_free(pkt->headers);
+ g_free(pkt);
+}
+
+static gboolean parse_headers(GObexPacket *pkt, const void *data, size_t len,
+ GObexDataPolicy data_policy)
+{
+ const guint8 *buf = data;
+
+ while (len > 0) {
+ GObexHeader *header;
+ size_t parsed;
+
+ header = g_obex_header_decode(buf, len, data_policy, &parsed);
+ if (header == NULL)
+ return FALSE;
+
+ pkt->headers = g_slist_append(pkt->headers, header);
+
+ len -= parsed;
+ buf += parsed;
+ }
+
+ return TRUE;
+}
+
+static const guint8 *get_bytes(void *to, const guint8 *from, size_t count)
+{
+ memcpy(to, from, count);
+ return (from + count);
+}
+
+GObexPacket *g_obex_packet_decode(const void *data, size_t len,
+ size_t header_offset,
+ GObexDataPolicy data_policy)
+{
+ const guint8 *buf = data;
+ guint16 packet_len;
+ guint8 opcode;
+ GObexPacket *pkt;
+ gboolean final;
+
+ if (len < 3)
+ return NULL;
+
+ buf = get_bytes(&opcode, buf, sizeof(opcode));
+ buf = get_bytes(&packet_len, buf, sizeof(packet_len));
+
+ packet_len = g_ntohs(packet_len);
+ if (packet_len < len)
+ return NULL;
+
+ final = (opcode & G_OBEX_PACKET_FINAL) ? TRUE : FALSE;
+ opcode &= ~G_OBEX_PACKET_FINAL;
+
+ pkt = g_obex_packet_new(opcode, final);
+
+ if (header_offset == 0)
+ goto headers;
+
+ if (3 + header_offset < len)
+ goto failed;
+
+ if (data_policy == G_OBEX_DATA_INHERIT)
+ goto failed;
+
+ if (!g_obex_packet_set_data(pkt, buf, header_offset, data_policy))
+ goto failed;
+
+ buf += header_offset;
+
+headers:
+ if (!parse_headers(pkt, buf, len - (buf - (guint8 *) data),
+ data_policy))
+ goto failed;
+
+ return pkt;
+
+failed:
+ g_obex_packet_free(pkt);
+ return NULL;
+}
+
+ssize_t g_obex_packet_encode(GObexPacket *pkt, guint8 *buf, size_t len)
+{
+ size_t count;
+ guint16 pkt_len, u16;
+ GSList *l;
+
+ pkt_len = 3 + pkt->data_len + pkt->hlen;
+
+ if (pkt_len > len)
+ return -ENOBUFS;
+
+ buf[0] = pkt->opcode;
+ if (pkt->final)
+ buf[0] |= G_OBEX_PACKET_FINAL;
+
+ u16 = g_htons(pkt_len);
+ memcpy(&buf[1], &u16, sizeof(u16));
+
+ if (pkt->data_len > 0) {
+ if (pkt->data_policy == G_OBEX_DATA_REF)
+ memcpy(&buf[3], pkt->data.buf_ref, pkt->data_len);
+ else
+ memcpy(&buf[3], pkt->data.buf, pkt->data_len);
+ }
+
+ count = 3 + pkt->data_len;
+
+ for (l = pkt->headers; l != NULL; l = g_slist_next(l)) {
+ GObexHeader *hdr = l->data;
+ count += g_obex_header_encode(hdr, buf + count, len - count);
+ }
+
+ g_assert_cmpuint(count, ==, pkt_len);
+
+ return count;
+}
--- /dev/null
+/*
+ *
+ * OBEX library with GLib integration
+ *
+ * Copyright (C) 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __GOBEX_PACKET_H
+#define __GOBEX_PACKET_H
+
+#include <unistd.h>
+
+#include <glib.h>
+
+#include <gobex/gobex-defs.h>
+#include <gobex/gobex-header.h>
+
+/* Opcodes */
+#define G_OBEX_OP_CONNECT 0x00
+#define G_OBEX_OP_DISCONNECT 0x01
+#define G_OBEX_OP_PUT 0x02
+#define G_OBEX_OP_GET 0x03
+#define G_OBEX_OP_SETPATH 0x05
+#define G_OBEX_OP_SESSION 0x07
+#define G_OBEX_OP_ABORT 0x7f
+
+#define G_OBEX_PACKET_FINAL 0x80
+
+typedef struct _GObexPacket GObexPacket;
+
+GObexHeader *g_obex_packet_get_header(GObexPacket *pkt, guint8 id);
+guint8 g_obex_packet_get_operation(GObexPacket *pkt, gboolean *final);
+gboolean g_obex_packet_add_header(GObexPacket *pkt, GObexHeader *header);
+gboolean g_obex_packet_set_data(GObexPacket *pkt, const void *data, size_t len,
+ GObexDataPolicy data_policy);
+const void *g_obex_packet_get_data(GObexPacket *pkt, size_t *len);
+GObexPacket *g_obex_packet_new(guint8 opcode, gboolean final);
+void g_obex_packet_free(GObexPacket *pkt);
+
+GObexPacket *g_obex_packet_decode(const void *data, size_t len,
+ size_t header_offset,
+ GObexDataPolicy data_policy);
+ssize_t g_obex_packet_encode(GObexPacket *pkt, guint8 *buf, size_t len);
+
+#endif /* __GOBEX_PACKET_H */
#include <unistd.h>
#include <string.h>
-#include <errno.h>
#include "gobex.h"
#define G_OBEX_MINIMUM_MTU 255
#define G_OBEX_MAXIMUM_MTU 65535
-/* Header types */
-#define G_OBEX_HDR_TYPE_UNICODE (0 << 6)
-#define G_OBEX_HDR_TYPE_BYTES (1 << 6)
-#define G_OBEX_HDR_TYPE_UINT8 (2 << 6)
-#define G_OBEX_HDR_TYPE_UINT32 (3 << 6)
-
-#define G_OBEX_HDR_TYPE(id) ((id) & 0xc0)
-
-#define G_OBEX_FINAL 0x80
-
-struct _GObexHeader {
- guint8 id;
- gboolean extdata;
- size_t vlen; /* Length of value */
- size_t hlen; /* Length of full encoded header */
- union {
- char *string; /* UTF-8 converted from UTF-16 */
- guint8 *data; /* Own buffer */
- const guint8 *extdata; /* Reference to external buffer */
- guint8 u8;
- guint32 u32;
- } v;
-};
-
-struct _GObexPacket {
- guint8 opcode;
- gboolean final;
-
- GObexDataPolicy data_policy;
-
- union {
- void *buf; /* Non-header data */
- const void *buf_ref; /* Reference to non-header data */
- } data;
- size_t data_len;
-
- size_t hlen; /* Length of all encoded headers */
- GSList *headers;
-};
-
struct _GObex {
gint ref_count;
GIOChannel *io;
guint8 constants;
} __attribute__ ((packed));
-static glong utf8_to_utf16(gunichar2 **utf16, const char *utf8) {
- glong utf16_len;
- int i;
-
- if (*utf8 == '\0') {
- *utf16 = NULL;
- return 0;
- }
-
- *utf16 = g_utf8_to_utf16(utf8, -1, NULL, &utf16_len, NULL);
- if (*utf16 == NULL)
- return -1;
-
- /* g_utf8_to_utf16 produces host-byteorder UTF-16,
- * but OBEX requires network byteorder (big endian) */
- for (i = 0; i < utf16_len; i++)
- (*utf16)[i] = g_htons((*utf16)[i]);
-
- utf16_len = (utf16_len + 1) << 1;
-
- return utf16_len;
-}
-
-static guint8 *put_bytes(guint8 *to, const void *from, size_t count)
-{
- memcpy(to, from, count);
- return (to + count);
-}
-
-static const guint8 *get_bytes(void *to, const guint8 *from, size_t count)
-{
- memcpy(to, from, count);
- return (from + count);
-}
-
-size_t g_obex_header_encode(GObexHeader *header, void *buf, size_t buf_len)
-{
- guint8 *ptr = buf;
- guint16 u16;
- guint32 u32;
- gunichar2 *utf16;
- glong utf16_len;
-
- if (buf_len < header->hlen)
- return 0;
-
- ptr = put_bytes(ptr, &header->id, sizeof(header->id));
-
- switch (G_OBEX_HDR_TYPE(header->id)) {
- case G_OBEX_HDR_TYPE_UNICODE:
- utf16_len = utf8_to_utf16(&utf16, header->v.string);
- if (utf16_len < 0 || (guint16) utf16_len > buf_len)
- return 0;
- g_assert_cmpuint(utf16_len + 3, ==, header->hlen);
- u16 = g_htons(utf16_len + 3);
- ptr = put_bytes(ptr, &u16, sizeof(u16));
- ptr = put_bytes(ptr, utf16, utf16_len);
- g_free(utf16);
- break;
- case G_OBEX_HDR_TYPE_BYTES:
- u16 = g_htons(header->hlen);
- ptr = put_bytes(ptr, &u16, sizeof(u16));
- if (header->extdata)
- ptr = put_bytes(ptr, header->v.extdata, header->vlen);
- else
- ptr = put_bytes(ptr, header->v.data, header->vlen);
- break;
- case G_OBEX_HDR_TYPE_UINT8:
- *ptr = header->v.u8;
- break;
- case G_OBEX_HDR_TYPE_UINT32:
- u32 = g_htonl(header->v.u32);
- ptr = put_bytes(ptr, &u32, sizeof(u32));
- break;
- default:
- g_assert_not_reached();
- }
-
- return header->hlen;
-}
-
-GObexHeader *g_obex_header_decode(const void *data, size_t len,
- GObexDataPolicy data_policy, size_t *parsed)
-{
- GObexHeader *header;
- const guint8 *ptr = data;
- guint16 hdr_len;
- size_t str_len;
-
- if (len < 2)
- return NULL;
-
- header = g_new0(GObexHeader, 1);
-
- ptr = get_bytes(&header->id, ptr, sizeof(header->id));
-
- switch (G_OBEX_HDR_TYPE(header->id)) {
- case G_OBEX_HDR_TYPE_UNICODE:
- if (len < 3)
- goto failed;
- ptr = get_bytes(&hdr_len, ptr, sizeof(hdr_len));
- hdr_len = g_ntohs(hdr_len);
- if (hdr_len > len || hdr_len < 5)
- goto failed;
-
- header->v.string = g_convert((const char *) ptr, hdr_len - 5,
- "UTF8", "UTF16BE",
- NULL, &str_len, NULL);
- if (header->v.string == NULL)
- goto failed;
-
- header->vlen = (size_t) str_len;
- header->hlen = hdr_len;
-
- *parsed = hdr_len;
-
- break;
- case G_OBEX_HDR_TYPE_BYTES:
- if (len < 3)
- goto failed;
- ptr = get_bytes(&hdr_len, ptr, sizeof(hdr_len));
- hdr_len = g_ntohs(hdr_len);
- if (hdr_len > len)
- goto failed;
-
- header->vlen = hdr_len - 3;
- header->hlen = hdr_len;
-
- switch (data_policy) {
- case G_OBEX_DATA_COPY:
- header->v.data = g_memdup(ptr, header->vlen);
- break;
- case G_OBEX_DATA_REF:
- header->extdata = TRUE;
- header->v.extdata = ptr;
- break;
- default:
- goto failed;
- }
-
- *parsed = hdr_len;
-
- break;
- case G_OBEX_HDR_TYPE_UINT8:
- header->vlen = 1;
- header->hlen = 2;
- header->v.u8 = *ptr;
- *parsed = 2;
- break;
- case G_OBEX_HDR_TYPE_UINT32:
- if (len < 5)
- goto failed;
- header->vlen = 4;
- header->hlen = 5;
- ptr = get_bytes(&header->v.u32, ptr, sizeof(header->v.u32));
- header->v.u32 = g_ntohl(header->v.u32);
- *parsed = 5;
- break;
- default:
- g_assert_not_reached();
- }
-
- return header;
-
-failed:
- g_obex_header_free(header);
- return NULL;
-}
-
-void g_obex_header_free(GObexHeader *header)
-{
- switch (G_OBEX_HDR_TYPE(header->id)) {
- case G_OBEX_HDR_TYPE_UNICODE:
- g_free(header->v.string);
- break;
- case G_OBEX_HDR_TYPE_BYTES:
- if (!header->extdata)
- g_free(header->v.data);
- break;
- case G_OBEX_HDR_TYPE_UINT8:
- case G_OBEX_HDR_TYPE_UINT32:
- break;
- default:
- g_assert_not_reached();
- }
-
- g_free(header);
-}
-
-gboolean g_obex_header_get_unicode(GObexHeader *header, const char **str)
-{
- if (G_OBEX_HDR_TYPE(header->id) != G_OBEX_HDR_TYPE_UNICODE)
- return FALSE;
-
- *str = header->v.string;
-
- return TRUE;
-}
-
-gboolean g_obex_header_get_bytes(GObexHeader *header, const guint8 **val,
- size_t *len)
-{
- if (G_OBEX_HDR_TYPE(header->id) != G_OBEX_HDR_TYPE_BYTES)
- return FALSE;
-
- *len = header->vlen;
-
- if (header->extdata)
- *val = header->v.extdata;
- else
- *val = header->v.data;
-
- return TRUE;
-}
-
-gboolean g_obex_header_get_uint8(GObexHeader *header, guint8 *val)
-{
- if (G_OBEX_HDR_TYPE(header->id) != G_OBEX_HDR_TYPE_UINT8)
- return FALSE;
-
- *val = header->v.u8;
-
- return TRUE;
-}
-
-gboolean g_obex_header_get_uint32(GObexHeader *header, guint32 *val)
-{
- if (G_OBEX_HDR_TYPE(header->id) != G_OBEX_HDR_TYPE_UINT32)
- return FALSE;
-
- *val = header->v.u32;
-
- return TRUE;
-}
-
-GObexHeader *g_obex_header_new_unicode(guint8 id, const char *str)
-{
- GObexHeader *header;
- size_t len;
-
- if (G_OBEX_HDR_TYPE(id) != G_OBEX_HDR_TYPE_UNICODE)
- return NULL;
-
- header = g_new0(GObexHeader, 1);
-
- header->id = id;
-
- len = g_utf8_strlen(str, -1);
-
- header->vlen = len;
- header->hlen = 3 + ((len + 1) * 2);
- header->v.string = g_strdup(str);
-
- return header;
-}
-
-GObexHeader *g_obex_header_new_bytes(guint8 id, void *data, size_t len,
- GObexDataPolicy data_policy)
-{
- GObexHeader *header;
-
- if (G_OBEX_HDR_TYPE(id) != G_OBEX_HDR_TYPE_BYTES)
- return NULL;
-
- header = g_new0(GObexHeader, 1);
-
- header->id = id;
- header->vlen = len;
- header->hlen = len + 3;
-
- switch (data_policy) {
- case G_OBEX_DATA_INHERIT:
- header->v.data = data;
- break;
- case G_OBEX_DATA_COPY:
- header->v.data = g_memdup(data, len);
- break;
- case G_OBEX_DATA_REF:
- header->extdata = TRUE;
- header->v.extdata = data;
- break;
- }
-
- return header;
-}
-
-GObexHeader *g_obex_header_new_uint8(guint8 id, guint8 val)
-{
- GObexHeader *header;
-
- if (G_OBEX_HDR_TYPE(id) != G_OBEX_HDR_TYPE_UINT8)
- return NULL;
-
- header = g_new0(GObexHeader, 1);
-
- header->id = id;
- header->vlen = 1;
- header->hlen = 2;
- header->v.u8 = val;
-
- return header;
-}
-
-GObexHeader *g_obex_header_new_uint32(guint8 id, guint32 val)
-{
- GObexHeader *header;
-
- if (G_OBEX_HDR_TYPE(id) != G_OBEX_HDR_TYPE_UINT32)
- return NULL;
-
- header = g_new0(GObexHeader, 1);
-
- header->id = id;
- header->vlen = 4;
- header->hlen = 5;
- header->v.u32 = val;
-
- return header;
-}
-
-GObexHeader *g_obex_packet_get_header(GObexPacket *pkt, guint8 id)
-{
- GSList *l;
-
- for (l = pkt->headers; l != NULL; l = g_slist_next(l)) {
- GObexHeader *hdr = l->data;
-
- if (hdr->id == id)
- return hdr;
- }
-
- return NULL;
-}
-
-guint8 g_obex_packet_get_operation(GObexPacket *pkt, gboolean *final)
-{
- if (final)
- *final = pkt->final;
-
- return pkt->opcode;
-}
-
-gboolean g_obex_packet_add_header(GObexPacket *pkt, GObexHeader *header)
-{
- pkt->headers = g_slist_append(pkt->headers, header);
- pkt->hlen += header->hlen;
-
- return TRUE;
-}
-
-const void *g_obex_packet_get_data(GObexPacket *pkt, size_t *len)
-{
- if (pkt->data_len == 0) {
- *len = 0;
- return NULL;
- }
-
- *len = pkt->data_len;
-
- switch (pkt->data_policy) {
- case G_OBEX_DATA_INHERIT:
- case G_OBEX_DATA_COPY:
- return pkt->data.buf;
- case G_OBEX_DATA_REF:
- return pkt->data.buf_ref;
- }
-
- g_assert_not_reached();
-}
-
-gboolean g_obex_packet_set_data(GObexPacket *pkt, const void *data, size_t len,
- GObexDataPolicy data_policy)
-{
- if (pkt->data.buf || pkt->data.buf_ref)
- return FALSE;
-
- pkt->data_policy = data_policy;
- pkt->data_len = len;
-
- switch (data_policy) {
- case G_OBEX_DATA_COPY:
- pkt->data.buf = g_memdup(data, len);
- break;
- case G_OBEX_DATA_REF:
- pkt->data.buf_ref = data;
- break;
- case G_OBEX_DATA_INHERIT:
- pkt->data.buf = (void *) data;
- break;
- }
-
- return TRUE;
-}
-
-GObexPacket *g_obex_packet_new(guint8 opcode, gboolean final)
-{
- GObexPacket *pkt;
-
- pkt = g_new0(GObexPacket, 1);
-
- pkt->opcode = opcode;
- pkt->final = final;
-
- pkt->data_policy = G_OBEX_DATA_COPY;
-
- return pkt;
-}
-
-void g_obex_packet_free(GObexPacket *pkt)
-{
- switch (pkt->data_policy) {
- case G_OBEX_DATA_INHERIT:
- case G_OBEX_DATA_COPY:
- g_free(pkt->data.buf);
- break;
- case G_OBEX_DATA_REF:
- break;
- }
-
- g_slist_foreach(pkt->headers, (GFunc) g_obex_header_free, NULL);
- g_slist_free(pkt->headers);
- g_free(pkt);
-}
-
static ssize_t req_header_offset(guint8 opcode)
{
switch (opcode) {
}
}
-static gboolean parse_headers(GObexPacket *pkt, const void *data, size_t len,
- GObexDataPolicy data_policy)
-{
- const guint8 *buf = data;
-
- while (len > 0) {
- GObexHeader *header;
- size_t parsed;
-
- header = g_obex_header_decode(buf, len, data_policy, &parsed);
- if (header == NULL)
- return FALSE;
-
- pkt->headers = g_slist_append(pkt->headers, header);
-
- len -= parsed;
- buf += parsed;
- }
-
- return TRUE;
-}
-
-GObexPacket *g_obex_packet_decode(const void *data, size_t len,
- size_t header_offset,
- GObexDataPolicy data_policy)
-{
- const guint8 *buf = data;
- guint16 packet_len;
- guint8 opcode;
- GObexPacket *pkt;
- gboolean final;
-
- if (len < 3)
- return NULL;
-
- buf = get_bytes(&opcode, buf, sizeof(opcode));
- buf = get_bytes(&packet_len, buf, sizeof(packet_len));
-
- packet_len = g_ntohs(packet_len);
- if (packet_len < len)
- return NULL;
-
- final = (opcode & G_OBEX_FINAL) ? TRUE : FALSE;
- opcode &= ~G_OBEX_FINAL;
-
- pkt = g_obex_packet_new(opcode, final);
-
- if (header_offset == 0)
- goto headers;
-
- if (3 + header_offset < len)
- goto failed;
-
- if (data_policy == G_OBEX_DATA_INHERIT)
- goto failed;
-
- if (!g_obex_packet_set_data(pkt, buf, header_offset, data_policy))
- goto failed;
-
- buf += header_offset;
-
-headers:
- if (!parse_headers(pkt, buf, len - (buf - (guint8 *) data),
- data_policy))
- goto failed;
-
- return pkt;
-
-failed:
- g_obex_packet_free(pkt);
- return NULL;
-}
-
-static ssize_t g_obex_packet_encode(GObexPacket *pkt, uint8_t *buf, size_t len)
-{
- size_t count;
- guint16 pkt_len, u16;
- GSList *l;
-
- pkt_len = 3 + pkt->data_len + pkt->hlen;
-
- if (pkt_len > len)
- return -ENOBUFS;
-
- buf[0] = pkt->opcode;
- if (pkt->final)
- buf[0] |= G_OBEX_FINAL;
-
- u16 = g_htons(pkt_len);
- memcpy(&buf[1], &u16, sizeof(u16));
-
- if (pkt->data_len > 0) {
- if (pkt->data_policy == G_OBEX_DATA_REF)
- memcpy(&buf[3], pkt->data.buf_ref, pkt->data_len);
- else
- memcpy(&buf[3], pkt->data.buf, pkt->data_len);
- }
-
- count = 3 + pkt->data_len;
-
- for (l = pkt->headers; l != NULL; l = g_slist_next(l)) {
- GObexHeader *hdr = l->data;
- count += g_obex_header_encode(hdr, buf + count, len - count);
- }
-
- g_assert_cmpuint(count, ==, pkt_len);
-
- return count;
-}
-
static void pending_pkt_free(struct pending_pkt *p)
{
g_obex_packet_free(p->pkt);
guint8 opcode = g_obex_packet_get_operation(p->pkt, NULL);
header_offset = req_header_offset(opcode);
} else {
- guint8 opcode = obex->rx_buf[0] & ~G_OBEX_FINAL;
+ guint8 opcode = obex->rx_buf[0] & ~G_OBEX_PACKET_FINAL;
header_offset = rsp_header_offset(opcode);
}
#ifndef __GOBEX_H
#define __GOBEX_H
-#include <stdint.h>
#include <glib.h>
-/* Opcodes */
-#define G_OBEX_OP_CONNECT 0x00
-#define G_OBEX_OP_DISCONNECT 0x01
-#define G_OBEX_OP_PUT 0x02
-#define G_OBEX_OP_GET 0x03
-#define G_OBEX_OP_SETPATH 0x05
-#define G_OBEX_OP_SESSION 0x07
-#define G_OBEX_OP_ABORT 0x7f
-
-/* Header ID's */
-#define G_OBEX_HDR_ID_COUNT 0xc0
-#define G_OBEX_HDR_ID_NAME 0x01
-#define G_OBEX_HDR_ID_TYPE 0x42
-#define G_OBEX_HDR_ID_LENGTH 0xc3
-#define G_OBEX_HDR_ID_TIME 0x44
-#define G_OBEX_HDR_ID_DESCRIPTION 0x05
-#define G_OBEX_HDR_ID_TARGET 0x46
-#define G_OBEX_HDR_ID_HTTP 0x47
-#define G_OBEX_HDR_ID_BODY 0x48
-#define G_OBEX_HDR_ID_BODY_END 0x49
-#define G_OBEX_HDR_ID_WHO 0x4a
-#define G_OBEX_HDR_ID_CONNECTION 0xcb
-#define G_OBEX_HDR_ID_APPARAM 0x4c
-#define G_OBEX_HDR_ID_AUTHCHAL 0x4d
-#define G_OBEX_HDR_ID_AUTHRESP 0x4e
-#define G_OBEX_HDR_ID_CREATOR 0xcf
-#define G_OBEX_HDR_ID_WANUUID 0x50
-#define G_OBEX_HDR_ID_OBJECTCLASS 0x51
-#define G_OBEX_HDR_ID_SESSIONPARAM 0x52
-#define G_OBEX_HDR_ID_SESSIONSEQ 0x93
-#define G_OBEX_HDR_ID_ACTION 0x94
-#define G_OBEX_HDR_ID_DESTNAME 0x15
-#define G_OBEX_HDR_ID_PERMISSIONS 0xd6
-#define G_OBEX_HDR_ID_SRM 0x97
-#define G_OBEX_HDR_ID_SRM_FLAGS 0x98
-
-typedef enum {
- G_OBEX_DATA_INHERIT,
- G_OBEX_DATA_COPY,
- G_OBEX_DATA_REF,
-} GObexDataPolicy;
+#include <gobex/gobex-packet.h>
typedef enum {
G_OBEX_TRANSPORT_STREAM,
} GObexTransportType;
typedef struct _GObex GObex;
-typedef struct _GObexPacket GObexPacket;
-typedef struct _GObexHeader GObexHeader;
typedef void (*GObexRequestFunc) (GObex *obex, GObexPacket *req,
gpointer user_data);
typedef void (*GObexResponseFunc) (GObex *obex, GError *err, GObexPacket *rsp,
gpointer user_data);
-gboolean g_obex_header_get_unicode(GObexHeader *header, const char **str);
-gboolean g_obex_header_get_bytes(GObexHeader *header, const guint8 **val,
- size_t *len);
-gboolean g_obex_header_get_uint8(GObexHeader *header, guint8 *val);
-gboolean g_obex_header_get_uint32(GObexHeader *header, guint32 *val);
-
-GObexHeader *g_obex_header_new_unicode(guint8 id, const char *str);
-GObexHeader *g_obex_header_new_bytes(guint8 id, void *data, size_t len,
- GObexDataPolicy data_policy);
-GObexHeader *g_obex_header_new_uint8(guint8 id, guint8 val);
-GObexHeader *g_obex_header_new_uint32(guint8 id, guint32 val);
-
-size_t g_obex_header_encode(GObexHeader *header, void *hdr_ptr, size_t buf_len);
-GObexHeader *g_obex_header_decode(const void *data, size_t len,
- GObexDataPolicy data_policy, size_t *parsed);
-void g_obex_header_free(GObexHeader *header);
-
-GObexHeader *g_obex_packet_get_header(GObexPacket *pkt, guint8 id);
-guint8 g_obex_packet_get_operation(GObexPacket *pkt, gboolean *final);
-gboolean g_obex_packet_add_header(GObexPacket *pkt, GObexHeader *header);
-gboolean g_obex_packet_set_data(GObexPacket *pkt, const void *data, size_t len,
- GObexDataPolicy data_policy);
-const void *g_obex_packet_get_data(GObexPacket *pkt, size_t *len);
-GObexPacket *g_obex_packet_new(guint8 opcode, gboolean final);
-void g_obex_packet_free(GObexPacket *pkt);
-
-GObexPacket *g_obex_packet_decode(const void *data, size_t len,
- size_t header_offset,
- GObexDataPolicy data_policy);
-
gboolean g_obex_send(GObex *obex, GObexPacket *pkt);
guint g_obex_send_req(GObex *obex, GObexPacket *req, GObexResponseFunc func,
#include <errno.h>
#include <unistd.h>
#include <string.h>
+#include <stdint.h>
#include <gobex/gobex.h>