libsyncml 0.5.4

- Main Page
- Modules
- Data Structures
- Files

- File List

sml_manager.c
1 /*
2 * libsyncml - A syncml protocol implementation
3 * Copyright (C) 2005 Armin Bauer <armin.bauer@opensync.org>
4 * Copyright (C) 2007-2009 Michael Bell <michael.bell@opensync.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22 #include "syncml.h"
23
24 #include "syncml_internals.h"
25 #include "sml_error_internals.h"
26 #include "sml_manager_internals.h"
27 #include "sml_transport_internals.h"
28 #include "sml_command_internals.h"
29 #include "sml_elements_internals.h"
30 #include "sml_session_internals.h"
31
32 typedef struct managerSession {
33 SmlLink *link;
34 SmlSession *session;
35 unsigned int finalLock;
36 SmlTransport *transport;
37 GList *objects;
38 } managerSession;
39
40 managerSession *_smlManagerGetManagerSession(SmlManager *manager, SmlSession *session);
41
42 SmlObject *smlManagerObjectFindInternal(
43 SmlManager *manager,
44 SmlSession *session,
45 SmlCommandType type,
46 SmlLocation *target,
47 SmlLocation *source,
48 const char* contentType);
49
50 static managerSession *_manager_session_find(SmlManager *manager, SmlSession *session)
51 {
52 smlAssert(session);
53 smlAssert(manager);
54
55 GList *s = NULL;
56 for (s = manager->sessions; s; s = s->next) {
57 managerSession *sess = s->data;
58 if (sess->session == session)
59 return sess;
60 }
61 return NULL;
62 }
63
64 static void _manager_session_free(managerSession *sess)
65 {
66 smlAssert(sess);
67
68 smlSessionUnref(sess->session);
69
70 if (sess->link)
71 smlLinkDeref(sess->link);
72
73 while (sess->objects) {
74 SmlObject *object = sess->objects->data;
75 smlManagerObjectFree(object);
76 sess->objects = g_list_delete_link(sess->objects, sess->objects);
77 }
78
79 smlSafeFree((gpointer *)&sess);
80 }
81
82 static gboolean _manager_prepare_internal(GSource *source, gint *timeout_)
83 {
84 smlTrace(TRACE_INTERNAL, "%s(%p, %p)", __func__, source, timeout_);
85 *timeout_ = 1;
86 return FALSE;
87 }
88
89 static gboolean _manager_check_internal(GSource *source)
90 {
91 SmlManager *manager = *((SmlManager **)(source + 1));
92 GList *s = NULL;
93 for (s = manager->sessions; s; s = s->next) {
94 managerSession *session = s->data;
95 if (smlSessionCheck(session->session))
96 return TRUE;
97 }
98 return FALSE;
99 }
100
101 static gboolean _manager_dispatch_internal(GSource *source, GSourceFunc callback, gpointer user_data)
102 {
103 smlTrace(TRACE_INTERNAL, "%s(%p, %p, %p)", __func__, source, callback, user_data);
104 int max = 100;
105
106 SmlManager *manager = user_data;
107 GList *s = NULL;
108 for (s = manager->sessions; s; s = s->next) {
109 managerSession *session = s->data;
110 while (smlSessionCheck(session->session) && max) {
111 /* A dispatch function should never block on a
112 * locked resource. This is like a busy wait
113 * because the thread is not available for this
114 * time which can block the whole system if two
115 * dispatchers use the same thread.
116 */
117 if (smlSessionTryLock(session->session))
118 {
119 smlSessionDispatch(session->session);
120 smlSessionUnlock(session->session);
121 }
122 max--;
123 }
124 }
125
126 return TRUE;
127 }
128
129 static void _smlManagerSendEvent(SmlManager *manager, SmlManagerEventType type, SmlSession *session, SmlCommand *command, SmlCommand *parent, SmlError *error)
130 {
131 smlTrace(TRACE_ENTRY, "%s(%p, %i, %p, %p, %p, %p)", __func__, manager, type, session, command, parent, error);
132
133 SmlError *lerr = NULL;
134 SmlManagerEvent *event = smlTryMalloc0(sizeof(SmlManagerEvent), &lerr);
135 if (event) {
136 event->type = type;
137
138 if (session) {
139 event->session = session;
140 smlSessionRef(session);
141 } else {
142 event->session = NULL;
143 }
144
145 if (command) {
146 event->command = command;
147 smlCommandRef(command);
148 } else {
149 event->command = NULL;
150 }
151
152 if (parent) {
153 event->parent = parent;
154 smlCommandRef(parent);
155 } else {
156 event->parent = NULL;
157 }
158
159 if (error) {
160 event->error = error;
161 smlErrorRef(&error);
162 }
163
164 smlQueueSend(manager->userEventQueue, event);
165 } else {
166 /* error handling is not possible here :( */
167 g_error("%s", smlErrorPrint(&lerr));
168 smlErrorDeref(&lerr);
169 }
170
171 smlTrace(TRACE_EXIT, "%s", __func__);
172 }
173
174 void _smlManagerEventFree(SmlManagerEvent *event)
175 {
176 smlTrace(TRACE_ENTRY, "%s(%p)", __func__, event);
177 smlAssert(event);
178
179 if (event->session)
180 smlSessionUnref(event->session);
181
182 if (event->command)
183 smlCommandUnref(event->command);
184
185 if (event->parent)
186 smlCommandUnref(event->parent);
187
188 if (event->error)
189 smlErrorDeref(&(event->error));
190
191 smlSafeFree((gpointer *)&event);
192
193 smlTrace(TRACE_EXIT, "%s", __func__);
194 }
195
196 /* If we return FALSE in this function, the current request will get
197 * aborted */
198 static SmlBool _smlManagerDataHandler(SmlTransport *tsp, SmlLink *link_, SmlTransportEventType type, SmlTransportData *data, SmlError *error, void *userdata)
199 {
200 smlTrace(TRACE_ENTRY, "%s(%p, %p, %i, %p, %p, %p)", __func__, tsp, link_, type, data, error, userdata);
201 smlAssert(userdata);
202 SmlManager *manager = userdata;
203 SmlParser *parser = NULL;
204 SmlHeader *header = NULL;
205 SmlCred *cred = NULL;
206 SmlSession *session = NULL;
207 SmlError *locerror = NULL;
208
209 switch (type) {
210 case SML_TRANSPORT_EVENT_CONNECT_DONE:
211 /* Pass the connect through */
212 _smlManagerSendEvent(manager, SML_MANAGER_CONNECT_DONE, NULL, NULL, NULL, NULL);
213 break;
214 case SML_TRANSPORT_EVENT_DISCONNECT_DONE:
215 /* Pass the disconnect through */
216 _smlManagerSendEvent(manager, SML_MANAGER_DISCONNECT_DONE, NULL, NULL, NULL, NULL);
217 break;
218 case SML_TRANSPORT_EVENT_DATA:
219
220 parser = smlParserNew(data->type, 0, &locerror);
221 if (!parser)
222 goto session_error;
223 /* add manager to parser for OMA DS 1.2 SAN handling */
224 smlParserSetManager(parser, manager);
225
226 /* start to parse the data */
227 if (!smlParserStart(parser, data->data, data->size, &locerror))
228 goto error_free_parser;
229
230 /* Get the header of the message*/
231 header = NULL;
232 cred = NULL;
233 if (!smlParserGetHeader(parser, &header, &cred, &locerror))
234 goto error_free_parser;
235
236 /* Find the session if available otherwise register it as new */
237 session = smlManagerSessionFind(manager, header->sessionID);
238 if (!session) {
239 /* If we use the target and source from the header of the received message
240 * then we MUST interchange source and target */
241 SmlSessionType sessionType;
242 switch(smlTransportGetType(tsp))
243 {
244 case SML_TRANSPORT_OBEX_CLIENT:
245 /* this can happen if the remote
246 * client creates a new session ID.
247 */
248 sessionType = SML_SESSION_TYPE_SERVER;
249 break;
250 case SML_TRANSPORT_OBEX_SERVER:
251 sessionType = SML_SESSION_TYPE_CLIENT;
252 break;
253 case SML_TRANSPORT_HTTP_SERVER:
254 sessionType = SML_SESSION_TYPE_SERVER;
255 break;
256 default:
257 smlErrorSet(&locerror,
258 SML_ERROR_NOT_IMPLEMENTED,
259 "New session was unexpectedly received for transport %d.",
260 smlTransportGetType(tsp));
261 goto error_free_header;
262 break;
263 }
264 if (!(session = smlSessionNew(
265 sessionType, data->type,
266 header->version, header->protocol,
267 header->source, header->target,
268 header->sessionID, 1, &locerror)))
269 goto error_free_header;
270 if (link_)
271 {
272 char *responseURI = smlTransportGetResponseURI(link_, session, &locerror);
273 if (!responseURI && locerror)
274 goto error_free_header;
275 if (responseURI)
276 {
277 if (!smlSessionSetResponseURI(session, responseURI, &locerror))
278 {
279 smlSafeCFree(&responseURI);
280 goto error_free_header;
281 }
282 smlSafeCFree(&responseURI);
283 }
284 }
285 if (!smlManagerSessionAdd(manager, session, link_, &locerror))
286 goto error_free_header;
287 smlSessionUnref(session);
288 } else {
289 /* SECURITY: let's check ResponseURI if supported
290 * SECURITY: this is important to avoid replay attacks
291 */
292 if (link_) {
293 char *responseUri = smlTransportGetResponseURI(link_, session, &locerror);
294 if (!responseUri && locerror) {
295 goto error_free_header;
296 }
297 if (responseUri)
298 smlSafeCFree(&responseUri);
299 }
300 }
301
302 /* This function is called by the tranport layer which
303 * runs in an own thread. Therefore we must lock the
304 * according session because otherwise we can get into
305 * trouble with parallel access to a SmlSession which is
306 * not safe against parallel use by multiple threads.
307 */
308 smlSessionLock(session);
309
310 /* Find the manager session so that we can update the link. We
311 * have to do this since each time a transport with links receives
312 * a new data packets, it might create a new link (connectionless
313 * protocols). So we have to update the link to be able to answer
314 * the data */
315 GList *s;
316 for (s = manager->sessions; s; s = s->next) {
317 managerSession *sess = s->data;
318 if (sess->session == session) {
319 if (sess->link)
320 smlLinkDeref(sess->link);
321 sess->link = link_;
322 if (link_)
323 smlLinkRef(sess->link);
324 break;
325 }
326 }
327
328 /* Now check if the header is valid etc */
329 if (!smlSessionReceiveHeader(session, header, &locerror))
330 goto error_free_header;
331
332 /* Then check if we are allowed to authenticate */
333 if (!smlManagerDispatchHeader(manager, session, header, cred, &locerror))
334 goto error_free_header;
335
336 smlHeaderFree(header);
337 if (cred)
338 smlCredUnref(cred);
339
340 /* Now let the session handle the commands etc */
341 if (!smlSessionReceiveBody(session, parser, &locerror))
342 goto error_free_parser;
343
344 /* Free the parser */
345 smlParserFree(parser);
346
347 /* make the session accessible for others */
348 smlSessionUnlock(session);
349
350 break;
351 case SML_TRANSPORT_EVENT_ERROR:
352 /* Pass the error through */
353 smlErrorDuplicate(&locerror, &error);
354 goto transport_error;
355 break;
356 }
357
358 smlTrace(TRACE_EXIT, "%s", __func__);
359 return TRUE;
360
361 error_free_header:
362 if (header)
363 smlHeaderFree(header);
364 if (cred)
365 smlCredUnref(cred);
366 error_free_parser:
367 smlParserFree(parser);
368 if (session)
369 smlSessionUnlock(session);
370 session_error:
371 if (session == NULL && link_ && type == SML_TRANSPORT_EVENT_DATA) {
372 /* If there is no session and a link then this means
373 * that there is a failing server connection.
374 * It is a good idea to close the connection because
375 * the session has no chance to signal a clean
376 * disconnect to the link.
377 */
378 SmlError *herror = NULL;
379 if (!smlTransportDisconnect(manager->transport, link_, &herror)) {
380 smlTrace(TRACE_ERROR, "%s: Disconnect on error failed. %s",
381 smlErrorPrint(&herror));
382 smlErrorDeref(&herror);
383 }
384 }
385 _smlManagerSendEvent(manager, SML_MANAGER_SESSION_ERROR, session, NULL, NULL, locerror);
386 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(&locerror));
387 smlErrorDeref(&locerror);
388 return FALSE;
389
390 transport_error:
391 _smlManagerSendEvent(manager, SML_MANAGER_TRANSPORT_ERROR, NULL, NULL, NULL, locerror);
392 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(&locerror));
393 smlErrorDeref(&locerror);
394 return FALSE;
395 }
396
397 SmlManager *smlManagerNew(SmlTransport *tsp, SmlError **error)
398 {
399 smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, tsp, error);
400 smlAssert(tsp);
401 CHECK_ERROR_REF
402
403 SmlManager *manager = smlTryMalloc0(sizeof(SmlManager), error);
404 if (!manager)
405 goto error;
406
407 smlTransportSetEventCallback(tsp, _smlManagerDataHandler, manager);
408 manager->transport = tsp;
409
410 manager->running_mutex = g_mutex_new();
411 manager->running = g_cond_new();
412
413 manager->userEventQueue = smlQueueNew(error);
414 if (!manager->userEventQueue)
415 goto error_free_manager;
416
417 smlTrace(TRACE_EXIT, "%s", __func__);
418 return manager;
419
420 error_free_manager:
421 smlSafeFree((gpointer *)&manager);
422 error:
423 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
424 return NULL;
425 }
426
427 void smlManagerFree(SmlManager *manager)
428 {
429 smlTrace(TRACE_ENTRY, "%s(%p)", __func__, manager);
430 smlAssert(manager);
431
432 /* stop automatic session dispatch environment if necessary */
433 if (manager->context)
434 smlManagerStop(manager);
435
436 /* Deactivate the event callback of the transport layer
437 * because the manager is no longer available
438 */
439
440 if (manager->transport)
441 smlTransportSetEventCallback(manager->transport, NULL, NULL);
442
443 while (manager->sessions) {
444 managerSession *sess = manager->sessions->data;
445
446 _manager_session_free(sess);
447
448 manager->sessions = g_list_delete_link(manager->sessions, manager->sessions);
449 }
450
451 while (manager->objects) {
452 SmlObject *object = manager->objects->data;
453
454 smlManagerObjectFree(object);
455 manager->objects = g_list_remove(manager->objects, object);
456 }
457
458 if (manager->userEventQueue) {
459 SmlManagerEvent *event = NULL;
460 while ((event = smlQueueTryPop(manager->userEventQueue)))
461 _smlManagerEventFree(event);
462
463 smlQueueFree(manager->userEventQueue);
464 manager->userEventQueue = NULL;
465 }
466
467 g_cond_free(manager->running);
468 g_mutex_free(manager->running_mutex);
469
470 smlSafeFree((gpointer *)&manager);
471
472 smlTrace(TRACE_EXIT, "%s", __func__);
473 }
474
475 void smlManagerSetEventCallback(SmlManager *manager, SmlManagerEventCb callback, void *userdata)
476 {
477 smlAssert(manager);
478 smlAssert(callback);
479
480 manager->eventCallback = callback;
481 manager->eventCallbackUserdata = userdata;
482 }
483
484 SmlBool smlManagerStart(SmlManager *manager, SmlError **error)
485 {
486 smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, manager, error);
487 smlAssert(manager);
488 CHECK_ERROR_REF
489
490 manager->context = g_main_context_new();
491 if (!manager->context) {
492 smlErrorSet(error, SML_ERROR_GENERIC,
493 "Cannot create new main context.");
494 goto error;
495 }
496
497 manager->functions = smlTryMalloc0(sizeof(GSourceFuncs), error);
498 if (!manager->functions)
499 goto error;
500
501 manager->functions->prepare = _manager_prepare_internal;
502 manager->functions->check = _manager_check_internal;
503 manager->functions->dispatch = _manager_dispatch_internal;
504 manager->functions->finalize = NULL;
505
506 manager->thread = smlThreadNew(manager->context, error);
507 if (!manager->thread)
508 goto error;
509 smlThreadStart(manager->thread);
510
511 manager->source = g_source_new(manager->functions, sizeof(GSource) + sizeof(SmlManager *));
512 SmlManager **managerptr = (SmlManager **)(manager->source + 1);
513 *managerptr = manager;
514 g_source_set_callback(manager->source, NULL, manager, NULL);
515 g_source_attach(manager->source, manager->context);
516
517 smlTrace(TRACE_EXIT, "%s", __func__);
518 return TRUE;
519
520 error:
521 if (manager->context) {
522 g_main_context_unref(manager->context);
523 manager->context = NULL;
524 }
525 if (manager->functions)
526 smlSafeFree((gpointer *)&(manager->functions));
527 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
528 return FALSE;
529 }
530
565 void smlManagerStop(SmlManager *manager)
566 {
567 smlTrace(TRACE_ENTRY, "%s(%p)", __func__, manager);
568 smlAssert(manager);
569 smlAssert(manager->thread);
570
571 /* cleanup automatic session dispatch environment
572 * the order is highly important
573 */
574
575 /* stop thread */
576 smlThreadStop(manager->thread);
577 smlThreadFree(manager->thread);
578 manager->thread = NULL;
579 /* detach source */
580 g_source_unref(manager->source);
581 manager->source = NULL;
582 /* free context */
583 g_main_context_unref(manager->context);
584 manager->context = NULL;
585 /* free functions */
586 smlSafeFree((gpointer *)&(manager->functions));
587 manager->functions = NULL;
588
589 /* close all open connections */
590
591 GList *sessionItem = manager->sessions;
592 while (sessionItem) {
593 managerSession *sess = sessionItem->data;
594
595 /* disconnect if necessary
596 *
597 * only do this if:
598 * 1. the transport layer is still connected
599 * and
600 * 2.1. this is a client connection or the server itself
601 * or
602 * 2.2. this is an active server connection
603 */
604 SmlError *error = NULL;
605 if (manager->transport->connected &&
606 (!sess->link || sess->link->link_data) &&
607 !smlTransportDisconnect(manager->transport, sess->link, &error)) {
608 g_warning("Errors from the transport layer " \
609 "cannot be handled while freeing the manager. %s",
610 smlErrorPrint(&error));
611 smlErrorDeref(&error);
612 }
613
614 sessionItem = g_list_next(sessionItem);
615 }
616
617 smlTrace(TRACE_EXIT, "%s", __func__);
618 }
619
620
621 void smlManagerRun(SmlManager *manager)
622 {
623 smlTrace(TRACE_ENTRY, "%s(%p)", __func__, manager);
624 smlAssert(manager);
625
626 g_mutex_lock(manager->running_mutex);
627 g_cond_wait(manager->running, manager->running_mutex);
628 g_mutex_unlock(manager->running_mutex);
629
630 smlTrace(TRACE_EXIT, "%s", __func__);
631 }
632
633 void smlManagerQuit(SmlManager *manager)
634 {
635 smlTrace(TRACE_ENTRY, "%s(%p)", __func__, manager);
636 smlAssert(manager);
637
638 g_mutex_lock(manager->running_mutex);
639 g_cond_signal(manager->running);
640 g_mutex_unlock(manager->running_mutex);
641
642 smlTrace(TRACE_EXIT, "%s", __func__);
643 }
644
645 SmlSession *smlManagerSessionFind(SmlManager *manager, const char *sessionID)
646 {
647 smlTrace(TRACE_ENTRY, "%s(%p, %s)", __func__, manager, VA_STRING(sessionID));
648 GList *s = NULL;
649 for (s = manager->sessions; s; s = s->next) {
650 managerSession *session = s->data;
651 if (!strcmp(smlSessionGetSessionID(session->session), sessionID)) {
652 smlTrace(TRACE_EXIT, "%s: FOUND %p", __func__, session);
653 return session->session;
654 }
655 }
656
657 smlTrace(TRACE_EXIT, "%s: NOT FOUND", __func__);
658 return NULL;
659 }
660
661 void smlManagerDispatch(SmlManager *manager)
662 {
663 smlTrace(TRACE_ENTRY, "%s(%p)", __func__, manager);
664 smlAssert(manager);
665 SmlManagerEvent *event = NULL;
666 while ((event = smlQueueTryPop(manager->userEventQueue))) {
667 smlTrace(TRACE_INTERNAL, "%s: type ::= %d", __func__, event->type);
668 /* Check that this is not a locked final event. */
669 if (event->session != NULL &&
670 event->type == SML_MANAGER_SESSION_FINAL)
671 {
672 managerSession *sess = _smlManagerGetManagerSession(manager, event->session);
673 if (sess && sess->finalLock)
674 {
675 smlTrace(TRACE_INTERNAL, "%s - locked final (%i)",
676 __func__, sess->finalLock);
677 smlQueuePushHead(manager->userEventQueue, event);
678 /* It is necessary to stop the dispatching here.
679 * The events MUST BE dispatched in the same
680 * order like they were received. If the while
681 * loop does not break here then the loop tries
682 * to dispatch the locked event again and again.
683 */
684 break;
685 }
686 }
687 /* Execute the event callback. */
688 smlAssert(manager->eventCallback);
689 manager->eventCallback(manager, event->type, event->session, event->error, manager->eventCallbackUserdata);
690 _smlManagerEventFree(event);
691 }
692 smlTrace(TRACE_EXIT, "%s", __func__);
693 }
694
695 SmlBool smlManagerCheck(SmlManager *manager)
696 {
697 return smlQueueCheck(manager->userEventQueue);
698 }
699
700 static void _event_callback(SmlSession *session, SmlSessionEventType type, SmlCommand *command, SmlCommand *parent, SmlStatus *reply, SmlError *error, void *userdata)
701 {
702 smlTrace(TRACE_ENTRY, "%s(%p, %i, %p, %p, %p, %p, %p)", __func__, session, type, command, parent, reply, error, userdata);
703 SmlManager *manager = userdata;
704 SmlError *locerror = NULL;
705
706 switch (type) {
707 case SML_SESSION_EVENT_ESTABLISHED:
708 /* Pass the established through */
709 _smlManagerSendEvent(manager, SML_MANAGER_SESSION_ESTABLISHED, session, NULL, NULL, NULL);
710 break;
711 case SML_SESSION_EVENT_HEADER_REPLY:
712 break;
713 case SML_SESSION_EVENT_RESPONSE_URI:
714 if (!smlTransportSetResponseURI(
715 manager->transport,
716 smlLocationGetURI(smlSessionGetTarget(session)),
717 &locerror))
718 {
719 _smlManagerSendEvent(manager, SML_MANAGER_SESSION_ERROR, session, NULL, NULL, locerror);
720 goto error;
721 }
722 break;
723 case SML_SESSION_EVENT_COMMAND_START:
724 case SML_SESSION_EVENT_COMMAND_END:
725 if (!smlManagerDispatchCommand(manager, session, command, &locerror)) {
726 _smlManagerSendEvent(manager, SML_MANAGER_SESSION_WARNING, session, NULL, NULL, locerror);
727 goto error;
728 }
729 break;
730 case SML_SESSION_EVENT_CHILD_COMMAND:
731 if (!smlManagerDispatchChildCommand(manager, session, parent, command, &locerror)) {
732 _smlManagerSendEvent(manager, SML_MANAGER_SESSION_WARNING, session, NULL, NULL, locerror);
733 goto error;
734 }
735 break;
736 case SML_SESSION_EVENT_FINAL:
737 /* Pass the final through */
738 _smlManagerSendEvent(manager, SML_MANAGER_SESSION_FINAL, session, NULL, NULL, NULL);
739 break;
740 case SML_SESSION_EVENT_END:
741 /* Pass the end through */
742 _smlManagerSendEvent(manager, SML_MANAGER_SESSION_END, session, NULL, NULL, NULL);
743 break;
744 case SML_SESSION_EVENT_FLUSH:
745 /* Pass the flush through */
746 _smlManagerSendEvent(manager, SML_MANAGER_SESSION_FLUSH, session, NULL, NULL, NULL);
747 break;
748 case SML_SESSION_EVENT_ERROR:
749 /* Pass the error through */
750 smlErrorDuplicate(&locerror, &error);
751 _smlManagerSendEvent(manager, SML_MANAGER_SESSION_ERROR, session, NULL, NULL, locerror);
752 goto error;
753 break;
754 }
755
756 smlTrace(TRACE_EXIT, "%s", __func__);
757 return;
758
759 error:
760 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(&locerror));
761 smlErrorDeref(&locerror);
762 }
763
764 static void _data_send_callback(SmlSession *session, SmlTransportData *data, void *userdata)
765 {
766 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, session, data, userdata);
767 managerSession *sess = userdata;
768
769 /* The transport layer is able to signal the error via an event. */
770 SmlError *error = NULL;
771 if (!smlTransportSend(sess->transport, sess->link, data, &error))
772 {
773 smlTrace(TRACE_ERROR, "%s - %s", __func__, smlErrorPrint(&error));
774 smlErrorDeref(&error);
775 }
776
777 smlTrace(TRACE_EXIT, "%s", __func__);
778 }
779
780 SmlBool smlManagerSessionAdd(SmlManager *manager, SmlSession *session, SmlLink *link_, SmlError **error)
781 {
782 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, manager, session, link_, error);
783 CHECK_ERROR_REF
784
785 smlSessionRef(session);
786
787 if (smlSessionGetSessionID(session)) {
788 //Check if sessionID exists
789 smlTrace(TRACE_INTERNAL, "Checking if session ID %s already exists", smlSessionGetSessionID(session));
790
791 if (smlManagerSessionFind(manager, smlSessionGetSessionID(session))) {
792 smlErrorSet(error, SML_ERROR_GENERIC, "Session ID already exists");
793 goto error;
794 }
795 } else {
796 char *lastid = smlManagerGetNewSessionID(manager);
797 smlSessionSetSessionID(session, lastid);
798 smlSafeCFree(&lastid);
799 }
800
801 managerSession *sess = smlTryMalloc0(sizeof(managerSession), error);
802 if (!sess)
803 goto error;
804
805 sess->session = session;
806 sess->finalLock = 0;
807
808 if (link_) {
809 sess->link = link_;
810 smlLinkRef(link_);
811 }
812
813 sess->transport = manager->transport;
814
815 manager->sessions = g_list_append(manager->sessions, sess);
816
817 /* prepare large object support */
818 if (0 < manager->localMaxMsgSize &&
819 (
820 manager->localMaxMsgSize < smlSessionGetLocalMaxMsgSize(session) ||
821 smlSessionGetLocalMaxMsgSize(session) <= 0
822 ))
823 smlSessionSetLocalMaxMsgSize(session, manager->localMaxMsgSize);
824 if (0 < manager->localMaxObjSize &&
825 (
826 manager->localMaxObjSize < smlSessionGetLocalMaxObjSize(session) ||
827 smlSessionGetLocalMaxObjSize(session) <= 0
828 ))
829 smlSessionSetLocalMaxObjSize(session, manager->localMaxObjSize);
830 if (smlSessionGetLocalMaxObjSize(session) &&
831 smlSessionGetLocalMaxMsgSize(session))
832 smlSessionUseLargeObjects(session, TRUE);
833 else
834 smlSessionUseLargeObjects(session, FALSE);
835
836 smlSessionSetEventCallback(session, _event_callback, manager);
837 smlSessionSetDataCallback(session, _data_send_callback, sess);
838
839 _smlManagerSendEvent(manager, SML_MANAGER_SESSION_NEW, session, NULL, NULL, NULL);
840
841 smlTrace(TRACE_EXIT, "%s", __func__);
842 return TRUE;
843
844 error:
845 smlSessionUnref(session);
846 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
847 return FALSE;
848 }
849
850 managerSession *_smlManagerGetManagerSession(SmlManager *manager, SmlSession *session)
851 {
852 smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, manager, session);
853
854 GList *s;
855 for (s = manager->sessions; s; s = s->next) {
856 managerSession *sess = s->data;
857 if (sess->session == session) {
858 smlTrace(TRACE_EXIT, "%s - %p", __func__, sess);
859 return sess;
860 }
861 }
862
863 smlTrace(TRACE_EXIT, "%s: Not Found", __func__);
864 return NULL;
865 }
866
867 void smlManagerSessionRemove(SmlManager *manager, SmlSession *session)
868 {
869 smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, manager, session);
870
871 managerSession *sess = _smlManagerGetManagerSession(manager, session);
872 if (sess) {
873 manager->sessions = g_list_remove(manager->sessions, sess);
874 _manager_session_free(sess);
875 smlTrace(TRACE_EXIT, "%s", __func__);
876 } else {
877 smlTrace(TRACE_EXIT, "%s: Not Found", __func__);
878 }
879 }
880
881 void smlManagerSessionFinalLockRef(SmlManager *manager, SmlSession *session)
882 {
883 smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, manager, session);
884
885 managerSession *sess = _smlManagerGetManagerSession(manager, session);
886 if (sess) {
887 sess->finalLock++;
888 smlTrace(TRACE_EXIT, "%s", __func__);
889 } else {
890 smlTrace(TRACE_EXIT, "%s: Not Found", __func__);
891 }
892 }
893
894 void smlManagerSessionFinalLockUnref(SmlManager *manager, SmlSession *session)
895 {
896 smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, manager, session);
897
898 managerSession *sess = _smlManagerGetManagerSession(manager, session);
899 if (sess) {
900 sess->finalLock--;
901 smlTrace(TRACE_EXIT, "%s - %i", __func__, sess->finalLock);
902 } else {
903 smlTrace(TRACE_EXIT, "%s: Not Found", __func__);
904 }
905 }
906
926 SmlBool smlManagerObjectRegister(SmlManager *manager, SmlCommandType type, SmlSession *session, SmlLocation *location, SmlLocation *source, const char *contentType, SmlCommandCb callback, SmlCommandCb childCallback, void *userdata, SmlError **error)
927 {
928 smlTrace(TRACE_ENTRY, "%s(%p, %i, %p, %p, %p, %s, %p, %p, %p, %p)", __func__, manager, type, session, location, source, VA_STRING(contentType), callback, childCallback, userdata, error);
929 smlAssert(manager);
930 smlAssert(callback);
931 CHECK_ERROR_REF
932
933 /* first we have to check if this an update for an already registered object */
934 /* this is important for actions which require more than one DsSession */
935
936 SmlObject *object = smlManagerObjectFindInternal(
937 manager, session, type,
938 location, source, contentType);
939 if (object != NULL && session != NULL)
940 {
941 /* check that it is not a global manager object */
942 SmlObject *hObject = smlManagerObjectFindInternal(
943 manager, NULL, type,
944 location, source, contentType);
945 if (hObject != NULL && hObject == object)
946 {
947 /* the found object is a global manager object */
948 /* so we have to register a new object */
949 object = NULL;
950 }
951 }
952 if (object)
953 {
954 /* there is an object and so we reconfigure it */
955 smlTrace(TRACE_INTERNAL, "%s: prepare a reusable object", __func__);
956
957 if (object->location)
958 smlLocationUnref(object->location);
959 if (object->source)
960 smlLocationUnref(object->source);
961 if (object->contentType)
962 smlSafeCFree(&(object->contentType));
963 }
964 else
965 {
966 /* let's create and register a new object */
967 smlTrace(TRACE_INTERNAL, "%s: create and register a new object", __func__);
968
969 object = smlTryMalloc0(sizeof(SmlObject), error);
970 if (!object)
971 goto error;
972
973 if (session) {
974 managerSession *sess = _manager_session_find(manager, session);
975 if (!sess) {
976 smlErrorSet(error, SML_ERROR_GENERIC, "Session not found");
977 goto error_free_object;
978 }
979
980 sess->objects = g_list_append(sess->objects, object);
981 } else {
982 manager->objects = g_list_append(manager->objects, object);
983 }
984 }
985
986 smlTrace(TRACE_INTERNAL, "%s: configure registered object", __func__);
987
988 object->type = type;
989
990 if (location) {
991 object->location = location;
992 smlLocationRef(location);
993 }
994
995 if (source) {
996 object->source = source;
997 smlLocationRef(source);
998 }
999
1000 if (contentType) {
1001 object->contentType = g_strdup(contentType);
1002 }
1003
1004 object->commandCallback = callback;
1005 object->childCallback = childCallback;
1006 object->commandCallbackUserdata = userdata;
1007
1008 smlTrace(TRACE_EXIT, "%s", __func__);
1009 return TRUE;
1010
1011 error_free_object:
1012 smlManagerObjectFree(object);
1013 error:
1014 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
1015 return FALSE;
1016 }
1017
1018 void smlManagerObjectDeregister(SmlManager *manager, SmlCommandType type, SmlLocation *location, SmlLocation *source)
1019 {
1020 smlTrace(TRACE_ENTRY, "%s(%p, %i, %p, %p)", __func__, manager, type, location, source);
1021 smlAssert(manager);
1022
1023 GList *o2 = g_list_copy(manager->objects);
1024 GList *o = NULL;
1025 for (o = o2; o; o = o->next) {
1026 SmlObject *object = o->data;
1027
1028
1029 if (object->type != type)
1030 continue;
1031
1032 if (!smlLocationCompare(NULL, object->location, NULL, location))
1033 continue;
1034
1035 if (!smlLocationCompare(NULL, object->source, NULL, source))
1036 continue;
1037
1038 smlManagerObjectFree(object);
1039 manager->objects = g_list_remove(manager->objects, object);
1040 }
1041 g_list_free(o2);
1042
1043 smlTrace(TRACE_EXIT, "%s", __func__);
1044 }
1045
1046 void smlManagerObjectFree(SmlObject *object)
1047 {
1048 smlTrace(TRACE_ENTRY, "%s(%p)", __func__, object);
1049 smlAssert(object);
1050
1051 if (object->location)
1052 smlLocationUnref(object->location);
1053
1054 if (object->source)
1055 smlLocationUnref(object->source);
1056
1057 if (object->contentType)
1058 smlSafeCFree(&(object->contentType));
1059
1060 smlSafeFree((gpointer *)&object);
1061
1062 smlTrace(TRACE_EXIT, "%s", __func__);
1063 }
1064
1065 SmlObject *smlManagerObjectFind(SmlManager *manager, SmlSession *session, SmlCommand *cmd)
1066 {
1067 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, manager, session, cmd);
1068 smlAssert(manager);
1069 smlAssert(cmd);
1070
1071 SmlObject *object = smlManagerObjectFindInternal(
1072 manager,
1073 session,
1074 cmd->type,
1075 cmd->target, cmd->source,
1076 cmd->private.alert.contentType);
1077 smlTrace(TRACE_EXIT, "%s(%p)", __func__, object);
1078 return object;
1079 }
1080
1081 SmlObject *smlManagerObjectFindInternal(
1082 SmlManager *manager,
1083 SmlSession *session,
1084 SmlCommandType type,
1085 SmlLocation *target,
1086 SmlLocation *source,
1087 const char* contentType)
1088 {
1089 smlTrace(TRACE_ENTRY, "%s(%p, %p, %d, %p, %p)", __func__, manager, session, type, target, source);
1090 smlAssert(manager);
1091 SmlObject *object = NULL;
1092 GList *o = NULL;
1093
1094 /* We first search for the object in the session specific objects */
1095 if (session) {
1096 managerSession *sess = _manager_session_find(manager, session);
1097 if (sess) {
1098 for (o = sess->objects; o; o = o->next) {
1099 object = o->data;
1100
1101 if (object->type != SML_COMMAND_TYPE_UNKNOWN && type != object->type)
1102 continue;
1103
1104 if (!smlLocationCompare(NULL, object->location, NULL, target))
1105 continue;
1106
1107 if (!smlLocationCompare(NULL, object->source, NULL, source))
1108 continue;
1109
1110 smlTrace(TRACE_EXIT, "%s: FOUND (session): %p", __func__, object);
1111 return object;
1112 }
1113 }
1114 }
1115
1116 for (o = manager->objects; o; o = o->next) {
1117 object = o->data;
1118
1119 if (object->type != SML_COMMAND_TYPE_UNKNOWN && type != object->type)
1120 continue;
1121
1122 if (type == SML_COMMAND_TYPE_ALERT && contentType) {
1123 if (object->contentType) {
1124 /* This item is a san 11 alert */
1125 if (!strcmp(contentType, object->contentType)) {
1126 smlTrace(TRACE_EXIT, "%s: FOUND SAN TARGET: %p", __func__, object);
1127 return object;
1128 }
1129 }
1130
1131 continue;
1132 }
1133
1134 if (!smlLocationCompare(NULL, object->location, NULL, target))
1135 continue;
1136
1137 if (!smlLocationCompare(NULL, object->source, NULL, source))
1138 continue;
1139
1140 /* Check if the target is a san target */
1141 if (object->contentType)
1142 continue;
1143
1144 smlTrace(TRACE_EXIT, "%s: FOUND: %p", __func__, object);
1145 return object;
1146 }
1147
1148 smlTrace(TRACE_EXIT, "%s: NOT FOUND", __func__);
1149 return NULL;
1150 }
1151
1152 SmlTransport *smlManagerGetTransport(SmlManager *manager)
1153 {
1154 smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, manager);
1155 smlAssert(manager);
1156
1157 SmlTransport *tsp = manager->transport;
1158
1159 smlTrace(TRACE_EXIT, "%s: %p", __func__, tsp);
1160 return tsp;
1161 }
1162
1163 SmlBool smlManagerDispatchHeader(SmlManager *manager, SmlSession *session, SmlHeader *header, SmlCred *cred, SmlError **error)
1164 {
1165 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p, %p, %p)", __func__, manager, session, header, cred, error);
1166 smlAssert(manager);
1167 smlAssert(session);
1168 smlAssert(header);
1169 CHECK_ERROR_REF
1170
1171 if (manager->headerCallback &&
1172 session->sessionType == SML_SESSION_TYPE_SERVER) {
1173 /* Authentication is only specified for OMA DS server. */
1174 manager->headerCallback(session, header, cred, manager->headerCallbackUserdata);
1175 } else {
1176 smlTrace(TRACE_INTERNAL, "%s: Header not handled!", __func__);
1177 if (session->sessionType == SML_SESSION_TYPE_SERVER &&
1178 !session->established) {
1179 /* An OMA DS server must handle the header for security
1180 * reasons - especially authentication.
1181 *
1182 * Question: can we detect such a bug in an earlier phase?
1183 */
1184 g_warning("%s: This is an OMA DS server. " \
1185 "The header callback is missing. " \
1186 "All requests will be accepted without authentication.",
1187 __func__);
1188 session->established = TRUE;
1189 smlSessionDispatchEvent(
1190 session, SML_SESSION_EVENT_ESTABLISHED,
1191 NULL, NULL, NULL, NULL);
1192 }
1193 SmlStatus *status = smlStatusNew(
1194 SML_NO_ERROR, 0,
1195 header->messageID,
1196 header->source, header->target,
1197 SML_COMMAND_TYPE_HEADER, error);
1198 if (!status)
1199 goto error;
1200
1201 if (!smlSessionSendReply(session, status, error)) {
1202 smlStatusUnref(status);
1203 goto error;
1204 }
1205
1206 smlStatusUnref(status);
1207 }
1208
1209 smlTrace(TRACE_EXIT, "%s", __func__);
1210 return TRUE;
1211
1212 error:
1213 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
1214 return FALSE;
1215 }
1216
1217 SmlBool smlManagerDispatchChildCommand(SmlManager *manager, SmlSession *session, SmlCommand *parent, SmlCommand *cmd, SmlError **error)
1218 {
1219 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p, %p, %p)", __func__, manager, session, parent, cmd, error);
1220 smlAssert(manager);
1221 smlAssert(session);
1222 smlAssert(parent);
1223 CHECK_ERROR_REF
1224
1225 //Check if a handler for this object at this path has been installed.
1226 SmlObject *object = smlManagerObjectFind(manager, session, parent);
1227 if (object) {
1228 //Check if a handler for this object at this path has been installed.
1229 if (!object->childCallback) {
1230 smlErrorSet(error, SML_ERROR_GENERIC, "No handler for the child was installed");
1231 goto error;
1232 }
1233
1234 object->childCallback(session, cmd, object->commandCallbackUserdata);
1235 } else {
1236 SmlStatus *reply = smlCommandNewReply(cmd, SML_ERROR_NOT_FOUND, error);
1237 if (!reply)
1238 goto error;
1239
1240 if (!smlSessionSendReply(session, reply, error)) {
1241 smlStatusUnref(reply);
1242 goto error;
1243 }
1244
1245 smlStatusUnref(reply);
1246
1247 smlErrorSet(error, SML_ERROR_GENERIC, "Unable to find child command handler");
1248
1249 goto error;
1250 }
1251
1252 smlTrace(TRACE_EXIT, "%s", __func__);
1253 return TRUE;
1254
1255 error:
1256 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
1257 return FALSE;
1258 }
1259
1260 SmlBool smlManagerDispatchCommand(SmlManager *manager, SmlSession *session, SmlCommand *cmd, SmlError **error)
1261 {
1262 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, manager, session, cmd, error);
1263 smlAssert(manager);
1264 smlAssert(session);
1265 smlAssert(cmd);
1266 CHECK_ERROR_REF
1267
1268 //Check if a handler for this object at this path has been installed.
1269 SmlObject *object = smlManagerObjectFind(manager, session, cmd);
1270 if (object) {
1271 //Check if a handler for this object at this path has been installed.
1272 if (!object->commandCallback) {
1273 smlErrorSet(error, SML_ERROR_GENERIC, "No handler for the child was installed");
1274 goto error;
1275 }
1276
1277 object->commandCallback(session, cmd, object->commandCallbackUserdata);
1278 } else {
1279 const char *type = smlCommandTypeToString(cmd->type, error);
1280 /* If the type is unknown then this can be part of the error. */
1281 smlErrorDeref(error);
1282 const char *srcuri = (cmd->source && cmd->source->locURI) ? cmd->source->locURI : "NULL";
1283 const char *dsturi = (cmd->target && cmd->target->locURI) ? cmd->target->locURI : "NULL";
1284 smlErrorSet(error, SML_ERROR_NOT_FOUND, "Unable to find command handler (%s: %s -> %s)", (type) ? type : "UNKNOWN", srcuri, dsturi);
1285
1286 SmlError *locerror = NULL;
1287 SmlStatus *reply = smlCommandNewReply(cmd, SML_ERROR_NOT_FOUND, &locerror);
1288 if (!reply) {
1289 smlErrorSet(error, SML_ERROR_NOT_FOUND, "%s %s",
1290 smlErrorPrint(error),
1291 smlErrorPrint(&locerror));
1292 goto error;
1293 }
1294
1295 if (!smlSessionSendReply(session, reply, &locerror)) {
1296 smlStatusUnref(reply);
1297 smlErrorSet(error, SML_ERROR_NOT_FOUND, "%s %s",
1298 smlErrorPrint(error),
1299 smlErrorPrint(&locerror));
1300 goto error;
1301 }
1302
1303 smlStatusUnref(reply);
1304
1305 goto error;
1306 }
1307
1308 smlTrace(TRACE_EXIT, "%s", __func__);
1309 return TRUE;
1310
1311 error:
1312 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
1313 return FALSE;
1314 }
1315
1316 void smlManagerRegisterHeaderHandler(SmlManager *manager, SmlHeaderCb callback, SmlStatusReplyCb statuscb, void *userdata)
1317 {
1318 smlAssert(manager);
1319
1320 manager->headerCallback = callback;
1321 manager->headerStatusCallback = statuscb;
1322 manager->headerCallbackUserdata = userdata;
1323 }
1324
1325 void smlManagerSetLocalMaxMsgSize(SmlManager *manager, unsigned int size)
1326 {
1327 smlAssert(manager);
1328 manager->localMaxMsgSize = size;
1329 }
1330
1331 void smlManagerSetLocalMaxObjSize(SmlManager *manager, unsigned int size)
1332 {
1333 smlAssert(manager);
1334 manager->localMaxObjSize = size;
1335 }
1336
1337 char *smlManagerGetNewSessionID(SmlManager *manager)
1338 {
1339 smlTrace(TRACE_ENTRY, "%s(%p)", __func__, manager);
1340 smlAssertMsg(manager, "The manager is required to avoid duplicated session IDs.");
1341
1342 char *sessionString = NULL;
1343 while (sessionString == NULL)
1344 {
1345 /* WARNING: only 4 byte session IDs are theoretically allowed !!! */
1346 /* create random session ID - glib only supports 32 bit random numbers */
1347 unsigned int sessionID = (unsigned int) g_random_int_range (0, 0xFFFF);
1348 sessionString = g_strdup_printf("%u", sessionID);
1349 smlTrace(TRACE_INTERNAL, "%s: new potential session ID is %lu.", __func__, sessionID);
1350 if (smlManagerSessionFind(manager, sessionString))
1351 smlSafeCFree(&sessionString);
1352 }
1353 smlTrace(TRACE_EXIT, "%s - %s", __func__, VA_STRING(sessionString));
1354 return sessionString;
1355 }
1356
1357 SmlLink *smlManagerSessionGetLink(
1358 SmlManager *manager,
1359 SmlSession *session,
1360 SmlError **error)
1361 {
1362 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, manager, session, error);
1363 CHECK_ERROR_REF
1364
1365 managerSession *_msession = _manager_session_find(manager, session);
1366 if (!_msession)
1367 {
1368 smlErrorSet(error, SML_ERROR_GENERIC,
1369 "The session %d is not registered at the manager.",
1370 smlSessionGetSessionID(session));
1371 goto error;
1372 }
1373
1374 if (_msession->link)
1375 smlLinkRef(_msession->link);
1376
1377 smlTrace(TRACE_EXIT, "%s - %p", __func__, _msession->link);
1378 return _msession->link;
1379 error:
1380 smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
1381 return NULL;
1382 }
1383