00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "syncml.h"
00023
00024 #include "syncml_internals.h"
00025 #include "sml_error_internals.h"
00026 #include "sml_transport_internals.h"
00027
00028 #ifdef ENABLE_HTTP
00029 #include "transports/http_client_internals.h"
00030 #include "transports/http_server_internals.h"
00031 #endif
00032
00033 #ifdef ENABLE_OBEX
00034 #include "transports/obex_client_internals.h"
00035 #include "transports/obex_server_internals.h"
00036 #endif
00037
00045
00046 static SmlBool smlTransportIsServer(SmlTransport *tsp)
00047 {
00048 smlAssert(tsp);
00049 if (tsp->type == SML_TRANSPORT_HTTP_SERVER)
00050 return TRUE;
00051 if (tsp->type == SML_TRANSPORT_OBEX_SERVER)
00052 return TRUE;
00053 return FALSE;
00054 }
00055
00056 void smlTransportSetEventCallback(SmlTransport *tsp, SmlTransportEventCb callback, void *userdata)
00057 {
00058 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, tsp, callback, userdata);
00059 smlAssert(tsp);
00060
00061 tsp->event_callback = callback;
00062 tsp->event_callback_userdata = userdata;
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076 while (g_atomic_int_get(&(tsp->event_callback_ref_count)) > 0)
00077 {
00078 usleep(50);
00079 }
00080
00081 smlTrace(TRACE_EXIT, "%s", __func__);
00082 }
00083
00084 SmlBool smlTransportSend(SmlTransport *tsp, SmlLink *link_, SmlTransportData *data, SmlError **error)
00085 {
00086 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, tsp, link_, data, error);
00087 CHECK_ERROR_REF
00088 smlAssert(tsp);
00089 smlAssert(data);
00090
00091 if (tsp->cached_error != NULL)
00092 {
00093
00094
00095 smlTransportReceiveEvent(tsp, NULL, SML_TRANSPORT_EVENT_ERROR, NULL, NULL);
00096 goto error;
00097 }
00098
00099 SmlTransportCommand *cmd = smlTryMalloc0(sizeof(SmlTransportCommand), error);
00100 if (!cmd) {
00101 smlTransportReceiveEvent(tsp, NULL, SML_TRANSPORT_EVENT_ERROR, NULL, *error);
00102 goto error;
00103 }
00104
00105 cmd->type = SML_TRANSPORT_CMD_SEND;
00106 cmd->data = data;
00107 if (link_) {
00108 cmd->link = link_;
00109 smlLinkRef(cmd->link);
00110 }
00111
00112 smlTransportDataRef(cmd->data);
00113
00114
00115 smlQueueSend(tsp->command_queue, cmd);
00116
00117 smlTrace(TRACE_EXIT, "%s", __func__);
00118 return TRUE;
00119
00120 error:
00121 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
00122 return FALSE;
00123 }
00124
00125 void smlTransportWorkerHandler(void *message, void *userdata)
00126 {
00127 smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, message, userdata);
00128 smlAssert(message);
00129 smlAssert(userdata);
00130 SmlTransportCommand *cmd = message;
00131 SmlTransport *tsp = userdata;
00132
00133 switch (cmd->type) {
00134 case SML_TRANSPORT_CMD_SEND:
00135 tsp->functions.send(tsp->transport_data, cmd->link ? cmd->link->link_data : NULL, cmd->data, cmd->error);
00136 break;
00137 case SML_TRANSPORT_CMD_CONNECT:
00138 if (!tsp->functions.connect) {
00139 smlTransportReceiveEvent(tsp, NULL, SML_TRANSPORT_EVENT_CONNECT_DONE, NULL, NULL);
00140 smlTrace(TRACE_INTERNAL, "%s: No connect function", __func__);
00141 break;
00142 }
00143 tsp->functions.connect(tsp->transport_data);
00144 break;
00145 case SML_TRANSPORT_CMD_DISCONNECT:
00146 if (!tsp->functions.disconnect) {
00147 smlTransportReceiveEvent(tsp, NULL, SML_TRANSPORT_EVENT_DISCONNECT_DONE, NULL, NULL);
00148 smlTrace(TRACE_INTERNAL, "%s: No disconnect function", __func__);
00149 break;
00150 }
00151
00152
00153
00154
00155
00156
00157 if (smlTransportIsServer(tsp) && !cmd->link->link_data) {
00158
00159 smlTrace(TRACE_INTERNAL,
00160 "%s: The server link was already disconnected.",
00161 __func__);
00162 break;
00163 }
00164 if (!smlTransportIsServer(tsp) && !tsp->connected) {
00165
00166 smlTrace(TRACE_INTERNAL,
00167 "%s: The client was already disconnected.",
00168 __func__);
00169 break;
00170 }
00171 tsp->functions.disconnect(tsp->transport_data, cmd->link ? cmd->link->link_data : NULL);
00172 break;
00173 }
00174
00175 if (cmd->link)
00176 smlLinkDeref(cmd->link);
00177
00178 if (cmd->data)
00179 smlTransportDataDeref(cmd->data);
00180
00181 smlSafeFree((gpointer *)&cmd);
00182
00183 smlTrace(TRACE_EXIT, "%s", __func__);
00184 return;
00185 }
00186
00187 SmlBool smlTransportReceiveEvent(SmlTransport *tsp, SmlLink *link_, SmlTransportEventType type, SmlTransportData *data, SmlError *error)
00188 {
00189 smlTrace(TRACE_ENTRY, "%s(%p, %p, %i, %p, %p)", __func__, tsp, link_, type, data, error);
00190 smlAssert(tsp);
00191
00192 SmlBool ret = TRUE;
00193 if (tsp->event_callback == NULL)
00194 {
00195 smlTrace(TRACE_INTERNAL, "%s: no callback available", __func__);
00196 if (type != SML_TRANSPORT_EVENT_ERROR &&
00197 type != SML_TRANSPORT_EVENT_DISCONNECT_DONE)
00198 {
00199
00200
00201
00202
00203 g_error("The transport layer of type %d " \
00204 "must send a normal event %d " \
00205 "but there is no event callback set.",
00206 tsp->type, type);
00207
00208 exit(1);
00209 }
00210
00211
00212
00213
00214 if (tsp->cached_error && error != NULL)
00215 {
00216
00217
00218
00219 g_warning("The transport layer already caches an error " \
00220 "because the event callback is not present until now." \
00221 "The received error is ignored. %s",
00222 smlErrorPrint(&error));
00223
00224 }
00225 if (!tsp->cached_error && error) {
00226
00227 smlTrace(TRACE_INTERNAL, "%s: init failed in transport protocol -> %s", __func__, smlErrorPrint(&error));
00228 tsp->state = SML_TRANSPORT_ERROR;
00229 tsp->cached_error = error;
00230 smlErrorRef(&error);
00231 }
00232 } else {
00233 smlTrace(TRACE_INTERNAL, "%s: callback available", __func__);
00234 if (tsp->cached_error != NULL)
00235 {
00236
00237 smlTrace(TRACE_INTERNAL, "%s: cached error detected - %s", __func__,
00238 smlErrorPrint(&(tsp->cached_error)));
00239 g_atomic_int_inc(&(tsp->event_callback_ref_count));
00240 ret = tsp->event_callback(
00241 tsp, NULL,
00242 SML_TRANSPORT_EVENT_ERROR, NULL,
00243 tsp->cached_error, tsp->event_callback_userdata);
00244 smlTrace(TRACE_INTERNAL, "%s: %d event callbacks",
00245 __func__, g_atomic_int_dec_and_test(&(tsp->event_callback_ref_count)));
00246
00247
00248
00249
00250 }
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267 if (type == SML_TRANSPORT_EVENT_CONNECT_DONE && !link_)
00268 {
00269 if (smlTransportIsServer(tsp))
00270 g_error("A connect event without a link was received " \
00271 "but the transport layer is a server.");
00272 if (tsp->connected)
00273 g_error("A connect event was received " \
00274 "but the transport layer is already connected.");
00275 smlTrace(TRACE_INTERNAL, "%s: connect + no link");
00276 tsp->connected = TRUE;
00277 }
00278
00279 if (type == SML_TRANSPORT_EVENT_DISCONNECT_DONE && !link_)
00280 {
00281 if (smlTransportIsServer(tsp))
00282 g_error("A disconnect event without a link was received " \
00283 "but the transport layer is a server.");
00284 if (!tsp->connected)
00285 g_error("A disconnect event was received " \
00286 "but there is no connected transport.");
00287 smlTrace(TRACE_INTERNAL, "%s: disconnect + no link");
00288 tsp->connected = FALSE;
00289 }
00290
00291 if (type == SML_TRANSPORT_EVENT_CONNECT_DONE && link_)
00292 {
00293 if (!smlTransportIsServer(tsp))
00294 g_error("A connect event with a link was received " \
00295 "but the transport layer is a server.");
00296 if (!link_->link_data)
00297 g_error("A connect event with a link was received " \
00298 "but the link does not contain the required " \
00299 "transport environment.");
00300 smlTrace(TRACE_INTERNAL, "%s: connect + link");
00301 g_mutex_lock(tsp->connections_mutex);
00302 tsp->connections++;
00303 g_mutex_unlock(tsp->connections_mutex);
00304 }
00305
00306 if (type == SML_TRANSPORT_EVENT_DISCONNECT_DONE && link_)
00307 {
00308 if (!smlTransportIsServer(tsp))
00309 g_error("A disconnect event with a link was received " \
00310 "but the transport layer is not a server.");
00311 if (link_->link_data)
00312 g_error("A disconnect event with a link was received " \
00313 "but the link still contains the " \
00314 "transport environment.");
00315 smlTrace(TRACE_INTERNAL, "%s: disconnect + link");
00316 g_mutex_lock(tsp->connections_mutex);
00317 tsp->connections--;
00318 g_mutex_unlock(tsp->connections_mutex);
00319 }
00320
00321
00322
00323 if (!(tsp->cached_error &&
00324 type == SML_TRANSPORT_EVENT_ERROR &&
00325 error == NULL))
00326 {
00327
00328 g_atomic_int_inc(&(tsp->event_callback_ref_count));
00329 ret = tsp->event_callback(tsp, link_, type, data, error, tsp->event_callback_userdata);
00330 smlTrace(TRACE_INTERNAL, "%s: %d event callbacks",
00331 __func__, g_atomic_int_dec_and_test(&(tsp->event_callback_ref_count)));
00332 }
00333 if (tsp->cached_error) {
00334 smlErrorDeref(&(tsp->cached_error));
00335 tsp->cached_error = NULL;
00336 }
00337 }
00338
00339 smlTrace(TRACE_EXIT, "%s: %i", __func__, ret);
00340 return ret;
00341 }
00342
00343
00344 SmlBool smlTransportRunAsync(SmlTransport *tsp, SmlError **error)
00345 {
00346 smlTrace(TRACE_ERROR, "%s(%p,%p)", __func__, tsp, error);
00347 CHECK_ERROR_REF
00348
00349
00350
00351
00352 return TRUE;
00353 }
00354
00355 static void _smlTransportStop(SmlTransport *tsp)
00356 {
00357 smlTrace(TRACE_ENTRY, "%s(%p)", __func__, tsp);
00358
00359 smlAssert(tsp->thread);
00360
00361 smlThreadStop(tsp->thread);
00362
00363 smlThreadFree(tsp->thread);
00364 tsp->thread = NULL;
00365
00366 smlTrace(TRACE_EXIT, "%s", __func__);
00367 }
00368
00369
00370 void smlTransportStop(SmlTransport *tsp)
00371 {
00372 _smlTransportStop(tsp);
00373 }
00374
00375 SmlBool smlTransportConnect(SmlTransport *tsp, SmlError **error)
00376 {
00377 smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, tsp, error);
00378 CHECK_ERROR_REF
00379 smlAssert(tsp);
00380
00381
00382
00383
00384
00385 if (smlTransportIsServer(tsp))
00386 {
00387 smlErrorSet(error, SML_ERROR_GENERIC,
00388 "Only a transport client can be actively connected.");
00389 goto error;
00390 }
00391
00392 if (tsp->connected)
00393 {
00394 smlErrorSet(error, SML_ERROR_GENERIC,
00395 "A transport client can be connected only once.");
00396 goto error;
00397 }
00398
00399
00400
00401 SmlTransportCommand *cmd = smlTryMalloc0(sizeof(SmlTransportCommand), error);
00402 if (!cmd)
00403 goto error;
00404
00405 cmd->type = SML_TRANSPORT_CMD_CONNECT;
00406
00407
00408 smlQueueSend(tsp->command_queue, cmd);
00409
00410 smlTrace(TRACE_EXIT, "%s", __func__);
00411 return TRUE;
00412
00413 error:
00414 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
00415 return FALSE;
00416 }
00417
00418 SmlBool smlTransportDisconnect(SmlTransport *tsp, SmlLink *link_, SmlError **error)
00419 {
00420 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, tsp, link_, error);
00421 CHECK_ERROR_REF
00422 smlAssert(tsp);
00423
00424
00425
00426 if (!tsp->connected)
00427 {
00428 smlErrorSet(error, SML_ERROR_GENERIC,
00429 "The transport is not connected and so it cannot be disconnected.");
00430 goto error;
00431 }
00432
00433
00434
00435
00436
00437 if (link_ && !smlTransportIsServer(tsp))
00438 {
00439 smlErrorSet(error, SML_ERROR_GENERIC,
00440 "A transport client has no link " \
00441 "because there is only one connection.");
00442 goto error;
00443 }
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455 if (link_ && !link_->link_data)
00456 {
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467 smlTrace(TRACE_EXIT,
00468 "%s: A server connection should be closed " \
00469 "but the connection is already closed.",
00470 __func__);
00471 return TRUE;
00472 }
00473
00474 if (!link_ && smlTransportIsServer(tsp) && tsp->connections)
00475 {
00476 smlErrorSet(error, SML_ERROR_GENERIC,
00477 "A server shutdown is requested " \
00478 "but there are still open connections (%d).",
00479 tsp->connections);
00480 goto error;
00481 }
00482
00483
00484
00485
00486
00487 if (link_)
00488 {
00489 if (tsp != link_->tsp)
00490 {
00491 smlErrorSet(error, SML_ERROR_GENERIC,
00492 "The link %p is registered at another transport layer %p than this one %p.",
00493 link_, link_->tsp, tsp);
00494 goto error;
00495 }
00496
00497 g_mutex_lock(tsp->links_mutex);
00498 if (!g_hash_table_lookup(tsp->links, link_)) {
00499 g_mutex_unlock(tsp->links_mutex);
00500 smlErrorSet(error, SML_ERROR_GENERIC,
00501 "The link %p is not registered at the transport layer %p",
00502 link_, tsp);
00503 goto error;
00504 }
00505 g_mutex_unlock(tsp->links_mutex);
00506 }
00507
00508
00509
00510 SmlTransportCommand *cmd = smlTryMalloc0(sizeof(SmlTransportCommand), error);
00511 if (!cmd)
00512 goto error;
00513
00514 cmd->type = SML_TRANSPORT_CMD_DISCONNECT;
00515 if (link_) {
00516 cmd->link = link_;
00517 smlLinkRef(cmd->link);
00518 }
00519
00520
00521 smlQueueSend(tsp->command_queue, cmd);
00522
00523 smlTrace(TRACE_EXIT, "%s", __func__);
00524 return TRUE;
00525
00526 error:
00527 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
00528 return FALSE;
00529 }
00530
00531 SmlTransportType smlTransportGetType(SmlTransport *tsp)
00532 {
00533 smlAssert(tsp);
00534 return tsp->type;
00535 }
00536
00537 SmlTransportData *smlTransportDataNew(char *data, unsigned long size, SmlMimeType mimetype, SmlBool ownsData, SmlError **error)
00538 {
00539 smlTrace(TRACE_ENTRY, "%s(%p, %d, %i, %i, %p)", __func__, data, size, mimetype, ownsData, error);
00540 CHECK_ERROR_REF
00541
00542
00543 SmlTransportData *cmd = smlTryMalloc0(sizeof(SmlTransportData), error);
00544 if (!cmd)
00545 goto error;
00546
00547 cmd->type = mimetype;
00548 cmd->data = data;
00549 cmd->size = size;
00550 cmd->ownsData = ownsData;
00551 cmd->refCount = 1;
00552 cmd->needsAnswer = TRUE;
00553 cmd->type_get = SML_MIMETYPE_UNKNOWN;
00554
00555 smlTrace(TRACE_EXIT, "%s: %p", __func__, cmd);
00556 return cmd;
00557
00558 error:
00559 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
00560 return NULL;
00561 }
00562
00563 SmlTransportData *smlTransportDataRef(SmlTransportData *data)
00564 {
00565 smlTrace(TRACE_ENTRY, "%s(%p)", __func__, data);
00566 smlAssert(data);
00567
00568 g_atomic_int_inc(&(data->refCount));
00569
00570 smlTrace(TRACE_EXIT, "%s", __func__);
00571 return data;
00572 }
00573
00574 void smlTransportDataDeref(SmlTransportData *data)
00575 {
00576 smlTrace(TRACE_ENTRY, "%s(%p)", __func__, data);
00577 smlAssert(data);
00578
00579 if (!g_atomic_int_dec_and_test(&(data->refCount))) {
00580 smlTrace(TRACE_EXIT, "%s: refCount > 0", __func__);
00581 return;
00582 }
00583
00584 if (data->ownsData && data->data != NULL)
00585 smlSafeCFree(&(data->data));
00586
00587 smlSafeFree((gpointer *)&data);
00588
00589 smlTrace(TRACE_EXIT, "%s: Freed", __func__);
00590 }
00591
00592 void smlTransportSetError(SmlTransport *tsp, SmlLink *link_, SmlError **error)
00593 {
00594 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p(%p))", __func__, tsp, link_, error, error ? *error : NULL);
00595
00596
00597
00598 smlAssert(tsp);
00599
00600 SmlError *locerror = NULL;
00601 SmlTransportCommand *cmd = smlTryMalloc0(sizeof(SmlTransportCommand), &locerror);
00602 if (!cmd)
00603 return;
00604
00605 cmd->type = SML_TRANSPORT_CMD_SEND;
00606 cmd->data = NULL;
00607 if (link_) {
00608 cmd->link = link_;
00609 smlLinkRef(cmd->link);
00610 }
00611
00612 if (error && *error) {
00613 cmd->error = *error;
00614 smlErrorRef(error);
00615 }
00616
00617
00618 smlQueueSend(tsp->command_queue, cmd);
00619
00620 smlTrace(TRACE_EXIT, "%s", __func__);
00621 }
00622
00623 SmlLink *smlLinkNew(SmlTransport *tsp, void *link_data, SmlError **error)
00624 {
00625 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, tsp, link_data, error);
00626 CHECK_ERROR_REF
00627 smlAssert(link_data);
00628
00629 SmlLink *link_ = smlTryMalloc0(sizeof(SmlLink), error);
00630 if (!link_)
00631 goto error;
00632 link_->tsp = tsp;
00633 link_->link_data = link_data;
00634 link_->refCount = 1;
00635
00636
00637
00638 g_mutex_lock(tsp->links_mutex);
00639 g_hash_table_insert(tsp->links, link_, GINT_TO_POINTER(1));
00640 g_mutex_unlock(tsp->links_mutex);
00641
00642 smlTrace(TRACE_EXIT, "%s: %p", __func__, link_);
00643 return link_;
00644
00645 error:
00646 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
00647 return NULL;
00648 }
00649
00650
00651 SmlLink *smlLinkFind(SmlTransport *tsp, void *link_data)
00652 {
00653
00654
00655
00656
00657 smlTrace(TRACE_INTERNAL, "%s(%p, %p)", __func__, tsp, link_data);
00658 return NULL;
00659 }
00660
00661 SmlLink *smlLinkRef(SmlLink *link_)
00662 {
00663 smlTrace(TRACE_ENTRY, "%s(%p)", __func__, link_);
00664 smlAssert(link_);
00665
00666 g_atomic_int_inc(&(link_->refCount));
00667
00668 smlTrace(TRACE_EXIT, "%s", __func__);
00669 return link_;
00670 }
00671
00672 void smlLinkDeref(SmlLink *link_)
00673 {
00674 smlTrace(TRACE_ENTRY, "%s(%p)", __func__, link_);
00675 smlAssert(link_);
00676
00677 if (!g_atomic_int_dec_and_test(&(link_->refCount))) {
00678 smlTrace(TRACE_EXIT, "%s: refCount > 0", __func__);
00679 return;
00680 }
00681
00682
00683
00684 g_mutex_lock(link_->tsp->links_mutex);
00685 if (!g_hash_table_remove(link_->tsp->links, link_))
00686 g_warning("The link %p was never registered.", link_);
00687 g_mutex_unlock(link_->tsp->links_mutex);
00688
00689
00690
00691 smlSafeFree((gpointer *)&link_);
00692
00693 smlTrace(TRACE_EXIT, "%s: Freed", __func__);
00694 }
00695
00705
00711
00721 SmlTransport *smlTransportNew(SmlTransportType type, SmlError **error)
00722 {
00723 smlTrace(TRACE_ENTRY, "%s(%i, %p)", __func__, type, error);
00724 CHECK_ERROR_REF
00725
00726
00727 if (!g_thread_supported ()) g_thread_init (NULL);
00728 g_type_init();
00729
00730 SmlTransport *tsp = smlTryMalloc0(sizeof(SmlTransport), error);
00731 if (!tsp)
00732 goto error;
00733 tsp->type = type;
00734 tsp->cached_error = NULL;
00735 tsp->event_callback = NULL;
00736 tsp->context = NULL;
00737
00738 switch (type) {
00739 #ifdef ENABLE_HTTP
00740 case SML_TRANSPORT_HTTP_SERVER:
00741 if (!smlTransportHttpServerNew(tsp, error))
00742 goto error_free_tsp;
00743 break;
00744 case SML_TRANSPORT_HTTP_CLIENT:
00745 if (!smlTransportHttpClientNew(tsp, error))
00746 goto error_free_tsp;
00747 break;
00748 #else
00749 case SML_TRANSPORT_HTTP_SERVER:
00750 case SML_TRANSPORT_HTTP_CLIENT:
00751 smlErrorSet(error, SML_ERROR_GENERIC, "HTTP Transport not enabled in this build");
00752 goto error_free_tsp;
00753 #endif
00754 #ifdef ENABLE_OBEX
00755 case SML_TRANSPORT_OBEX_CLIENT:
00756 if (!smlTransportObexClientNew(tsp, error))
00757 goto error_free_tsp;
00758 break;
00759 case SML_TRANSPORT_OBEX_SERVER:
00760 if (!smlTransportObexServerNew(tsp, error))
00761 goto error_free_tsp;
00762 break;
00763 #else
00764 case SML_TRANSPORT_OBEX_SERVER:
00765 case SML_TRANSPORT_OBEX_CLIENT:
00766 smlErrorSet(error, SML_ERROR_GENERIC, "OBEX Transport not enabled in this build");
00767 goto error_free_tsp;
00768 #endif
00769 }
00770
00771 tsp->command_queue = smlQueueNew(error);
00772 if (!tsp->command_queue)
00773 goto error_free_tsp;
00774
00775
00776
00777
00778
00779
00780
00781 if (smlTransportIsServer(tsp))
00782 {
00783 tsp->links = g_hash_table_new(g_direct_hash, g_direct_equal);
00784 tsp->links_mutex = g_mutex_new();
00785 tsp->connections = 0;
00786 tsp->connections_mutex = g_mutex_new();
00787 } else {
00788 tsp->links = NULL;
00789 tsp->links_mutex = NULL;
00790 tsp->connections = 0;
00791 tsp->connections_mutex = NULL;
00792 }
00793 tsp->connected = FALSE;
00794
00795 smlTrace(TRACE_EXIT, "%s: %p", __func__, tsp);
00796 return tsp;
00797
00798 error_free_tsp:
00799 smlTransportFree(tsp);
00800 error:
00801 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
00802 return NULL;
00803 }
00804
00810 void smlTransportFree(SmlTransport *tsp)
00811 {
00812 smlTrace(TRACE_ENTRY, "%s(%p)", __func__, tsp);
00813 smlAssert(tsp);
00814
00815 if (tsp->command_queue)
00816 smlQueueFree(tsp->command_queue);
00817
00818 SmlError *error = NULL;
00819 if (tsp->transport_data &&
00820 !tsp->functions.finalize(tsp->transport_data, &error))
00821 {
00822 g_warning("The library libsyncml cannot free the transport. %s",
00823 smlErrorPrint(&error));
00824 smlErrorDeref(&error);
00825 }
00826
00827 if (tsp->context)
00828 g_main_context_unref(tsp->context);
00829 tsp->context = NULL;
00830
00831
00832
00833 if (tsp->connections)
00834 {
00835 g_warning("The transport layer of libsyncml is freed " \
00836 "but not all connections were close (%d).",
00837 tsp->connections);
00838 }
00839 if (tsp->connections_mutex)
00840 g_mutex_free(tsp->connections_mutex);
00841
00842
00843
00844 if (tsp->links && g_hash_table_size(tsp->links))
00845 g_warning("The transport layer of libsyncml is freed " \
00846 "but not all connections were cleaned up (%d).",
00847 g_hash_table_size(tsp->links));
00848 if (tsp->links)
00849 g_hash_table_unref(tsp->links);
00850 if (tsp->links_mutex)
00851 g_mutex_free(tsp->links_mutex);
00852
00853
00854
00855 if (tsp->cached_error) {
00856 g_warning("The transport layer is cleaned up and an error is ignored. %s",
00857 smlErrorPrint(&(tsp->cached_error)));
00858 smlErrorDeref(&(tsp->cached_error));
00859 }
00860
00861
00862
00863 smlSafeFree((gpointer *)&tsp);
00864
00865 smlTrace(TRACE_EXIT, "%s", __func__);
00866 }
00867
00883 SmlBool smlTransportSetConfigOption(
00884 SmlTransport *tsp,
00885 const char *name,
00886 const char *value,
00887 SmlError **error)
00888 {
00889 smlTrace(TRACE_ENTRY, "%s(%p, %s, %s, %p)", __func__, tsp, VA_STRING(name), strcmp(name, "PASSWORD") ? VA_STRING(value) : "***sensitive***", error);
00890
00891
00892
00893
00894 CHECK_ERROR_REF
00895 smlAssert(tsp);
00896 smlAssert(tsp->state == SML_TRANSPORT_UNINITIALIZED);
00897 smlAssert(tsp->functions.set_config_option);
00898
00899 if (!name)
00900 {
00901 smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION,
00902 "The name of the configuration option is missing.");
00903 goto error;
00904 }
00905
00906 if (!tsp->functions.set_config_option(tsp, name, value, error))
00907 goto error;
00908
00909 smlTrace(TRACE_EXIT, "%s", __func__);
00910 return TRUE;
00911 error:
00912 smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
00913 return FALSE;
00914 }
00915
00931 SmlBool smlTransportSetConnectionType(
00932 SmlTransport *tsp,
00933 SmlTransportConnectionType type,
00934 SmlError **error)
00935 {
00936 smlTrace(TRACE_ENTRY, "%s(%p, %i, %p)", __func__, tsp, type, error);
00937
00938
00939
00940
00941 CHECK_ERROR_REF
00942 smlAssert(tsp);
00943 smlAssert(type != SML_TRANSPORT_CONNECTION_TYPE_UNKNOWN);
00944 smlAssert(tsp->state == SML_TRANSPORT_UNINITIALIZED);
00945 smlAssert(tsp->functions.set_connection_type);
00946
00947 if (tsp->functions.set_connection_type(tsp, type, error))
00948 {
00949 smlTrace(TRACE_EXIT, "%s", __func__);
00950 return TRUE;
00951 } else {
00952 smlTrace(TRACE_EXIT_ERROR, "%s", __func__);
00953 return FALSE;
00954 }
00955 }
00956
00969 SmlBool smlTransportInitialize(SmlTransport *tsp, SmlError **error)
00970 {
00971 smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, tsp, error);
00972 CHECK_ERROR_REF
00973 smlAssert(tsp);
00974 smlAssert(tsp->state == SML_TRANSPORT_UNINITIALIZED);
00975
00976
00977
00978 tsp->context = g_main_context_new();
00979 if (!tsp->context) {
00980 smlErrorSet(error, SML_ERROR_GENERIC,
00981 "Cannot create new GMainContext for asynchronous transport.");
00982 goto error;
00983 }
00984
00985 tsp->thread = smlThreadNew(tsp->context, error);
00986 if (!tsp->thread)
00987 goto error_free_loop;
00988
00989
00990
00991
00992
00993
00994
00995 smlQueueSetHandler(tsp->command_queue, (SmlQueueHandler)smlTransportWorkerHandler, tsp);
00996 smlQueueAttach(tsp->command_queue, tsp->context);
00997
00998 if (tsp->functions.initialize && !tsp->functions.initialize(tsp, error))
00999 goto error_detach;
01000
01001
01002
01003
01004 smlThreadStart(tsp->thread);
01005
01006 tsp->state = SML_TRANSPORT_INITIALIZED;
01007
01008
01009 if (smlTransportIsServer(tsp))
01010 tsp->connected = TRUE;
01011
01012 smlTrace(TRACE_EXIT, "%s", __func__);
01013 return TRUE;
01014
01015 error_detach:
01016 smlQueueDetach(tsp->command_queue);
01017 error_free_loop:
01018 if (tsp->context) {
01019 g_main_context_unref(tsp->context);
01020 tsp->context = NULL;
01021 }
01022 error:
01023 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
01024 return FALSE;
01025 }
01026
01041 SmlBool smlTransportSetResponseURI(
01042 SmlTransport *tsp,
01043 const char *uri,
01044 SmlError **error)
01045 {
01046 smlTrace(TRACE_ENTRY, "%s(%p, %s, %p)", __func__, tsp, VA_STRING(uri), error);
01047
01048
01049
01050
01051 CHECK_ERROR_REF
01052 smlAssert(tsp);
01053 smlAssert(uri);
01054 smlAssert(tsp->state == SML_TRANSPORT_INITIALIZED ||
01055 tsp->state == SML_TRANSPORT_CONNECTED);
01056 smlAssert(tsp->functions.set_response_uri);
01057
01058 if (tsp->functions.set_response_uri(tsp, uri, error))
01059 {
01060 smlTrace(TRACE_EXIT, "%s", __func__);
01061 return TRUE;
01062 } else {
01063 smlTrace(TRACE_EXIT_ERROR, "%s", __func__);
01064 return FALSE;
01065 }
01066 }
01067
01068 static SmlBool smlTransportDetachQueueCallback(
01069 gpointer data,
01070 SmlError **error)
01071 {
01072 smlTrace(TRACE_ENTRY, "%s", __func__);
01073 CHECK_ERROR_REF
01074 smlAssert(data);
01075 SmlQueue *queue = data;
01076 smlQueueDetach(queue);
01077 smlTrace(TRACE_EXIT, "%s", __func__);
01078 return TRUE;
01079 }
01080
01081 static SmlBool smlTransportDispatchQueueCallback(
01082 gpointer data,
01083 SmlError **error)
01084 {
01085 smlTrace(TRACE_ENTRY, "%s", __func__);
01086 CHECK_ERROR_REF
01087 smlAssert(data);
01088 SmlQueue *queue = data;
01089 smlQueueDispatch(queue);
01090 smlTrace(TRACE_EXIT, "%s", __func__);
01091 return TRUE;
01092 }
01093
01104 SmlBool smlTransportFinalize(SmlTransport *tsp, SmlError **error)
01105 {
01106 smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, tsp, error);
01107 CHECK_ERROR_REF
01108 smlAssert(tsp);
01109 smlAssert(tsp->functions.finalize);
01110
01111 if (tsp->connected && !smlTransportIsServer(tsp))
01112 {
01113 smlErrorSet(error, SML_ERROR_GENERIC,
01114 "If a client transport is connected then it cannot be finalized.");
01115 goto error;
01116 }
01117
01118 if (tsp->state != SML_TRANSPORT_INITIALIZED &&
01119 tsp->state != SML_TRANSPORT_ERROR) {
01120 smlErrorSet(error, SML_ERROR_GENERIC, "Transport was not in the state \"Initialized\"");
01121 goto error;
01122 }
01123
01124
01125
01126
01127 if (tsp->type != SML_TRANSPORT_HTTP_CLIENT &&
01128 tsp->type != SML_TRANSPORT_HTTP_SERVER && tsp->thread)
01129 _smlTransportStop(tsp);
01130
01131
01132 if (tsp->thread) {
01133
01134 if (!smlThreadCallFunction(
01135 tsp->thread,
01136 smlTransportDetachQueueCallback,
01137 tsp->command_queue,
01138 error))
01139 goto error;
01140 } else {
01141
01142 smlQueueDetach(tsp->command_queue);
01143 }
01144
01145
01146 unsigned int i = 0;
01147 unsigned int queueLength = smlQueueLength(tsp->command_queue);
01148 for (; i < queueLength; i++) {
01149 if (tsp->thread) {
01150
01151 if (!smlThreadCallFunction(
01152 tsp->thread,
01153 smlTransportDispatchQueueCallback,
01154 tsp->command_queue,
01155 error))
01156 goto error;
01157 } else {
01158
01159 smlQueueDispatch(tsp->command_queue);
01160 }
01161 }
01162
01163 if (!tsp->functions.finalize(tsp->transport_data, error))
01164 goto error;
01165
01166
01167 if (tsp->thread)
01168 _smlTransportStop(tsp);
01169
01170 tsp->transport_data = NULL;
01171
01172 tsp->state = SML_TRANSPORT_UNINITIALIZED;
01173
01174
01175 if (smlTransportIsServer(tsp))
01176 tsp->connected = FALSE;
01177
01178 smlTrace(TRACE_EXIT, "%s", __func__);
01179 return TRUE;
01180
01181 error:
01182 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
01183 return FALSE;
01184 }
01185
01186 char * smlTransportGetResponseURI(SmlLink *link_, SmlSession *session, SmlError **error)
01187 {
01188 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, link_, session, error);
01189
01190
01191
01192
01193 CHECK_ERROR_REF
01194 smlAssert(link_);
01195 smlAssert(link_->tsp);
01196 smlAssert(session);
01197
01198 if (link_->tsp->functions.get_response_uri)
01199 {
01200 char *result = link_->tsp->functions.get_response_uri(link_, session, error);
01201 smlTrace(TRACE_EXIT, "%s - %s", __func__, VA_STRING(result));
01202 return result;
01203 } else {
01204 smlTrace(TRACE_EXIT, "%s - unsupported feature", __func__);
01205 return NULL;
01206 }
01207 }
01208