OSDN Git Service

gobex: Add packet transport support
authorJohan Hedberg <johan.hedberg@intel.com>
Thu, 30 Jun 2011 11:13:04 +0000 (14:13 +0300)
committerMarcel Holtmann <marcel@holtmann.org>
Tue, 4 Dec 2012 21:21:58 +0000 (22:21 +0100)
gobex/gobex.c
unit/test-gobex.c

index de2fba2..6ee5e09 100644 (file)
@@ -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);
 
index 3bbc65c..13a0668 100644 (file)
@@ -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();