gobex-packet.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. *
  4. * OBEX library with GLib integration
  5. *
  6. * Copyright (C) 2011 Intel Corporation. All rights reserved.
  7. *
  8. */
  9. #ifdef HAVE_CONFIG_H
  10. #include <config.h>
  11. #endif
  12. #include <string.h>
  13. #include <errno.h>
  14. #include "gobex-defs.h"
  15. #include "gobex-packet.h"
  16. #include "gobex-debug.h"
  17. #define FINAL_BIT 0x80
  18. struct _GObexPacket {
  19. guint8 opcode;
  20. gboolean final;
  21. GObexDataPolicy data_policy;
  22. union {
  23. void *buf; /* Non-header data */
  24. const void *buf_ref; /* Reference to non-header data */
  25. } data;
  26. gsize data_len;
  27. gsize hlen; /* Length of all encoded headers */
  28. GSList *headers;
  29. GObexDataProducer get_body;
  30. gpointer get_body_data;
  31. };
  32. GObexHeader *g_obex_packet_get_header(GObexPacket *pkt, guint8 id)
  33. {
  34. GSList *l;
  35. g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
  36. for (l = pkt->headers; l != NULL; l = g_slist_next(l)) {
  37. GObexHeader *hdr = l->data;
  38. if (g_obex_header_get_id(hdr) == id)
  39. return hdr;
  40. }
  41. return NULL;
  42. }
  43. GObexHeader *g_obex_packet_get_body(GObexPacket *pkt)
  44. {
  45. GObexHeader *body;
  46. g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
  47. body = g_obex_packet_get_header(pkt, G_OBEX_HDR_BODY);
  48. if (body != NULL)
  49. return body;
  50. return g_obex_packet_get_header(pkt, G_OBEX_HDR_BODY_END);
  51. }
  52. guint8 g_obex_packet_get_operation(GObexPacket *pkt, gboolean *final)
  53. {
  54. g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
  55. if (final)
  56. *final = pkt->final;
  57. return pkt->opcode;
  58. }
  59. gboolean g_obex_packet_prepend_header(GObexPacket *pkt, GObexHeader *header)
  60. {
  61. g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
  62. pkt->headers = g_slist_prepend(pkt->headers, header);
  63. pkt->hlen += g_obex_header_get_length(header);
  64. return TRUE;
  65. }
  66. gboolean g_obex_packet_add_header(GObexPacket *pkt, GObexHeader *header)
  67. {
  68. g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
  69. pkt->headers = g_slist_append(pkt->headers, header);
  70. pkt->hlen += g_obex_header_get_length(header);
  71. return TRUE;
  72. }
  73. gboolean g_obex_packet_add_body(GObexPacket *pkt, GObexDataProducer func,
  74. gpointer user_data)
  75. {
  76. g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
  77. if (pkt->get_body != NULL)
  78. return FALSE;
  79. pkt->get_body = func;
  80. pkt->get_body_data = user_data;
  81. return TRUE;
  82. }
  83. gboolean g_obex_packet_add_unicode(GObexPacket *pkt, guint8 id,
  84. const char *str)
  85. {
  86. GObexHeader *hdr;
  87. g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
  88. hdr = g_obex_header_new_unicode(id, str);
  89. if (hdr == NULL)
  90. return FALSE;
  91. return g_obex_packet_add_header(pkt, hdr);
  92. }
  93. gboolean g_obex_packet_add_bytes(GObexPacket *pkt, guint8 id,
  94. const void *data, gsize len)
  95. {
  96. GObexHeader *hdr;
  97. g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
  98. hdr = g_obex_header_new_bytes(id, data, len);
  99. if (hdr == NULL)
  100. return FALSE;
  101. return g_obex_packet_add_header(pkt, hdr);
  102. }
  103. gboolean g_obex_packet_add_uint8(GObexPacket *pkt, guint8 id, guint8 val)
  104. {
  105. GObexHeader *hdr;
  106. g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
  107. hdr = g_obex_header_new_uint8(id, val);
  108. if (hdr == NULL)
  109. return FALSE;
  110. return g_obex_packet_add_header(pkt, hdr);
  111. }
  112. gboolean g_obex_packet_add_uint32(GObexPacket *pkt, guint8 id, guint32 val)
  113. {
  114. GObexHeader *hdr;
  115. g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
  116. hdr = g_obex_header_new_uint32(id, val);
  117. if (hdr == NULL)
  118. return FALSE;
  119. return g_obex_packet_add_header(pkt, hdr);
  120. }
  121. const void *g_obex_packet_get_data(GObexPacket *pkt, gsize *len)
  122. {
  123. g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
  124. if (pkt->data_len == 0) {
  125. *len = 0;
  126. return NULL;
  127. }
  128. *len = pkt->data_len;
  129. switch (pkt->data_policy) {
  130. case G_OBEX_DATA_INHERIT:
  131. case G_OBEX_DATA_COPY:
  132. return pkt->data.buf;
  133. case G_OBEX_DATA_REF:
  134. return pkt->data.buf_ref;
  135. }
  136. g_assert_not_reached();
  137. }
  138. gboolean g_obex_packet_set_data(GObexPacket *pkt, const void *data, gsize len,
  139. GObexDataPolicy data_policy)
  140. {
  141. g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
  142. if (pkt->data.buf || pkt->data.buf_ref)
  143. return FALSE;
  144. pkt->data_policy = data_policy;
  145. pkt->data_len = len;
  146. switch (data_policy) {
  147. case G_OBEX_DATA_COPY:
  148. pkt->data.buf = g_memdup(data, len);
  149. break;
  150. case G_OBEX_DATA_REF:
  151. pkt->data.buf_ref = data;
  152. break;
  153. case G_OBEX_DATA_INHERIT:
  154. pkt->data.buf = (void *) data;
  155. break;
  156. }
  157. return TRUE;
  158. }
  159. GObexPacket *g_obex_packet_new_valist(guint8 opcode, gboolean final,
  160. guint first_hdr_id, va_list args)
  161. {
  162. GObexPacket *pkt;
  163. g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", opcode);
  164. pkt = g_new0(GObexPacket, 1);
  165. pkt->opcode = opcode;
  166. pkt->final = final;
  167. pkt->headers = g_obex_header_create_list(first_hdr_id, args,
  168. &pkt->hlen);
  169. pkt->data_policy = G_OBEX_DATA_COPY;
  170. return pkt;
  171. }
  172. GObexPacket *g_obex_packet_new(guint8 opcode, gboolean final,
  173. guint first_hdr_id, ...)
  174. {
  175. GObexPacket *pkt;
  176. va_list args;
  177. g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", opcode);
  178. va_start(args, first_hdr_id);
  179. pkt = g_obex_packet_new_valist(opcode, final, first_hdr_id, args);
  180. va_end(args);
  181. return pkt;
  182. }
  183. static void header_free(void *data, void *user_data)
  184. {
  185. g_obex_header_free(data);
  186. }
  187. void g_obex_packet_free(GObexPacket *pkt)
  188. {
  189. g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
  190. switch (pkt->data_policy) {
  191. case G_OBEX_DATA_INHERIT:
  192. case G_OBEX_DATA_COPY:
  193. g_free(pkt->data.buf);
  194. break;
  195. case G_OBEX_DATA_REF:
  196. break;
  197. }
  198. g_slist_foreach(pkt->headers, header_free, NULL);
  199. g_slist_free(pkt->headers);
  200. g_free(pkt);
  201. }
  202. static gboolean parse_headers(GObexPacket *pkt, const void *data, gsize len,
  203. GObexDataPolicy data_policy,
  204. GError **err)
  205. {
  206. const guint8 *buf = data;
  207. g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
  208. while (len > 0) {
  209. GObexHeader *header;
  210. gsize parsed;
  211. header = g_obex_header_decode(buf, len, data_policy, &parsed,
  212. err);
  213. if (header == NULL)
  214. return FALSE;
  215. pkt->headers = g_slist_append(pkt->headers, header);
  216. pkt->hlen += parsed;
  217. len -= parsed;
  218. buf += parsed;
  219. }
  220. return TRUE;
  221. }
  222. static const guint8 *get_bytes(void *to, const guint8 *from, gsize count)
  223. {
  224. memcpy(to, from, count);
  225. return (from + count);
  226. }
  227. GObexPacket *g_obex_packet_decode(const void *data, gsize len,
  228. gsize header_offset,
  229. GObexDataPolicy data_policy,
  230. GError **err)
  231. {
  232. const guint8 *buf = data;
  233. guint16 packet_len;
  234. guint8 opcode;
  235. GObexPacket *pkt;
  236. gboolean final;
  237. g_obex_debug(G_OBEX_DEBUG_PACKET, "");
  238. if (data_policy == G_OBEX_DATA_INHERIT) {
  239. if (!err)
  240. return NULL;
  241. g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_INVALID_ARGS,
  242. "Invalid data policy");
  243. g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
  244. return NULL;
  245. }
  246. if (len < 3 + header_offset) {
  247. if (!err)
  248. return NULL;
  249. g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
  250. "Not enough data to decode packet");
  251. g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
  252. return NULL;
  253. }
  254. buf = get_bytes(&opcode, buf, sizeof(opcode));
  255. buf = get_bytes(&packet_len, buf, sizeof(packet_len));
  256. packet_len = g_ntohs(packet_len);
  257. if (packet_len != len) {
  258. if (!err)
  259. return NULL;
  260. g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
  261. "Incorrect packet length (%u != %zu)",
  262. packet_len, len);
  263. g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
  264. return NULL;
  265. }
  266. final = (opcode & FINAL_BIT) ? TRUE : FALSE;
  267. opcode &= ~FINAL_BIT;
  268. pkt = g_obex_packet_new(opcode, final, G_OBEX_HDR_INVALID);
  269. if (header_offset == 0)
  270. goto headers;
  271. g_obex_packet_set_data(pkt, buf, header_offset, data_policy);
  272. buf += header_offset;
  273. headers:
  274. if (!parse_headers(pkt, buf, len - (3 + header_offset),
  275. data_policy, err))
  276. goto failed;
  277. return pkt;
  278. failed:
  279. g_obex_packet_free(pkt);
  280. return NULL;
  281. }
  282. static gssize get_body(GObexPacket *pkt, guint8 *buf, gsize len)
  283. {
  284. guint16 u16;
  285. gssize ret;
  286. g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
  287. if (len < 3)
  288. return -ENOBUFS;
  289. ret = pkt->get_body(buf + 3, len - 3, pkt->get_body_data);
  290. if (ret < 0)
  291. return ret;
  292. if (ret > 0)
  293. buf[0] = G_OBEX_HDR_BODY;
  294. else
  295. buf[0] = G_OBEX_HDR_BODY_END;
  296. u16 = g_htons(ret + 3);
  297. memcpy(&buf[1], &u16, sizeof(u16));
  298. return ret;
  299. }
  300. gssize g_obex_packet_encode(GObexPacket *pkt, guint8 *buf, gsize len)
  301. {
  302. gssize ret;
  303. gsize count;
  304. guint16 u16;
  305. GSList *l;
  306. g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
  307. if (3 + pkt->data_len + pkt->hlen > len)
  308. return -ENOBUFS;
  309. buf[0] = pkt->opcode;
  310. if (pkt->final)
  311. buf[0] |= FINAL_BIT;
  312. if (pkt->data_len > 0) {
  313. if (pkt->data_policy == G_OBEX_DATA_REF)
  314. memcpy(&buf[3], pkt->data.buf_ref, pkt->data_len);
  315. else
  316. memcpy(&buf[3], pkt->data.buf, pkt->data_len);
  317. }
  318. count = 3 + pkt->data_len;
  319. for (l = pkt->headers; l != NULL; l = g_slist_next(l)) {
  320. GObexHeader *hdr = l->data;
  321. if (count >= len)
  322. return -ENOBUFS;
  323. ret = g_obex_header_encode(hdr, buf + count, len - count);
  324. if (ret < 0)
  325. return ret;
  326. count += ret;
  327. }
  328. if (pkt->get_body) {
  329. ret = get_body(pkt, buf + count, len - count);
  330. if (ret < 0)
  331. return ret;
  332. if (ret == 0) {
  333. if (pkt->opcode == G_OBEX_RSP_CONTINUE)
  334. buf[0] = G_OBEX_RSP_SUCCESS;
  335. buf[0] |= FINAL_BIT;
  336. }
  337. count += ret + 3;
  338. }
  339. u16 = g_htons(count);
  340. memcpy(&buf[1], &u16, sizeof(u16));
  341. return count;
  342. }