OSDN Git Service

gobex: Add per-request timeouts
authorJohan Hedberg <johan.hedberg@intel.com>
Wed, 29 Jun 2011 15:30:18 +0000 (18:30 +0300)
committerMarcel Holtmann <marcel@holtmann.org>
Tue, 4 Dec 2012 21:21:57 +0000 (22:21 +0100)
gobex/gobex-defs.h
gobex/gobex.c
gobex/gobex.h
unit/test-gobex.c

index e81d0fb..10e3fbb 100644 (file)
@@ -34,6 +34,7 @@ typedef enum {
        G_OBEX_ERROR_PARSE_ERROR,
        G_OBEX_ERROR_INVALID_ARGS,
        G_OBEX_ERROR_DISCONNECTED,
+       G_OBEX_ERROR_TIMEOUT,
 } GObexError;
 
 #define G_OBEX_ERROR g_obex_error_quark()
index c53a733..d536125 100644 (file)
@@ -28,6 +28,8 @@
 #define G_OBEX_MINIMUM_MTU     255
 #define G_OBEX_MAXIMUM_MTU     65535
 
+#define G_OBEX_DEFAULT_TIMEOUT 5
+
 #define FINAL_BIT              0x80
 
 struct _GObex {
@@ -65,6 +67,8 @@ struct _GObex {
 struct pending_pkt {
        guint id;
        GObexPacket *pkt;
+       guint timeout;
+       guint timeout_id;
        GObexResponseFunc rsp_func;
        gpointer rsp_data;
 };
@@ -121,6 +125,27 @@ static void pending_pkt_free(struct pending_pkt *p)
        g_free(p);
 }
 
+static gboolean req_timeout(gpointer user_data)
+{
+       GObex *obex = user_data;
+       struct pending_pkt *p = obex->pending_req;
+
+       g_assert(p != NULL);
+
+       obex->pending_req = NULL;
+
+       if (p->rsp_func) {
+               GError *err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_TIMEOUT,
+                                       "Timed out waiting for response");
+               p->rsp_func(obex, err, NULL, p->rsp_data);
+               g_error_free(err);
+       }
+
+       pending_pkt_free(p);
+
+       return FALSE;
+}
+
 static gboolean write_stream(GObex *obex)
 {
        GIOStatus status;
@@ -174,9 +199,11 @@ static gboolean write_data(GIOChannel *io, GIOCondition cond,
                        goto done;
                }
 
-               if (p->id > 0)
+               if (p->id > 0) {
                        obex->pending_req = p;
-               else
+                       p->timeout_id = g_timeout_add_seconds(p->timeout,
+                                                       req_timeout, obex);
+               } else
                        pending_pkt_free(p);
 
                obex->tx_data = len;
@@ -252,8 +279,9 @@ gboolean g_obex_send(GObex *obex, GObexPacket *pkt, GError **err)
        return ret;
 }
 
