24 #include "syncml_internals.h"
25 #include "sml_error_internals.h"
26 #include "sml_transport_internals.h"
29 #include "transports/http_client_internals.h"
30 #include "transports/http_server_internals.h"
34 #include "transports/obex_client_internals.h"
35 #include "transports/obex_server_internals.h"
49 if (tsp->type == SML_TRANSPORT_HTTP_SERVER)
51 if (tsp->type == SML_TRANSPORT_OBEX_SERVER)
56 void smlTransportSetEventCallback(
SmlTransport *tsp, SmlTransportEventCb callback,
void *userdata)
58 smlTrace(TRACE_ENTRY,
"%s(%p, %p, %p)", __func__, tsp, callback, userdata);
61 tsp->event_callback = callback;
62 tsp->event_callback_userdata = userdata;
76 while (g_atomic_int_get(&(tsp->event_callback_ref_count)) > 0)
81 smlTrace(TRACE_EXIT,
"%s", __func__);
86 smlTrace(TRACE_ENTRY,
"%s(%p, %p, %p, %p)", __func__, tsp, link_, data, error);
91 if (tsp->cached_error != NULL)
95 smlTransportReceiveEvent(tsp, NULL, SML_TRANSPORT_EVENT_ERROR, NULL, NULL);
101 smlTransportReceiveEvent(tsp, NULL, SML_TRANSPORT_EVENT_ERROR, NULL, *error);
105 cmd->type = SML_TRANSPORT_CMD_SEND;
109 smlLinkRef(cmd->link);
112 smlTransportDataRef(cmd->data);
117 smlTrace(TRACE_EXIT,
"%s", __func__);
125 void smlTransportWorkerHandler(
void *message,
void *userdata)
127 smlTrace(TRACE_ENTRY,
"%s(%p, %p)", __func__, message, userdata);
134 case SML_TRANSPORT_CMD_SEND:
135 tsp->functions.send(tsp->transport_data, cmd->link ? cmd->link->link_data : NULL, cmd->data, cmd->error);
137 case SML_TRANSPORT_CMD_CONNECT:
138 if (!tsp->functions.connect) {
139 smlTransportReceiveEvent(tsp, NULL, SML_TRANSPORT_EVENT_CONNECT_DONE, NULL, NULL);
140 smlTrace(TRACE_INTERNAL,
"%s: No connect function", __func__);
143 tsp->functions.connect(tsp->transport_data);
145 case SML_TRANSPORT_CMD_DISCONNECT:
146 if (!tsp->functions.disconnect) {
147 smlTransportReceiveEvent(tsp, NULL, SML_TRANSPORT_EVENT_DISCONNECT_DONE, NULL, NULL);
148 smlTrace(TRACE_INTERNAL,
"%s: No disconnect function", __func__);
157 if (smlTransportIsServer(tsp) && !cmd->link->link_data) {
160 "%s: The server link was already disconnected.",
164 if (!smlTransportIsServer(tsp) && !tsp->connected) {
167 "%s: The client was already disconnected.",
171 tsp->functions.disconnect(tsp->transport_data, cmd->link ? cmd->link->link_data : NULL);
176 smlLinkDeref(cmd->link);
179 smlTransportDataDeref(cmd->data);
181 smlSafeFree((gpointer *)&cmd);
183 smlTrace(TRACE_EXIT,
"%s", __func__);
189 smlTrace(TRACE_ENTRY,
"%s(%p, %p, %i, %p, %p)", __func__, tsp, link_, type, data, error);
193 if (tsp->event_callback == NULL)
195 smlTrace(TRACE_INTERNAL,
"%s: no callback available", __func__);
196 if (type != SML_TRANSPORT_EVENT_ERROR &&
197 type != SML_TRANSPORT_EVENT_DISCONNECT_DONE)
203 g_error(
"The transport layer of type %d " \
204 "must send a normal event %d " \
205 "but there is no event callback set.",
214 if (tsp->cached_error && error != NULL)
219 g_warning(
"The transport layer already caches an error " \
220 "because the event callback is not present until now." \
221 "The received error is ignored. %s",
225 if (!tsp->cached_error && error) {
227 smlTrace(TRACE_INTERNAL,
"%s: init failed in transport protocol -> %s", __func__,
smlErrorPrint(&error));
228 tsp->state = SML_TRANSPORT_ERROR;
229 tsp->cached_error = error;
233 smlTrace(TRACE_INTERNAL,
"%s: callback available", __func__);
234 if (tsp->cached_error != NULL)
237 smlTrace(TRACE_INTERNAL,
"%s: cached error detected - %s", __func__,
239 g_atomic_int_inc(&(tsp->event_callback_ref_count));
240 ret = tsp->event_callback(
242 SML_TRANSPORT_EVENT_ERROR, NULL,
243 tsp->cached_error, tsp->event_callback_userdata);
244 smlTrace(TRACE_INTERNAL,
"%s: %d event callbacks",
245 __func__, g_atomic_int_dec_and_test(&(tsp->event_callback_ref_count)));
267 if (type == SML_TRANSPORT_EVENT_CONNECT_DONE && !link_)
269 if (smlTransportIsServer(tsp))
270 g_error(
"A connect event without a link was received " \
271 "but the transport layer is a server.");
273 g_error(
"A connect event was received " \
274 "but the transport layer is already connected.");
275 smlTrace(TRACE_INTERNAL,
"%s: connect + no link");
276 tsp->connected = TRUE;
279 if (type == SML_TRANSPORT_EVENT_DISCONNECT_DONE && !link_)
281 if (smlTransportIsServer(tsp))
282 g_error(
"A disconnect event without a link was received " \
283 "but the transport layer is a server.");
285 g_error(
"A disconnect event was received " \
286 "but there is no connected transport.");
287 smlTrace(TRACE_INTERNAL,
"%s: disconnect + no link");
288 tsp->connected = FALSE;
291 if (type == SML_TRANSPORT_EVENT_CONNECT_DONE && link_)
293 if (!smlTransportIsServer(tsp))
294 g_error(
"A connect event with a link was received " \
295 "but the transport layer is a server.");
296 if (!link_->link_data)
297 g_error(
"A connect event with a link was received " \
298 "but the link does not contain the required " \
299 "transport environment.");
300 smlTrace(TRACE_INTERNAL,
"%s: connect + link");
301 g_mutex_lock(tsp->connections_mutex);
303 g_mutex_unlock(tsp->connections_mutex);
306 if (type == SML_TRANSPORT_EVENT_DISCONNECT_DONE && link_)
308 if (!smlTransportIsServer(tsp))
309 g_error(
"A disconnect event with a link was received " \
310 "but the transport layer is not a server.");
311 if (link_->link_data)
312 g_error(
"A disconnect event with a link was received " \
313 "but the link still contains the " \
314 "transport environment.");
315 smlTrace(TRACE_INTERNAL,
"%s: disconnect + link");
316 g_mutex_lock(tsp->connections_mutex);
318 g_mutex_unlock(tsp->connections_mutex);
323 if (!(tsp->cached_error &&
324 type == SML_TRANSPORT_EVENT_ERROR &&
328 g_atomic_int_inc(&(tsp->event_callback_ref_count));
329 ret = tsp->event_callback(tsp, link_, type, data, error, tsp->event_callback_userdata);
330 smlTrace(TRACE_INTERNAL,
"%s: %d event callbacks",
331 __func__, g_atomic_int_dec_and_test(&(tsp->event_callback_ref_count)));
333 if (tsp->cached_error) {
334 smlErrorDeref(&(tsp->cached_error));
335 tsp->cached_error = NULL;
339 smlTrace(TRACE_EXIT,
"%s: %i", __func__, ret);
346 smlTrace(TRACE_ERROR,
"%s(%p,%p)", __func__, tsp, error);
357 smlTrace(TRACE_ENTRY,
"%s(%p)", __func__, tsp);
359 smlAssert(tsp->thread);
361 smlThreadStop(tsp->thread);
363 smlThreadFree(tsp->thread);
366 smlTrace(TRACE_EXIT,
"%s", __func__);
372 _smlTransportStop(tsp);
377 smlTrace(TRACE_ENTRY,
"%s(%p, %p)", __func__, tsp, error);
385 if (smlTransportIsServer(tsp))
388 "Only a transport client can be actively connected.");
395 "A transport client can be connected only once.");
405 cmd->type = SML_TRANSPORT_CMD_CONNECT;
410 smlTrace(TRACE_EXIT,
"%s", __func__);
420 smlTrace(TRACE_ENTRY,
"%s(%p, %p, %p)", __func__, tsp, link_, error);
429 "The transport is not connected and so it cannot be disconnected.");
437 if (link_ && !smlTransportIsServer(tsp))
440 "A transport client has no link " \
441 "because there is only one connection.");
455 if (link_ && !link_->link_data)
468 "%s: A server connection should be closed " \
469 "but the connection is already closed.",
474 if (!link_ && smlTransportIsServer(tsp) && tsp->connections)
477 "A server shutdown is requested " \
478 "but there are still open connections (%d).",
489 if (tsp != link_->tsp)
492 "The link %p is registered at another transport layer %p than this one %p.",
493 link_, link_->tsp, tsp);
497 g_mutex_lock(tsp->links_mutex);
498 if (!g_hash_table_lookup(tsp->links, link_)) {
499 g_mutex_unlock(tsp->links_mutex);
501 "The link %p is not registered at the transport layer %p",
505 g_mutex_unlock(tsp->links_mutex);
514 cmd->type = SML_TRANSPORT_CMD_DISCONNECT;
517 smlLinkRef(cmd->link);
523 smlTrace(TRACE_EXIT,
"%s", __func__);
537 SmlTransportData *smlTransportDataNew(
char *data,
unsigned long size, SmlMimeType mimetype, SmlBool ownsData,
SmlError **error)
539 smlTrace(TRACE_ENTRY,
"%s(%p, %d, %i, %i, %p)", __func__, data, size, mimetype, ownsData, error);
547 cmd->
type = mimetype;
550 cmd->ownsData = ownsData;
552 cmd->needsAnswer = TRUE;
553 cmd->type_get = SML_MIMETYPE_UNKNOWN;
555 smlTrace(TRACE_EXIT,
"%s: %p", __func__, cmd);
565 smlTrace(TRACE_ENTRY,
"%s(%p)", __func__, data);
568 g_atomic_int_inc(&(data->refCount));
570 smlTrace(TRACE_EXIT,
"%s", __func__);
576 smlTrace(TRACE_ENTRY,
"%s(%p)", __func__, data);
579 if (!g_atomic_int_dec_and_test(&(data->refCount))) {
580 smlTrace(TRACE_EXIT,
"%s: refCount > 0", __func__);
584 if (data->ownsData && data->data != NULL)
585 smlSafeCFree(&(data->data));
587 smlSafeFree((gpointer *)&data);
589 smlTrace(TRACE_EXIT,
"%s: Freed", __func__);
594 smlTrace(TRACE_ENTRY,
"%s(%p, %p, %p(%p))", __func__, tsp, link_, error, error ? *error : NULL);
605 cmd->type = SML_TRANSPORT_CMD_SEND;
609 smlLinkRef(cmd->link);
612 if (error && *error) {
620 smlTrace(TRACE_EXIT,
"%s", __func__);
625 smlTrace(TRACE_ENTRY,
"%s(%p, %p, %p)", __func__, tsp, link_data, error);
627 smlAssert(link_data);
633 link_->link_data = link_data;
638 g_mutex_lock(tsp->links_mutex);
639 g_hash_table_insert(tsp->links, link_, GINT_TO_POINTER(1));
640 g_mutex_unlock(tsp->links_mutex);
642 smlTrace(TRACE_EXIT,
"%s: %p", __func__, link_);
657 smlTrace(TRACE_INTERNAL,
"%s(%p, %p)", __func__, tsp, link_data);
663 smlTrace(TRACE_ENTRY,
"%s(%p)", __func__, link_);
666 g_atomic_int_inc(&(link_->refCount));
668 smlTrace(TRACE_EXIT,
"%s", __func__);
672 void smlLinkDeref(
SmlLink *link_)
674 smlTrace(TRACE_ENTRY,
"%s(%p)", __func__, link_);
677 if (!g_atomic_int_dec_and_test(&(link_->refCount))) {
678 smlTrace(TRACE_EXIT,
"%s: refCount > 0", __func__);
684 g_mutex_lock(link_->tsp->links_mutex);
685 if (!g_hash_table_remove(link_->tsp->links, link_))
686 g_warning(
"The link %p was never registered.", link_);
687 g_mutex_unlock(link_->tsp->links_mutex);
691 smlSafeFree((gpointer *)&link_);
693 smlTrace(TRACE_EXIT,
"%s: Freed", __func__);
723 smlTrace(TRACE_ENTRY,
"%s(%i, %p)", __func__, type, error);
727 if (!g_thread_supported ()) g_thread_init (NULL);
734 tsp->cached_error = NULL;
735 tsp->event_callback = NULL;
740 case SML_TRANSPORT_HTTP_SERVER:
741 if (!smlTransportHttpServerNew(tsp, error))
744 case SML_TRANSPORT_HTTP_CLIENT:
745 if (!smlTransportHttpClientNew(tsp, error))
749 case SML_TRANSPORT_HTTP_SERVER:
750 case SML_TRANSPORT_HTTP_CLIENT:
751 smlErrorSet(error, SML_ERROR_GENERIC,
"HTTP Transport not enabled in this build");
755 case SML_TRANSPORT_OBEX_CLIENT:
756 if (!smlTransportObexClientNew(tsp, error))
759 case SML_TRANSPORT_OBEX_SERVER:
760 if (!smlTransportObexServerNew(tsp, error))
764 case SML_TRANSPORT_OBEX_SERVER:
765 case SML_TRANSPORT_OBEX_CLIENT:
766 smlErrorSet(error, SML_ERROR_GENERIC,
"OBEX Transport not enabled in this build");
772 if (!tsp->command_queue)
781 if (smlTransportIsServer(tsp))
783 tsp->links = g_hash_table_new(g_direct_hash, g_direct_equal);
784 tsp->links_mutex = g_mutex_new();
785 tsp->connections = 0;
786 tsp->connections_mutex = g_mutex_new();
789 tsp->links_mutex = NULL;
790 tsp->connections = 0;
791 tsp->connections_mutex = NULL;
793 tsp->connected = FALSE;
795 smlTrace(TRACE_EXIT,
"%s: %p", __func__, tsp);
812 smlTrace(TRACE_ENTRY,
"%s(%p)", __func__, tsp);
815 if (tsp->command_queue)
816 smlQueueFree(tsp->command_queue);
819 if (tsp->transport_data &&
820 !tsp->functions.finalize(tsp->transport_data, &error))
822 g_warning(
"The library libsyncml cannot free the transport. %s",
824 smlErrorDeref(&error);
828 g_main_context_unref(tsp->context);
833 if (tsp->connections)
835 g_warning(
"The transport layer of libsyncml is freed " \
836 "but not all connections were close (%d).",
839 if (tsp->connections_mutex)
840 g_mutex_free(tsp->connections_mutex);
844 if (tsp->links && g_hash_table_size(tsp->links))
845 g_warning(
"The transport layer of libsyncml is freed " \
846 "but not all connections were cleaned up (%d).",
847 g_hash_table_size(tsp->links));
849 g_hash_table_unref(tsp->links);
850 if (tsp->links_mutex)
851 g_mutex_free(tsp->links_mutex);
855 if (tsp->cached_error) {
856 g_warning(
"The transport layer is cleaned up and an error is ignored. %s",
858 smlErrorDeref(&(tsp->cached_error));
863 smlSafeFree((gpointer *)&tsp);
865 smlTrace(TRACE_EXIT,
"%s", __func__);
889 smlTrace(TRACE_ENTRY,
"%s(%p, %s, %s, %p)", __func__, tsp, VA_STRING(name), strcmp(name,
"PASSWORD") ? VA_STRING(value) :
"***sensitive***", error);
896 smlAssert(tsp->state == SML_TRANSPORT_UNINITIALIZED);
897 smlAssert(tsp->functions.set_config_option);
901 smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION,
902 "The name of the configuration option is missing.");
906 if (!tsp->functions.set_config_option(tsp, name, value, error))
909 smlTrace(TRACE_EXIT,
"%s", __func__);
933 SmlTransportConnectionType type,
936 smlTrace(TRACE_ENTRY,
"%s(%p, %i, %p)", __func__, tsp, type, error);
943 smlAssert(type != SML_TRANSPORT_CONNECTION_TYPE_UNKNOWN);
944 smlAssert(tsp->state == SML_TRANSPORT_UNINITIALIZED);
945 smlAssert(tsp->functions.set_connection_type);
947 if (tsp->functions.set_connection_type(tsp, type, error))
949 smlTrace(TRACE_EXIT,
"%s", __func__);
952 smlTrace(TRACE_EXIT_ERROR,
"%s", __func__);
971 smlTrace(TRACE_ENTRY,
"%s(%p, %p)", __func__, tsp, error);
974 smlAssert(tsp->state == SML_TRANSPORT_UNINITIALIZED);
978 tsp->context = g_main_context_new();
981 "Cannot create new GMainContext for asynchronous transport.");
985 tsp->thread = smlThreadNew(tsp->context, error);
987 goto error_free_loop;
995 smlQueueSetHandler(tsp->command_queue, (SmlQueueHandler)smlTransportWorkerHandler, tsp);
998 if (tsp->functions.initialize && !tsp->functions.initialize(tsp, error))
1004 smlThreadStart(tsp->thread);
1006 tsp->state = SML_TRANSPORT_INITIALIZED;
1009 if (smlTransportIsServer(tsp))
1010 tsp->connected = TRUE;
1012 smlTrace(TRACE_EXIT,
"%s", __func__);
1016 smlQueueDetach(tsp->command_queue);
1019 g_main_context_unref(tsp->context);
1020 tsp->context = NULL;
1046 smlTrace(TRACE_ENTRY,
"%s(%p, %s, %p)", __func__, tsp, VA_STRING(uri), error);
1054 smlAssert(tsp->state == SML_TRANSPORT_INITIALIZED ||
1055 tsp->state == SML_TRANSPORT_CONNECTED);
1056 smlAssert(tsp->functions.set_response_uri);
1058 if (tsp->functions.set_response_uri(tsp, uri, error))
1060 smlTrace(TRACE_EXIT,
"%s", __func__);
1063 smlTrace(TRACE_EXIT_ERROR,
"%s", __func__);
1068 static SmlBool smlTransportDetachQueueCallback(
1072 smlTrace(TRACE_ENTRY,
"%s", __func__);
1076 smlQueueDetach(queue);
1077 smlTrace(TRACE_EXIT,
"%s", __func__);
1081 static SmlBool smlTransportDispatchQueueCallback(
1085 smlTrace(TRACE_ENTRY,
"%s", __func__);
1089 smlQueueDispatch(queue);
1090 smlTrace(TRACE_EXIT,
"%s", __func__);
1106 smlTrace(TRACE_ENTRY,
"%s(%p, %p)", __func__, tsp, error);
1109 smlAssert(tsp->functions.finalize);
1111 if (tsp->connected && !smlTransportIsServer(tsp))
1114 "If a client transport is connected then it cannot be finalized.");
1118 if (tsp->state != SML_TRANSPORT_INITIALIZED &&
1119 tsp->state != SML_TRANSPORT_ERROR) {
1120 smlErrorSet(error, SML_ERROR_GENERIC,
"Transport was not in the state \"Initialized\"");
1127 if (tsp->type != SML_TRANSPORT_HTTP_CLIENT &&
1128 tsp->type != SML_TRANSPORT_HTTP_SERVER && tsp->thread)
1129 _smlTransportStop(tsp);
1136 smlTransportDetachQueueCallback,
1142 smlQueueDetach(tsp->command_queue);
1147 unsigned int queueLength = smlQueueLength(tsp->command_queue);
1148 for (; i < queueLength; i++) {
1153 smlTransportDispatchQueueCallback,
1159 smlQueueDispatch(tsp->command_queue);
1163 if (!tsp->functions.finalize(tsp->transport_data, error))
1168 _smlTransportStop(tsp);
1170 tsp->transport_data = NULL;
1172 tsp->state = SML_TRANSPORT_UNINITIALIZED;
1175 if (smlTransportIsServer(tsp))
1176 tsp->connected = FALSE;
1178 smlTrace(TRACE_EXIT,
"%s", __func__);
1188 smlTrace(TRACE_ENTRY,
"%s(%p, %p, %p)", __func__, link_, session, error);
1195 smlAssert(link_->tsp);
1198 if (link_->tsp->functions.get_response_uri)
1200 char *result = link_->tsp->functions.get_response_uri(link_, session, error);
1201 smlTrace(TRACE_EXIT,
"%s - %s", __func__, VA_STRING(result));
1204 smlTrace(TRACE_EXIT,
"%s - unsupported feature", __func__);