22 #include <libsyncml/syncml.h>
23 #include <libsyncml/syncml_internals.h>
24 #include <libsyncml/sml_error_internals.h>
26 #include <libsyncml/sml_transport_internals.h>
28 #include "obex_internals.h"
29 #include "obex_server_internals.h"
35 #include <sys/types.h>
37 #include <sys/socket.h>
38 #include <netinet/in.h>
42 static gboolean _dispatch_obex(gpointer data)
46 int result = OBEX_HandleInput(linkenv->handle, 0);
50 "The handling of the obex input failed (%i).",
52 smlTransportReceiveEvent(linkenv->env->tsp, linkenv->link, SML_TRANSPORT_EVENT_ERROR, NULL, error);
54 smlErrorDeref(&error);
58 if (linkenv->disconnect) {
59 smlTrace(TRACE_INTERNAL,
"%s: disconnecting link", __func__);
60 OBEX_TransportDisconnect(linkenv->handle);
62 linkenv->destroy = TRUE;
66 if (linkenv->destroy) {
67 smlTrace(TRACE_INTERNAL,
"%s: Destroying link %p %p", __func__, linkenv, linkenv->link);
75 smlLinkDeref(linkenv->link);
76 g_source_unref(linkenv->source);
77 OBEX_Cleanup(linkenv->handle);
79 g_main_context_unref(tsp->context);
80 smlSafeFree((gpointer *)&linkenv);
81 link_->link_data = NULL;
84 smlTransportReceiveEvent(tsp, link_, SML_TRANSPORT_EVENT_DISCONNECT_DONE, NULL, NULL);
92 static void _smlTransportObexServerLinkEvent(obex_t *handle, obex_object_t *
object,
int mode,
int event,
int obex_cmd,
int obex_rsp)
94 smlTrace(TRACE_ENTRY,
"%s(%p, %p, %i, %i, %i, %i)", __func__, handle,
object, mode, event, obex_cmd, obex_rsp);
97 obex_headerdata_t header;
98 uint8_t headertype = 0;
101 SmlMimeType mimetype = SML_MIMETYPE_UNKNOWN;
103 if (linkenv->disconnect) {
104 OBEX_ObjectSetRsp(
object, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
105 smlTrace(TRACE_EXIT,
"%s: This link was disconnected", __func__);
110 case OBEX_EV_PROGRESS:
111 smlTrace(TRACE_INTERNAL,
"%s: Progress", __func__);
113 case OBEX_EV_REQDONE:
114 smlTrace(TRACE_INTERNAL,
"%s: Done", __func__);
115 if (obex_cmd == OBEX_CMD_DISCONNECT) {
116 linkenv->destroy = TRUE;
119 case OBEX_EV_REQHINT:
120 smlTrace(TRACE_INTERNAL,
"%s: Hint", __func__);
126 while (!linkenv->send_data && !linkenv->disconnect && !linkenv->error) {
127 if (!g_main_context_pending(linkenv->env->tsp->context)) {
131 smlTrace(TRACE_INTERNAL,
"%s: Dispatching command queue since we dont have data to send", __func__);
132 g_main_context_iteration(linkenv->env->tsp->context, TRUE);
136 if (linkenv->disconnect) {
137 OBEX_ObjectSetRsp(
object, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
138 smlTrace(TRACE_INTERNAL,
"%s: Get was aborted", __func__);
142 case OBEX_CMD_CONNECT:
143 case OBEX_CMD_DISCONNECT:
144 OBEX_ObjectSetRsp(
object, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS);
147 OBEX_ObjectSetRsp(
object, OBEX_RSP_NOT_IMPLEMENTED, OBEX_RSP_NOT_IMPLEMENTED);
153 case OBEX_CMD_SETPATH:
154 smlTrace(TRACE_INTERNAL,
"%s: Got SETPATH command", __func__);
155 OBEX_ObjectSetRsp(
object, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS);
158 smlTrace(TRACE_INTERNAL,
"%s: Got PUT command", __func__);
162 while (OBEX_ObjectGetNextHeader(handle,
object, &headertype, &header, &len)) {
163 smlTrace(TRACE_INTERNAL,
"%s: Next header %i, %d, %p", __func__, headertype, header.bq4, header.bs);
164 switch (headertype) {
165 case OBEX_HDR_CONNECTION:
166 smlTrace(TRACE_INTERNAL,
"%s: Found connection number: %d", __func__, header.bq4);
170 char *mimetypestr = g_strndup((
char *)header.bs, len);
178 smlTrace(TRACE_INTERNAL,
"%s: Found type: %s", __func__, VA_STRING(mimetypestr));
180 if (!strcmp(mimetypestr, SML_ELEMENT_WBXML)) {
181 mimetype = SML_MIMETYPE_WBXML;
182 }
else if (!strcmp(mimetypestr, SML_ELEMENT_XML)) {
183 mimetype = SML_MIMETYPE_XML;
184 }
else if (!strcmp(mimetypestr, SML_ELEMENT_SAN)) {
185 mimetype = SML_MIMETYPE_SAN;
187 smlSafeCFree(&mimetypestr);
188 smlErrorSet(&error, SML_ERROR_GENERIC,
"Unknown mime type");
192 smlSafeCFree(&mimetypestr);
194 case OBEX_HDR_LENGTH:
195 smlTrace(TRACE_INTERNAL,
"%s: Found length: %d", __func__, header.bq4);
200 smlErrorSet(&error, SML_ERROR_GENERIC,
"Length must come before the body");
216 memcpy(body, header.bs, length);
219 smlTrace(TRACE_INTERNAL,
"%s: Unknown header", __func__);
224 smlErrorSet(&error, SML_ERROR_GENERIC,
"Missing connection id");
228 if (conid != linkenv->conid) {
229 smlErrorSet(&error, SML_ERROR_GENERIC,
"Wrong connection id");
233 if (mimetype == SML_MIMETYPE_UNKNOWN) {
234 smlErrorSet(&error, SML_ERROR_GENERIC,
"Missing mime type");
239 smlErrorSet(&error, SML_ERROR_GENERIC,
"Missing length");
244 smlErrorSet(&error, SML_ERROR_GENERIC,
"Missing body");
248 SmlTransportData *tspdata = smlTransportDataNew(body, length, mimetype, TRUE, &error);
252 if (smlTransportReceiveEvent(linkenv->env->tsp, linkenv->link, SML_TRANSPORT_EVENT_DATA, tspdata, NULL))
253 OBEX_ObjectSetRsp(
object, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS);
255 OBEX_ObjectSetRsp(
object, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
257 smlTransportDataDeref(tspdata);
260 smlTrace(TRACE_INTERNAL,
"%s: Got GET command", __func__);
262 while (OBEX_ObjectGetNextHeader(handle,
object, &headertype, &header, &len)) {
263 smlTrace(TRACE_INTERNAL,
"%s: Next header %i, %d, %p", __func__, headertype, header.bq4, header.bs);
264 switch (headertype) {
265 case OBEX_HDR_CONNECTION:
266 smlTrace(TRACE_INTERNAL,
"%s: Found connection number: %d", __func__, header.bq4);
270 char *mimetypestr = g_strndup((
char *)header.bs, len);
278 smlTrace(TRACE_INTERNAL,
"%s: Found type: %s", __func__, VA_STRING(mimetypestr));
280 if (!strcmp(mimetypestr, SML_ELEMENT_WBXML)) {
281 mimetype = SML_MIMETYPE_WBXML;
282 }
else if (!strcmp(mimetypestr, SML_ELEMENT_XML)) {
283 mimetype = SML_MIMETYPE_XML;
284 }
else if (!strcmp(mimetypestr, SML_ELEMENT_SAN)) {
285 mimetype = SML_MIMETYPE_SAN;
287 smlSafeCFree(&mimetypestr);
288 smlErrorSet(&error, SML_ERROR_GENERIC,
"Unknown mime type");
292 smlSafeCFree(&mimetypestr);
295 smlTrace(TRACE_INTERNAL,
"%s: Unknown header", __func__);
300 smlErrorSet(&error, SML_ERROR_GENERIC,
"Missing connection id");
304 if (conid != linkenv->conid) {
305 smlErrorSet(&error, SML_ERROR_GENERIC,
"Wrong connection id");
309 if (mimetype == SML_MIMETYPE_UNKNOWN) {
310 smlErrorSet(&error, SML_ERROR_GENERIC,
"Missing mime type");
314 if (linkenv->error) {
316 OBEX_ObjectSetRsp(
object, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
318 OBEX_ObjectSetRsp(
object, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
320 smlErrorDeref(&(linkenv->error));
321 linkenv->error = NULL;
322 smlTrace(TRACE_INTERNAL,
"%s: Sent error in response to get", __func__);
326 if (!linkenv->send_data) {
327 smlErrorSet(&error, SML_ERROR_GENERIC,
"No data to send");
331 if (mimetype != linkenv->send_data->type) {
333 "Wrong mimetype %d requested. %d was expected.",
334 mimetype, linkenv->send_data->type);
339 header.bq4 = (uint32_t)linkenv->send_data->size;
340 OBEX_ObjectAddHeader(handle,
object, OBEX_HDR_LENGTH, header,
sizeof(uint32_t), 0);
342 header.bs = (
unsigned char *)linkenv->send_data->data;
343 OBEX_ObjectAddHeader(handle,
object, OBEX_HDR_BODY, header, linkenv->send_data->size, 0);
345 smlTransportDataDeref(linkenv->send_data);
346 linkenv->send_data = NULL;
348 OBEX_ObjectSetRsp(
object, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS);
350 case OBEX_CMD_CONNECT:;
351 smlTrace(TRACE_INTERNAL,
"%s: Got CONNECT command", __func__);
354 while (OBEX_ObjectGetNextHeader(handle,
object, &headertype, &header, &len)) {
355 smlTrace(TRACE_INTERNAL,
"%s: Next header %i, %d, %p", __func__, headertype, header.bq4, header.bs);
356 switch (headertype) {
357 case OBEX_HDR_TARGET:
358 target = g_strndup((
char *)header.bs, len);
359 smlTrace(TRACE_INTERNAL,
"%s: Found target: %s", __func__, VA_STRING(target));
362 smlTrace(TRACE_INTERNAL,
"%s: Unknown header", __func__);
366 if (!target || strcmp(target,
"SYNCML-SYNC")) {
367 smlSafeCFree(&target);
368 smlErrorSet(&error, SML_ERROR_GENERIC,
"Missing target");
371 smlSafeCFree(&target);
373 header.bq4 = linkenv->conid;
374 OBEX_ObjectAddHeader(handle,
object, OBEX_HDR_CONNECTION, header,
sizeof(linkenv->conid), OBEX_FL_FIT_ONE_PACKET);
376 header.bs = (
unsigned char *)
"SYNCML-SYNC";
377 OBEX_ObjectAddHeader(handle,
object, OBEX_HDR_WHO, header, strlen((
char *)header.bs), OBEX_FL_FIT_ONE_PACKET);
380 linkenv->link = smlLinkNew(linkenv->env->tsp, linkenv, &error);
384 if (smlTransportReceiveEvent(linkenv->env->tsp, linkenv->link, SML_TRANSPORT_EVENT_CONNECT_DONE, NULL, NULL))
385 OBEX_ObjectSetRsp(
object, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS);
387 OBEX_ObjectSetRsp(
object, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
388 linkenv->disconnect = TRUE;
391 case OBEX_CMD_DISCONNECT:
392 smlTrace(TRACE_INTERNAL,
"%s: Got DISCONNECT command", __func__);
393 OBEX_ObjectSetRsp(
object, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS);
396 smlTrace(TRACE_INTERNAL,
"%s: Denied %02x request", __func__, obex_cmd);
397 OBEX_ObjectSetRsp(
object, OBEX_RSP_NOT_IMPLEMENTED, OBEX_RSP_NOT_IMPLEMENTED);
402 case OBEX_EV_LINKERR:
403 smlTrace(TRACE_INTERNAL,
"%s: Link broken (this does not have to be an error)!", __func__);
406 smlTrace(TRACE_INTERNAL,
"%s: Unknown event!", __func__);
410 smlTrace(TRACE_EXIT,
"%s", __func__);
414 OBEX_ObjectSetRsp(
object, OBEX_RSP_BAD_REQUEST, OBEX_RSP_BAD_REQUEST);
416 smlTransportReceiveEvent(linkenv->env->tsp, linkenv->link, SML_TRANSPORT_EVENT_ERROR, NULL, error);
418 smlErrorDeref(&error);
421 static void _smlTransportObexServerMainEvent(obex_t *handle, obex_object_t *
object,
int mode,
int event,
int obex_cmd,
int obex_rsp)
423 smlTrace(TRACE_ENTRY,
"%s(%p, %p, %i, %i, %i, %i)",
424 __func__, handle,
object, mode, event, obex_cmd, obex_rsp);
430 case OBEX_EV_ACCEPTHINT:
439 linkenv->handle = OBEX_ServerAccept(env->handle, _smlTransportObexServerLinkEvent, linkenv);
440 if (!linkenv->handle) {
442 "OBEX_ServerAccept failed.");
443 smlSafeFree((gpointer *)&linkenv);
446 smlTrace(TRACE_INTERNAL,
"%s: New obex_t * handle %p", __func__, linkenv->handle);
449 linkenv->source = g_idle_source_new();
450 g_source_set_callback(linkenv->source, _dispatch_obex, linkenv, NULL);
451 g_source_attach(linkenv->source, env->tsp->context);
452 if (env->tsp->context)
453 g_main_context_ref(env->tsp->context);
457 linkenv->conid = env->lastConId;
465 "Unknown OBEX event %d.", event);
470 smlTrace(TRACE_EXIT,
"%s", __func__);
474 OBEX_ObjectSetRsp(
object, OBEX_RSP_BAD_REQUEST, OBEX_RSP_BAD_REQUEST);
476 smlTransportReceiveEvent(env->tsp, NULL, SML_TRANSPORT_EVENT_ERROR, NULL, error);
478 smlErrorDeref(&error);
483 static gboolean _fd_prepare(GSource *source, gint *timeout_)
485 smlTrace(TRACE_INTERNAL,
"%s(%p, %p)", __func__, source, timeout_);
493 static gboolean _fd_check(GSource *source)
499 int fd = OBEX_GetFD(env->handle);
506 int retval = select(fd + 1, &rfds, NULL, NULL, &tv);
509 smlTrace(TRACE_ERROR,
"%s: Unable to select()", __func__);
516 static gboolean _fd_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
518 smlTrace(TRACE_ENTRY,
"%s(%p, %p, %p)", __func__, source, callback, user_data);
523 int result = OBEX_HandleInput(env->handle, 0);
526 "OBEX_HandleInput on main handle returned %d.",
532 "OBEX_HandleInput on main handle get a timeout.");
536 smlTrace(TRACE_EXIT,
"%s", __func__);
539 smlTransportReceiveEvent(env->tsp, NULL, SML_TRANSPORT_EVENT_ERROR, NULL, error);
544 static SmlBool smlTransportObexServerSetConfigOption(
550 smlTrace(TRACE_ENTRY,
"%s(%p, %s, %s, %p)", __func__, tsp, VA_STRING(name), VA_STRING(value), error);
553 smlAssert(tsp->transport_data);
556 if (!strcmp(name, SML_TRANSPORT_CONFIG_PORT)) {
557 env->port = atoi(value);
558 smlTrace(TRACE_INTERNAL,
"%s: Port %i detected", __func__, env->port);
559 }
else if (!strcmp(name, SML_TRANSPORT_CONFIG_BLUETOOTH_ADDRESS)) {
560 #ifdef ENABLE_BLUETOOTH
561 int code = str2ba(value, env->bdaddr);
563 smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION,
564 "Bluetooth MAC cannot be interpreted (%d).", code);
567 smlTrace(TRACE_INTERNAL,
"%s: Bluetooth MAC %s detected",
568 __func__, VA_STRING(value));
570 smlErrorSet(error, SML_ERROR_GENERIC,
"Bluetooth not enabled");
573 }
else if (!strcmp(name, SML_TRANSPORT_CONFIG_BLUETOOTH_CHANNEL)) {
574 env->port = atoi(value);
575 smlTrace(TRACE_INTERNAL,
"%s: Bluetooth channel %i detected",
576 __func__, env->port);
577 }
else if (!strcmp(name, SML_TRANSPORT_CONFIG_IRDA_SERVICE)) {
578 env->irda_service = g_strdup(value);
579 smlTrace(TRACE_INTERNAL,
"%s: IRDA service %s detected",
580 __func__, VA_STRING(env->irda_service));
582 smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION,
583 "Unknown parameter %s found.", name);
587 smlTrace(TRACE_EXIT,
"%s - TRUE", __func__);
594 static SmlBool smlTransportObexServerSetConnectionType(
596 SmlTransportConnectionType type,
599 smlTrace(TRACE_ENTRY,
"%s(%p, %i, %p)", __func__, tsp, type, error);
602 smlAssert(tsp->transport_data);
607 smlTrace(TRACE_EXIT,
"%s", __func__);
613 smlTrace(TRACE_ENTRY,
"%s(%p, %p)", __func__, tsp, error);
616 smlAssert(tsp->transport_data);
618 smlAssert(env->handle == NULL);
621 #ifdef ENABLE_OPENOBEX_TCP
622 case SML_TRANSPORT_CONNECTION_TYPE_NET:;
624 env->handle = OBEX_Init(OBEX_TRANS_INET,
625 _smlTransportObexServerMainEvent,
629 "Unable to create OBEX IRDA transport.");
632 OBEX_SetUserData(env->handle, env);
635 g_warning(
"Using default INET port.");
636 size_t size =
sizeof(
struct sockaddr_in);
640 addr->sin_family = PF_INET;
641 addr->sin_port = htons(env->port);
642 addr->sin_addr.s_addr = INADDR_ANY;
644 if (GET_OBEX_RESULT(TcpOBEX_ServerRegister(env->handle, (
struct sockaddr *) addr, size)) < 0)
647 "Unable to register INET OBEX server. %s (%i).",
648 strerror(errno), errno);
649 smlSafeFree((gpointer *)&addr);
652 smlSafeFree((gpointer *)&addr);
655 case SML_TRANSPORT_CONNECTION_TYPE_SERIAL:
657 env->handle = OBEX_Init(OBEX_TRANS_IRDA,
658 _smlTransportObexServerMainEvent,
662 "Unable to create OBEX IRDA transport.");
665 OBEX_SetUserData(env->handle, env);
667 if (GET_OBEX_RESULT(IrOBEX_ServerRegister(env->handle, env->irda_service)))
670 "Unable to register IRDA OBEX server. %s (%i).",
671 strerror(errno), errno);
675 case SML_TRANSPORT_CONNECTION_TYPE_BLUETOOTH:
676 #ifdef ENABLE_BLUETOOTH
678 env->handle = OBEX_Init(OBEX_TRANS_BLUETOOTH,
679 _smlTransportObexServerMainEvent,
683 "Unable to create OBEX Bluetooth transport.");
686 OBEX_SetUserData(env->handle, env);
688 if (GET_OBEX_RESULT(BtOBEX_ServerRegister(env->handle, env->bdaddr, env->port)) < 0)
691 "Unable to register Bluetooth OBEX server. %s (%i).",
692 strerror(errno), errno);
696 smlErrorSet(error, SML_ERROR_GENERIC,
"Bluetooth not enabled");
701 smlErrorSet(error, SML_ERROR_GENERIC,
"Unknown obex type");
704 smlTrace(TRACE_INTERNAL,
"%s: server registered successfully", __func__);
710 env->functions->prepare = _fd_prepare;
711 env->functions->check = _fd_check;
712 env->functions->dispatch = _fd_dispatch;
713 env->functions->finalize = NULL;
718 g_source_set_callback(env->source, NULL, env, NULL);
719 g_source_attach(env->source, tsp->context);
721 g_main_context_ref(tsp->context);
723 smlTrace(TRACE_EXIT,
"%s: %p", __func__, env);
728 OBEX_Cleanup(env->handle);
732 smlSafeFree((gpointer *)&env);
737 static SmlBool smlTransportObexServerFinalize(
void *data,
SmlError **error)
739 smlTrace(TRACE_ENTRY,
"%s(%p, %p)", __func__, data, error);
747 OBEX_Cleanup(env->handle);
751 g_source_destroy(env->source);
752 g_source_unref(env->source);
756 if (env->tsp->context)
757 g_main_context_unref(env->tsp->context);
761 smlSafeFree((gpointer *)&(env->functions));
764 if (env->irda_service)
765 smlSafeCFree(&(env->irda_service));
767 smlSafeFree((gpointer *)&env);
769 smlTrace(TRACE_EXIT,
"%s", __func__);
775 smlTrace(TRACE_ENTRY,
"%s(%p, %p, %p, %p)", __func__, userdata, linkdata, data, error);
776 smlAssert(data || error);
783 if (linkdata == NULL) {
788 "The OBEX server tries to send before a connection with a client was established or the link was ignored.");
794 linkenv->error = error;
796 smlTrace(TRACE_EXIT,
"%s: Error set", __func__);
800 if (linkenv->send_data) {
801 smlErrorSet(&local_error, SML_ERROR_GENERIC,
"We already have waiting data");
805 linkenv->send_data = data;
806 smlTransportDataRef(linkenv->send_data);
808 smlTrace(TRACE_EXIT,
"%s", __func__);
813 smlTransportReceiveEvent(linkenv->env->tsp, linkenv->link, SML_TRANSPORT_EVENT_ERROR, NULL, local_error);
814 smlErrorDeref(&local_error);
818 static void smlTransportObexServerDisconnect(
void *data,
void *linkdata)
820 smlTrace(TRACE_ENTRY,
"%s(%p, %p)", __func__, data, linkdata);
830 linkenv->disconnect = TRUE;
831 smlTrace(TRACE_ERROR,
"%s - explicit disconnect by OBEX server", __func__);
834 smlTrace(TRACE_EXIT,
"%s", __func__);
843 tsp->functions.set_config_option = smlTransportObexServerSetConfigOption;
844 tsp->functions.set_connection_type = smlTransportObexServerSetConnectionType;
845 tsp->functions.initialize = smlTransportObexServerInit;
846 tsp->functions.finalize = smlTransportObexServerFinalize;
847 tsp->functions.send = smlTransportObexServerSend;
848 tsp->functions.disconnect = smlTransportObexServerDisconnect;
853 tsp->transport_data = env;