From a14e52b4712a0457fe79e41608f876f77b04f3c1 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 30 Jun 2011 14:13:04 +0300 Subject: [PATCH] gobex: Add packet transport support --- gobex/gobex.c | 94 +++++++++++++++++++++++++++++++---------- unit/test-gobex.c | 105 ++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 164 insertions(+), 35 deletions(-) diff --git a/gobex/gobex.c b/gobex/gobex.c index de2fba20e..6ee5e09d7 100644 --- a/gobex/gobex.c +++ b/gobex/gobex.c @@ -167,9 +167,23 @@ static gboolean write_stream(GObex *obex, GError **err) static gboolean write_packet(GObex *obex, GError **err) { - g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_FAILED, - "Packet based writing not implemented"); - return FALSE; + GIOStatus status; + gsize bytes_written; + gchar *buf; + + buf = (gchar *) &obex->tx_buf[obex->tx_sent]; + status = g_io_channel_write_chars(obex->io, buf, obex->tx_data, + &bytes_written, err); + if (status != G_IO_STATUS_NORMAL) + return FALSE; + + if (bytes_written != obex->tx_data) + return FALSE; + + obex->tx_sent += bytes_written; + obex->tx_data -= bytes_written; + + return TRUE; } static gboolean write_data(GIOChannel *io, GIOCondition cond, @@ -446,18 +460,6 @@ static void handle_request(GObex *obex, GError *err, GObexPacket *req) obex->ev_func(obex, err, req, obex->ev_func_data); } -static gboolean g_obex_handle_packet(GObex *obex, GError *err, GObexPacket *pkt) -{ - if (obex->pending_req) - handle_response(obex, err, pkt); - else - handle_request(obex, err, pkt); - - /* FIXME: Application callback needed for err != NULL? */ - - return TRUE; -} - static gboolean read_stream(GObex *obex, GError **err) { GIOChannel *io = obex->io; @@ -504,9 +506,46 @@ read_body: static gboolean read_packet(GObex *obex, GError **err) { - g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_DISCONNECTED, - "Packet reading not implemented"); - return FALSE; + GIOChannel *io = obex->io; + GError *read_err = NULL; + GIOStatus status; + gsize rbytes; + guint16 u16; + + if (obex->rx_data > 0) { + g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR, + "RX buffer not empty before reading packet"); + return FALSE; + } + + status = g_io_channel_read_chars(io, (gchar *) obex->rx_buf, + obex->rx_mtu, &rbytes, &read_err); + if (status != G_IO_STATUS_NORMAL) { + g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR, + "Unable to read data: %s", read_err->message); + g_error_free(read_err); + return FALSE; + } + + obex->rx_data += rbytes; + + if (rbytes < 3) { + g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR, + "Incomplete packet received"); + return FALSE; + } + + memcpy(&u16, &obex->rx_buf[1], sizeof(u16)); + obex->rx_pkt_len = g_ntohs(u16); + + if (obex->rx_pkt_len != rbytes) { + g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR, + "Data size doesn't match packet size (%zu != %u)", + rbytes, obex->rx_pkt_len); + return FALSE; + } + + return TRUE; } static gboolean incoming_data(GIOChannel *io, GIOCondition cond, @@ -516,6 +555,7 @@ static gboolean incoming_data(GIOChannel *io, GIOCondition cond, GObexPacket *pkt; ssize_t header_offset; GError *err = NULL; + guint8 opcode; if (cond & G_IO_NVAL) return FALSE; @@ -534,20 +574,27 @@ static gboolean incoming_data(GIOChannel *io, GIOCondition cond, if (obex->pending_req) { struct pending_pkt *p = obex->pending_req; - guint8 opcode = g_obex_packet_get_operation(p->pkt, NULL); + opcode = g_obex_packet_get_operation(p->pkt, NULL); header_offset = req_header_offset(opcode); } else { - guint8 opcode = obex->rx_buf[0] & ~FINAL_BIT; + opcode = obex->rx_buf[0] & ~FINAL_BIT; header_offset = rsp_header_offset(opcode); } - if (header_offset < 0) + if (header_offset < 0) { + err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR, + "Unkown header offset for opcode 0x%02x", + opcode); goto failed; + } pkt = g_obex_packet_decode(obex->rx_buf, obex->rx_data, header_offset, G_OBEX_DATA_REF, &err); - g_obex_handle_packet(obex, err, pkt); + if (obex->pending_req) + handle_response(obex, err, pkt); + else + handle_request(obex, err, pkt); if (err != NULL) g_error_free(err); @@ -564,6 +611,9 @@ failed: obex->io = NULL; obex->io_source = 0; + if (obex->pending_req) + handle_response(obex, err, NULL); + if (obex->ev_func) obex->ev_func(obex, err, NULL, obex->ev_func_data); diff --git a/unit/test-gobex.c b/unit/test-gobex.c index 3bbc65ced..13a06687d 100644 --- a/unit/test-gobex.c +++ b/unit/test-gobex.c @@ -42,6 +42,7 @@ static uint8_t pkt_connect_rsp[] = { 0x10 | FINAL_BIT, 0x00, 0x07, static uint8_t pkt_nval_connect_rsp[] = { 0x10 | FINAL_BIT, 0x00, 0x05, 0x10, 0x00, }; static uint8_t pkt_abort_rsp[] = { 0x90, 0x00, 0x03 }; +static uint8_t pkt_nval_short_rsp[] = { 0x10 | FINAL_BIT, 0x12 }; static gboolean test_timeout(gpointer user_data) { @@ -248,6 +249,18 @@ static gboolean send_nval_connect_rsp(GIOChannel *io, GIOCondition cond, return FALSE; } +static gboolean send_nval_short_rsp(GIOChannel *io, GIOCondition cond, + gpointer user_data) +{ + GError **err = user_data; + + if (!recv_and_send(io, pkt_nval_short_rsp, + sizeof(pkt_nval_short_rsp), err)) + g_main_loop_quit(mainloop); + + return FALSE; +} + static gboolean send_nothing(GIOChannel *io, GIOCondition cond, gpointer user_data) { @@ -260,7 +273,7 @@ static gboolean send_nothing(GIOChannel *io, GIOCondition cond, } static void send_connect(GObexResponseFunc rsp_func, GIOFunc send_rsp_func, - gint req_timeout) + gint req_timeout, int transport_type) { guint8 connect_data[] = { 0x10, 0x00, 0x10, 0x00 }; GError *gerr = NULL; @@ -270,7 +283,7 @@ static void send_connect(GObexResponseFunc rsp_func, GIOFunc send_rsp_func, guint io_id, timer_id, test_time; GObex *obex; - create_endpoints(&obex, &io, SOCK_STREAM); + create_endpoints(&obex, &io, transport_type); req = g_obex_packet_new(G_OBEX_OP_CONNECT, TRUE); g_assert(req != NULL); @@ -308,17 +321,39 @@ static void send_connect(GObexResponseFunc rsp_func, GIOFunc send_rsp_func, static void test_send_connect_req_stream(void) { - send_connect(connect_rsp, send_connect_rsp, -1); + send_connect(connect_rsp, send_connect_rsp, -1, SOCK_STREAM); +} + +static void test_send_connect_req_pkt(void) +{ + send_connect(connect_rsp, send_connect_rsp, -1, SOCK_SEQPACKET); } static void test_send_nval_connect_req_stream(void) { - send_connect(nval_connect_rsp, send_nval_connect_rsp, -1); + send_connect(nval_connect_rsp, send_nval_connect_rsp, -1, SOCK_STREAM); +} + +static void test_send_nval_connect_req_pkt(void) +{ + send_connect(nval_connect_rsp, send_nval_connect_rsp, -1, + SOCK_SEQPACKET); +} + +static void test_send_nval_connect_req_short_pkt(void) +{ + send_connect(nval_connect_rsp, send_nval_short_rsp, -1, + SOCK_SEQPACKET); } static void test_send_connect_req_timeout_stream(void) { - send_connect(timeout_rsp, send_nothing, 1); + send_connect(timeout_rsp, send_nothing, 1, SOCK_STREAM); +} + +static void test_send_connect_req_timeout_pkt(void) +{ + send_connect(timeout_rsp, send_nothing, 1, SOCK_SEQPACKET); } struct req_info { @@ -418,7 +453,7 @@ failed: return FALSE; } -static void test_cancel_req_delay(void) +static void test_cancel_req_delay(int transport_type) { GIOChannel *io; guint io_id, timer_id; @@ -426,7 +461,7 @@ static void test_cancel_req_delay(void) GObexPacket *req; GIOCondition cond; - create_endpoints(&r.obex, &io, SOCK_STREAM); + create_endpoints(&r.obex, &io, transport_type); r.err = NULL; @@ -453,7 +488,17 @@ static void test_cancel_req_delay(void) g_main_loop_unref(mainloop); } -static void test_send_connect_stream(void) +static void test_cancel_req_delay_stream(void) +{ + test_cancel_req_delay(SOCK_STREAM); +} + +static void test_cancel_req_delay_pkt(void) +{ + test_cancel_req_delay(SOCK_SEQPACKET); +} + +static void test_send_connect(int transport_type) { guint8 connect_data[] = { 0x10, 0x00, 0x10, 0x00 }; GError *gerr = NULL; @@ -463,7 +508,7 @@ static void test_send_connect_stream(void) guint io_id, timer_id; GObex *obex; - create_endpoints(&obex, &io, SOCK_STREAM); + create_endpoints(&obex, &io, transport_type); req = g_obex_packet_new(G_OBEX_OP_CONNECT, TRUE); g_assert(req != NULL); @@ -493,6 +538,16 @@ static void test_send_connect_stream(void) g_assert_no_error(gerr); } +static void test_send_connect_stream(void) +{ + test_send_connect(SOCK_STREAM); +} + +static void test_send_connect_pkt(void) +{ + test_send_connect(SOCK_SEQPACKET); +} + static void handle_connect_event(GObex *obex, GError *err, GObexPacket *pkt, gpointer user_data) { @@ -510,7 +565,7 @@ static void handle_connect_event(GObex *obex, GError *err, GObexPacket *pkt, "Unexpected operation"); } -static void test_recv_connect_stream(void) +static void recv_connect(int transport_type) { GError *gerr = NULL; guint timer_id; @@ -519,7 +574,7 @@ static void test_recv_connect_stream(void) GIOStatus status; gsize bytes_written; - create_endpoints(&obex, &io, SOCK_STREAM); + create_endpoints(&obex, &io, transport_type); g_obex_set_event_function(obex, handle_connect_event, &gerr); @@ -545,6 +600,16 @@ static void test_recv_connect_stream(void) g_assert_no_error(gerr); } +static void test_recv_connect_stream(void) +{ + recv_connect(SOCK_STREAM); +} + +static void test_recv_connect_pkt(void) +{ + recv_connect(SOCK_SEQPACKET); +} + static void disconn_ev(GObex *obex, GError *err, GObexPacket *req, gpointer user_data) { @@ -632,19 +697,33 @@ int main(int argc, char *argv[]) g_test_add_func("/gobex/test_recv_connect_stream", test_recv_connect_stream); + g_test_add_func("/gobex/test_recv_connect_pkt", + test_recv_connect_pkt); g_test_add_func("/gobex/test_send_connect_stream", test_send_connect_stream); + g_test_add_func("/gobex/test_send_connect_pkt", + test_send_connect_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", + test_send_connect_req_pkt); g_test_add_func("/gobex/test_send_nval_connect_req_stream", test_send_nval_connect_req_stream); + g_test_add_func("/gobex/test_send_nval_connect_req_pkt", + test_send_nval_connect_req_pkt); + g_test_add_func("/gobex/test_send_nval_connect_req_short_pkt", + test_send_nval_connect_req_short_pkt); g_test_add_func("/gobex/test_send_connect_req_timeout_stream", test_send_connect_req_timeout_stream); + g_test_add_func("/gobex/test_send_connect_req_timeout_pkt", + test_send_connect_req_timeout_pkt); g_test_add_func("/gobex/test_cancel_req_immediate", test_cancel_req_immediate); - g_test_add_func("/gobex/test_cancel_req_delay", - test_cancel_req_delay); + g_test_add_func("/gobex/test_cancel_req_delay_stream", + test_cancel_req_delay_stream); + g_test_add_func("/gobex/test_cancel_req_delay_pkt", + test_cancel_req_delay_pkt); g_test_run(); -- 2.47.3