diff options
-rw-r--r-- | gobex/gobex.c | 131 | ||||
-rw-r--r-- | gobex/gobex.h | 3 | ||||
-rw-r--r-- | unit/test-gobex.c | 13 |
3 files changed, 147 insertions, 0 deletions
diff --git a/gobex/gobex.c b/gobex/gobex.c index 428fbda41..3c70337ec 100644 --- a/gobex/gobex.c +++ b/gobex/gobex.c @@ -19,6 +19,7 @@ * */ +#include <unistd.h> #include <string.h> #include "gobex.h" @@ -47,6 +48,15 @@ struct _GObexHeader { struct _GObexRequest { guint8 opcode; + + GObexDataPolicy data_policy; + + union { + void *data; /* Non-header data */ + const void *data_ref; /* Reference to non-header data */ + } req; + size_t req_data_len; + size_t hlen; /* Length of all encoded headers */ GSList *headers; }; @@ -58,6 +68,17 @@ struct _GObex { GQueue *req_queue; }; +struct connect_data { + guint8 version; + guint8 flags; + guint16 mtu; +} __attribute__ ((packed)); + +struct setpath_data { + guint8 flags; + guint8 constants; +} __attribute__ ((packed)); + static glong utf8_to_utf16(gunichar2 **utf16, const char *utf8) { glong utf16_len; int i; @@ -348,16 +369,126 @@ GObexRequest *g_obex_request_new(guint8 opcode) req->opcode = opcode; + req->data_policy = G_OBEX_DATA_COPY; + return req; } void g_obex_request_free(GObexRequest *req) { + switch (req->data_policy) { + case G_OBEX_DATA_INHERIT: + case G_OBEX_DATA_COPY: + g_free(req->req.data); + break; + case G_OBEX_DATA_REF: + break; + } + g_slist_foreach(req->headers, (GFunc) g_obex_header_free, NULL); g_slist_free(req->headers); g_free(req); } +static ssize_t get_header_offset(guint8 opcode) +{ + switch (opcode) { + case G_OBEX_OP_CONNECT: + return sizeof(struct connect_data); + case G_OBEX_OP_SETPATH: + return sizeof(struct setpath_data); + case G_OBEX_OP_DISCONNECT: + case G_OBEX_OP_PUT: + case G_OBEX_OP_GET: + case G_OBEX_OP_SESSION: + case G_OBEX_OP_ABORT: + return 0; + default: + return -1; + } +} + +static gboolean parse_headers(GObexRequest *req, 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; + + req->headers = g_slist_append(req->headers, header); + + len -= parsed; + buf += parsed; + } + + return TRUE; +} + +GObexRequest *g_obex_request_decode(const void *data, size_t len, + GObexDataPolicy data_policy) +{ + const guint8 *buf = data; + guint16 packet_len; + guint8 opcode; + ssize_t header_offset; + GObexRequest *req; + + 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; + + header_offset = get_header_offset(opcode); + if (header_offset < 0) + return NULL; + + req = g_obex_request_new(opcode); + + req->data_policy = data_policy; + + if (header_offset == 0) + goto headers; + + if (3 + header_offset < (ssize_t) len) + goto failed; + + req->req_data_len = header_offset; + switch (data_policy) { + case G_OBEX_DATA_COPY: + req->req.data = g_malloc(header_offset); + buf = get_bytes(req->req.data, buf, header_offset); + break; + case G_OBEX_DATA_REF: + req->req.data_ref = buf; + buf += header_offset; + break; + default: + goto failed; + } + +headers: + if (!parse_headers(req, buf, len - (buf - (guint8 *) data), + data_policy)) + goto failed; + + return req; + +failed: + g_obex_request_free(req); + return NULL; +} + gboolean g_obex_send(GObex *obex, GObexRequest *req) { if (obex == NULL || req == NULL) diff --git a/gobex/gobex.h b/gobex/gobex.h index ae34d4878..3fa243997 100644 --- a/gobex/gobex.h +++ b/gobex/gobex.h @@ -88,6 +88,9 @@ gboolean g_obex_request_add_header(GObexRequest *req, GObexHeader *header); GObexRequest *g_obex_request_new(guint8 opcode); void g_obex_request_free(GObexRequest *req); +GObexRequest *g_obex_request_decode(const void *data, size_t len, + GObexDataPolicy data_policy); + gboolean g_obex_send(GObex *obex, GObexRequest *req); GObex *g_obex_new(GIOChannel *io); diff --git a/unit/test-gobex.c b/unit/test-gobex.c index 8504a7eab..ddbf9ac0d 100644 --- a/unit/test-gobex.c +++ b/unit/test-gobex.c @@ -149,6 +149,17 @@ static void test_header_uint32(void) g_obex_header_free(header); } +static void test_decode_req(void) +{ + GObexRequest *req; + uint8_t buf[] = { G_OBEX_OP_PUT, 0x00, 0x03 }; + + req = g_obex_request_decode(buf, sizeof(buf), G_OBEX_DATA_REF); + g_assert(req != NULL); + + g_obex_request_free(req); +} + static void parse_and_encode(uint8_t *buf, size_t buf_len) { GObexHeader *header; @@ -411,6 +422,8 @@ int main(int argc, char *argv[]) g_test_add_func("/gobex/test_header_uint8", test_header_uint8); g_test_add_func("/gobex/test_header_uint32", test_header_uint32); + g_test_add_func("/gobex/test_decode_req", test_decode_req); + g_test_run(); return 0; |