From 9292a83d92ab0d7b0788aa7bc2a85a7bb8829be7 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 29 Jun 2011 18:30:18 +0300 Subject: [PATCH] gobex: Add per-request timeouts --- gobex/gobex-defs.h | 1 + gobex/gobex.c | 41 +++++++++++++++++++++++++++++++++---- gobex/gobex.h | 5 +++-- unit/test-gobex.c | 51 ++++++++++++++++++++++++++++++++++++++++------ 4 files changed, 86 insertions(+), 12 deletions(-) diff --git a/gobex/gobex-defs.h b/gobex/gobex-defs.h index e81d0fb6b..10e3fbbe7 100644 --- a/gobex/gobex-defs.h +++ b/gobex/gobex-defs.h @@ -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() diff --git a/gobex/gobex.c b/gobex/gobex.c index c53a733ce..d53612562 100644 --- a/gobex/gobex.c +++ b/gobex/gobex.c @@ -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; diff --git a/gobex/gobex.h b/gobex/gobex.h index 918a60342..d074698f2 100644 --- a/gobex/gobex.h +++ b/gobex/gobex.h @@ -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, diff --git a/unit/test-gobex.c b/unit/test-gobex.c index 96aebf4fd..b216b42cd 100644 --- a/unit/test-gobex.c +++ b/unit/test-gobex.c @@ -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(); -- 2.47.3