From aa1b87b6d8a8d51632ab31b637d85183944ac3a8 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 29 Jun 2011 13:15:05 +0300 Subject: [PATCH] gobex: Add initial GError support --- gobex/gobex-defs.c | 29 ++++++++++++++++++++++ gobex/gobex-defs.h | 10 ++++++++ gobex/gobex-header.c | 46 ++++++++++++++++++++++++++++------ gobex/gobex-header.h | 3 ++- gobex/gobex-packet.c | 40 ++++++++++++++++++++---------- gobex/gobex-packet.h | 3 ++- gobex/gobex.c | 35 ++++++++++++++------------ unit/test-gobex-header.c | 53 +++++++++++++++++++++++----------------- unit/test-gobex-packet.c | 10 +++++--- 9 files changed, 165 insertions(+), 64 deletions(-) create mode 100644 gobex/gobex-defs.c diff --git a/gobex/gobex-defs.c b/gobex/gobex-defs.c new file mode 100644 index 000000000..f1f3b38ff --- /dev/null +++ b/gobex/gobex-defs.c @@ -0,0 +1,29 @@ +/* + * + * 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 + +#include "gobex-defs.h" + +GQuark g_obex_error_quark(void) +{ + return g_quark_from_static_string("g-obex-error-quark"); +} diff --git a/gobex/gobex-defs.h b/gobex/gobex-defs.h index ad8b046fd..76b274f24 100644 --- a/gobex/gobex-defs.h +++ b/gobex/gobex-defs.h @@ -22,10 +22,20 @@ #ifndef __GOBEX_DEFS_H #define __GOBEX_DEFS_H +#include + typedef enum { G_OBEX_DATA_INHERIT, G_OBEX_DATA_COPY, G_OBEX_DATA_REF, } GObexDataPolicy; +typedef enum { + G_OBEX_ERROR_PARSE_ERROR, + G_OBEX_ERROR_INVALID_ARGS, +} GObexError; + +#define G_OBEX_ERROR g_obex_error_quark() +GQuark g_obex_error_quark(void); + #endif /* __GOBEX_DEFS_H */ diff --git a/gobex/gobex-header.c b/gobex/gobex-header.c index 949e48a7d..72ea5defd 100644 --- a/gobex/gobex-header.c +++ b/gobex/gobex-header.c @@ -127,15 +127,20 @@ gsize g_obex_header_encode(GObexHeader *header, void *buf, gsize buf_len) } GObexHeader *g_obex_header_decode(const void *data, gsize len, - GObexDataPolicy data_policy, gsize *parsed) + GObexDataPolicy data_policy, gsize *parsed, + GError **err) { GObexHeader *header; const guint8 *ptr = data; guint16 hdr_len; gsize str_len; + GError *conv_err = NULL; - if (len < 2) + if (len < 2) { + g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR, + "Too short header in packet"); return NULL; + } header = g_new0(GObexHeader, 1); @@ -147,14 +152,24 @@ GObexHeader *g_obex_header_decode(const void *data, gsize len, goto failed; ptr = get_bytes(&hdr_len, ptr, sizeof(hdr_len)); hdr_len = g_ntohs(hdr_len); - if (hdr_len > len || hdr_len < 5) + if (hdr_len > len || hdr_len < 5) { + g_set_error(err, G_OBEX_ERROR, + G_OBEX_ERROR_PARSE_ERROR, + "Invalid unicode header length"); goto failed; + } header->v.string = g_convert((const char *) ptr, hdr_len - 5, "UTF8", "UTF16BE", - NULL, &str_len, NULL); - if (header->v.string == NULL) + NULL, &str_len, &conv_err); + if (header->v.string == NULL) { + g_set_error(err, G_OBEX_ERROR, + G_OBEX_ERROR_PARSE_ERROR, + "Unicode conversion failed: %s", + conv_err->message); + g_error_free(conv_err); goto failed; + } header->vlen = (gsize) str_len; header->hlen = hdr_len; @@ -163,12 +178,20 @@ GObexHeader *g_obex_header_decode(const void *data, gsize len, break; case G_OBEX_HDR_TYPE_BYTES: - if (len < 3) + if (len < 3) { + g_set_error(err, G_OBEX_ERROR, + G_OBEX_ERROR_PARSE_ERROR, + "Too short byte array header"); goto failed; + } ptr = get_bytes(&hdr_len, ptr, sizeof(hdr_len)); hdr_len = g_ntohs(hdr_len); - if (hdr_len > len) + if (hdr_len > len) { + g_set_error(err, G_OBEX_ERROR, + G_OBEX_ERROR_PARSE_ERROR, + "Too long byte array header"); goto failed; + } header->vlen = hdr_len - 3; header->hlen = hdr_len; @@ -182,6 +205,9 @@ GObexHeader *g_obex_header_decode(const void *data, gsize len, header->v.extdata = ptr; break; default: + g_set_error(err, G_OBEX_ERROR, + G_OBEX_ERROR_INVALID_ARGS, + "Invalid data policy"); goto failed; } @@ -195,8 +221,12 @@ GObexHeader *g_obex_header_decode(const void *data, gsize len, *parsed = 2; break; case G_OBEX_HDR_TYPE_UINT32: - if (len < 5) + if (len < 5) { + g_set_error(err, G_OBEX_ERROR, + G_OBEX_ERROR_PARSE_ERROR, + "Too short uint32 header"); goto failed; + } header->vlen = 4; header->hlen = 5; ptr = get_bytes(&header->v.u32, ptr, sizeof(header->v.u32)); diff --git a/gobex/gobex-header.h b/gobex/gobex-header.h index b5b91007e..1df7f148d 100644 --- a/gobex/gobex-header.h +++ b/gobex/gobex-header.h @@ -72,7 +72,8 @@ guint16 g_obex_header_get_length(GObexHeader *header); gsize g_obex_header_encode(GObexHeader *header, void *hdr_ptr, gsize buf_len); GObexHeader *g_obex_header_decode(const void *data, gsize len, - GObexDataPolicy data_policy, gsize *parsed); + GObexDataPolicy data_policy, gsize *parsed, + GError **err); void g_obex_header_free(GObexHeader *header); #endif /* __GOBEX_HEADER_H */ diff --git a/gobex/gobex-packet.c b/gobex/gobex-packet.c index 12acb70f3..957e1cc39 100644 --- a/gobex/gobex-packet.c +++ b/gobex/gobex-packet.c @@ -145,7 +145,8 @@ void g_obex_packet_free(GObexPacket *pkt) } static gboolean parse_headers(GObexPacket *pkt, const void *data, gsize len, - GObexDataPolicy data_policy) + GObexDataPolicy data_policy, + GError **err) { const guint8 *buf = data; @@ -153,7 +154,8 @@ static gboolean parse_headers(GObexPacket *pkt, const void *data, gsize len, GObexHeader *header; gsize parsed; - header = g_obex_header_decode(buf, len, data_policy, &parsed); + header = g_obex_header_decode(buf, len, data_policy, &parsed, + err); if (header == NULL) return FALSE; @@ -174,7 +176,8 @@ static const guint8 *get_bytes(void *to, const guint8 *from, gsize count) GObexPacket *g_obex_packet_decode(const void *data, gsize len, gsize header_offset, - GObexDataPolicy data_policy) + GObexDataPolicy data_policy, + GError **err) { const guint8 *buf = data; guint16 packet_len; @@ -182,15 +185,28 @@ GObexPacket *g_obex_packet_decode(const void *data, gsize len, GObexPacket *pkt; gboolean final; - if (len < 3) + if (data_policy == G_OBEX_DATA_INHERIT) { + g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_INVALID_ARGS, + "Invalid data policy"); + return NULL; + } + + if (len < 3) { + g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR, + "Not enough data to decode packet"); 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) + if (packet_len != len) { + g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR, + "Incorrect packet length (%u != %zu)", + packet_len, len); return NULL; + } final = (opcode & G_OBEX_PACKET_FINAL) ? TRUE : FALSE; opcode &= ~G_OBEX_PACKET_FINAL; @@ -200,20 +216,18 @@ GObexPacket *g_obex_packet_decode(const void *data, gsize len, 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)) + if (3 + header_offset < len) { + g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR, + "Too short packet"); goto failed; + } + g_obex_packet_set_data(pkt, buf, header_offset, data_policy); buf += header_offset; headers: if (!parse_headers(pkt, buf, len - (buf - (guint8 *) data), - data_policy)) + data_policy, err)) goto failed; return pkt; diff --git a/gobex/gobex-packet.h b/gobex/gobex-packet.h index 908efac3d..38a8ff280 100644 --- a/gobex/gobex-packet.h +++ b/gobex/gobex-packet.h @@ -51,7 +51,8 @@ void g_obex_packet_free(GObexPacket *pkt); GObexPacket *g_obex_packet_decode(const void *data, gsize len, gsize header_offset, - GObexDataPolicy data_policy); + GObexDataPolicy data_policy, + GError **err); gssize g_obex_packet_encode(GObexPacket *pkt, guint8 *buf, gsize len); #endif /* __GOBEX_PACKET_H */ diff --git a/gobex/gobex.c b/gobex/gobex.c index be65feac2..5b7739904 100644 --- a/gobex/gobex.c +++ b/gobex/gobex.c @@ -273,21 +273,24 @@ static void parse_connect_data(GObex *obex, GObexPacket *pkt) obex->tx_buf = g_realloc(obex->tx_buf, obex->tx_mtu); } -static void handle_response(GObex *obex, GObexPacket *rsp) +static void handle_response(GObex *obex, GError *err, GObexPacket *rsp) { struct pending_pkt *p = obex->pending_req; - if (g_obex_packet_get_operation(p->pkt, NULL) == G_OBEX_OP_CONNECT) - parse_connect_data(obex, rsp); + if (rsp != NULL) { + guint8 op = g_obex_packet_get_operation(p->pkt, NULL); + if (op == G_OBEX_OP_CONNECT) + parse_connect_data(obex, rsp); + } if (p->rsp_func) - p->rsp_func(obex, NULL, rsp, p->rsp_data); + p->rsp_func(obex, err, rsp, p->rsp_data); pending_pkt_free(p); obex->pending_req = NULL; } -static void handle_request(GObex *obex, GObexPacket *req) +static void handle_request(GObex *obex, GError *err, GObexPacket *req) { if (g_obex_packet_get_operation(req, NULL) == G_OBEX_OP_CONNECT) parse_connect_data(obex, req); @@ -296,12 +299,14 @@ static void handle_request(GObex *obex, GObexPacket *req) obex->req_func(obex, req, obex->req_func_data); } -static gboolean g_obex_handle_packet(GObex *obex, GObexPacket *pkt) +static gboolean g_obex_handle_packet(GObex *obex, GError *err, GObexPacket *pkt) { if (obex->pending_req) - handle_response(obex, pkt); - else - handle_request(obex, pkt); + handle_response(obex, err, pkt); + else if (pkt != NULL) + handle_request(obex, err, pkt); + + /* FIXME: Application callback needed for err != NULL? */ return TRUE; } @@ -361,6 +366,7 @@ static gboolean incoming_data(GIOChannel *io, GIOCondition cond, GObex *obex = user_data; GObexPacket *pkt; ssize_t header_offset; + GError *err = NULL; if (cond & G_IO_NVAL) return FALSE; @@ -387,13 +393,12 @@ static gboolean incoming_data(GIOChannel *io, GIOCondition cond, goto failed; pkt = g_obex_packet_decode(obex->rx_buf, obex->rx_data, header_offset, - G_OBEX_DATA_REF); - if (pkt == NULL) { - /* FIXME: Handle decoding error */ - } else { - g_obex_handle_packet(obex, pkt); + G_OBEX_DATA_REF, &err); + + g_obex_handle_packet(obex, err, pkt); + + if (pkt != NULL) g_obex_packet_free(pkt); - } obex->rx_data = 0; diff --git a/unit/test-gobex-header.c b/unit/test-gobex-header.c index 4185a70b7..2ac0c4332 100644 --- a/unit/test-gobex-header.c +++ b/unit/test-gobex-header.c @@ -124,9 +124,11 @@ static GObexHeader *parse_and_encode(uint8_t *buf, size_t buf_len) GObexHeader *header; uint8_t encoded[1024]; size_t len; + GError *err = NULL; - header = g_obex_header_decode(buf, buf_len, G_OBEX_DATA_REF, &len); - g_assert(header != NULL); + header = g_obex_header_decode(buf, buf_len, G_OBEX_DATA_REF, &len, + &err); + g_assert_no_error(err); g_assert_cmpuint(len, ==, buf_len); len = g_obex_header_encode(header, encoded, sizeof(encoded)); @@ -222,10 +224,11 @@ static void test_decode_header_connid(void) { GObexHeader *header; size_t parsed; + GError *err = NULL; header = g_obex_header_decode(hdr_connid, sizeof(hdr_connid), - G_OBEX_DATA_REF, &parsed); - g_assert(header != NULL); + G_OBEX_DATA_REF, &parsed, &err); + g_assert_no_error(err); g_assert_cmpuint(parsed, ==, sizeof(hdr_connid)); @@ -236,10 +239,11 @@ static void test_decode_header_name_ascii(void) { GObexHeader *header; size_t parsed; + GError *err = NULL; header = g_obex_header_decode(hdr_name_ascii, sizeof(hdr_name_ascii), - G_OBEX_DATA_REF, &parsed); - g_assert(header != NULL); + G_OBEX_DATA_REF, &parsed, &err); + g_assert_no_error(err); g_assert_cmpuint(parsed, ==, sizeof(hdr_name_ascii)); @@ -250,10 +254,11 @@ static void test_decode_header_name_umlaut(void) { GObexHeader *header; size_t parsed; + GError *err = NULL; header = g_obex_header_decode(hdr_name_umlaut, sizeof(hdr_name_umlaut), - G_OBEX_DATA_REF, &parsed); - g_assert(header != NULL); + G_OBEX_DATA_REF, &parsed, &err); + g_assert_no_error(err); g_assert_cmpuint(parsed, ==, sizeof(hdr_name_umlaut)); @@ -264,10 +269,11 @@ static void test_decode_header_body(void) { GObexHeader *header; size_t parsed; + GError *err = NULL; header = g_obex_header_decode(hdr_body, sizeof(hdr_body), - G_OBEX_DATA_COPY, &parsed); - g_assert(header != NULL); + G_OBEX_DATA_COPY, &parsed, &err); + g_assert_no_error(err); g_assert_cmpuint(parsed, ==, sizeof(hdr_body)); @@ -278,10 +284,11 @@ static void test_decode_header_body_extdata(void) { GObexHeader *header; size_t parsed; + GError *err = NULL; header = g_obex_header_decode(hdr_body, sizeof(hdr_body), - G_OBEX_DATA_REF, &parsed); - g_assert(header != NULL); + G_OBEX_DATA_REF, &parsed, &err); + g_assert_no_error(err); g_assert_cmpuint(parsed, ==, sizeof(hdr_body)); @@ -292,10 +299,11 @@ static void test_decode_header_actionid(void) { GObexHeader *header; size_t parsed; + GError *err = NULL; header = g_obex_header_decode(hdr_actionid, sizeof(hdr_actionid), - G_OBEX_DATA_REF, &parsed); - g_assert(header != NULL); + G_OBEX_DATA_REF, &parsed, &err); + g_assert_no_error(err); g_assert_cmpuint(parsed, ==, sizeof(hdr_actionid)); @@ -307,6 +315,7 @@ static void test_decode_header_multi(void) GObexHeader *header; GByteArray *buf; size_t parsed; + GError *err = NULL; buf = g_byte_array_sized_new(sizeof(hdr_connid) + sizeof(hdr_name_ascii) + @@ -319,29 +328,29 @@ static void test_decode_header_multi(void) g_byte_array_append(buf, hdr_body, sizeof(hdr_body)); header = g_obex_header_decode(buf->data, buf->len, G_OBEX_DATA_REF, - &parsed); - g_assert(header != NULL); + &parsed, &err); + g_assert_no_error(err); g_assert_cmpuint(parsed, ==, sizeof(hdr_connid)); g_byte_array_remove_range(buf, 0, parsed); g_obex_header_free(header); header = g_obex_header_decode(buf->data, buf->len, G_OBEX_DATA_REF, - &parsed); - g_assert(header != NULL); + &parsed, &err); + g_assert_no_error(err); g_assert_cmpuint(parsed, ==, sizeof(hdr_name_ascii)); g_byte_array_remove_range(buf, 0, parsed); g_obex_header_free(header); header = g_obex_header_decode(buf->data, buf->len, G_OBEX_DATA_REF, - &parsed); - g_assert(header != NULL); + &parsed, &err); + g_assert_no_error(err); g_assert_cmpuint(parsed, ==, sizeof(hdr_actionid)); g_byte_array_remove_range(buf, 0, parsed); g_obex_header_free(header); header = g_obex_header_decode(buf->data, buf->len, G_OBEX_DATA_REF, - &parsed); - g_assert(header != NULL); + &parsed, &err); + g_assert_no_error(err); g_assert_cmpuint(parsed, ==, sizeof(hdr_body)); g_byte_array_remove_range(buf, 0, parsed); g_obex_header_free(header); diff --git a/unit/test-gobex-packet.c b/unit/test-gobex-packet.c index 8792a5994..fcbe398e2 100644 --- a/unit/test-gobex-packet.c +++ b/unit/test-gobex-packet.c @@ -40,9 +40,10 @@ static void test_decode_pkt(void) { GObexPacket *pkt; uint8_t buf[] = { G_OBEX_OP_PUT, 0x00, 0x03 }; + GError *err = NULL; - pkt = g_obex_packet_decode(buf, sizeof(buf), 0, G_OBEX_DATA_REF); - g_assert(pkt != NULL); + pkt = g_obex_packet_decode(buf, sizeof(buf), 0, G_OBEX_DATA_REF, &err); + g_assert_no_error(err); g_obex_packet_free(pkt); } @@ -51,13 +52,14 @@ static void test_decode_pkt_header(void) { GObexPacket *pkt; GObexHeader *header; + GError *err = NULL; gboolean ret; uint8_t buf[] = { G_OBEX_OP_PUT, 0x00, 0x05, G_OBEX_HDR_ID_ACTION, 0xab }; guint8 val; - pkt = g_obex_packet_decode(buf, sizeof(buf), 0, G_OBEX_DATA_REF); - g_assert(pkt != NULL); + pkt = g_obex_packet_decode(buf, sizeof(buf), 0, G_OBEX_DATA_REF, &err); + g_assert_no_error(err); header = g_obex_packet_get_header(pkt, G_OBEX_HDR_ID_ACTION); g_assert(header != NULL); -- 2.47.3