Diff between 966b77d0c007cf213b1125848c5e3bab8df5c720 and 9292a83d92ab0d7b0788aa7bc2a85a7bb8829be7

Changed Files

File Additions Deletions Status
gobex/gobex-defs.h +1 -0 modified
gobex/gobex.c +37 -4 modified
gobex/gobex.h +3 -2 modified
unit/test-gobex.c +45 -6 modified

Full Patch

diff --git a/gobex/gobex-defs.h b/gobex/gobex-defs.h
index e81d0fb..10e3fbb 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 c53a733..d536125 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 918a603..d074698 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 96aebf4..b216b42 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();