1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * OBEX library with GLib integration
6 * Copyright (C) 2011 Intel Corporation. All rights reserved.
19 #include "gobex-debug.h"
21 #define G_OBEX_DEFAULT_MTU 4096
22 #define G_OBEX_MINIMUM_MTU 255
23 #define G_OBEX_MAXIMUM_MTU 65535
25 #define G_OBEX_DEFAULT_TIMEOUT 10
26 #define G_OBEX_ABORT_TIMEOUT 5
28 #define G_OBEX_OP_NONE 0xff
30 #define FINAL_BIT 0x80
32 #define CONNID_INVALID 0xffffffff
34 /* Challenge request */
35 #define NONCE_TAG 0x00
38 /* Challenge response */
39 #define DIGEST_TAG 0x00
41 guint gobex_debug = 0;
56 gboolean (*read) (GObex *obex, GError **err);
57 gboolean (*write) (GObex *obex, GError **err);
71 struct srm_config *srm;
82 GObexApparam *authchal;
88 GObexFunc disconn_func;
89 gpointer disconn_func_data;
91 struct pending_pkt *pending_req;
100 GObexResponseFunc rsp_func;
104 gboolean authenticating;
110 GObexRequestFunc func;
114 struct connect_data {
118 } __attribute__ ((packed));
120 struct setpath_data {
123 } __attribute__ ((packed));
125 static struct error_code {
129 { G_OBEX_RSP_CONTINUE, "Continue" },
130 { G_OBEX_RSP_SUCCESS, "Success" },
131 { G_OBEX_RSP_CREATED, "Created" },
132 { G_OBEX_RSP_ACCEPTED, "Accepted" },
133 { G_OBEX_RSP_NON_AUTHORITATIVE, "Non Authoritative" },
134 { G_OBEX_RSP_NO_CONTENT, "No Content" },
135 { G_OBEX_RSP_RESET_CONTENT, "Reset Content" },
136 { G_OBEX_RSP_PARTIAL_CONTENT, "Partial Content" },
137 { G_OBEX_RSP_MULTIPLE_CHOICES, "Multiple Choices" },
138 { G_OBEX_RSP_MOVED_PERMANENTLY, "Moved Permanently" },
139 { G_OBEX_RSP_MOVED_TEMPORARILY, "Moved Temporarily" },
140 { G_OBEX_RSP_SEE_OTHER, "See Other" },
141 { G_OBEX_RSP_NOT_MODIFIED, "Not Modified" },
142 { G_OBEX_RSP_USE_PROXY, "Use Proxy" },
143 { G_OBEX_RSP_BAD_REQUEST, "Bad Request" },
144 { G_OBEX_RSP_UNAUTHORIZED, "Unauthorized" },
145 { G_OBEX_RSP_PAYMENT_REQUIRED, "Payment Required" },
146 { G_OBEX_RSP_FORBIDDEN, "Forbidden" },
147 { G_OBEX_RSP_NOT_FOUND, "Not Found" },
148 { G_OBEX_RSP_METHOD_NOT_ALLOWED, "Method Not Allowed" },
149 { G_OBEX_RSP_NOT_ACCEPTABLE, "Not Acceptable" },
150 { G_OBEX_RSP_PROXY_AUTH_REQUIRED, "Proxy Authentication Required" },
151 { G_OBEX_RSP_REQUEST_TIME_OUT, "Request Time Out" },
152 { G_OBEX_RSP_CONFLICT, "Conflict" },
153 { G_OBEX_RSP_GONE, "Gone" },
154 { G_OBEX_RSP_LENGTH_REQUIRED, "Length Required" },
155 { G_OBEX_RSP_PRECONDITION_FAILED, "Precondition Failed" },
156 { G_OBEX_RSP_REQ_ENTITY_TOO_LARGE, "Request Entity Too Large" },
157 { G_OBEX_RSP_REQ_URL_TOO_LARGE, "Request URL Too Large" },
158 { G_OBEX_RSP_UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type" },
159 { G_OBEX_RSP_INTERNAL_SERVER_ERROR, "Internal Server Error" },
160 { G_OBEX_RSP_NOT_IMPLEMENTED, "Not Implemented" },
161 { G_OBEX_RSP_BAD_GATEWAY, "Bad Gateway" },
162 { G_OBEX_RSP_SERVICE_UNAVAILABLE, "Service Unavailable" },
163 { G_OBEX_RSP_GATEWAY_TIMEOUT, "Gateway Timeout" },
164 { G_OBEX_RSP_VERSION_NOT_SUPPORTED, "Version Not Supported" },
165 { G_OBEX_RSP_DATABASE_FULL, "Database Full" },
166 { G_OBEX_RSP_DATABASE_LOCKED, "Database Locked" },
170 const char *g_obex_strerror(guint8 err_code)
172 struct error_code *error;
174 for (error = obex_errors; error->name != NULL; error++) {
175 if (error->code == err_code)
182 static ssize_t req_header_offset(guint8 opcode)
185 case G_OBEX_OP_CONNECT:
186 return sizeof(struct connect_data);
187 case G_OBEX_OP_SETPATH:
188 return sizeof(struct setpath_data);
189 case G_OBEX_OP_DISCONNECT:
192 case G_OBEX_OP_SESSION:
193 case G_OBEX_OP_ABORT:
194 case G_OBEX_OP_ACTION:
201 static ssize_t rsp_header_offset(guint8 opcode)
204 case G_OBEX_OP_CONNECT:
205 return sizeof(struct connect_data);
206 case G_OBEX_OP_SETPATH:
207 case G_OBEX_OP_DISCONNECT:
210 case G_OBEX_OP_SESSION:
211 case G_OBEX_OP_ABORT:
212 case G_OBEX_OP_ACTION:
219 static void pending_pkt_free(struct pending_pkt *p)
222 g_obex_unref(p->obex);
224 if (p->timeout_id > 0)
225 g_source_remove(p->timeout_id);
227 g_obex_packet_free(p->pkt);
232 static gboolean req_timeout(gpointer user_data)
234 GObex *obex = user_data;
235 struct pending_pkt *p = obex->pending_req;
241 obex->pending_req = NULL;
243 err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_TIMEOUT,
244 "Timed out waiting for response");
246 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
249 p->rsp_func(obex, err, NULL, p->rsp_data);
257 static gboolean write_stream(GObex *obex, GError **err)
263 buf = (char *) &obex->tx_buf[obex->tx_sent];
264 status = g_io_channel_write_chars(obex->io, buf, obex->tx_data,
265 &bytes_written, err);
266 if (status != G_IO_STATUS_NORMAL)
269 g_obex_dump(G_OBEX_DEBUG_DATA, "<", buf, bytes_written);
271 obex->tx_sent += bytes_written;
272 obex->tx_data -= bytes_written;
277 static gboolean write_packet(GObex *obex, GError **err)
283 buf = (char *) &obex->tx_buf[obex->tx_sent];
284 status = g_io_channel_write_chars(obex->io, buf, obex->tx_data,
285 &bytes_written, err);
286 if (status != G_IO_STATUS_NORMAL)
289 if (bytes_written != obex->tx_data)
292 g_obex_dump(G_OBEX_DEBUG_DATA, "<", buf, bytes_written);
294 obex->tx_sent += bytes_written;
295 obex->tx_data -= bytes_written;
300 static void set_srmp(GObex *obex, guint8 srmp, gboolean outgoing)
302 struct srm_config *config = obex->srm;
307 /* Dont't reset if direction doesn't match */
308 if (srmp > G_OBEX_SRMP_NEXT_WAIT && config->outgoing != outgoing)
312 config->outgoing = outgoing;
315 static void set_srm(GObex *obex, guint8 op, guint8 srm)
317 struct srm_config *config = obex->srm;
320 if (config == NULL) {
321 if (srm == G_OBEX_SRM_DISABLE)
324 config = g_new0(struct srm_config, 1);
331 /* Indicate response, treat it as request */
332 if (config->srm == G_OBEX_SRM_INDICATE) {
333 if (srm != G_OBEX_SRM_ENABLE)
339 enable = (srm == G_OBEX_SRM_ENABLE);
340 if (config->enabled == enable)
343 config->enabled = enable;
345 g_obex_debug(G_OBEX_DEBUG_COMMAND, "SRM %s", config->enabled ?
346 "Enabled" : "Disabled");
356 static gboolean g_obex_srm_enabled(GObex *obex)
361 if (obex->srm == NULL)
364 return obex->srm->enabled;
367 static void check_srm_final(GObex *obex, guint8 op)
369 if (!g_obex_srm_enabled(obex))
372 switch (obex->srm->op) {
373 case G_OBEX_OP_CONNECT:
376 if (op <= G_OBEX_RSP_CONTINUE)
380 set_srm(obex, op, G_OBEX_SRM_DISABLE);
383 static void setup_srm(GObex *obex, GObexPacket *pkt, gboolean outgoing)
392 op = g_obex_packet_get_operation(pkt, &final);
394 hdr = g_obex_packet_get_header(pkt, G_OBEX_HDR_SRM);
397 g_obex_header_get_uint8(hdr, &srm);
398 g_obex_debug(G_OBEX_DEBUG_COMMAND, "srm 0x%02x", srm);
399 set_srm(obex, op, srm);
400 } else if (!g_obex_srm_enabled(obex))
401 set_srm(obex, op, G_OBEX_SRM_DISABLE);
403 hdr = g_obex_packet_get_header(pkt, G_OBEX_HDR_SRMP);
406 g_obex_header_get_uint8(hdr, &srmp);
407 g_obex_debug(G_OBEX_DEBUG_COMMAND, "srmp 0x%02x", srmp);
408 set_srmp(obex, srmp, outgoing);
409 } else if (obex->pending_req && obex->pending_req->suspended)
410 g_obex_packet_add_uint8(pkt, G_OBEX_HDR_SRMP, G_OBEX_SRMP_WAIT);
412 set_srmp(obex, -1, outgoing);
415 check_srm_final(obex, op);
418 static gboolean write_data(GIOChannel *io, GIOCondition cond,
421 GObex *obex = user_data;
423 if (cond & G_IO_NVAL)
426 if (cond & (G_IO_HUP | G_IO_ERR))
429 if (obex->tx_data == 0) {
430 struct pending_pkt *p = g_queue_pop_head(obex->tx_queue);
436 setup_srm(obex, p->pkt, TRUE);
438 if (g_obex_srm_enabled(obex))
441 /* Can't send a request while there's a pending one */
442 if (obex->pending_req && p->id > 0) {
443 g_queue_push_head(obex->tx_queue, p);
448 len = g_obex_packet_encode(p->pkt, obex->tx_buf, obex->tx_mtu);
449 if (len == -EAGAIN) {
450 g_queue_push_head(obex->tx_queue, p);
451 g_obex_suspend(obex);
461 if (obex->pending_req != NULL)
462 pending_pkt_free(obex->pending_req);
463 obex->pending_req = p;
464 p->timeout_id = g_timeout_add_seconds(p->timeout,
467 /* During packet encode final bit can be set */
468 if (obex->tx_buf[0] & FINAL_BIT)
469 check_srm_final(obex,
470 obex->tx_buf[0] & ~FINAL_BIT);
478 if (obex->suspended) {
479 obex->write_source = 0;
483 if (!obex->write(obex, NULL))
487 if (obex->tx_data > 0 || g_queue_get_length(obex->tx_queue) > 0)
491 obex->rx_last_op = G_OBEX_OP_NONE;
493 obex->write_source = 0;
497 static void enable_tx(GObex *obex)
504 if (!obex->io || obex->write_source > 0)
507 cond = G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
508 obex->write_source = g_io_add_watch(obex->io, cond, write_data, obex);
511 void g_obex_drop_tx_queue(GObex *obex)
513 struct pending_pkt *p;
515 g_obex_debug(G_OBEX_DEBUG_COMMAND, "");
517 while ((p = g_queue_pop_head(obex->tx_queue)))
521 static gboolean g_obex_send_internal(GObex *obex, struct pending_pkt *p,
525 if (obex->io == NULL) {
528 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_DISCONNECTED,
529 "The transport is not connected");
530 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
534 if (g_obex_packet_get_operation(p->pkt, NULL) == G_OBEX_OP_ABORT)
535 g_queue_push_head(obex->tx_queue, p);
537 g_queue_push_tail(obex->tx_queue, p);
539 if (obex->pending_req == NULL || p->id == 0)
545 static void init_connect_data(GObex *obex, struct connect_data *data)
549 memset(data, 0, sizeof(*data));
551 data->version = 0x10;
554 u16 = g_htons(obex->rx_mtu);
555 memcpy(&data->mtu, &u16, sizeof(u16));
558 static guint8 *digest_response(const guint8 *nonce)
564 result = g_new0(guint8, NONCE_LEN);
566 md5 = g_checksum_new(G_CHECKSUM_MD5);
570 g_checksum_update(md5, nonce, NONCE_LEN);
571 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
572 g_checksum_update(md5, (guint8 *) ":0000", 5);
574 g_checksum_update(md5, (guint8 *) ":BlueZ", 6);
575 #endif /* TIZEN_FEATURE_BLUEZ_MODIFY */
579 g_checksum_get_digest(md5, result, &size);
581 g_checksum_free(md5);
586 static void prepare_auth_rsp(GObex *obex, GObexPacket *rsp)
589 GObexApparam *authrsp;
594 /* Check if client is already responding to authentication challenge */
595 hdr = g_obex_packet_get_header(rsp, G_OBEX_HDR_AUTHRESP);
599 if (!g_obex_apparam_get_bytes(obex->authchal, NONCE_TAG, &nonce, &len))
602 if (len != NONCE_LEN)
605 result = digest_response(nonce);
606 authrsp = g_obex_apparam_set_bytes(NULL, DIGEST_TAG, result, NONCE_LEN);
608 hdr = g_obex_header_new_tag(G_OBEX_HDR_AUTHRESP, authrsp);
609 g_obex_packet_add_header(rsp, hdr);
611 g_obex_apparam_free(authrsp);
615 g_obex_apparam_free(obex->authchal);
616 obex->authchal = NULL;
619 static void prepare_connect_rsp(GObex *obex, GObexPacket *rsp)
622 struct connect_data data;
623 static guint32 next_connid = 1;
625 init_connect_data(obex, &data);
626 g_obex_packet_set_data(rsp, &data, sizeof(data), G_OBEX_DATA_COPY);
628 hdr = g_obex_packet_get_header(rsp, G_OBEX_HDR_CONNECTION);
630 g_obex_header_get_uint32(hdr, &obex->conn_id);
634 obex->conn_id = next_connid++;
636 hdr = g_obex_header_new_uint32(G_OBEX_HDR_CONNECTION, obex->conn_id);
637 g_obex_packet_prepend_header(rsp, hdr);
641 prepare_auth_rsp(obex, rsp);
644 static void prepare_srm_rsp(GObex *obex, GObexPacket *pkt)
648 if (!obex->use_srm || obex->srm == NULL)
651 if (obex->srm->enabled)
654 hdr = g_obex_packet_get_header(pkt, G_OBEX_HDR_SRM);
658 hdr = g_obex_header_new_uint8(G_OBEX_HDR_SRM, G_OBEX_SRM_ENABLE);
659 g_obex_packet_prepend_header(pkt, hdr);
662 gboolean g_obex_send(GObex *obex, GObexPacket *pkt, GError **err)
664 struct pending_pkt *p;
667 g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
669 if (obex == NULL || pkt == NULL) {
672 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_INVALID_ARGS,
673 "Invalid arguments");
674 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
678 switch (obex->rx_last_op) {
679 case G_OBEX_OP_CONNECT:
680 prepare_connect_rsp(obex, pkt);
684 prepare_srm_rsp(obex, pkt);
688 p = g_new0(struct pending_pkt, 1);
691 ret = g_obex_send_internal(obex, p, err);
698 static void prepare_srm_req(GObex *obex, GObexPacket *pkt)
705 if (obex->srm != NULL && obex->srm->enabled)
708 hdr = g_obex_packet_get_header(pkt, G_OBEX_HDR_SRM);
712 hdr = g_obex_header_new_uint8(G_OBEX_HDR_SRM, G_OBEX_SRM_ENABLE);
713 g_obex_packet_prepend_header(pkt, hdr);
716 guint g_obex_send_req(GObex *obex, GObexPacket *req, int timeout,
717 GObexResponseFunc func, gpointer user_data,
721 struct pending_pkt *p;
725 g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
727 op = g_obex_packet_get_operation(req, NULL);
728 if (op == G_OBEX_OP_PUT || op == G_OBEX_OP_GET) {
729 /* Only enable SRM automatically for GET and PUT */
730 prepare_srm_req(obex, req);
733 if (obex->conn_id == CONNID_INVALID)
736 if (obex->rx_last_op == G_OBEX_RSP_CONTINUE)
739 if (g_obex_srm_enabled(obex) && obex->pending_req != NULL)
742 hdr = g_obex_packet_get_header(req, G_OBEX_HDR_CONNECTION);
746 hdr = g_obex_header_new_uint32(G_OBEX_HDR_CONNECTION, obex->conn_id);
747 g_obex_packet_prepend_header(req, hdr);
750 p = g_new0(struct pending_pkt, 1);
755 p->rsp_data = user_data;
758 p->timeout = G_OBEX_DEFAULT_TIMEOUT;
760 p->timeout = timeout;
762 if (!g_obex_send_internal(obex, p, err)) {
770 static int pending_pkt_cmp(gconstpointer a, gconstpointer b)
772 const struct pending_pkt *p = a;
773 guint id = GPOINTER_TO_UINT(b);
778 static gboolean pending_req_abort(GObex *obex, GError **err)
780 struct pending_pkt *p = obex->pending_req;
788 if (p->timeout_id > 0)
789 g_source_remove(p->timeout_id);
791 p->timeout = G_OBEX_ABORT_TIMEOUT;
792 p->timeout_id = g_timeout_add_seconds(p->timeout, req_timeout, obex);
794 req = g_obex_packet_new(G_OBEX_OP_ABORT, TRUE, G_OBEX_HDR_INVALID);
796 return g_obex_send(obex, req, err);
799 static gboolean cancel_complete(gpointer user_data)
801 struct pending_pkt *p = user_data;
802 GObex *obex = p->obex;
805 g_assert(p->rsp_func != NULL);
807 err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
808 "The request was cancelled");
809 p->rsp_func(obex, err, NULL, p->rsp_data);
818 gboolean g_obex_cancel_req(GObex *obex, guint req_id, gboolean remove_callback)
821 struct pending_pkt *p;
823 if (obex->pending_req && obex->pending_req->id == req_id) {
824 if (!pending_req_abort(obex, NULL)) {
825 p = obex->pending_req;
826 obex->pending_req = NULL;
827 goto immediate_completion;
831 obex->pending_req->rsp_func = NULL;
836 match = g_queue_find_custom(obex->tx_queue, GUINT_TO_POINTER(req_id),
843 g_queue_delete_link(obex->tx_queue, match);
845 immediate_completion:
847 p->obex = g_obex_ref(obex);
849 if (remove_callback || p->rsp_func == NULL)
852 g_idle_add(cancel_complete, p);
857 gboolean g_obex_send_rsp(GObex *obex, guint8 rspcode, GError **err,
858 guint first_hdr_type, ...)
863 va_start(args, first_hdr_type);
864 rsp = g_obex_packet_new_valist(rspcode, TRUE, first_hdr_type, args);
867 return g_obex_send(obex, rsp, err);
870 void g_obex_set_disconnect_function(GObex *obex, GObexFunc func,
873 obex->disconn_func = func;
874 obex->disconn_func_data = user_data;
877 static int req_handler_cmpop(gconstpointer a, gconstpointer b)
879 const struct req_handler *handler = a;
880 guint opcode = GPOINTER_TO_UINT(b);
882 return (int) handler->opcode - (int) opcode;
885 static int req_handler_cmpid(gconstpointer a, gconstpointer b)
887 const struct req_handler *handler = a;
888 guint id = GPOINTER_TO_UINT(b);
890 return (int) handler->id - (int) id;
893 guint g_obex_add_request_function(GObex *obex, guint8 opcode,
894 GObexRequestFunc func,
897 struct req_handler *handler;
898 static guint next_id = 1;
900 handler = g_new0(struct req_handler, 1);
901 handler->id = next_id++;
902 handler->opcode = opcode;
903 handler->func = func;
904 handler->user_data = user_data;
906 obex->req_handlers = g_slist_prepend(obex->req_handlers, handler);
911 gboolean g_obex_remove_request_function(GObex *obex, guint id)
913 struct req_handler *handler;
916 match = g_slist_find_custom(obex->req_handlers, GUINT_TO_POINTER(id),
921 handler = match->data;
923 obex->req_handlers = g_slist_delete_link(obex->req_handlers, match);
929 static void g_obex_srm_suspend(GObex *obex)
931 struct pending_pkt *p = obex->pending_req;
934 if (p->timeout_id > 0) {
935 g_source_remove(p->timeout_id);
941 req = g_obex_packet_new(G_OBEX_OP_GET, TRUE,
942 G_OBEX_HDR_SRMP, G_OBEX_SRMP_WAIT,
945 g_obex_send(obex, req, NULL);
948 void g_obex_suspend(GObex *obex)
950 struct pending_pkt *req = obex->pending_req;
952 g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
954 if (!g_obex_srm_active(obex) || !req)
957 /* Send SRMP wait in case of GET */
958 if (g_obex_packet_get_operation(req->pkt, NULL) == G_OBEX_OP_GET) {
959 g_obex_srm_suspend(obex);
964 obex->suspended = TRUE;
966 if (obex->write_source > 0) {
967 g_source_remove(obex->write_source);
968 obex->write_source = 0;
972 static void g_obex_srm_resume(GObex *obex)
974 struct pending_pkt *p = obex->pending_req;
977 p->timeout_id = g_timeout_add_seconds(p->timeout, req_timeout, obex);
978 p->suspended = FALSE;
980 req = g_obex_packet_new(G_OBEX_OP_GET, TRUE, G_OBEX_HDR_INVALID);
982 g_obex_send(obex, req, NULL);
985 void g_obex_resume(GObex *obex)
987 struct pending_pkt *req = obex->pending_req;
989 g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
991 obex->suspended = FALSE;
993 if (g_obex_srm_active(obex) || !req)
996 if (g_obex_packet_get_operation(req->pkt, NULL) == G_OBEX_OP_GET)
997 g_obex_srm_resume(obex);
1000 if (g_queue_get_length(obex->tx_queue) > 0 || obex->tx_data > 0)
1004 gboolean g_obex_srm_active(GObex *obex)
1006 gboolean ret = FALSE;
1008 if (!g_obex_srm_enabled(obex))
1011 if (obex->srm->srmp <= G_OBEX_SRMP_NEXT_WAIT)
1016 g_obex_debug(G_OBEX_DEBUG_COMMAND, "%s", ret ? "yes" : "no");
1020 static void auth_challenge(GObex *obex)
1022 struct pending_pkt *p = obex->pending_req;
1024 if (p->authenticating)
1027 p->authenticating = TRUE;
1029 prepare_auth_rsp(obex, p->pkt);
1031 /* Remove it as pending and add it back to the queue so it gets sent
1033 if (p->timeout_id > 0) {
1034 g_source_remove(p->timeout_id);
1037 obex->pending_req = NULL;
1038 g_obex_send_internal(obex, p, NULL);
1041 static void parse_connect_data(GObex *obex, GObexPacket *pkt)
1043 const struct connect_data *data;
1048 data = g_obex_packet_get_data(pkt, &data_len);
1049 if (data == NULL || data_len != sizeof(*data))
1052 memcpy(&u16, &data->mtu, sizeof(u16));
1054 obex->tx_mtu = g_ntohs(u16);
1055 if (obex->io_tx_mtu > 0 && obex->tx_mtu > obex->io_tx_mtu)
1056 obex->tx_mtu = obex->io_tx_mtu;
1057 obex->tx_buf = g_realloc(obex->tx_buf, obex->tx_mtu);
1059 hdr = g_obex_packet_get_header(pkt, G_OBEX_HDR_CONNECTION);
1061 g_obex_header_get_uint32(hdr, &obex->conn_id);
1063 hdr = g_obex_packet_get_header(pkt, G_OBEX_HDR_AUTHCHAL);
1065 obex->authchal = g_obex_header_get_apparam(hdr);
1068 static gboolean parse_response(GObex *obex, GObexPacket *rsp)
1070 struct pending_pkt *p = obex->pending_req;
1071 guint8 opcode, rspcode;
1074 rspcode = g_obex_packet_get_operation(rsp, &final);
1076 opcode = g_obex_packet_get_operation(p->pkt, NULL);
1077 if (opcode == G_OBEX_OP_CONNECT) {
1078 parse_connect_data(obex, rsp);
1079 if (rspcode == G_OBEX_RSP_UNAUTHORIZED && obex->authchal)
1080 auth_challenge(obex);
1083 setup_srm(obex, rsp, FALSE);
1085 if (!g_obex_srm_enabled(obex))
1089 * Resposes have final bit set but in case of GET with SRM
1090 * we should not remove the request since the remote side will
1091 * continue sending responses until the transfer is finished
1093 if (opcode == G_OBEX_OP_GET && rspcode == G_OBEX_RSP_CONTINUE) {
1094 if (p->timeout_id > 0)
1095 g_source_remove(p->timeout_id);
1097 p->timeout_id = g_timeout_add_seconds(p->timeout, req_timeout,
1105 static void handle_response(GObex *obex, GError *err, GObexPacket *rsp)
1107 struct pending_pkt *p;
1108 gboolean disconn = err ? TRUE : FALSE, final_rsp = TRUE;
1111 final_rsp = parse_response(obex, rsp);
1113 if (!obex->pending_req)
1116 p = obex->pending_req;
1118 /* Reset if final so it can no longer be cancelled */
1120 obex->pending_req = NULL;
1123 err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
1124 "The operation was cancelled");
1127 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
1130 p->rsp_func(obex, err, rsp, p->rsp_data);
1132 /* Check if user callback removed the request */
1133 if (!final_rsp && p != obex->pending_req)
1141 pending_pkt_free(p);
1143 if (!disconn && g_queue_get_length(obex->tx_queue) > 0)
1147 static gboolean check_connid(GObex *obex, GObexPacket *pkt)
1152 if (obex->conn_id == CONNID_INVALID)
1155 hdr = g_obex_packet_get_header(pkt, G_OBEX_HDR_CONNECTION);
1159 g_obex_header_get_uint32(hdr, &id);
1161 return obex->conn_id == id;
1164 static int parse_request(GObex *obex, GObexPacket *req)
1169 op = g_obex_packet_get_operation(req, &final);
1171 case G_OBEX_OP_CONNECT:
1172 parse_connect_data(obex, req);
1174 case G_OBEX_OP_ABORT:
1177 if (check_connid(obex, req))
1180 return -G_OBEX_RSP_SERVICE_UNAVAILABLE;
1183 setup_srm(obex, req, FALSE);
1188 static void handle_request(GObex *obex, GObexPacket *req)
1193 op = parse_request(obex, req);
1197 match = g_slist_find_custom(obex->req_handlers, GUINT_TO_POINTER(op),
1200 struct req_handler *handler = match->data;
1201 handler->func(obex, req, handler->user_data);
1205 op = -G_OBEX_RSP_NOT_IMPLEMENTED;
1208 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", g_obex_strerror(-op));
1209 g_obex_send_rsp(obex, -op, NULL, G_OBEX_HDR_INVALID);
1212 static gboolean read_stream(GObex *obex, GError **err)
1214 GIOChannel *io = obex->io;
1216 gsize rbytes, toread;
1220 if (obex->rx_data >= 3)
1224 toread = 3 - obex->rx_data;
1225 buf = (char *) &obex->rx_buf[obex->rx_data];
1227 status = g_io_channel_read_chars(io, buf, toread, &rbytes, NULL);
1228 if (status != G_IO_STATUS_NORMAL)
1231 obex->rx_data += rbytes;
1232 if (obex->rx_data < 3)
1235 memcpy(&u16, &buf[1], sizeof(u16));
1236 obex->rx_pkt_len = g_ntohs(u16);
1238 if (obex->rx_pkt_len > obex->rx_mtu) {
1241 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
1242 "Too big incoming packet");
1243 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
1248 if (obex->rx_data >= obex->rx_pkt_len)
1252 toread = obex->rx_pkt_len - obex->rx_data;
1253 buf = (char *) &obex->rx_buf[obex->rx_data];
1255 status = g_io_channel_read_chars(io, buf, toread, &rbytes, NULL);
1256 if (status != G_IO_STATUS_NORMAL)
1259 obex->rx_data += rbytes;
1260 } while (rbytes > 0 && obex->rx_data < obex->rx_pkt_len);
1263 g_obex_dump(G_OBEX_DEBUG_DATA, ">", obex->rx_buf, obex->rx_data);
1268 static gboolean read_packet(GObex *obex, GError **err)
1270 GIOChannel *io = obex->io;
1271 GError *read_err = NULL;
1276 if (obex->rx_data > 0) {
1277 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
1278 "RX buffer not empty before reading packet");
1282 status = g_io_channel_read_chars(io, (char *) obex->rx_buf,
1283 obex->rx_mtu, &rbytes, &read_err);
1284 if (status != G_IO_STATUS_NORMAL) {
1285 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
1286 "Unable to read data: %s", read_err->message);
1287 g_error_free(read_err);
1291 obex->rx_data += rbytes;
1294 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
1295 "Incomplete packet received");
1299 memcpy(&u16, &obex->rx_buf[1], sizeof(u16));
1300 obex->rx_pkt_len = g_ntohs(u16);
1302 if (obex->rx_pkt_len != rbytes) {
1303 g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
1304 "Data size doesn't match packet size (%zu != %u)",
1305 rbytes, obex->rx_pkt_len);
1309 g_obex_dump(G_OBEX_DEBUG_DATA, ">", obex->rx_buf, obex->rx_data);
1314 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
1319 static gboolean incoming_data(GIOChannel *io, GIOCondition cond,
1322 GObex *obex = user_data;
1324 ssize_t header_offset;
1328 if (cond & G_IO_NVAL)
1331 if (cond & (G_IO_HUP | G_IO_ERR)) {
1332 err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_DISCONNECTED,
1333 "Transport got disconnected");
1337 if (!obex->read(obex, &err))
1340 if (obex->rx_data < 3 || obex->rx_data < obex->rx_pkt_len)
1343 obex->rx_last_op = obex->rx_buf[0] & ~FINAL_BIT;
1345 if (obex->pending_req) {
1346 struct pending_pkt *p = obex->pending_req;
1347 opcode = g_obex_packet_get_operation(p->pkt, NULL);
1348 header_offset = rsp_header_offset(opcode);
1350 opcode = obex->rx_last_op;
1351 /* Unexpected response -- fail silently */
1352 if (opcode > 0x1f && opcode != G_OBEX_OP_ABORT) {
1356 header_offset = req_header_offset(opcode);
1359 if (header_offset < 0) {
1360 err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
1361 "Unknown header offset for opcode 0x%02x",
1366 pkt = g_obex_packet_decode(obex->rx_buf, obex->rx_data, header_offset,
1367 G_OBEX_DATA_REF, &err);
1371 /* Protect against user callback freeing the object */
1374 if (obex->pending_req)
1375 handle_response(obex, NULL, pkt);
1377 handle_request(obex, pkt);
1387 g_obex_packet_free(pkt);
1393 g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
1395 g_io_channel_unref(obex->io);
1397 obex->io_source = 0;
1400 /* Protect against user callback freeing the object */
1403 if (obex->pending_req)
1404 handle_response(obex, err, NULL);
1406 if (obex->disconn_func)
1407 obex->disconn_func(obex, err, obex->disconn_func_data);
1416 static GDebugKey keys[] = {
1417 { "error", G_OBEX_DEBUG_ERROR },
1418 { "command", G_OBEX_DEBUG_COMMAND },
1419 { "transfer", G_OBEX_DEBUG_TRANSFER },
1420 { "header", G_OBEX_DEBUG_HEADER },
1421 { "packet", G_OBEX_DEBUG_PACKET },
1422 { "data", G_OBEX_DEBUG_DATA },
1423 { "apparam", G_OBEX_DEBUG_APPARAM },
1426 GObex *g_obex_new(GIOChannel *io, GObexTransportType transport_type,
1427 gssize io_rx_mtu, gssize io_tx_mtu)
1432 if (gobex_debug == 0) {
1433 const char *env = g_getenv("GOBEX_DEBUG");
1436 gobex_debug = g_parse_debug_string(env, keys, 7);
1437 g_setenv("G_MESSAGES_DEBUG", "gobex", FALSE);
1439 gobex_debug = G_OBEX_DEBUG_NONE;
1442 g_obex_debug(G_OBEX_DEBUG_COMMAND, "");
1447 if (io_rx_mtu >= 0 && io_rx_mtu < G_OBEX_MINIMUM_MTU)
1450 if (io_tx_mtu >= 0 && io_tx_mtu < G_OBEX_MINIMUM_MTU)
1453 obex = g_new0(GObex, 1);
1455 obex->io = g_io_channel_ref(io);
1456 obex->ref_count = 1;
1457 obex->conn_id = CONNID_INVALID;
1458 obex->rx_last_op = G_OBEX_OP_NONE;
1460 obex->io_rx_mtu = io_rx_mtu;
1461 obex->io_tx_mtu = io_tx_mtu;
1463 if (io_rx_mtu > G_OBEX_MAXIMUM_MTU)
1464 obex->rx_mtu = G_OBEX_MAXIMUM_MTU;
1465 else if (io_rx_mtu < G_OBEX_MINIMUM_MTU)
1466 obex->rx_mtu = G_OBEX_DEFAULT_MTU;
1468 obex->rx_mtu = io_rx_mtu;
1470 obex->tx_mtu = G_OBEX_MINIMUM_MTU;
1472 obex->tx_queue = g_queue_new();
1473 obex->rx_buf = g_malloc(obex->rx_mtu);
1474 obex->tx_buf = g_malloc(obex->tx_mtu);
1476 switch (transport_type) {
1477 case G_OBEX_TRANSPORT_STREAM:
1478 obex->read = read_stream;
1479 obex->write = write_stream;
1481 case G_OBEX_TRANSPORT_PACKET:
1482 obex->use_srm = TRUE;
1483 obex->read = read_packet;
1484 obex->write = write_packet;
1491 g_io_channel_set_encoding(io, NULL, NULL);
1492 g_io_channel_set_buffered(io, FALSE);
1493 cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
1494 obex->io_source = g_io_add_watch(io, cond, incoming_data, obex);
1499 GObex *g_obex_ref(GObex *obex)
1506 refs = __sync_add_and_fetch(&obex->ref_count, 1);
1508 g_obex_debug(G_OBEX_DEBUG_COMMAND, "ref %u", refs);
1513 static void tx_queue_free(void *data, void *user_data)
1515 pending_pkt_free(data);
1518 void g_obex_unref(GObex *obex)
1522 refs = __sync_sub_and_fetch(&obex->ref_count, 1);
1524 g_obex_debug(G_OBEX_DEBUG_COMMAND, "ref %u", refs);
1529 g_slist_free_full(obex->req_handlers, g_free);
1531 g_queue_foreach(obex->tx_queue, tx_queue_free, NULL);
1532 g_queue_free(obex->tx_queue);
1534 if (obex->io != NULL)
1535 g_io_channel_unref(obex->io);
1537 if (obex->io_source > 0)
1538 g_source_remove(obex->io_source);
1540 if (obex->write_source > 0)
1541 g_source_remove(obex->write_source);
1543 g_free(obex->rx_buf);
1544 g_free(obex->tx_buf);
1547 if (obex->pending_req)
1548 pending_pkt_free(obex->pending_req);
1551 g_obex_apparam_free(obex->authchal);
1556 /* Higher level functions */
1557 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1558 void g_obex_io_shutdown(GObex *obex)
1561 if (obex->io != NULL)
1562 g_io_channel_shutdown(obex->io, FALSE, &err);
1565 guint g_obex_connect(GObex *obex, GObexResponseFunc func, gpointer user_data,
1566 GError **err, guint first_hdr_id, ...)
1569 struct connect_data data;
1572 g_obex_debug(G_OBEX_DEBUG_COMMAND, "");
1574 va_start(args, first_hdr_id);
1575 req = g_obex_packet_new_valist(G_OBEX_OP_CONNECT, TRUE,
1576 first_hdr_id, args);
1579 init_connect_data(obex, &data);
1580 g_obex_packet_set_data(req, &data, sizeof(data), G_OBEX_DATA_COPY);
1582 return g_obex_send_req(obex, req, -1, func, user_data, err);
1585 guint g_obex_disconnect(GObex *obex, GObexResponseFunc func, gpointer user_data,
1590 g_obex_debug(G_OBEX_DEBUG_COMMAND, "");
1592 req = g_obex_packet_new(G_OBEX_OP_DISCONNECT, TRUE, G_OBEX_HDR_INVALID);
1594 return g_obex_send_req(obex, req, -1, func, user_data, err);
1597 guint g_obex_setpath(GObex *obex, const char *path, GObexResponseFunc func,
1598 gpointer user_data, GError **err)
1601 struct setpath_data data;
1604 g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
1606 req = g_obex_packet_new(G_OBEX_OP_SETPATH, TRUE, G_OBEX_HDR_INVALID);
1608 memset(&data, 0, sizeof(data));
1610 if (path != NULL && strncmp("..", path, 2) == 0) {
1612 folder = (path[2] == '/') ? &path[3] : NULL;
1618 if (folder != NULL) {
1620 hdr = g_obex_header_new_unicode(G_OBEX_HDR_NAME, folder);
1621 g_obex_packet_add_header(req, hdr);
1624 g_obex_packet_set_data(req, &data, sizeof(data), G_OBEX_DATA_COPY);
1626 return g_obex_send_req(obex, req, -1, func, user_data, err);
1629 guint g_obex_mkdir(GObex *obex, const char *path, GObexResponseFunc func,
1630 gpointer user_data, GError **err)
1633 struct setpath_data data;
1635 g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
1637 req = g_obex_packet_new(G_OBEX_OP_SETPATH, TRUE, G_OBEX_HDR_NAME, path,
1638 G_OBEX_HDR_INVALID);
1640 memset(&data, 0, sizeof(data));
1641 g_obex_packet_set_data(req, &data, sizeof(data), G_OBEX_DATA_COPY);
1643 return g_obex_send_req(obex, req, -1, func, user_data, err);
1646 guint g_obex_delete(GObex *obex, const char *name, GObexResponseFunc func,
1647 gpointer user_data, GError **err)
1651 g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
1653 req = g_obex_packet_new(G_OBEX_OP_PUT, TRUE, G_OBEX_HDR_NAME, name,
1654 G_OBEX_HDR_INVALID);
1656 return g_obex_send_req(obex, req, -1, func, user_data, err);
1659 guint g_obex_copy(GObex *obex, const char *name, const char *dest,
1660 GObexResponseFunc func, gpointer user_data,
1665 g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
1667 req = g_obex_packet_new(G_OBEX_OP_ACTION, TRUE,
1668 G_OBEX_HDR_ACTION, G_OBEX_ACTION_COPY,
1669 G_OBEX_HDR_NAME, name,
1670 G_OBEX_HDR_DESTNAME, dest,
1671 G_OBEX_HDR_INVALID);
1673 return g_obex_send_req(obex, req, -1, func, user_data, err);
1676 guint g_obex_move(GObex *obex, const char *name, const char *dest,
1677 GObexResponseFunc func, gpointer user_data,
1682 g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
1684 req = g_obex_packet_new(G_OBEX_OP_ACTION, TRUE,
1685 G_OBEX_HDR_ACTION, G_OBEX_ACTION_MOVE,
1686 G_OBEX_HDR_NAME, name,
1687 G_OBEX_HDR_DESTNAME, dest,
1688 G_OBEX_HDR_INVALID);
1690 return g_obex_send_req(obex, req, -1, func, user_data, err);
1693 guint g_obex_abort(GObex *obex, GObexResponseFunc func, gpointer user_data,
1698 req = g_obex_packet_new(G_OBEX_OP_ABORT, TRUE, G_OBEX_HDR_INVALID);
1700 return g_obex_send_req(obex, req, -1, func, user_data, err);
1703 guint8 g_obex_errno_to_rsp(int err)
1707 return G_OBEX_RSP_SUCCESS;
1710 return G_OBEX_RSP_FORBIDDEN;
1712 return G_OBEX_RSP_NOT_FOUND;
1715 return G_OBEX_RSP_BAD_REQUEST;
1717 return G_OBEX_RSP_SERVICE_UNAVAILABLE;
1719 return G_OBEX_RSP_NOT_IMPLEMENTED;
1722 return G_OBEX_RSP_PRECONDITION_FAILED;
1724 return G_OBEX_RSP_INTERNAL_SERVER_ERROR;