libsyncml  0.5.4
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;
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 
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:
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 
SmlBool smlSessionSendReply(SmlSession *session, SmlStatus *status, SmlError **error)
Sends a reply to a command.
Definition: sml_session.c:2536
const char * smlErrorPrint(SmlError **error)
Returns the message of the error.
Definition: sml_error.c:299
SmlBool smlParserGetHeader(SmlParser *parser, SmlHeader **header, SmlCred **cred, SmlError **error)
Parses the SyncHdr.
Definition: sml_parse.c:216
void smlManagerStop(SmlManager *manager)
Stops the active manager part.
Definition: sml_manager.c:565
void smlSessionSetLocalMaxObjSize(SmlSession *session, unsigned int limit)
Definition: sml_session.c:2363
void smlParserFree(SmlParser *parser)
Frees a parser.
Definition: sml_parse.c:108
void smlErrorDuplicate(SmlError **target, SmlError **source)
Duplicates the error into the target.
Definition: sml_error.c:337
void smlQueueSend(SmlQueue *queue, void *data)
Sends a message down a queue.
Definition: sml_queue.c:353
SmlQueue * smlQueueNew(SmlError **error)
Creates a new asynchronous queue.
Definition: sml_queue.c:81
SmlBool smlTransportSetResponseURI(SmlTransport *tsp, const char *uri, SmlError **error)
Sets the response URI after initialization.
SmlParser * smlParserNew(SmlMimeType type, unsigned int limit, SmlError **error)
Creates a new parser.
Definition: sml_parse.c:50
void smlTrace(SmlTraceType type, const char *message,...)
Used for tracing the application.
Definition: sml_support.c:120
SmlBool smlParserStart(SmlParser *parser, const char *data, unsigned int size, SmlError **error)
Starts the parser on a given data buffer.
Definition: sml_parse.c:132
SmlSession * smlSessionNew(SmlSessionType sessionType, SmlMimeType mimetype, SmlProtocolVersion version, SmlProtocolType protocol, SmlLocation *target, SmlLocation *source, const char *sessionID, unsigned int messageID, SmlError **error)
Creates a new session.
Definition: sml_session.c:1832
SmlBool smlManagerObjectRegister(SmlManager *manager, SmlCommandType type, SmlSession *session, SmlLocation *location, SmlLocation *source, const char *contentType, SmlCommandCb callback, SmlCommandCb childCallback, void *userdata, SmlError **error)
Register an object with a session.
Definition: sml_manager.c:926
void * smlTryMalloc0(long n_bytes, SmlError **error)
Safely mallocs.
Definition: sml_support.c:335
void smlErrorSet(SmlError **error, SmlErrorType type, const char *format,...)
Sets the error.
Definition: sml_error.c:355
Represent an error.