--- /dev/null
+/*
+ *
+ * OBEX library with GLib integration
+ *
+ * Copyright (C) 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <glib.h>
+
+#include "gobex-defs.h"
+
+GQuark g_obex_error_quark(void)
+{
+ return g_quark_from_static_string("g-obex-error-quark");
+}
#ifndef __GOBEX_DEFS_H
#define __GOBEX_DEFS_H
+#include <glib.h>
+
typedef enum {
G_OBEX_DATA_INHERIT,
G_OBEX_DATA_COPY,
G_OBEX_DATA_REF,
} GObexDataPolicy;
+typedef enum {
+ G_OBEX_ERROR_PARSE_ERROR,
+ G_OBEX_ERROR_INVALID_ARGS,
+} GObexError;
+
+#define G_OBEX_ERROR g_obex_error_quark()
+GQuark g_obex_error_quark(void);
+
#endif /* __GOBEX_DEFS_H */
}
GObexHeader *g_obex_header_decode(const void *data, gsize len,
- GObexDataPolicy data_policy, gsize *parsed)
+ GObexDataPolicy data_policy, gsize *parsed,
+ GError **err)
{
GObexHeader *header;
const guint8 *ptr = data;
guint16 hdr_len;
gsize str_len;
+ GError *conv_err = NULL;
- if (len < 2)
+ if (len < 2) {
+ g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
+ "Too short header in packet");
return NULL;
+ }
header = g_new0(GObexHeader, 1);
goto failed;
ptr = get_bytes(&hdr_len, ptr, sizeof(hdr_len));
hdr_len = g_ntohs(hdr_len);
- if (hdr_len > len || hdr_len < 5)
+ if (hdr_len > len || hdr_len < 5) {
+ g_set_error(err, G_OBEX_ERROR,
+ G_OBEX_ERROR_PARSE_ERROR,
+ "Invalid unicode header length");
goto failed;
+ }
header->v.string = g_convert((const char *) ptr, hdr_len - 5,
"UTF8", "UTF16BE",
- NULL, &str_len, NULL);
- if (header->v.string == NULL)
+ NULL, &str_len, &conv_err);
+ if (header->v.string == NULL) {
+ g_set_error(err, G_OBEX_ERROR,
+ G_OBEX_ERROR_PARSE_ERROR,
+ "Unicode conversion failed: %s",
+ conv_err->message);
+ g_error_free(conv_err);
goto failed;
+ }
header->vlen = (gsize) str_len;
header->hlen = hdr_len;
break;
case G_OBEX_HDR_TYPE_BYTES:
- if (len < 3)
+ if (len < 3) {
+ g_set_error(err, G_OBEX_ERROR,
+ G_OBEX_ERROR_PARSE_ERROR,
+ "Too short byte array header");
goto failed;
+ }
ptr = get_bytes(&hdr_len, ptr, sizeof(hdr_len));
hdr_len = g_ntohs(hdr_len);
- if (hdr_len > len)
+ if (hdr_len > len) {
+ g_set_error(err, G_OBEX_ERROR,
+ G_OBEX_ERROR_PARSE_ERROR,
+ "Too long byte array header");
goto failed;
+ }
header->vlen = hdr_len - 3;
header->hlen = hdr_len;
header->v.extdata = ptr;
break;
default:
+ g_set_error(err, G_OBEX_ERROR,
+ G_OBEX_ERROR_INVALID_ARGS,
+ "Invalid data policy");
goto failed;
}
*parsed = 2;
break;
case G_OBEX_HDR_TYPE_UINT32:
- if (len < 5)
+ if (len < 5) {
+ g_set_error(err, G_OBEX_ERROR,
+ G_OBEX_ERROR_PARSE_ERROR,
+ "Too short uint32 header");
goto failed;
+ }
header->vlen = 4;
header->hlen = 5;
ptr = get_bytes(&header->v.u32, ptr, sizeof(header->v.u32));
gsize g_obex_header_encode(GObexHeader *header, void *hdr_ptr, gsize buf_len);
GObexHeader *g_obex_header_decode(const void *data, gsize len,
- GObexDataPolicy data_policy, gsize *parsed);
+ GObexDataPolicy data_policy, gsize *parsed,
+ GError **err);
void g_obex_header_free(GObexHeader *header);
#endif /* __GOBEX_HEADER_H */
}
static gboolean parse_headers(GObexPacket *pkt, const void *data, gsize len,
- GObexDataPolicy data_policy)
+ GObexDataPolicy data_policy,
+ GError **err)
{
const guint8 *buf = data;
GObexHeader *header;
gsize parsed;
- header = g_obex_header_decode(buf, len, data_policy, &parsed);
+ header = g_obex_header_decode(buf, len, data_policy, &parsed,
+ err);
if (header == NULL)
return FALSE;
GObexPacket *g_obex_packet_decode(const void *data, gsize len,
gsize header_offset,
- GObexDataPolicy data_policy)
+ GObexDataPolicy data_policy,
+ GError **err)
{
const guint8 *buf = data;
guint16 packet_len;
GObexPacket *pkt;
gboolean final;
- if (len < 3)
+ if (data_policy == G_OBEX_DATA_INHERIT) {
+ g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_INVALID_ARGS,
+ "Invalid data policy");
+ return NULL;
+ }
+
+ if (len < 3) {
+ g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
+ "Not enough data to decode packet");
return NULL;
+ }
buf = get_bytes(&opcode, buf, sizeof(opcode));
buf = get_bytes(&packet_len, buf, sizeof(packet_len));
packet_len = g_ntohs(packet_len);
- if (packet_len < len)
+ if (packet_len != len) {
+ g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
+ "Incorrect packet length (%u != %zu)",
+ packet_len, len);
return NULL;
+ }
final = (opcode & G_OBEX_PACKET_FINAL) ? TRUE : FALSE;
opcode &= ~G_OBEX_PACKET_FINAL;
if (header_offset == 0)
goto headers;
- if (3 + header_offset < len)
- goto failed;
-
- if (data_policy == G_OBEX_DATA_INHERIT)
- goto failed;
-
- if (!g_obex_packet_set_data(pkt, buf, header_offset, data_policy))
+ if (3 + header_offset < len) {
+ g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
+ "Too short packet");
goto failed;
+ }
+ g_obex_packet_set_data(pkt, buf, header_offset, data_policy);
buf += header_offset;
headers:
if (!parse_headers(pkt, buf, len - (buf - (guint8 *) data),
- data_policy))
+ data_policy, err))
goto failed;
return pkt;
GObexPacket *g_obex_packet_decode(const void *data, gsize len,
gsize header_offset,
- GObexDataPolicy data_policy);
+ GObexDataPolicy data_policy,
+ GError **err);
gssize g_obex_packet_encode(GObexPacket *pkt, guint8 *buf, gsize len);
#endif /* __GOBEX_PACKET_H */
obex->tx_buf = g_realloc(obex->tx_buf, obex->tx_mtu);
}
-static void handle_response(GObex *obex, GObexPacket *rsp)
+static void handle_response(GObex *obex, GError *err, GObexPacket *rsp)
{
struct pending_pkt *p = obex->pending_req;
- if (g_obex_packet_get_operation(p->pkt, NULL) == G_OBEX_OP_CONNECT)
- parse_connect_data(obex, rsp);
+ if (rsp != NULL) {
+ guint8 op = g_obex_packet_get_operation(p->pkt, NULL);
+ if (op == G_OBEX_OP_CONNECT)
+ parse_connect_data(obex, rsp);
+ }
if (p->rsp_func)
- p->rsp_func(obex, NULL, rsp, p->rsp_data);
+ p->rsp_func(obex, err, rsp, p->rsp_data);
pending_pkt_free(p);
obex->pending_req = NULL;
}
-static void handle_request(GObex *obex, GObexPacket *req)
+static void handle_request(GObex *obex, GError *err, GObexPacket *req)
{
if (g_obex_packet_get_operation(req, NULL) == G_OBEX_OP_CONNECT)
parse_connect_data(obex, req);
obex->req_func(obex, req, obex->req_func_data);
}
-static gboolean g_obex_handle_packet(GObex *obex, GObexPacket *pkt)
+static gboolean g_obex_handle_packet(GObex *obex, GError *err, GObexPacket *pkt)
{
if (obex->pending_req)
- handle_response(obex, pkt);
- else
- handle_request(obex, pkt);
+ handle_response(obex, err, pkt);
+ else if (pkt != NULL)
+ handle_request(obex, err, pkt);
+
+ /* FIXME: Application callback needed for err != NULL? */
return TRUE;
}
GObex *obex = user_data;
GObexPacket *pkt;
ssize_t header_offset;
+ GError *err = NULL;
if (cond & G_IO_NVAL)
return FALSE;
goto failed;
pkt = g_obex_packet_decode(obex->rx_buf, obex->rx_data, header_offset,
- G_OBEX_DATA_REF);
- if (pkt == NULL) {
- /* FIXME: Handle decoding error */
- } else {
- g_obex_handle_packet(obex, pkt);
+ G_OBEX_DATA_REF, &err);
+
+ g_obex_handle_packet(obex, err, pkt);
+
+ if (pkt != NULL)
g_obex_packet_free(pkt);
- }
obex->rx_data = 0;
GObexHeader *header;
uint8_t encoded[1024];
size_t len;
+ GError *err = NULL;
- header = g_obex_header_decode(buf, buf_len, G_OBEX_DATA_REF, &len);
- g_assert(header != NULL);
+ header = g_obex_header_decode(buf, buf_len, G_OBEX_DATA_REF, &len,
+ &err);
+ g_assert_no_error(err);
g_assert_cmpuint(len, ==, buf_len);
len = g_obex_header_encode(header, encoded, sizeof(encoded));
{
GObexHeader *header;
size_t parsed;
+ GError *err = NULL;
header = g_obex_header_decode(hdr_connid, sizeof(hdr_connid),
- G_OBEX_DATA_REF, &parsed);
- g_assert(header != NULL);
+ G_OBEX_DATA_REF, &parsed, &err);
+ g_assert_no_error(err);
g_assert_cmpuint(parsed, ==, sizeof(hdr_connid));
{
GObexHeader *header;
size_t parsed;
+ GError *err = NULL;
header = g_obex_header_decode(hdr_name_ascii, sizeof(hdr_name_ascii),
- G_OBEX_DATA_REF, &parsed);
- g_assert(header != NULL);
+ G_OBEX_DATA_REF, &parsed, &err);
+ g_assert_no_error(err);
g_assert_cmpuint(parsed, ==, sizeof(hdr_name_ascii));
{
GObexHeader *header;
size_t parsed;
+ GError *err = NULL;
header = g_obex_header_decode(hdr_name_umlaut, sizeof(hdr_name_umlaut),
- G_OBEX_DATA_REF, &parsed);
- g_assert(header != NULL);
+ G_OBEX_DATA_REF, &parsed, &err);
+ g_assert_no_error(err);
g_assert_cmpuint(parsed, ==, sizeof(hdr_name_umlaut));
{
GObexHeader *header;
size_t parsed;
+ GError *err = NULL;
header = g_obex_header_decode(hdr_body, sizeof(hdr_body),
- G_OBEX_DATA_COPY, &parsed);
- g_assert(header != NULL);
+ G_OBEX_DATA_COPY, &parsed, &err);
+ g_assert_no_error(err);
g_assert_cmpuint(parsed, ==, sizeof(hdr_body));
{
GObexHeader *header;
size_t parsed;
+ GError *err = NULL;
header = g_obex_header_decode(hdr_body, sizeof(hdr_body),
- G_OBEX_DATA_REF, &parsed);
- g_assert(header != NULL);
+ G_OBEX_DATA_REF, &parsed, &err);
+ g_assert_no_error(err);
g_assert_cmpuint(parsed, ==, sizeof(hdr_body));
{
GObexHeader *header;
size_t parsed;
+ GError *err = NULL;
header = g_obex_header_decode(hdr_actionid, sizeof(hdr_actionid),
- G_OBEX_DATA_REF, &parsed);
- g_assert(header != NULL);
+ G_OBEX_DATA_REF, &parsed, &err);
+ g_assert_no_error(err);
g_assert_cmpuint(parsed, ==, sizeof(hdr_actionid));
GObexHeader *header;
GByteArray *buf;
size_t parsed;
+ GError *err = NULL;
buf = g_byte_array_sized_new(sizeof(hdr_connid) +
sizeof(hdr_name_ascii) +
g_byte_array_append(buf, hdr_body, sizeof(hdr_body));
header = g_obex_header_decode(buf->data, buf->len, G_OBEX_DATA_REF,
- &parsed);
- g_assert(header != NULL);
+ &parsed, &err);
+ g_assert_no_error(err);
g_assert_cmpuint(parsed, ==, sizeof(hdr_connid));
g_byte_array_remove_range(buf, 0, parsed);
g_obex_header_free(header);
header = g_obex_header_decode(buf->data, buf->len, G_OBEX_DATA_REF,
- &parsed);
- g_assert(header != NULL);
+ &parsed, &err);
+ g_assert_no_error(err);
g_assert_cmpuint(parsed, ==, sizeof(hdr_name_ascii));
g_byte_array_remove_range(buf, 0, parsed);
g_obex_header_free(header);
header = g_obex_header_decode(buf->data, buf->len, G_OBEX_DATA_REF,
- &parsed);
- g_assert(header != NULL);
+ &parsed, &err);
+ g_assert_no_error(err);
g_assert_cmpuint(parsed, ==, sizeof(hdr_actionid));
g_byte_array_remove_range(buf, 0, parsed);
g_obex_header_free(header);
header = g_obex_header_decode(buf->data, buf->len, G_OBEX_DATA_REF,
- &parsed);
- g_assert(header != NULL);
+ &parsed, &err);
+ g_assert_no_error(err);
g_assert_cmpuint(parsed, ==, sizeof(hdr_body));
g_byte_array_remove_range(buf, 0, parsed);
g_obex_header_free(header);
{
GObexPacket *pkt;
uint8_t buf[] = { G_OBEX_OP_PUT, 0x00, 0x03 };
+ GError *err = NULL;
- pkt = g_obex_packet_decode(buf, sizeof(buf), 0, G_OBEX_DATA_REF);
- g_assert(pkt != NULL);
+ pkt = g_obex_packet_decode(buf, sizeof(buf), 0, G_OBEX_DATA_REF, &err);
+ g_assert_no_error(err);
g_obex_packet_free(pkt);
}
{
GObexPacket *pkt;
GObexHeader *header;
+ GError *err = NULL;
gboolean ret;
uint8_t buf[] = { G_OBEX_OP_PUT, 0x00, 0x05,
G_OBEX_HDR_ID_ACTION, 0xab };
guint8 val;
- pkt = g_obex_packet_decode(buf, sizeof(buf), 0, G_OBEX_DATA_REF);
- g_assert(pkt != NULL);
+ pkt = g_obex_packet_decode(buf, sizeof(buf), 0, G_OBEX_DATA_REF, &err);
+ g_assert_no_error(err);
header = g_obex_packet_get_header(pkt, G_OBEX_HDR_ID_ACTION);
g_assert(header != NULL);