-guint g_obex_send_req(GObex *obex, GObexPacket *req, GObexResponseFunc func,
-                                       gpointer user_data, GError **err)
+guint g_obex_send_req(GObex *obex, GObexPacket *req, gint timeout,
+                       GObexResponseFunc func, gpointer user_data,
+                       GError **err)
 {
        struct pending_pkt *p;
        static guint id = 1;
@@ -265,6 +293,11 @@ guint g_obex_send_req(GObex *obex, GObexPacket *req, GObexResponseFunc func,
        p->rsp_func = func;
        p->rsp_data = user_data;
 
+       if (timeout < 0)
+               p->timeout = G_OBEX_DEFAULT_TIMEOUT;
+       else
+               p->timeout = timeout;
+
        if (!g_obex_send_internal(obex, p, err)) {
                pending_pkt_free(p);
                return 0;
index 918a603..d074698 100644 (file)
@@ -41,8 +41,9 @@ typedef void (*GObexDisconnectFunc) (GObex *obex, gpointer user_data);
 
 gboolean g_obex_send(GObex *obex, GObexPacket *pkt, GError **err);
 
-guint g_obex_send_req(GObex *obex, GObexPacket *req, GObexResponseFunc func,
-                                       gpointer user_data, GError **err);
+guint g_obex_send_req(GObex *obex, GObexPacket *req, gint timeout,
+                       GObexResponseFunc func, gpointer user_data,
+                       GError **err);
 gboolean g_obex_cancel_req(GObex *obex, guint req_id);
 
 void g_obex_set_request_function(GObex *obex, GObexRequestFunc func,
index 96aebf4..b216b42 100644 (file)
@@ -180,6 +180,18 @@ static void nval_connect_rsp(GObex *obex, GError *err, GObexPacket *rsp,
        g_main_loop_quit(mainloop);
 }
 
+static void timeout_rsp(GObex *obex, GError *err, GObexPacket *rsp,
+                                                       gpointer user_data)
+{
+       GError **test_err = user_data;
+
+       if (!g_error_matches(err, G_OBEX_ERROR, G_OBEX_ERROR_TIMEOUT))
+               g_set_error(test_err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                               "Did not get expected timeout error");
+
+       g_main_loop_quit(mainloop);
+}
+
 static gboolean recv_and_send(GIOChannel *io, void *data, gsize len,
                                                                GError **err)
 {
@@ -194,6 +206,9 @@ static gboolean recv_and_send(GIOChannel *io, void *data, gsize len,
                return FALSE;
        }
 
+       if (data == NULL)
+               return TRUE;
+
        g_io_channel_write_chars(io, data, len, &bytes_written, NULL);
        if (bytes_written != len) {
                g_set_error(err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
@@ -227,14 +242,26 @@ static gboolean send_nval_connect_rsp(GIOChannel *io, GIOCondition cond,
        return FALSE;
 }
 
-static void send_connect(GObexResponseFunc rsp_func, GIOFunc send_rsp_func)
+static gboolean send_nothing(GIOChannel *io, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       GError **err = user_data;
+
+       if (!recv_and_send(io, NULL, 0, err))
+               g_main_loop_quit(mainloop);
+
+       return FALSE;
+}
+
+static void send_connect(GObexResponseFunc rsp_func, GIOFunc send_rsp_func,
+                                                       gint req_timeout)
 {
        guint8 connect_data[] = { 0x10, 0x00, 0x10, 0x00 };
        GError *gerr = NULL;
        GIOChannel *io;
        GIOCondition cond;
        GObexPacket *req;
-       guint io_id, timer_id;
+       guint io_id, timer_id, test_time;
        GObex *obex;
 
        create_endpoints(&obex, &io, SOCK_STREAM);
@@ -245,7 +272,7 @@ static void send_connect(GObexResponseFunc rsp_func, GIOFunc send_rsp_func)
        g_obex_packet_set_data(req, connect_data, sizeof(connect_data),
                                                        G_OBEX_DATA_REF);
 
-       g_obex_send_req(obex, req, rsp_func, &gerr, &gerr);
+       g_obex_send_req(obex, req, req_timeout, rsp_func, &gerr, &gerr);
        g_assert_no_error(gerr);
 
        cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
@@ -253,7 +280,12 @@ static void send_connect(GObexResponseFunc rsp_func, GIOFunc send_rsp_func)
 
        mainloop = g_main_loop_new(NULL, FALSE);
 
-       timer_id = g_timeout_add_seconds(1, test_timeout, &gerr);
+       if (req_timeout > 0)
+               test_time = req_timeout + 1;
+       else
+               test_time = 1;
+
+       timer_id = g_timeout_add_seconds(test_time, test_timeout, &gerr);
 
        g_main_loop_run(mainloop);
 
@@ -270,12 +302,17 @@ 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);
+       send_connect(connect_rsp, send_connect_rsp, -1);
 }
 
 static void test_send_nval_connect_req_stream(void)
 {
-       send_connect(nval_connect_rsp, send_nval_connect_rsp);
+       send_connect(nval_connect_rsp, send_nval_connect_rsp, -1);
+}
+
+static void test_send_connect_req_timeout_stream(void)
+{
+       send_connect(timeout_rsp, send_nothing, 1);
 }
 
 static void test_send_connect_stream(void)
@@ -456,6 +493,8 @@ int main(int argc, char *argv[])
                                        test_send_connect_req_stream);
        g_test_add_func("/gobex/test_send_nval_connect_req_stream",
                                        test_send_nval_connect_req_stream);
+       g_test_add_func("/gobex/test_send_connect_req_timeout_stream",
+                                       test_send_connect_req_timeout_stream);
 
        g_test_run();