/gobex/gobex-packet.c

https://github.com/syamsidhardhan/obexd · C · 409 lines · 298 code · 91 blank · 20 comment · 53 complexity · 280973c13726588e12a5a0efa6c122d9 MD5 · raw file

  1. /*
  2. *
  3. * OBEX library with GLib integration
  4. *
  5. * Copyright (C) 2011 Intel Corporation. All rights reserved.
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  19. *
  20. */
  21. #include <string.h>
  22. #include <errno.h>
  23. #include "gobex-defs.h"
  24. #include "gobex-packet.h"
  25. #define FINAL_BIT 0x80
  26. struct _GObexPacket {
  27. guint8 opcode;
  28. gboolean final;
  29. GObexDataPolicy data_policy;
  30. union {
  31. void *buf; /* Non-header data */
  32. const void *buf_ref; /* Reference to non-header data */
  33. } data;
  34. gsize data_len;
  35. gsize hlen; /* Length of all encoded headers */
  36. GSList *headers;
  37. GObexDataProducer get_body;
  38. gpointer get_body_data;
  39. };
  40. GObexHeader *g_obex_packet_get_header(GObexPacket *pkt, guint8 id)
  41. {
  42. GSList *l;
  43. for (l = pkt->headers; l != NULL; l = g_slist_next(l)) {
  44. GObexHeader *hdr = l->data;
  45. if (g_obex_header_get_id(hdr) == id)
  46. return hdr;
  47. }
  48. return NULL;
  49. }
  50. GObexHeader *g_obex_packet_get_body(GObexPacket *pkt)
  51. {
  52. GObexHeader *body;
  53. body = g_obex_packet_get_header(pkt, G_OBEX_HDR_BODY);
  54. if (body != NULL)
  55. return body;
  56. return g_obex_packet_get_header(pkt, G_OBEX_HDR_BODY_END);
  57. }
  58. guint8 g_obex_packet_get_operation(GObexPacket *pkt, gboolean *final)
  59. {
  60. if (final)
  61. *final = pkt->final;
  62. return pkt->opcode;
  63. }
  64. gboolean g_obex_packet_prepend_header(GObexPacket *pkt, GObexHeader *header)
  65. {
  66. pkt->headers = g_slist_prepend(pkt->headers, header);
  67. pkt->hlen += g_obex_header_get_length(header);
  68. return TRUE;
  69. }
  70. gboolean g_obex_packet_add_header(GObexPacket *pkt, GObexHeader *header)
  71. {
  72. pkt->headers = g_slist_append(pkt->headers, header);
  73. pkt->hlen += g_obex_header_get_length(header);
  74. return TRUE;
  75. }
  76. gboolean g_obex_packet_add_body(GObexPacket *pkt, GObexDataProducer func,
  77. gpointer user_data)
  78. {
  79. if (pkt->get_body != NULL)
  80. return FALSE;
  81. pkt->get_body = func;
  82. pkt->get_body_data = user_data;
  83. return TRUE;
  84. }
  85. gboolean g_obex_packet_add_unicode(GObexPacket *pkt, guint8 id,
  86. const char *str)
  87. {
  88. GObexHeader *hdr;
  89. hdr = g_obex_header_new_unicode(id, str);
  90. if (hdr == NULL)
  91. return FALSE;
  92. return g_obex_packet_add_header(pkt, hdr);
  93. }
  94. gboolean g_obex_packet_add_bytes(GObexPacket *pkt, guint8 id,
  95. const void *data, gsize len)
  96. {
  97. GObexHeader *hdr;
  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. hdr = g_obex_header_new_uint8(id, val);
  107. if (hdr == NULL)
  108. return FALSE;
  109. return g_obex_packet_add_header(pkt, hdr);
  110. }
  111. gboolean g_obex_packet_add_uint32(GObexPacket *pkt, guint8 id, guint32 val)
  112. {
  113. GObexHeader *hdr;
  114. hdr = g_obex_header_new_uint32(id, val);
  115. if (hdr == NULL)
  116. return FALSE;
  117. return g_obex_packet_add_header(pkt, hdr);
  118. }
  119. const void *g_obex_packet_get_data(GObexPacket *pkt, gsize *len)
  120. {
  121. if (pkt->data_len == 0) {
  122. *len = 0;
  123. return NULL;
  124. }
  125. *len = pkt->data_len;
  126. switch (pkt->data_policy) {
  127. case G_OBEX_DATA_INHERIT:
  128. case G_OBEX_DATA_COPY:
  129. return pkt->data.buf;
  130. case G_OBEX_DATA_REF:
  131. return pkt->data.buf_ref;
  132. }
  133. g_assert_not_reached();
  134. }
  135. gboolean g_obex_packet_set_data(GObexPacket *pkt, const void *data, gsize len,
  136. GObexDataPolicy data_policy)
  137. {
  138. if (pkt->data.buf || pkt->data.buf_ref)
  139. return FALSE;
  140. pkt->data_policy = data_policy;
  141. pkt->data_len = len;
  142. switch (data_policy) {
  143. case G_OBEX_DATA_COPY:
  144. pkt->data.buf = g_memdup(data, len);
  145. break;
  146. case G_OBEX_DATA_REF:
  147. pkt->data.buf_ref = data;
  148. break;
  149. case G_OBEX_DATA_INHERIT:
  150. pkt->data.buf = (void *) data;
  151. break;
  152. }
  153. return TRUE;
  154. }
  155. GObexPacket *g_obex_packet_new_valist(guint8 opcode, gboolean final,
  156. guint8 first_hdr_id, va_list args)
  157. {
  158. GObexPacket *pkt;
  159. pkt = g_new0(GObexPacket, 1);
  160. pkt->opcode = opcode;
  161. pkt->final = final;
  162. pkt->headers = g_obex_header_create_list(first_hdr_id, args,
  163. &pkt->hlen);
  164. pkt->data_policy = G_OBEX_DATA_COPY;
  165. return pkt;
  166. }
  167. GObexPacket *g_obex_packet_new(guint8 opcode, gboolean final,
  168. guint8 first_hdr_id, ...)
  169. {
  170. GObexPacket *pkt;
  171. va_list args;
  172. va_start(args, first_hdr_id);
  173. pkt = g_obex_packet_new_valist(opcode, final, first_hdr_id, args);
  174. va_end(args);
  175. return pkt;
  176. }
  177. void g_obex_packet_free(GObexPacket *pkt)
  178. {
  179. switch (pkt->data_policy) {
  180. case G_OBEX_DATA_INHERIT:
  181. case G_OBEX_DATA_COPY:
  182. g_free(pkt->data.buf);
  183. break;
  184. case G_OBEX_DATA_REF:
  185. break;
  186. }
  187. g_slist_foreach(pkt->headers, (GFunc) g_obex_header_free, NULL);
  188. g_slist_free(pkt->headers);
  189. g_free(pkt);
  190. }
  191. static gboolean parse_headers(GObexPacket *pkt, const void *data, gsize len,
  192. GObexDataPolicy data_policy,
  193. GError **err)
  194. {
  195. const guint8 *buf = data;
  196. while (len > 0) {
  197. GObexHeader *header;
  198. gsize parsed;
  199. header = g_obex_header_decode(buf, len, data_policy, &parsed,
  200. err);
  201. if (header == NULL)
  202. return FALSE;
  203. pkt->headers = g_slist_append(pkt->headers, header);
  204. pkt->hlen += parsed;
  205. len -= parsed;
  206. buf += parsed;
  207. }
  208. return TRUE;
  209. }
  210. static const guint8 *get_bytes(void *to, const guint8 *from, gsize count)
  211. {
  212. memcpy(to, from, count);
  213. return (from + count);
  214. }
  215. GObexPacket *g_obex_packet_decode(const void *data, gsize len,
  216. gsize header_offset,
  217. GObexDataPolicy data_policy,
  218. GError **err)
  219. {
  220. const guint8 *buf = data;
  221. guint16 packet_len;
  222. guint8 opcode;
  223. GObexPacket *pkt;
  224. gboolean final;
  225. if (data_policy == G_OBEX_DATA_INHERIT) {
  226. g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_INVALID_ARGS,
  227. "Invalid data policy");
  228. return NULL;
  229. }
  230. if (len < 3 + header_offset) {
  231. g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
  232. "Not enough data to decode packet");
  233. return NULL;
  234. }
  235. buf = get_bytes(&opcode, buf, sizeof(opcode));
  236. buf = get_bytes(&packet_len, buf, sizeof(packet_len));
  237. packet_len = g_ntohs(packet_len);
  238. if (packet_len != len) {
  239. g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
  240. "Incorrect packet length (%u != %zu)",
  241. packet_len, len);
  242. return NULL;
  243. }
  244. final = (opcode & FINAL_BIT) ? TRUE : FALSE;
  245. opcode &= ~FINAL_BIT;
  246. pkt = g_obex_packet_new(opcode, final, G_OBEX_HDR_INVALID);
  247. if (header_offset == 0)
  248. goto headers;
  249. g_obex_packet_set_data(pkt, buf, header_offset, data_policy);
  250. buf += header_offset;
  251. headers:
  252. if (!parse_headers(pkt, buf, len - (3 + header_offset),
  253. data_policy, err))
  254. goto failed;
  255. return pkt;
  256. failed:
  257. g_obex_packet_free(pkt);
  258. return NULL;
  259. }
  260. static gssize get_body(GObexPacket *pkt, guint8 *buf, gsize len)
  261. {
  262. guint16 u16;
  263. gssize ret;
  264. if (len < 3)
  265. return -ENOBUFS;
  266. ret = pkt->get_body(buf + 3, len - 3, pkt->get_body_data);
  267. if (ret < 0)
  268. return ret;
  269. if (ret > 0)
  270. buf[0] = G_OBEX_HDR_BODY;
  271. else
  272. buf[0] = G_OBEX_HDR_BODY_END;
  273. u16 = g_htons(ret + 3);
  274. memcpy(&buf[1], &u16, sizeof(u16));
  275. return ret;
  276. }
  277. gssize g_obex_packet_encode(GObexPacket *pkt, guint8 *buf, gsize len)
  278. {
  279. gssize ret;
  280. gsize count;
  281. guint16 u16;
  282. GSList *l;
  283. if (3 + pkt->data_len + pkt->hlen > len)
  284. return -ENOBUFS;
  285. buf[0] = pkt->opcode;
  286. if (pkt->final)
  287. buf[0] |= FINAL_BIT;
  288. if (pkt->data_len > 0) {
  289. if (pkt->data_policy == G_OBEX_DATA_REF)
  290. memcpy(&buf[3], pkt->data.buf_ref, pkt->data_len);
  291. else
  292. memcpy(&buf[3], pkt->data.buf, pkt->data_len);
  293. }
  294. count = 3 + pkt->data_len;
  295. for (l = pkt->headers; l != NULL; l = g_slist_next(l)) {
  296. GObexHeader *hdr = l->data;
  297. if (count >= len)
  298. return -ENOBUFS;
  299. ret = g_obex_header_encode(hdr, buf + count, len - count);
  300. if (ret < 0)
  301. return ret;
  302. count += ret;
  303. }
  304. if (pkt->get_body) {
  305. ret = get_body(pkt, buf + count, len - count);
  306. if (ret < 0)
  307. return ret;
  308. if (ret == 0) {
  309. if (pkt->opcode == G_OBEX_RSP_CONTINUE)
  310. buf[0] = G_OBEX_RSP_SUCCESS;
  311. buf[0] |= FINAL_BIT;
  312. }
  313. count += ret + 3;
  314. }
  315. u16 = g_htons(count);
  316. memcpy(&buf[1], &u16, sizeof(u16));
  317. return count;
  318. }