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,
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;
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,
GObexPacket *pkt;
ssize_t header_offset;
GError *err = NULL;
+ guint8 opcode;
if (cond & G_IO_NVAL)
return FALSE;
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);
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);
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)
{
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)
{
}
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;
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);
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 {
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;
GObexPacket *req;
GIOCondition cond;
- create_endpoints(&r.obex, &io, SOCK_STREAM);
+ create_endpoints(&r.obex, &io, transport_type);
r.err = NULL;
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;
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);
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)
{
"Unexpected operation");
}
-static void test_recv_connect_stream(void)
+static void recv_connect(int transport_type)
{
GError *gerr = NULL;
guint timer_id;
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);
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)
{
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();