gobex-transfer.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  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/gobex.h"
  15. #include "gobex/gobex-debug.h"
  16. #define FIRST_PACKET_TIMEOUT 60
  17. static GSList *transfers = NULL;
  18. static void transfer_response(GObex *obex, GError *err, GObexPacket *rsp,
  19. gpointer user_data);
  20. struct transfer {
  21. guint id;
  22. guint8 opcode;
  23. GObex *obex;
  24. guint req_id;
  25. guint put_id;
  26. guint get_id;
  27. guint abort_id;
  28. GObexDataProducer data_producer;
  29. GObexDataConsumer data_consumer;
  30. GObexFunc complete_func;
  31. gpointer user_data;
  32. };
  33. static void transfer_free(struct transfer *transfer)
  34. {
  35. g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
  36. transfers = g_slist_remove(transfers, transfer);
  37. if (transfer->req_id > 0)
  38. g_obex_cancel_req(transfer->obex, transfer->req_id, TRUE);
  39. if (transfer->put_id > 0)
  40. g_obex_remove_request_function(transfer->obex,
  41. transfer->put_id);
  42. if (transfer->get_id > 0)
  43. g_obex_remove_request_function(transfer->obex,
  44. transfer->get_id);
  45. if (transfer->abort_id > 0)
  46. g_obex_remove_request_function(transfer->obex,
  47. transfer->abort_id);
  48. g_obex_unref(transfer->obex);
  49. g_free(transfer);
  50. }
  51. static struct transfer *find_transfer(guint id)
  52. {
  53. GSList *l;
  54. for (l = transfers; l != NULL; l = g_slist_next(l)) {
  55. struct transfer *t = l->data;
  56. if (t->id == id)
  57. return t;
  58. }
  59. return NULL;
  60. }
  61. static void transfer_complete(struct transfer *transfer, GError *err)
  62. {
  63. guint id = transfer->id;
  64. g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", id);
  65. if (err) {
  66. /* No further tx must be performed */
  67. g_obex_drop_tx_queue(transfer->obex);
  68. }
  69. transfer->complete_func(transfer->obex, err, transfer->user_data);
  70. /* Check if the complete_func removed the transfer */
  71. if (find_transfer(id) == NULL)
  72. return;
  73. transfer_free(transfer);
  74. }
  75. static void transfer_abort_response(GObex *obex, GError *err, GObexPacket *rsp,
  76. gpointer user_data)
  77. {
  78. struct transfer *transfer = user_data;
  79. g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
  80. transfer->req_id = 0;
  81. /* Intentionally override error */
  82. err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
  83. "Operation was aborted");
  84. g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
  85. transfer_complete(transfer, err);
  86. g_error_free(err);
  87. }
  88. static gssize put_get_data(void *buf, gsize len, gpointer user_data)
  89. {
  90. struct transfer *transfer = user_data;
  91. GObexPacket *req;
  92. GError *err = NULL;
  93. gssize ret;
  94. ret = transfer->data_producer(buf, len, transfer->user_data);
  95. if (ret == 0 || ret == -EAGAIN)
  96. return ret;
  97. if (ret > 0) {
  98. /* Check if SRM is active */
  99. if (!g_obex_srm_active(transfer->obex))
  100. return ret;
  101. /* Generate next packet */
  102. req = g_obex_packet_new(transfer->opcode, FALSE,
  103. G_OBEX_HDR_INVALID);
  104. g_obex_packet_add_body(req, put_get_data, transfer);
  105. transfer->req_id = g_obex_send_req(transfer->obex, req, -1,
  106. transfer_response, transfer,
  107. &err);
  108. goto done;
  109. }
  110. transfer->req_id = g_obex_abort(transfer->obex, transfer_abort_response,
  111. transfer, &err);
  112. done:
  113. if (err != NULL) {
  114. transfer_complete(transfer, err);
  115. g_error_free(err);
  116. }
  117. return ret;
  118. }
  119. static gboolean handle_get_body(struct transfer *transfer, GObexPacket *rsp,
  120. GError **err)
  121. {
  122. GObexHeader *body = g_obex_packet_get_body(rsp);
  123. gboolean ret;
  124. const guint8 *buf;
  125. gsize len;
  126. if (body == NULL)
  127. return TRUE;
  128. g_obex_header_get_bytes(body, &buf, &len);
  129. if (len == 0)
  130. return TRUE;
  131. ret = transfer->data_consumer(buf, len, transfer->user_data);
  132. if (ret == FALSE)
  133. g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
  134. "Data consumer callback failed");
  135. return ret;
  136. }
  137. static void transfer_response(GObex *obex, GError *err, GObexPacket *rsp,
  138. gpointer user_data)
  139. {
  140. struct transfer *transfer = user_data;
  141. GObexPacket *req;
  142. gboolean rspcode, final;
  143. guint id;
  144. g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
  145. id = transfer->req_id;
  146. transfer->req_id = 0;
  147. if (err != NULL) {
  148. transfer_complete(transfer, err);
  149. return;
  150. }
  151. rspcode = g_obex_packet_get_operation(rsp, &final);
  152. if (rspcode != G_OBEX_RSP_SUCCESS && rspcode != G_OBEX_RSP_CONTINUE) {
  153. err = g_error_new(G_OBEX_ERROR, rspcode, "%s",
  154. g_obex_strerror(rspcode));
  155. goto failed;
  156. }
  157. if (transfer->opcode == G_OBEX_OP_GET) {
  158. handle_get_body(transfer, rsp, &err);
  159. if (err != NULL)
  160. goto failed;
  161. }
  162. if (rspcode == G_OBEX_RSP_SUCCESS) {
  163. transfer_complete(transfer, NULL);
  164. return;
  165. }
  166. if (transfer->opcode == G_OBEX_OP_PUT) {
  167. req = g_obex_packet_new(transfer->opcode, FALSE,
  168. G_OBEX_HDR_INVALID);
  169. g_obex_packet_add_body(req, put_get_data, transfer);
  170. } else if (!g_obex_srm_active(transfer->obex)) {
  171. req = g_obex_packet_new(transfer->opcode, TRUE,
  172. G_OBEX_HDR_INVALID);
  173. } else {
  174. /* Keep id since request still outstanting */
  175. transfer->req_id = id;
  176. return;
  177. }
  178. transfer->req_id = g_obex_send_req(obex, req, -1, transfer_response,
  179. transfer, &err);
  180. failed:
  181. if (err != NULL) {
  182. g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
  183. transfer_complete(transfer, err);
  184. g_error_free(err);
  185. }
  186. }
  187. static struct transfer *transfer_new(GObex *obex, guint8 opcode,
  188. GObexFunc complete_func, gpointer user_data)
  189. {
  190. static guint next_id = 1;
  191. struct transfer *transfer;
  192. g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p opcode %u", obex, opcode);
  193. transfer = g_new0(struct transfer, 1);
  194. transfer->id = next_id++;
  195. transfer->opcode = opcode;
  196. transfer->obex = g_obex_ref(obex);
  197. transfer->complete_func = complete_func;
  198. transfer->user_data = user_data;
  199. transfers = g_slist_append(transfers, transfer);
  200. return transfer;
  201. }
  202. guint g_obex_put_req_pkt(GObex *obex, GObexPacket *req,
  203. GObexDataProducer data_func, GObexFunc complete_func,
  204. gpointer user_data, GError **err)
  205. {
  206. struct transfer *transfer;
  207. g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
  208. if (g_obex_packet_get_operation(req, NULL) != G_OBEX_OP_PUT)
  209. return 0;
  210. transfer = transfer_new(obex, G_OBEX_OP_PUT, complete_func, user_data);
  211. transfer->data_producer = data_func;
  212. g_obex_packet_add_body(req, put_get_data, transfer);
  213. transfer->req_id = g_obex_send_req(obex, req, FIRST_PACKET_TIMEOUT,
  214. transfer_response, transfer, err);
  215. if (transfer->req_id == 0) {
  216. transfer_free(transfer);
  217. return 0;
  218. }
  219. g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
  220. return transfer->id;
  221. }
  222. guint g_obex_put_req(GObex *obex, GObexDataProducer data_func,
  223. GObexFunc complete_func, gpointer user_data,
  224. GError **err, guint first_hdr_id, ...)
  225. {
  226. GObexPacket *req;
  227. va_list args;
  228. g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
  229. va_start(args, first_hdr_id);
  230. req = g_obex_packet_new_valist(G_OBEX_OP_PUT, FALSE,
  231. first_hdr_id, args);
  232. va_end(args);
  233. return g_obex_put_req_pkt(obex, req, data_func, complete_func,
  234. user_data, err);
  235. }
  236. static void transfer_abort_req(GObex *obex, GObexPacket *req, gpointer user_data)
  237. {
  238. struct transfer *transfer = user_data;
  239. GObexPacket *rsp;
  240. GError *err;
  241. g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
  242. err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
  243. "Request was aborted");
  244. rsp = g_obex_packet_new(G_OBEX_RSP_SUCCESS, TRUE, G_OBEX_HDR_INVALID);
  245. g_obex_send(obex, rsp, NULL);
  246. transfer_complete(transfer, err);
  247. g_error_free(err);
  248. }
  249. static guint8 put_get_bytes(struct transfer *transfer, GObexPacket *req)
  250. {
  251. GObexHeader *body;
  252. gboolean final;
  253. guint8 rsp;
  254. const guint8 *buf;
  255. gsize len;
  256. g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
  257. g_obex_packet_get_operation(req, &final);
  258. if (final)
  259. rsp = G_OBEX_RSP_SUCCESS;
  260. else
  261. rsp = G_OBEX_RSP_CONTINUE;
  262. body = g_obex_packet_get_body(req);
  263. if (body == NULL)
  264. return rsp;
  265. g_obex_header_get_bytes(body, &buf, &len);
  266. if (len == 0)
  267. return rsp;
  268. if (transfer->data_consumer(buf, len, transfer->user_data) == FALSE)
  269. rsp = G_OBEX_RSP_FORBIDDEN;
  270. return rsp;
  271. }
  272. static void transfer_put_req_first(struct transfer *transfer, GObexPacket *req,
  273. guint8 first_hdr_id, va_list args)
  274. {
  275. GError *err = NULL;
  276. GObexPacket *rsp;
  277. guint8 rspcode;
  278. g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
  279. rspcode = put_get_bytes(transfer, req);
  280. rsp = g_obex_packet_new_valist(rspcode, TRUE, first_hdr_id, args);
  281. if (!g_obex_send(transfer->obex, rsp, &err)) {
  282. transfer_complete(transfer, err);
  283. g_error_free(err);
  284. return;
  285. }
  286. if (rspcode != G_OBEX_RSP_CONTINUE)
  287. transfer_complete(transfer, NULL);
  288. }
  289. static void transfer_put_req(GObex *obex, GObexPacket *req, gpointer user_data)
  290. {
  291. struct transfer *transfer = user_data;
  292. GError *err = NULL;
  293. GObexPacket *rsp;
  294. guint8 rspcode;
  295. g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
  296. rspcode = put_get_bytes(transfer, req);
  297. /* Don't send continue while SRM is active */
  298. if (g_obex_srm_active(transfer->obex) &&
  299. rspcode == G_OBEX_RSP_CONTINUE)
  300. goto done;
  301. rsp = g_obex_packet_new(rspcode, TRUE, G_OBEX_HDR_INVALID);
  302. if (!g_obex_send(obex, rsp, &err)) {
  303. transfer_complete(transfer, err);
  304. g_error_free(err);
  305. return;
  306. }
  307. done:
  308. if (rspcode != G_OBEX_RSP_CONTINUE)
  309. transfer_complete(transfer, NULL);
  310. }
  311. guint g_obex_put_rsp(GObex *obex, GObexPacket *req,
  312. GObexDataConsumer data_func, GObexFunc complete_func,
  313. gpointer user_data, GError **err,
  314. guint first_hdr_id, ...)
  315. {
  316. struct transfer *transfer;
  317. va_list args;
  318. guint id;
  319. g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
  320. transfer = transfer_new(obex, G_OBEX_OP_PUT, complete_func, user_data);
  321. transfer->data_consumer = data_func;
  322. va_start(args, first_hdr_id);
  323. transfer_put_req_first(transfer, req, first_hdr_id, args);
  324. va_end(args);
  325. if (!g_slist_find(transfers, transfer))
  326. return 0;
  327. id = g_obex_add_request_function(obex, G_OBEX_OP_PUT, transfer_put_req,
  328. transfer);
  329. transfer->put_id = id;
  330. id = g_obex_add_request_function(obex, G_OBEX_OP_ABORT,
  331. transfer_abort_req, transfer);
  332. transfer->abort_id = id;
  333. g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
  334. return transfer->id;
  335. }
  336. guint g_obex_get_req_pkt(GObex *obex, GObexPacket *req,
  337. GObexDataConsumer data_func, GObexFunc complete_func,
  338. gpointer user_data, GError **err)
  339. {
  340. struct transfer *transfer;
  341. g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
  342. if (g_obex_packet_get_operation(req, NULL) != G_OBEX_OP_GET)
  343. return 0;
  344. transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data);
  345. transfer->data_consumer = data_func;
  346. transfer->req_id = g_obex_send_req(obex, req, FIRST_PACKET_TIMEOUT,
  347. transfer_response, transfer, err);
  348. if (transfer->req_id == 0) {
  349. transfer_free(transfer);
  350. return 0;
  351. }
  352. g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
  353. return transfer->id;
  354. }
  355. guint g_obex_get_req(GObex *obex, GObexDataConsumer data_func,
  356. GObexFunc complete_func, gpointer user_data,
  357. GError **err, guint first_hdr_id, ...)
  358. {
  359. struct transfer *transfer;
  360. GObexPacket *req;
  361. va_list args;
  362. g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
  363. transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data);
  364. transfer->data_consumer = data_func;
  365. va_start(args, first_hdr_id);
  366. req = g_obex_packet_new_valist(G_OBEX_OP_GET, TRUE,
  367. first_hdr_id, args);
  368. va_end(args);
  369. transfer->req_id = g_obex_send_req(obex, req, FIRST_PACKET_TIMEOUT,
  370. transfer_response, transfer, err);
  371. if (transfer->req_id == 0) {
  372. transfer_free(transfer);
  373. return 0;
  374. }
  375. g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
  376. return transfer->id;
  377. }
  378. static gssize get_get_data(void *buf, gsize len, gpointer user_data)
  379. {
  380. struct transfer *transfer = user_data;
  381. GObexPacket *req, *rsp;
  382. GError *err = NULL;
  383. gssize ret;
  384. guint8 op;
  385. g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
  386. ret = transfer->data_producer(buf, len, transfer->user_data);
  387. if (ret > 0) {
  388. if (!g_obex_srm_active(transfer->obex))
  389. return ret;
  390. /* Generate next response */
  391. rsp = g_obex_packet_new(G_OBEX_RSP_CONTINUE, TRUE,
  392. G_OBEX_HDR_INVALID);
  393. g_obex_packet_add_body(rsp, get_get_data, transfer);
  394. if (!g_obex_send(transfer->obex, rsp, &err)) {
  395. transfer_complete(transfer, err);
  396. g_error_free(err);
  397. }
  398. return ret;
  399. }
  400. if (ret == -EAGAIN)
  401. return ret;
  402. if (ret == 0) {
  403. transfer_complete(transfer, NULL);
  404. return ret;
  405. }
  406. op = g_obex_errno_to_rsp(ret);
  407. req = g_obex_packet_new(op, TRUE, G_OBEX_HDR_INVALID);
  408. g_obex_send(transfer->obex, req, NULL);
  409. err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
  410. "Data producer function failed");
  411. g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
  412. transfer_complete(transfer, err);
  413. g_error_free(err);
  414. return ret;
  415. }
  416. static gboolean transfer_get_req_first(struct transfer *transfer,
  417. GObexPacket *rsp)
  418. {
  419. GError *err = NULL;
  420. g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
  421. g_obex_packet_add_body(rsp, get_get_data, transfer);
  422. if (!g_obex_send(transfer->obex, rsp, &err)) {
  423. transfer_complete(transfer, err);
  424. g_error_free(err);
  425. return FALSE;
  426. }
  427. return TRUE;
  428. }
  429. static void transfer_get_req(GObex *obex, GObexPacket *req, gpointer user_data)
  430. {
  431. struct transfer *transfer = user_data;
  432. GError *err = NULL;
  433. GObexPacket *rsp;
  434. g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
  435. rsp = g_obex_packet_new(G_OBEX_RSP_CONTINUE, TRUE, G_OBEX_HDR_INVALID);
  436. g_obex_packet_add_body(rsp, get_get_data, transfer);
  437. if (!g_obex_send(obex, rsp, &err)) {
  438. transfer_complete(transfer, err);
  439. g_error_free(err);
  440. }
  441. }
  442. guint g_obex_get_rsp_pkt(GObex *obex, GObexPacket *rsp,
  443. GObexDataProducer data_func, GObexFunc complete_func,
  444. gpointer user_data, GError **err)
  445. {
  446. struct transfer *transfer;
  447. guint id;
  448. g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
  449. transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data);
  450. transfer->data_producer = data_func;
  451. if (!transfer_get_req_first(transfer, rsp))
  452. return 0;
  453. if (!g_slist_find(transfers, transfer))
  454. return 0;
  455. id = g_obex_add_request_function(obex, G_OBEX_OP_GET, transfer_get_req,
  456. transfer);
  457. transfer->get_id = id;
  458. id = g_obex_add_request_function(obex, G_OBEX_OP_ABORT,
  459. transfer_abort_req, transfer);
  460. transfer->abort_id = id;
  461. g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
  462. return transfer->id;
  463. }
  464. guint g_obex_get_rsp(GObex *obex, GObexDataProducer data_func,
  465. GObexFunc complete_func, gpointer user_data,
  466. GError **err, guint first_hdr_id, ...)
  467. {
  468. GObexPacket *rsp;
  469. va_list args;
  470. g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
  471. va_start(args, first_hdr_id);
  472. rsp = g_obex_packet_new_valist(G_OBEX_RSP_CONTINUE, TRUE,
  473. first_hdr_id, args);
  474. va_end(args);
  475. return g_obex_get_rsp_pkt(obex, rsp, data_func, complete_func,
  476. user_data, err);
  477. }
  478. gboolean g_obex_cancel_transfer(guint id, GObexFunc complete_func,
  479. gpointer user_data)
  480. {
  481. struct transfer *transfer = NULL;
  482. gboolean ret = TRUE;
  483. g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", id);
  484. transfer = find_transfer(id);
  485. if (transfer == NULL)
  486. return FALSE;
  487. if (complete_func == NULL)
  488. goto done;
  489. transfer->complete_func = complete_func;
  490. transfer->user_data = user_data;
  491. if (!transfer->req_id) {
  492. transfer->req_id = g_obex_abort(transfer->obex,
  493. transfer_abort_response,
  494. transfer, NULL);
  495. if (transfer->req_id)
  496. return TRUE;
  497. }
  498. ret = g_obex_cancel_req(transfer->obex, transfer->req_id, FALSE);
  499. if (ret)
  500. return TRUE;
  501. done:
  502. transfer_free(transfer);
  503. return ret;
  504. }