5 * Copyright (C) 2007-2010 Nokia Corporation
6 * Copyright (C) 2007-2010 Marcel Holtmann <marcel@holtmann.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
36 #include <sys/types.h>
38 #include <sys/statvfs.h>
44 #include "gobex/gobex.h"
46 #include "btio/btio.h"
50 #include "obex-priv.h"
55 #include "transport.h"
57 static GSList *sessions = NULL;
63 } __attribute__ ((packed)) obex_connect_hdr_t;
69 } __attribute__ ((packed));
71 /* Possible commands */
76 { G_OBEX_OP_CONNECT, "CONNECT" },
77 { G_OBEX_OP_DISCONNECT, "DISCONNECT" },
78 { G_OBEX_OP_PUT, "PUT" },
79 { G_OBEX_OP_GET, "GET" },
80 { G_OBEX_OP_SETPATH, "SETPATH" },
81 { G_OBEX_OP_SESSION, "SESSION" },
82 { G_OBEX_OP_ABORT, "ABORT" },
83 { G_OBEX_OP_ACTION, "ACTION" },
87 /* Possible Response */
92 { G_OBEX_RSP_CONTINUE, "CONTINUE" },
93 { G_OBEX_RSP_SUCCESS, "SUCCESS" },
94 { G_OBEX_RSP_CREATED, "CREATED" },
95 { G_OBEX_RSP_ACCEPTED, "ACCEPTED" },
96 { G_OBEX_RSP_NON_AUTHORITATIVE, "NON_AUTHORITATIVE" },
97 { G_OBEX_RSP_NO_CONTENT, "NO_CONTENT" },
98 { G_OBEX_RSP_RESET_CONTENT, "RESET_CONTENT" },
99 { G_OBEX_RSP_PARTIAL_CONTENT, "PARTIAL_CONTENT" },
100 { G_OBEX_RSP_MULTIPLE_CHOICES, "MULTIPLE_CHOICES" },
101 { G_OBEX_RSP_MOVED_PERMANENTLY, "MOVED_PERMANENTLY" },
102 { G_OBEX_RSP_MOVED_TEMPORARILY, "MOVED_TEMPORARILY" },
103 { G_OBEX_RSP_SEE_OTHER, "SEE_OTHER" },
104 { G_OBEX_RSP_NOT_MODIFIED, "NOT_MODIFIED" },
105 { G_OBEX_RSP_USE_PROXY, "USE_PROXY" },
106 { G_OBEX_RSP_BAD_REQUEST, "BAD_REQUEST" },
107 { G_OBEX_RSP_UNAUTHORIZED, "UNAUTHORIZED" },
108 { G_OBEX_RSP_PAYMENT_REQUIRED, "PAYMENT_REQUIRED" },
109 { G_OBEX_RSP_FORBIDDEN, "FORBIDDEN" },
110 { G_OBEX_RSP_NOT_FOUND, "NOT_FOUND" },
111 { G_OBEX_RSP_METHOD_NOT_ALLOWED, "METHOD_NOT_ALLOWED" },
112 { G_OBEX_RSP_NOT_ACCEPTABLE, "NOT_ACCEPTABLE" },
113 { G_OBEX_RSP_PROXY_AUTH_REQUIRED, "PROXY_AUTH_REQUIRED" },
114 { G_OBEX_RSP_REQUEST_TIME_OUT, "REQUEST_TIME_OUT" },
115 { G_OBEX_RSP_CONFLICT, "CONFLICT" },
116 { G_OBEX_RSP_GONE, "GONE" },
117 { G_OBEX_RSP_LENGTH_REQUIRED, "LENGTH_REQUIRED" },
118 { G_OBEX_RSP_PRECONDITION_FAILED, "PRECONDITION_FAILED" },
119 { G_OBEX_RSP_REQ_ENTITY_TOO_LARGE, "REQ_ENTITY_TOO_LARGE" },
120 { G_OBEX_RSP_REQ_URL_TOO_LARGE, "REQ_URL_TOO_LARGE" },
121 { G_OBEX_RSP_UNSUPPORTED_MEDIA_TYPE, "UNSUPPORTED_MEDIA_TYPE"},
122 { G_OBEX_RSP_INTERNAL_SERVER_ERROR, "INTERNAL_SERVER_ERROR" },
123 { G_OBEX_RSP_NOT_IMPLEMENTED, "NOT_IMPLEMENTED" },
124 { G_OBEX_RSP_BAD_GATEWAY, "BAD_GATEWAY" },
125 { G_OBEX_RSP_SERVICE_UNAVAILABLE, "SERVICE_UNAVAILABLE" },
126 { G_OBEX_RSP_GATEWAY_TIMEOUT, "GATEWAY_TIMEOUT" },
127 { G_OBEX_RSP_VERSION_NOT_SUPPORTED, "VERSION_NOT_SUPPORTED" },
128 { G_OBEX_RSP_DATABASE_FULL, "DATABASE_FULL" },
129 { G_OBEX_RSP_DATABASE_LOCKED, "DATABASE_LOCKED" },
133 static gboolean handle_async_io(void *object, int flags, int err,
136 static void print_event(int cmd, int rsp)
138 const char *cmdstr = NULL, *rspstr = NULL;
147 for (i = 0; obex_command[i].cmd != 0xFF; i++) {
148 if (obex_command[i].cmd != cmd)
150 cmdstr = obex_command[i].name;
153 for (i = 0; obex_response[i].rsp != 0xFF; i++) {
154 if (obex_response[i].rsp != rsp)
156 rspstr = obex_response[i].name;
159 obex_debug("%s(0x%x), %s(0x%x)", cmdstr, cmd, rspstr, rsp);
162 static void os_set_response(struct obex_session *os, int err)
166 rsp = g_obex_errno_to_rsp(err);
168 print_event(-1, rsp);
170 g_obex_send_rsp(os->obex, rsp, NULL, G_OBEX_HDR_INVALID);
173 static void os_session_mark_aborted(struct obex_session *os)
175 /* the session was already cancelled/aborted or size in unknown */
176 if (os->aborted || os->size == OBJECT_SIZE_UNKNOWN)
179 os->aborted = (os->size != os->offset);
182 static void os_reset_session(struct obex_session *os)
184 os_session_mark_aborted(os);
187 os->driver->set_io_watch(os->object, NULL, NULL);
188 os->driver->close(os->object);
189 if (os->aborted && os->cmd == G_OBEX_OP_PUT && os->path &&
191 os->driver->remove(os->path);
194 if (os->service && os->service->reset)
195 os->service->reset(os, os->service_data);
219 if (os->get_rsp > 0) {
220 g_obex_remove_request_function(os->obex, os->get_rsp);
229 os->size = OBJECT_SIZE_DELETE;
230 os->headers_sent = FALSE;
234 static void obex_session_free(struct obex_session *os)
236 sessions = g_slist_remove(sessions, os);
239 g_io_channel_unref(os->io);
242 g_obex_unref(os->obex);
250 /* From Imendio's GnomeVFS OBEX module (om-utils.c) */
251 static time_t parse_iso8610(const char *val, int size)
253 time_t time, tz_offset = 0;
259 memset(&tm, 0, sizeof(tm));
260 /* According to spec the time doesn't have to be null terminated */
261 date = g_strndup(val, size);
262 nr = sscanf(date, "%04u%02u%02uT%02u%02u%02u%c",
263 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
264 &tm.tm_hour, &tm.tm_min, &tm.tm_sec,
268 /* Invalid time format */
272 tm.tm_year -= 1900; /* Year since 1900 */
273 tm.tm_mon--; /* Months since January, values 0-11 */
274 tm.tm_isdst = -1; /* Daylight savings information not avail */
276 #if defined(HAVE_TM_GMTOFF)
277 tz_offset = tm.tm_gmtoff;
278 #elif defined(HAVE_TIMEZONE)
279 tz_offset = -timezone;
287 * Date/Time was in localtime (to remote device)
288 * already. Since we don't know anything about the
289 * timezone on that one we won't try to apply UTC offset
297 static void parse_service(struct obex_session *os, GObexPacket *req)
300 const guint8 *target = NULL, *who = NULL;
301 gsize target_size = 0, who_size = 0;
303 hdr = g_obex_packet_get_header(req, G_OBEX_HDR_WHO);
307 g_obex_header_get_bytes(hdr, &who, &who_size);
310 hdr = g_obex_packet_get_header(req, G_OBEX_HDR_TARGET);
314 g_obex_header_get_bytes(hdr, &target, &target_size);
317 os->service = obex_service_driver_find(os->server->drivers,
322 static void cmd_connect(GObex *obex, GObexPacket *req, void *user_data)
324 struct obex_session *os = user_data;
331 print_event(G_OBEX_OP_CONNECT, -1);
333 parse_service(os, req);
335 if (os->service == NULL || os->service->connect == NULL) {
336 error("Connect attempt to a non-supported target");
337 os_set_response(os, -EPERM);
341 DBG("Selected driver: %s", os->service->name);
343 os->service_data = os->service->connect(os, &err);
345 os_set_response(os, err);
349 os->cmd = G_OBEX_OP_CONNECT;
351 rsp = g_obex_packet_new(G_OBEX_RSP_SUCCESS, TRUE, G_OBEX_HDR_INVALID);
353 if (os->service->target) {
354 hdr = g_obex_header_new_bytes(G_OBEX_HDR_WHO,
356 os->service->target_size);
357 g_obex_packet_add_header(rsp, hdr);
360 g_obex_send(obex, rsp, NULL);
365 static void cmd_disconnect(GObex *obex, GObexPacket *req, void *user_data)
367 struct obex_session *os = user_data;
369 DBG("session %p", os);
371 print_event(G_OBEX_OP_DISCONNECT, -1);
373 os->cmd = G_OBEX_OP_DISCONNECT;
375 os_set_response(os, 0);
378 static ssize_t driver_write(struct obex_session *os)
382 while (os->pending > 0) {
385 w = os->driver->write(os->object, os->buf + len, os->pending);
387 error("write(): %s (%zd)", strerror(-w), -w);
390 else if (w == -EINVAL)
391 memmove(os->buf, os->buf + len, os->pending);
401 DBG("%zd written", len);
403 if (os->service->progress != NULL)
404 os->service->progress(os, os->service_data);
409 static gssize driver_read(struct obex_session *os, void *buf, gsize size)
413 if (os->object == NULL)
416 if (os->service->progress != NULL)
417 os->service->progress(os, os->service_data);
419 len = os->driver->read(os->object, buf, size);
421 error("read(): %s (%zd)", strerror(-len), -len);
425 os->driver->set_io_watch(os->object, handle_async_io,
431 DBG("%zd read", len);
436 static gssize send_data(void *buf, gsize size, gpointer user_data)
438 struct obex_session *os = user_data;
440 DBG("name=%s type=%s file=%p size=%zu", os->name, os->type, os->object,
444 return os->err < 0 ? os->err : -EPERM;
446 return driver_read(os, buf, size);
449 static void transfer_complete(GObex *obex, GError *err, gpointer user_data)
451 struct obex_session *os = user_data;
456 error("transfer failed: %s\n", err->message);
460 if (os->object && os->driver && os->driver->flush) {
461 if (os->driver->flush(os->object) == -EAGAIN) {
462 g_obex_suspend(os->obex);
463 os->driver->set_io_watch(os->object, handle_async_io,
470 os_reset_session(os);
473 static int driver_get_headers(struct obex_session *os)
481 DBG("name=%s type=%s object=%p", os->name, os->type, os->object);
484 return os->err < 0 ? os->err : -EPERM;
486 if (os->object == NULL)
489 if (os->headers_sent)
492 rsp = g_obex_packet_new(G_OBEX_RSP_CONTINUE, TRUE, G_OBEX_HDR_INVALID);
494 if (os->driver->get_next_header == NULL)
497 while ((len = os->driver->get_next_header(os->object, &data,
498 sizeof(data), &id))) {
500 error("get_next_header(): %s (%zd)", strerror(-len),
503 g_obex_packet_free(rsp);
514 hdr = g_obex_header_new_bytes(id, data, len);
515 g_obex_packet_add_header(rsp, hdr);
519 if (os->size != OBJECT_SIZE_UNKNOWN && os->size < UINT32_MAX) {
520 hdr = g_obex_header_new_uint32(G_OBEX_HDR_LENGTH, os->size);
521 g_obex_packet_add_header(rsp, hdr);
524 g_obex_get_rsp_pkt(os->obex, rsp, send_data, transfer_complete, os,
527 os->headers_sent = TRUE;
529 print_event(-1, G_OBEX_RSP_CONTINUE);
534 static gboolean handle_async_io(void *object, int flags, int err,
537 struct obex_session *os = user_data;
542 if (flags & G_IO_OUT)
543 err = driver_write(os);
544 if ((flags & G_IO_IN) && !os->headers_sent)
545 err = driver_get_headers(os);
556 g_obex_resume(os->obex);
561 static gboolean recv_data(const void *buf, gsize size, gpointer user_data)
563 struct obex_session *os = user_data;
566 DBG("name=%s type=%s file=%p size=%zu", os->name, os->type, os->object,
572 /* workaround: client didn't send the object length */
573 if (os->size == OBJECT_SIZE_DELETE)
574 os->size = OBJECT_SIZE_UNKNOWN;
576 os->buf = g_realloc(os->buf, os->pending + size);
577 memcpy(os->buf + os->pending, buf, size);
580 /* only write if both object and driver are valid */
581 if (os->object == NULL || os->driver == NULL) {
582 DBG("Stored %" PRIu64 " bytes into temporary buffer",
587 ret = driver_write(os);
591 if (ret == -EAGAIN) {
592 g_obex_suspend(os->obex);
593 os->driver->set_io_watch(os->object, handle_async_io, os);
600 static void parse_type(struct obex_session *os, GObexPacket *req)
609 hdr = g_obex_packet_get_header(req, G_OBEX_HDR_TYPE);
613 if (!g_obex_header_get_bytes(hdr, &type, &len))
616 /* Ensure null termination */
617 if (type[len - 1] != '\0')
620 os->type = g_strndup((const char *) type, len);
621 DBG("TYPE: %s", os->type);
624 os->driver = obex_mime_type_driver_find(os->service->target,
625 os->service->target_size,
628 os->service->who_size);
631 static void parse_name(struct obex_session *os, GObexPacket *req)
639 hdr = g_obex_packet_get_header(req, G_OBEX_HDR_NAME);
643 if (!g_obex_header_get_unicode(hdr, &name))
645 #ifdef __TIZEN_PATCH__
646 DBG("TYPE===>: %s", os->type);
647 if (name && strcmp(os->type, "x-bt/phonebook")) {
649 new_name = strrchr(name, '/');
652 DBG("FileName %s", name);
656 os->name = g_strdup(name);
657 DBG("NAME: %s", os->name);
660 static void parse_apparam(struct obex_session *os, GObexPacket *req)
663 const guint8 *apparam;
666 hdr = g_obex_packet_get_header(req, G_OBEX_HDR_APPARAM);
670 if (!g_obex_header_get_bytes(hdr, &apparam, &len))
673 os->apparam = g_memdup(apparam, len);
674 os->apparam_len = len;
678 static void cmd_get(GObex *obex, GObexPacket *req, gpointer user_data)
680 struct obex_session *os = user_data;
683 DBG("session %p", os);
685 print_event(G_OBEX_OP_GET, -1);
687 if (os->service == NULL) {
688 os_set_response(os, -EPERM);
692 if (os->service->get == NULL) {
693 os_set_response(os, -ENOSYS);
697 os->headers_sent = FALSE;
707 error("No driver found");
708 os_set_response(os, -ENOSYS);
712 os->cmd = G_OBEX_OP_GET;
716 parse_apparam(os, req);
718 err = os->service->get(os, os->service_data);
722 os_set_response(os, err);
725 static void cmd_setpath(GObex *obex, GObexPacket *req, gpointer user_data)
727 struct obex_session *os = user_data;
732 print_event(G_OBEX_OP_SETPATH, -1);
734 if (os->service == NULL) {
739 if (os->service->setpath == NULL) {
744 os->cmd = G_OBEX_OP_SETPATH;
748 os->nonhdr = g_obex_packet_get_data(req, &os->nonhdr_len);
750 err = os->service->setpath(os, os->service_data);
752 os_set_response(os, err);
755 int obex_get_stream_start(struct obex_session *os, const char *filename)
759 size_t size = OBJECT_SIZE_UNKNOWN;
761 object = os->driver->open(filename, O_RDONLY, 0, os->service_data,
763 if (object == NULL) {
764 error("open(%s): %s (%d)", filename, strerror(-err), -err);
772 err = driver_get_headers(os);
776 g_obex_suspend(os->obex);
777 os->driver->set_io_watch(os->object, handle_async_io, os);
781 int obex_put_stream_start(struct obex_session *os, const char *filename)
785 os->object = os->driver->open(filename, O_WRONLY | O_CREAT | O_TRUNC,
786 #ifdef __TIZEN_PATCH__
787 0644, os->service_data,
789 0600, os->service_data,
791 os->size != OBJECT_SIZE_UNKNOWN ?
792 (size_t *) &os->size : NULL, &err);
793 if (os->object == NULL) {
794 error("open(%s): %s (%d)", filename, strerror(-err), -err);
798 os->path = g_strdup(filename);
803 static void parse_length(struct obex_session *os, GObexPacket *req)
808 hdr = g_obex_packet_get_header(req, G_OBEX_HDR_LENGTH);
812 if (!g_obex_header_get_uint32(hdr, &size))
816 DBG("LENGTH: %" PRIu64, os->size);
819 static void parse_time(struct obex_session *os, GObexPacket *req)
825 hdr = g_obex_packet_get_header(req, G_OBEX_HDR_TIME);
830 if (!g_obex_header_get_bytes(hdr, &time, &len))
833 os->time = parse_iso8610((const char *) time, len);
834 DBG("TIME: %s", ctime(&os->time));
837 static gboolean check_put(GObex *obex, GObexPacket *req, void *user_data)
839 struct obex_session *os = user_data;
842 if (os->service->chkput == NULL)
845 ret = os->service->chkput(os, os->service_data);
850 g_obex_suspend(os->obex);
851 os->driver->set_io_watch(os->object, handle_async_io, os);
854 os_set_response(os, ret);
858 if (os->size == OBJECT_SIZE_DELETE || os->size == OBJECT_SIZE_UNKNOWN)
859 DBG("Got a PUT without a Length");
867 static void cmd_put(GObex *obex, GObexPacket *req, gpointer user_data)
869 struct obex_session *os = user_data;
874 print_event(G_OBEX_OP_PUT, -1);
876 if (os->service == NULL) {
877 os_set_response(os, -EPERM);
883 if (os->driver == NULL) {
884 error("No driver found");
885 os_set_response(os, -ENOSYS);
889 os->cmd = G_OBEX_OP_PUT;
891 /* Set size to unknown if a body header exists */
892 if (g_obex_packet_get_body(req))
893 os->size = OBJECT_SIZE_UNKNOWN;
896 parse_length(os, req);
898 parse_apparam(os, req);
901 if (!check_put(obex, req, user_data))
905 if (os->service->put == NULL) {
906 os_set_response(os, -ENOSYS);
910 err = os->service->put(os, os->service_data);
912 g_obex_put_rsp(obex, req, recv_data, transfer_complete, os,
913 NULL, G_OBEX_HDR_INVALID);
914 print_event(G_OBEX_OP_PUT, G_OBEX_RSP_CONTINUE);
918 os_set_response(os, err);
921 static void parse_destname(struct obex_session *os, GObexPacket *req)
924 const char *destname;
926 g_free(os->destname);
929 hdr = g_obex_packet_get_header(req, G_OBEX_HDR_DESTNAME);
933 if (!g_obex_header_get_unicode(hdr, &destname))
936 os->destname = g_strdup(destname);
937 DBG("DESTNAME: %s", os->destname);
940 static void parse_action(struct obex_session *os, GObexPacket *req)
945 hdr = g_obex_packet_get_header(req, G_OBEX_HDR_ACTION);
949 if (!g_obex_header_get_uint8(hdr, &id))
953 DBG("ACTION: 0x%02x", os->action_id);
956 static void cmd_action(GObex *obex, GObexPacket *req, gpointer user_data)
958 struct obex_session *os = user_data;
963 print_event(G_OBEX_OP_ACTION, -1);
965 if (os->service == NULL) {
970 if (os->service->action == NULL) {
975 os->cmd = G_OBEX_OP_ACTION;
978 parse_destname(os, req);
979 parse_action(os, req);
981 os->driver = obex_mime_type_driver_find(os->service->target,
982 os->service->target_size,
985 os->service->who_size);
986 if (os->driver == NULL) {
991 err = os->service->action(os, os->service_data);
993 os_set_response(os, err);
996 static void cmd_abort(GObex *obex, GObexPacket *req, gpointer user_data)
998 struct obex_session *os = user_data;
1002 print_event(G_OBEX_OP_ABORT, -1);
1004 os_reset_session(os);
1006 os_set_response(os, 0);
1009 static void obex_session_destroy(struct obex_session *os)
1013 os_reset_session(os);
1015 if (os->service && os->service->disconnect)
1016 os->service->disconnect(os, os->service_data);
1018 obex_session_free(os);
1021 static void disconn_func(GObex *obex, GError *err, gpointer user_data)
1023 struct obex_session *os = user_data;
1025 error("disconnected: %s\n", err ? err->message : "<no err>");
1026 obex_session_destroy(os);
1029 int obex_session_start(GIOChannel *io, uint16_t tx_mtu, uint16_t rx_mtu,
1030 gboolean stream, struct obex_server *server)
1032 struct obex_session *os;
1034 GObexTransportType type;
1035 static uint32_t id = 0;
1039 os = g_new0(struct obex_session, 1);
1042 os->service = obex_service_driver_find(server->drivers, NULL,
1044 os->server = server;
1045 os->size = OBJECT_SIZE_DELETE;
1047 type = stream ? G_OBEX_TRANSPORT_STREAM : G_OBEX_TRANSPORT_PACKET;
1049 obex = g_obex_new(io, type, rx_mtu, tx_mtu);
1051 obex_session_free(os);
1055 g_obex_set_disconnect_function(obex, disconn_func, os);
1056 g_obex_add_request_function(obex, G_OBEX_OP_CONNECT, cmd_connect, os);
1057 g_obex_add_request_function(obex, G_OBEX_OP_DISCONNECT, cmd_disconnect,
1059 g_obex_add_request_function(obex, G_OBEX_OP_PUT, cmd_put, os);
1060 g_obex_add_request_function(obex, G_OBEX_OP_GET, cmd_get, os);
1061 g_obex_add_request_function(obex, G_OBEX_OP_SETPATH, cmd_setpath, os);
1062 g_obex_add_request_function(obex, G_OBEX_OP_ACTION, cmd_action, os);
1063 g_obex_add_request_function(obex, G_OBEX_OP_ABORT, cmd_abort, os);
1066 os->io = g_io_channel_ref(io);
1068 obex_getsockname(os, &os->src);
1069 obex_getpeername(os, &os->dst);
1071 sessions = g_slist_prepend(sessions, os);
1076 const char *obex_get_name(struct obex_session *os)
1081 const char *obex_get_destname(struct obex_session *os)
1083 return os->destname;
1086 void obex_set_name(struct obex_session *os, const char *name)
1089 os->name = g_strdup(name);
1090 DBG("Name changed: %s", os->name);
1093 ssize_t obex_get_size(struct obex_session *os)
1098 const char *obex_get_type(struct obex_session *os)
1103 int obex_remove(struct obex_session *os, const char *path)
1105 if (os->driver == NULL)
1108 return os->driver->remove(path);
1111 int obex_copy(struct obex_session *os, const char *source,
1112 const char *destination)
1114 if (os->driver == NULL || os->driver->copy == NULL)
1117 DBG("%s %s", source, destination);
1119 return os->driver->copy(source, destination);
1122 int obex_move(struct obex_session *os, const char *source,
1123 const char *destination)
1125 if (os->driver == NULL || os->driver->move == NULL)
1128 DBG("%s %s", source, destination);
1130 return os->driver->move(source, destination);
1133 uint8_t obex_get_action_id(struct obex_session *os)
1135 return os->action_id;
1138 ssize_t obex_get_apparam(struct obex_session *os, const uint8_t **buffer)
1140 *buffer = os->apparam;
1142 return os->apparam_len;
1145 ssize_t obex_get_non_header_data(struct obex_session *os,
1146 const uint8_t **data)
1150 return os->nonhdr_len;
1153 int obex_getpeername(struct obex_session *os, char **name)
1155 struct obex_transport_driver *transport = os->server->transport;
1157 if (transport == NULL || transport->getpeername == NULL)
1160 return transport->getpeername(os->io, name);
1163 int obex_getsockname(struct obex_session *os, char **name)
1165 struct obex_transport_driver *transport = os->server->transport;
1167 if (transport == NULL || transport->getsockname == NULL)
1170 return transport->getsockname(os->io, name);
1173 int memncmp0(const void *a, size_t na, const void *b, size_t nb)
1184 return memcmp(a, b, na);