1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * OBEX library with GLib integration
6 * Copyright (C) 2011 Intel Corporation. All rights reserved.
17 #include "gobex-defs.h"
18 #include "gobex-packet.h"
19 #include "gobex-debug.h"
21 #define FINAL_BIT 0x80
27 GObexDataPolicy data_policy;
30 void *buf; /* Non-header data */
31 const void *buf_ref; /* Reference to non-header data */
35 gsize hlen; /* Length of all encoded headers */
38 GObexDataProducer get_body;
39 gpointer get_body_data;
42 GObexHeader *g_obex_packet_get_header(GObexPacket *pkt, guint8 id)
46 g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
48 for (l = pkt->headers; l != NULL; l = g_slist_next(l)) {
49 GObexHeader *hdr = l->data;
51 if (g_obex_header_get_id(hdr) == id)
58 GObexHeader *g_obex_packet_get_body(GObexPacket *pkt)
62 g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
64 body = g_obex_packet_get_header(pkt, G_OBEX_HDR_BODY);
68 return g_obex_packet_get_header(pkt, G_OBEX_HDR_BODY_END);
71 guint8 g_obex_packet_get_operation(GObexPacket *pkt, gboolean *final)
73 g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
81 gboolean g_obex_packet_prepend_header(GObexPacket *pkt, GObexHeader *header)
83 g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
85 pkt->headers = g_slist_prepend(pkt->headers, header);
86 pkt->hlen += g_obex_header_get_length(header);
91 gboolean g_obex_packet_add_header(GObexPacket *pkt, GObexHeader *header)
93 g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
95 pkt->headers = g_slist_append(pkt->headers, header);
96 pkt->hlen += g_obex_header_get_length(header);
101 gboolean g_obex_packet_add_body(GObexPacket *pkt, GObexDataProducer func,
104 g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
106 if (pkt->get_body != NULL)
109 pkt->get_body = func;
110 pkt->get_body_data = user_data;
115 gboolean g_obex_packet_add_unicode(GObexPacket *pkt, guint8 id,
120 g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
122 hdr = g_obex_header_new_unicode(id, str);
126 return g_obex_packet_add_header(pkt, hdr);
129 gboolean g_obex_packet_add_bytes(GObexPacket *pkt, guint8 id,
130 const void *data, gsize len)
134 g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
136 hdr = g_obex_header_new_bytes(id, data, len);
140 return g_obex_packet_add_header(pkt, hdr);
143 gboolean g_obex_packet_add_uint8(GObexPacket *pkt, guint8 id, guint8 val)
147 g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
149 hdr = g_obex_header_new_uint8(id, val);
153 return g_obex_packet_add_header(pkt, hdr);
156 gboolean g_obex_packet_add_uint32(GObexPacket *pkt, guint8 id, guint32 val)
160 g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
162 hdr = g_obex_header_new_uint32(id, val);
166 return g_obex_packet_add_header(pkt, hdr);
169 const void *g_obex_packet_get_data(GObexPacket *pkt, gsize *len)
171 g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
173 if (pkt->data_len == 0) {
178 *len = pkt->data_len;
180 switch (pkt->data_policy) {
181 case G_OBEX_DATA_INHERIT:
182 case G_OBEX_DATA_COPY:
183 return pkt->data.buf;
184 case G_OBEX_DATA_REF:
185 return pkt->data.buf_ref;
188 g_assert_not_reached();
191 gboolean g_obex_packet_set_data(GObexPacket *pkt, const void *data, gsize len,
192 GObexDataPolicy data_policy)
194 g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
196 if (pkt->data.buf || pkt->data.buf_ref)
199 pkt->data_policy = data_policy;
202 switch (data_policy) {
203 case G_OBEX_DATA_COPY:
204 pkt->data.buf = g_memdup(data, len);
206 case G_OBEX_DATA_REF:
207 pkt->data.buf_ref = data;
209 case G_OBEX_DATA_INHERIT:
210 pkt->data.buf = (void *) data;
217 GObexPacket *g_obex_packet_new_valist(guint8 opcode, gboolean final,
218 guint first_hdr_id, va_list args)
222 g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", opcode);
224 pkt = g_new0(GObexPacket, 1);
226 pkt->opcode = opcode;
228 pkt->headers = g_obex_header_create_list(first_hdr_id, args,
230 pkt->data_policy = G_OBEX_DATA_COPY;
235 GObexPacket *g_obex_packet_new(guint8 opcode, gboolean final,
236 guint first_hdr_id, ...)
241 g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", opcode);
243 va_start(args, first_hdr_id);
244 pkt = g_obex_packet_new_valist(opcode, final, first_hdr_id, args);
250 static void header_free(void *data, void *user_data)
252 g_obex_header_free(data);
255 void g_obex_packet_free(GObexPacket *pkt)
257 g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
259 switch (pkt->data_policy) {
260 case G_OBEX_DATA_INHERIT:
261 case G_OBEX_DATA_COPY:
262 g_free(pkt->data.buf);
264 case G_OBEX_DATA_REF:
268 g_slist_foreach(pkt->headers, header_free, NULL);
269 g_slist_free(pkt->headers);
273 static gboolean parse_headers(GObexPacket *pkt, const void *data, gsize len,
274 GObexDataPolicy data_policy,
277 const guint8 *buf = data;
279 g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
285 header = g_obex_header_decode(buf, len, data_policy, &parsed,
290 pkt->headers = g_slist_append(pkt->headers, header);
300 static const guint8 *get_bytes(void *to, const guint8 *from, gsize count)
302 memcpy(to, from, count);
303 return (from + count);
306 GObexPacket *g_obex_packet_decode(const void *data, gsize len,
308 GObexDataPolicy data_policy,
311 const guint8 *buf = data;
317 g_obex_debug(G_OBEX_DEBUG_PACKET, "");
319 if (data_policy == G_OBEX_DATA_INHERIT) {
322 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_INVALID_ARGS,
323 "Invalid data policy");
324 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
328 if (len < 3 + header_offset) {
331 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
332 "Not enough data to decode packet");
333 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
337 buf = get_bytes(&opcode, buf, sizeof(opcode));
338 buf = get_bytes(&packet_len, buf, sizeof(packet_len));
340 packet_len = g_ntohs(packet_len);
341 if (packet_len != len) {
344 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
345 "Incorrect packet length (%u != %zu)",
347 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
351 final = (opcode & FINAL_BIT) ? TRUE : FALSE;
352 opcode &= ~FINAL_BIT;
354 pkt = g_obex_packet_new(opcode, final, G_OBEX_HDR_INVALID);
356 if (header_offset == 0)
359 g_obex_packet_set_data(pkt, buf, header_offset, data_policy);
360 buf += header_offset;
363 if (!parse_headers(pkt, buf, len - (3 + header_offset),
370 g_obex_packet_free(pkt);
374 static gssize get_body(GObexPacket *pkt, guint8 *buf, gsize len)
379 g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
384 ret = pkt->get_body(buf + 3, len - 3, pkt->get_body_data);
389 buf[0] = G_OBEX_HDR_BODY;
391 buf[0] = G_OBEX_HDR_BODY_END;
393 u16 = g_htons(ret + 3);
394 memcpy(&buf[1], &u16, sizeof(u16));
399 gssize g_obex_packet_encode(GObexPacket *pkt, guint8 *buf, gsize len)
406 g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
408 if (3 + pkt->data_len + pkt->hlen > len)
411 buf[0] = pkt->opcode;
415 if (pkt->data_len > 0) {
416 if (pkt->data_policy == G_OBEX_DATA_REF)
417 memcpy(&buf[3], pkt->data.buf_ref, pkt->data_len);
419 memcpy(&buf[3], pkt->data.buf, pkt->data_len);
422 count = 3 + pkt->data_len;
424 for (l = pkt->headers; l != NULL; l = g_slist_next(l)) {
425 GObexHeader *hdr = l->data;
430 ret = g_obex_header_encode(hdr, buf + count, len - count);
438 ret = get_body(pkt, buf + count, len - count);
442 if (pkt->opcode == G_OBEX_RSP_CONTINUE)
443 buf[0] = G_OBEX_RSP_SUCCESS;
450 u16 = g_htons(count);
451 memcpy(&buf[1], &u16, sizeof(u16));