From 714abdfc725dfb94e049e25674437541b9770c98 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 5 Jul 2011 12:33:57 +0300 Subject: [PATCH] gobex: Make on-demand header callbacks able to fail cleanly --- gobex/gobex-header.c | 14 +++++++++----- gobex/gobex-header.h | 4 ++-- gobex/gobex-packet.c | 9 ++++++++- unit/test-gobex-header.c | 25 ++++++++++++++++++++++++- unit/test-gobex-packet.c | 30 +++++++++++++++++++++++++++++- unit/test-gobex.c | 36 ++++++++++++++++++++++++++++-------- 6 files changed, 100 insertions(+), 18 deletions(-) diff --git a/gobex/gobex-header.c b/gobex/gobex-header.c index 6d0136cd5..3446bb9e7 100644 --- a/gobex/gobex-header.c +++ b/gobex/gobex-header.c @@ -83,13 +83,17 @@ static const guint8 *get_bytes(void *to, const guint8 *from, gsize count) return (from + count); } -static gsize get_data(GObexHeader *header, guint8 *buf, gsize len) +static gssize get_data(GObexHeader *header, guint8 *buf, gsize len) { guint16 u16; + gssize ret; - header->vlen = header->get_data(header, buf + 2, len - 2, + ret = header->get_data(header, buf + 2, len - 2, header->get_data_data); + if (ret < 0) + return ret; + header->vlen = ret; header->hlen = header->vlen + 3; u16 = g_htons(header->hlen); memcpy(buf, &u16, sizeof(u16)); @@ -97,7 +101,7 @@ static gsize get_data(GObexHeader *header, guint8 *buf, gsize len) return header->hlen; } -gsize g_obex_header_encode(GObexHeader *header, void *buf, gsize buf_len) +gssize g_obex_header_encode(GObexHeader *header, void *buf, gsize buf_len) { guint8 *ptr = buf; guint16 u16; @@ -106,7 +110,7 @@ gsize g_obex_header_encode(GObexHeader *header, void *buf, gsize buf_len) glong utf16_len; if (buf_len < header->hlen) - return 0; + return -1; ptr = put_bytes(ptr, &header->id, sizeof(header->id)); @@ -114,7 +118,7 @@ gsize g_obex_header_encode(GObexHeader *header, void *buf, gsize buf_len) 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; + return -1; g_assert_cmpuint(utf16_len + 3, ==, header->hlen); u16 = g_htons(utf16_len + 3); ptr = put_bytes(ptr, &u16, sizeof(u16)); diff --git a/gobex/gobex-header.h b/gobex/gobex-header.h index 7ea319393..b25051fb6 100644 --- a/gobex/gobex-header.h +++ b/gobex/gobex-header.h @@ -55,7 +55,7 @@ typedef struct _GObexHeader GObexHeader; -typedef guint16 (*GObexHeaderDataFunc) (GObexHeader *header, void *buf, +typedef gssize (*GObexHeaderDataFunc) (GObexHeader *header, void *buf, gsize len, gpointer user_data); gboolean g_obex_header_get_unicode(GObexHeader *header, const char **str); @@ -76,7 +76,7 @@ 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); -gsize g_obex_header_encode(GObexHeader *header, void *hdr_ptr, gsize buf_len); +gssize 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, GError **err); diff --git a/gobex/gobex-packet.c b/gobex/gobex-packet.c index 29a6aa2d9..16d4b7a77 100644 --- a/gobex/gobex-packet.c +++ b/gobex/gobex-packet.c @@ -281,9 +281,16 @@ gssize g_obex_packet_encode(GObexPacket *pkt, guint8 *buf, gsize len) for (l = pkt->headers; l != NULL; l = g_slist_next(l)) { GObexHeader *hdr = l->data; + gssize ret; + if (count >= len) return -ENOBUFS; - count += g_obex_header_encode(hdr, buf + count, len - count); + + ret = g_obex_header_encode(hdr, buf + count, len - count); + if (ret < 0) + return ret; + + count += ret; } u16 = g_htons(count); diff --git a/unit/test-gobex-header.c b/unit/test-gobex-header.c index 61536e268..bf69abb48 100644 --- a/unit/test-gobex-header.c +++ b/unit/test-gobex-header.c @@ -130,7 +130,7 @@ static void test_header_uint32(void) g_obex_header_free(header); } -static guint16 get_body_data(GObexHeader *header, void *buf, gsize len, +static gssize get_body_data(GObexHeader *header, void *buf, gsize len, gpointer user_data) { uint8_t body_data[] = { 1, 2, 3, 4 }; @@ -156,6 +156,27 @@ static void test_header_on_demand(void) g_obex_header_free(header); } +static gssize get_body_data_fail(GObexHeader *header, void *buf, gsize len, + gpointer user_data) +{ + return -1; +} + +static void test_header_on_demand_fail(void) +{ + GObexHeader *header; + uint8_t buf[1024]; + gssize len; + + header = g_obex_header_new_on_demand(G_OBEX_HDR_ID_BODY, + get_body_data_fail, NULL); + + len = g_obex_header_encode(header, buf, sizeof(buf)); + g_assert_cmpint(len, ==, -1); + + g_obex_header_free(header); +} + static GObexHeader *parse_and_encode(uint8_t *buf, size_t buf_len) { GObexHeader *header; @@ -485,6 +506,8 @@ int main(int argc, char *argv[]) g_test_add_func("/gobex/test_header_uint32", test_header_uint32); g_test_add_func("/gobex/test_header_on_demand", test_header_on_demand); + g_test_add_func("/gobex/test_header_on_demand_fail", + test_header_on_demand_fail); g_test_run(); diff --git a/unit/test-gobex-packet.c b/unit/test-gobex-packet.c index 501d924f6..33be55d9a 100644 --- a/unit/test-gobex-packet.c +++ b/unit/test-gobex-packet.c @@ -144,7 +144,7 @@ static void test_decode_encode(void) g_obex_packet_free(pkt); } -static guint16 get_body_data(GObexHeader *header, void *buf, gsize len, +static gssize get_body_data(GObexHeader *header, void *buf, gsize len, gpointer user_data) { uint8_t data[] = { 1, 2, 3, 4 }; @@ -178,6 +178,32 @@ static void test_encode_on_demand(void) g_obex_packet_free(pkt); } +static gssize get_body_data_fail(GObexHeader *header, void *buf, gsize len, + gpointer user_data) +{ + return -1; +} + +static void test_encode_on_demand_fail(void) +{ + GObexPacket *pkt; + GObexHeader *hdr; + uint8_t buf[255]; + gssize len; + + pkt = g_obex_packet_new(G_OBEX_OP_PUT, FALSE, NULL); + + hdr = g_obex_header_new_on_demand(G_OBEX_HDR_ID_BODY, + get_body_data_fail, NULL); + g_obex_packet_add_header(pkt, hdr); + + len = g_obex_packet_encode(pkt, buf, sizeof(buf)); + + g_assert_cmpint(len, ==, -1); + + g_obex_packet_free(pkt); +} + int main(int argc, char *argv[]) { g_test_init(&argc, &argv, NULL); @@ -194,6 +220,8 @@ int main(int argc, char *argv[]) g_test_add_func("/gobex/test_encode_pkt", test_decode_encode); g_test_add_func("/gobex/test_encode_on_demand", test_encode_on_demand); + g_test_add_func("/gobex/test_encode_on_demand_fail", + test_encode_on_demand_fail); g_test_run(); diff --git a/unit/test-gobex.c b/unit/test-gobex.c index 5d65dde58..1fb74b55a 100644 --- a/unit/test-gobex.c +++ b/unit/test-gobex.c @@ -528,7 +528,7 @@ static void test_send_connect(int transport_type) create_endpoints(&obex, &io, transport_type); - r.err = NULL; + memset(&r, 0, sizeof(r)); r.buf = pkt_connect_req; r.len = sizeof(pkt_connect_req); @@ -570,7 +570,7 @@ static void test_send_connect_pkt(void) test_send_connect(SOCK_SEQPACKET); } -static guint16 get_body_data(GObexHeader *header, void *buf, gsize len, +static gssize get_body_data(GObexHeader *header, void *buf, gsize len, gpointer user_data) { uint8_t data[] = { 1, 2, 3, 4 }; @@ -580,7 +580,14 @@ static guint16 get_body_data(GObexHeader *header, void *buf, gsize len, return sizeof(data); } -static void test_send_on_demand(int transport_type) +static gssize get_body_data_fail(GObexHeader *header, void *buf, gsize len, + gpointer user_data) +{ + g_main_loop_quit(mainloop); + return -1; +} + +static void test_send_on_demand(int transport_type, GObexHeaderDataFunc func) { struct rcv_buf_info r; GIOChannel *io; @@ -592,14 +599,13 @@ static void test_send_on_demand(int transport_type) create_endpoints(&obex, &io, transport_type); - r.err = NULL; + memset(&r, 0, sizeof(r)); r.buf = pkt_put_body; r.len = sizeof(pkt_put_body); req = g_obex_packet_new(G_OBEX_OP_PUT, FALSE, NULL); - hdr = g_obex_header_new_on_demand(G_OBEX_HDR_ID_BODY, - get_body_data, NULL); + hdr = g_obex_header_new_on_demand(G_OBEX_HDR_ID_BODY, func, &r); g_obex_packet_add_header(req, hdr); g_obex_send(obex, req, &r.err); @@ -627,12 +633,22 @@ static void test_send_on_demand(int transport_type) static void test_send_on_demand_stream(void) { - test_send_on_demand(SOCK_STREAM); + test_send_on_demand(SOCK_STREAM, get_body_data); } static void test_send_on_demand_pkt(void) { - test_send_on_demand(SOCK_SEQPACKET); + test_send_on_demand(SOCK_SEQPACKET, get_body_data); +} + +static void test_send_on_demand_fail_stream(void) +{ + test_send_on_demand(SOCK_STREAM, get_body_data_fail); +} + +static void test_send_on_demand_fail_pkt(void) +{ + test_send_on_demand(SOCK_SEQPACKET, get_body_data_fail); } static void handle_connect_req(GObex *obex, GObexPacket *req, @@ -802,6 +818,10 @@ int main(int argc, char *argv[]) test_send_on_demand_stream); g_test_add_func("/gobex/test_send_on_demand_pkt", test_send_on_demand_pkt); + g_test_add_func("/gobex/test_send_on_demand_fail_stream", + test_send_on_demand_fail_stream); + g_test_add_func("/gobex/test_send_on_demand_fail_pkt", + test_send_on_demand_fail_pkt); g_test_add_func("/gobex/test_send_connect_req_stream", test_send_connect_req_stream); g_test_add_func("/gobex/test_send_connect_req_pkt", -- 2.47.3