Diff between 13d42a094583fbcc6c750ee1a0a34e0075b6c7bc and a14e52b4712a0457fe79e41608f876f77b04f3c1

Changed Files

File Additions Deletions Status
gobex/gobex.c +72 -22 modified
unit/test-gobex.c +92 -13 modified

Full Patch

diff --git a/gobex/gobex.c b/gobex/gobex.c
index de2fba2..6ee5e09 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 3bbc65c..13a0668 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();