summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gobex/gobex.c131
-rw-r--r--gobex/gobex.h3
-rw-r--r--unit/test-gobex.c13
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;