gboolean g_obex_header_get_uint8(GObexHeader *header, guint8 *val) { g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", G_OBEX_HDR_ENC(header->id)); if (G_OBEX_HDR_ENC(header->id) != G_OBEX_HDR_ENC_UINT8) return FALSE; *val = header->v.u8; g_obex_debug(G_OBEX_DEBUG_HEADER, "%u", *val); return TRUE; }
gboolean g_obex_header_get_unicode(GObexHeader *header, const char **str) { g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", G_OBEX_HDR_ENC(header->id)); if (G_OBEX_HDR_ENC(header->id) != G_OBEX_HDR_ENC_UNICODE) return FALSE; *str = header->v.string; g_obex_debug(G_OBEX_DEBUG_HEADER, "%s", *str); return TRUE; }
void g_obex_unref(GObex *obex) { int refs; refs = __sync_sub_and_fetch(&obex->ref_count, 1); g_obex_debug(G_OBEX_DEBUG_COMMAND, "ref %u", refs); if (refs > 0) return; g_slist_free_full(obex->req_handlers, g_free); g_queue_foreach(obex->tx_queue, (GFunc) pending_pkt_free, NULL); g_queue_free(obex->tx_queue); if (obex->io != NULL) g_io_channel_unref(obex->io); if (obex->io_source > 0) g_source_remove(obex->io_source); if (obex->write_source > 0) g_source_remove(obex->write_source); g_free(obex->rx_buf); g_free(obex->tx_buf); g_free(obex->srm); if (obex->pending_req) pending_pkt_free(obex->pending_req); g_free(obex); }
static void handle_response(GObex *obex, GError *err, GObexPacket *rsp) { struct pending_pkt *p = obex->pending_req; gboolean disconn = err ? TRUE : FALSE, final_rsp = TRUE; if (rsp != NULL) final_rsp = parse_response(obex, rsp); if (p->cancelled) err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED, "The operation was cancelled"); if (err) g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message); if (p->rsp_func) { p->rsp_func(obex, err, rsp, p->rsp_data); /* Check if user callback removed the request */ if (p != obex->pending_req) return; } if (p->cancelled) g_error_free(err); if (final_rsp) { pending_pkt_free(p); obex->pending_req = NULL; } if (!disconn && g_queue_get_length(obex->tx_queue) > 0) enable_tx(obex); }
guint g_obex_setpath(GObex *obex, const char *path, GObexResponseFunc func, gpointer user_data, GError **err) { GObexPacket *req; struct setpath_data data; const char *folder; g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id); req = g_obex_packet_new(G_OBEX_OP_SETPATH, TRUE, G_OBEX_HDR_INVALID); memset(&data, 0, sizeof(data)); if (path != NULL && strncmp("..", path, 2) == 0) { data.flags = 0x03; folder = (path[2] == '/') ? &path[3] : NULL; } else { data.flags = 0x02; folder = path; } if (folder != NULL) { GObexHeader *hdr; hdr = g_obex_header_new_unicode(G_OBEX_HDR_NAME, folder); g_obex_packet_add_header(req, hdr); } g_obex_packet_set_data(req, &data, sizeof(data), G_OBEX_DATA_COPY); return g_obex_send_req(obex, req, -1, func, user_data, err); }
guint8 g_obex_header_get_id(GObexHeader *header) { g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x id 0x%02x", G_OBEX_HDR_ENC(header->id), header->id); return header->id; }
void g_obex_unref(GObex *obex) { gboolean last_ref; last_ref = g_atomic_int_dec_and_test(&obex->ref_count); g_obex_debug(G_OBEX_DEBUG_COMMAND, "ref %u", obex->ref_count); if (!last_ref) return; g_slist_free_full(obex->req_handlers, g_free); g_queue_foreach(obex->tx_queue, (GFunc) pending_pkt_free, NULL); g_queue_free(obex->tx_queue); if (obex->io != NULL) g_io_channel_unref(obex->io); if (obex->io_source > 0) g_source_remove(obex->io_source); if (obex->write_source > 0) g_source_remove(obex->write_source); g_free(obex->rx_buf); g_free(obex->tx_buf); g_free(obex->srm); if (obex->pending_req) pending_pkt_free(obex->pending_req); g_free(obex); }
guint16 g_obex_header_get_length(GObexHeader *header) { g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x length %zu", G_OBEX_HDR_ENC(header->id), header->hlen); return header->hlen; }
static void transfer_abort_response(GObex *obex, GError *err, GObexPacket *rsp, gpointer user_data) { struct transfer *transfer = user_data; g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id); transfer->req_id = 0; /* Intentionally override error */ err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED, "Operation was aborted"); g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message); transfer_complete(transfer, err); g_error_free(err); }
void g_obex_resume(GObex *obex) { g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id); obex->suspended = FALSE; if (g_queue_get_length(obex->tx_queue) > 0 || obex->tx_data > 0) enable_tx(obex); }
void g_obex_suspend(GObex *obex) { g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id); if (obex->write_source > 0) { g_source_remove(obex->write_source); obex->write_source = 0; } obex->suspended = TRUE; }
GObexHeader *g_obex_header_new_uint32(guint8 id, guint32 val) { GObexHeader *header; g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", G_OBEX_HDR_ENC(id)); if (G_OBEX_HDR_ENC(id) != G_OBEX_HDR_ENC_UINT32) return NULL; header = g_new0(GObexHeader, 1); header->id = id; header->vlen = 4; header->hlen = 5; header->v.u32 = val; g_obex_debug(G_OBEX_DEBUG_HEADER, "%u", header->v.u32); return header; }
GObex *g_obex_ref(GObex *obex) { if (obex == NULL) return NULL; g_atomic_int_inc(&obex->ref_count); g_obex_debug(G_OBEX_DEBUG_COMMAND, "ref %u", obex->ref_count); return obex; }
guint g_obex_send_req(GObex *obex, GObexPacket *req, gint timeout, GObexResponseFunc func, gpointer user_data, GError **err) { GObexHeader *hdr; struct pending_pkt *p; static guint id = 1; guint8 op; g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id); op = g_obex_packet_get_operation(req, NULL); if (op == G_OBEX_OP_PUT || op == G_OBEX_OP_GET) { /* Only enable SRM automatically for GET and PUT */ prepare_srm_req(obex, req); } if (obex->conn_id == CONNID_INVALID) goto create_pending; if (obex->rx_last_op == G_OBEX_RSP_CONTINUE) goto create_pending; if (g_obex_srm_active(obex) && obex->pending_req != NULL) goto create_pending; hdr = g_obex_packet_get_header(req, G_OBEX_HDR_CONNECTION); if (hdr != NULL) goto create_pending; hdr = g_obex_header_new_uint32(G_OBEX_HDR_CONNECTION, obex->conn_id); g_obex_packet_prepend_header(req, hdr); create_pending: p = g_new0(struct pending_pkt, 1); p->pkt = req; p->id = id++; 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; } return p->id; }
guint g_obex_delete(GObex *obex, const char *name, GObexResponseFunc func, gpointer user_data, GError **err) { GObexPacket *req; g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id); req = g_obex_packet_new(G_OBEX_OP_PUT, TRUE, G_OBEX_HDR_NAME, name, G_OBEX_HDR_INVALID); return g_obex_send_req(obex, req, -1, func, user_data, err); }
static gboolean read_stream(GObex *obex, GError **err) { GIOChannel *io = obex->io; GIOStatus status; gsize rbytes, toread; guint16 u16; gchar *buf; if (obex->rx_data >= 3) goto read_body; rbytes = 0; toread = 3 - obex->rx_data; buf = (gchar *) &obex->rx_buf[obex->rx_data]; status = g_io_channel_read_chars(io, buf, toread, &rbytes, NULL); if (status != G_IO_STATUS_NORMAL) return TRUE; obex->rx_data += rbytes; if (obex->rx_data < 3) goto done; memcpy(&u16, &buf[1], sizeof(u16)); obex->rx_pkt_len = g_ntohs(u16); if (obex->rx_pkt_len > obex->rx_mtu) { g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR, "Too big incoming packet"); g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message); return FALSE; } read_body: if (obex->rx_data >= obex->rx_pkt_len) goto done; do { toread = obex->rx_pkt_len - obex->rx_data; buf = (gchar *) &obex->rx_buf[obex->rx_data]; status = g_io_channel_read_chars(io, buf, toread, &rbytes, NULL); if (status != G_IO_STATUS_NORMAL) goto done; obex->rx_data += rbytes; } while (rbytes > 0 && obex->rx_data < obex->rx_pkt_len); done: g_obex_dump(G_OBEX_DEBUG_DATA, ">", obex->rx_buf, obex->rx_data); return TRUE; }
GObex *g_obex_ref(GObex *obex) { int refs; if (obex == NULL) return NULL; refs = __sync_add_and_fetch(&obex->ref_count, 1); g_obex_debug(G_OBEX_DEBUG_COMMAND, "ref %u", refs); return obex; }
static void transfer_complete(struct transfer *transfer, GError *err) { guint id = transfer->id; g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", id); transfer->complete_func(transfer->obex, err, transfer->user_data); /* Check if the complete_func removed the transfer */ if (find_transfer(id) == NULL) return; transfer_free(transfer); }
static guint8 put_get_bytes(struct transfer *transfer, GObexPacket *req) { GObexHeader *body; gboolean final; guint8 rsp; const guint8 *buf; gsize len; g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id); g_obex_packet_get_operation(req, &final); if (final) rsp = G_OBEX_RSP_SUCCESS; else
GObexHeader *g_obex_header_new_unicode(guint8 id, const char *str) { GObexHeader *header; gsize len; g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", G_OBEX_HDR_ENC(id)); if (G_OBEX_HDR_ENC(id) != G_OBEX_HDR_ENC_UNICODE) return NULL; header = g_new0(GObexHeader, 1); header->id = id; len = g_utf8_strlen(str, -1); header->vlen = len; header->hlen = len == 0 ? 3 : 3 + ((len + 1) * 2); header->v.string = g_strdup(str); g_obex_debug(G_OBEX_DEBUG_HEADER, "%s", header->v.string); return header; }
gssize g_obex_header_encode(GObexHeader *header, void *buf, gsize buf_len) { guint8 *ptr = buf; guint16 u16; guint32 u32; gunichar2 *utf16; glong utf16_len; g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", G_OBEX_HDR_ENC(header->id)); if (buf_len < header->hlen) return -1; ptr = put_bytes(ptr, &header->id, sizeof(header->id)); switch (G_OBEX_HDR_ENC(header->id)) { case G_OBEX_HDR_ENC_UNICODE: utf16_len = utf8_to_utf16(&utf16, header->v.string); if (utf16_len < 0 || (guint16) utf16_len > buf_len) return -1; g_assert_cmpuint(utf16_len + 3, ==, header->hlen); u16 = g_htons(utf16_len + 3); ptr = put_bytes(ptr, &u16, sizeof(u16)); ptr = put_bytes(ptr, utf16, utf16_len); g_free(utf16); break; case G_OBEX_HDR_ENC_BYTES: u16 = g_htons(header->hlen); ptr = put_bytes(ptr, &u16, sizeof(u16)); if (header->extdata) ptr = put_bytes(ptr, header->v.extdata, header->vlen); else ptr = put_bytes(ptr, header->v.data, header->vlen); break; case G_OBEX_HDR_ENC_UINT8: *ptr = header->v.u8; break; case G_OBEX_HDR_ENC_UINT32: u32 = g_htonl(header->v.u32); ptr = put_bytes(ptr, &u32, sizeof(u32)); break; default: g_assert_not_reached(); } return header->hlen; }
static gboolean read_packet(GObex *obex, GError **err) { 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"); goto fail; } 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); goto fail; } obex->rx_data += rbytes; if (rbytes < 3) { g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR, "Incomplete packet received"); goto fail; } 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; } g_obex_dump(G_OBEX_DEBUG_DATA, ">", obex->rx_buf, obex->rx_data); return TRUE; fail: g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message); return FALSE; }
guint g_obex_mkdir(GObex *obex, const char *path, GObexResponseFunc func, gpointer user_data, GError **err) { GObexPacket *req; struct setpath_data data; g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id); req = g_obex_packet_new(G_OBEX_OP_SETPATH, TRUE, G_OBEX_HDR_NAME, path, G_OBEX_HDR_INVALID); memset(&data, 0, sizeof(data)); g_obex_packet_set_data(req, &data, sizeof(data), G_OBEX_DATA_COPY); return g_obex_send_req(obex, req, -1, func, user_data, err); }
static void transfer_abort_req(GObex *obex, GObexPacket *req, gpointer user_data) { struct transfer *transfer = user_data; GObexPacket *rsp; GError *err; g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id); err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED, "Request was aborted"); rsp = g_obex_packet_new(G_OBEX_RSP_SUCCESS, TRUE, G_OBEX_HDR_INVALID); g_obex_send(obex, rsp, NULL); transfer_complete(transfer, err); g_error_free(err); }
GSList *g_obex_header_create_list(guint8 first_hdr_id, va_list args, gsize *total_len) { unsigned int id = first_hdr_id; GSList *l = NULL; g_obex_debug(G_OBEX_DEBUG_HEADER, ""); *total_len = 0; while (id != G_OBEX_HDR_INVALID) { GObexHeader *hdr; const char *str; const void *bytes; unsigned int val; gsize len; switch (G_OBEX_HDR_ENC(id)) { case G_OBEX_HDR_ENC_UNICODE: str = va_arg(args, const char *); hdr = g_obex_header_new_unicode(id, str); break; case G_OBEX_HDR_ENC_BYTES: bytes = va_arg(args, void *); len = va_arg(args, gsize); hdr = g_obex_header_new_bytes(id, bytes, len); break; case G_OBEX_HDR_ENC_UINT8: val = va_arg(args, unsigned int); hdr = g_obex_header_new_uint8(id, val); break; case G_OBEX_HDR_ENC_UINT32: val = va_arg(args, unsigned int); hdr = g_obex_header_new_uint32(id, val); break; default: g_assert_not_reached(); } l = g_slist_append(l, hdr); *total_len += hdr->hlen; id = va_arg(args, int); } return l; }
guint g_obex_put_req(GObex *obex, GObexDataProducer data_func, GObexFunc complete_func, gpointer user_data, GError **err, guint8 first_hdr_id, ...) { GObexPacket *req; va_list args; g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex); va_start(args, first_hdr_id); req = g_obex_packet_new_valist(G_OBEX_OP_PUT, FALSE, first_hdr_id, args); va_end(args); return g_obex_put_req_pkt(obex, req, data_func, complete_func, user_data, err); }
GObexHeader *g_obex_header_new_bytes(guint8 id, const void *data, gsize len) { GObexHeader *header; g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", G_OBEX_HDR_ENC(id)); if (G_OBEX_HDR_ENC(id) != G_OBEX_HDR_ENC_BYTES) return NULL; header = g_new0(GObexHeader, 1); header->id = id; header->vlen = len; header->hlen = len + 3; header->v.data = g_memdup(data, len); return header; }
gboolean g_obex_srm_active(GObex *obex) { gboolean ret = FALSE; if (!obex->use_srm) return FALSE; if (obex->srm == NULL || !obex->srm->enabled) goto done; if (obex->srm->srmp <= G_OBEX_SRMP_NEXT_WAIT) goto done; ret = TRUE; done: g_obex_debug(G_OBEX_DEBUG_COMMAND, "%s", ret ? "yes" : "no"); return ret; }
gboolean g_obex_header_get_bytes(GObexHeader *header, const guint8 **val, gsize *len) { g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", G_OBEX_HDR_ENC(header->id)); if (G_OBEX_HDR_ENC(header->id) != G_OBEX_HDR_ENC_BYTES) return FALSE; *len = header->vlen; if (header->extdata) *val = header->v.extdata; else *val = header->v.data; return TRUE; }
guint g_obex_connect(GObex *obex, GObexResponseFunc func, gpointer user_data, GError **err, guint8 first_hdr_id, ...) { GObexPacket *req; struct connect_data data; va_list args; g_obex_debug(G_OBEX_DEBUG_COMMAND, ""); va_start(args, first_hdr_id); req = g_obex_packet_new_valist(G_OBEX_OP_CONNECT, TRUE, first_hdr_id, args); va_end(args); init_connect_data(obex, &data); g_obex_packet_set_data(req, &data, sizeof(data), G_OBEX_DATA_COPY); return g_obex_send_req(obex, req, -1, func, user_data, err); }