libsyncml 0.5.4

- Main Page
- Modules
- Data Structures
- Files

- File List

sml_ds_server.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 <libsyncml/syncml.h>
23 #include "sml_ds_server.h"
24
25 #include <libsyncml/syncml_internals.h>
26 #include "sml_ds_server_internals.h"
27 #include <libsyncml/sml_error_internals.h>
28 #include <libsyncml/sml_manager_internals.h>
29 #include <libsyncml/sml_session_internals.h>
30 #include <libsyncml/sml_command_internals.h>
31 #include <libsyncml/sml_elements_internals.h>
32
33 static SmlWriteContext *_write_context_find(SmlDsSession *dsession, const char *uid, SmlChangeType type)
34 {
35 smlTrace(TRACE_ENTRY, "%s(%p, %s, %i)", __func__, dsession, VA_STRING(uid), type);
36
37 g_mutex_lock(dsession->pendingMapsLock);
38 GList *c = NULL;
39 for (c = dsession->pendingMaps; c; c = c->next) {
40 SmlWriteContext *ctx = c->data;
41 if (!strcmp(uid, ctx->uid) && ctx->type == type) {
42 g_mutex_unlock(dsession->pendingMapsLock);
43 smlTrace(TRACE_EXIT, "%s: %p", __func__, ctx);
44 return ctx;
45 }
46 }
47 g_mutex_unlock(dsession->pendingMapsLock);
48
49 smlTrace(TRACE_EXIT_ERROR, "%s: Not found", __func__);
50 return NULL;
51 }
52
53 static void _write_context_free(SmlWriteContext *ctx)
54 {
55 smlTrace(TRACE_ENTRY, "%s(%p)", __func__, ctx);
56
57 if (ctx->status)
58 smlStatusUnref(ctx->status);
59
60 if (ctx->uid)
61 smlSafeCFree(&(ctx->uid));
62
63 if (ctx->newuid)
64 smlSafeCFree(&(ctx->newuid));
65
66 smlSafeFree((gpointer *)&ctx);
67
68 smlTrace(TRACE_EXIT, "%s", __func__);
69 }
70
71 static void _write_context_dispatch(SmlDsSession *dsession, SmlWriteContext *ctx)
72 {
73 smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, dsession, ctx);
74
75 if (!ctx->status) {
76 smlTrace(TRACE_EXIT, "%s: No status yet", __func__);
77 return;
78 }
79
80 smlTrace(TRACE_INTERNAL, "%s: Dispatching: uid %s, Type %i, newuid %s, result %i", __func__, VA_STRING(ctx->uid), ctx->type, VA_STRING(ctx->newuid), smlStatusGetCode(ctx->status));
81
82 if (ctx->type == SML_CHANGE_ADD &&
83 smlStatusGetClass(ctx->status) == SML_ERRORCLASS_SUCCESS &&
84 !dsession->recvMappingCallback &&
85 !ctx->newuid &&
86 dsession->server->servertype == SML_DS_SERVER)
87 {
88 smlTrace(TRACE_EXIT, "%s: No mapitem yet", __func__);
89 return;
90 }
91
92 ctx->callback(dsession, ctx->status, ctx->newuid, ctx->userdata);
93
94 g_mutex_lock(dsession->pendingMapsLock);
95 dsession->pendingMaps = g_list_remove(dsession->pendingMaps, ctx);
96 g_mutex_unlock(dsession->pendingMapsLock);
97
98 if (ctx->type == SML_CHANGE_ADD &&
99 smlStatusGetClass(ctx->status) == SML_ERRORCLASS_SUCCESS &&
100 dsession->recvEventCallback &&
101 !dsession->pendingMaps)
102 {
103 /* FIXME: I'm sure that this event is buggy.
104 * FIXME: What is the semantic of this event?
105 * Now there are no more MapItems ...
106 * do some fancy callback. Some applications will love it ;)
107 */
108 dsession->recvEventCallback(dsession, SML_DS_EVENT_COMMITEDCHANGES, dsession->recvEventCallbackUserdata);
109 smlTrace(TRACE_INTERNAL, "%s: recvEventCallback commited changes callback", __func__);
110 }
111
112 _write_context_free(ctx);
113
114 smlTrace(TRACE_EXIT, "%s", __func__);
115 }
116
117 static void _alert_reply(SmlSession *session, SmlStatus *status, void *userdata)
118 {
119 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, session, status, userdata);
120 SmlDsSession *dsession = userdata;
121
122 if (dsession->sentAlertCallback)
123 dsession->sentAlertCallback(session, status, dsession->sentAlertCallbackUserdata);
124
125 dsession->sentAlertCallback = NULL;
126 dsession->sentAlertCallbackUserdata = NULL;
127
128 smlTrace(TRACE_EXIT, "%s", __func__);
129 }
130
131 static void _sync_reply(SmlSession *session, SmlStatus *status, void *userdata)
132 {
133 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, session, status, userdata);
134 SmlDsSession *dsession = userdata;
135
136 if (dsession->sentSyncCallback)
137 dsession->sentSyncCallback(session, status, dsession->sentSyncCallbackUserdata);
138
139 dsession->sentSyncCallback = NULL;
140 dsession->sentSyncCallbackUserdata = NULL;
141
142 // Now there are no more MapItems ... do some fancy callback. Some applications will love it ;)
143 if (dsession->recvEventCallback && !dsession->pendingMaps) {
144 dsession->recvEventCallback(dsession, SML_DS_EVENT_COMMITEDCHANGES, dsession->recvEventCallbackUserdata);
145 smlTrace(TRACE_INTERNAL, "%s: recvEventCallback commited changes callback", __func__);
146 }
147
148 smlTrace(TRACE_EXIT, "%s", __func__);
149 }
150
151 static void _change_reply(SmlSession *session, SmlStatus *status, void *userdata)
152 {
153 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, session, status, userdata);
154 smlAssert(session);
155 smlAssert(status);
156 SmlWriteContext *ctx = userdata;
157 SmlDsSession *dsession = ctx->session;
158
159 /* Please see smlChangeAssemble in sml_xml_parser.c for
160 * a more detailed description on the checked behaviour.
161 * If the received command is an Add or the remote peer
162 * is an OMA DS client then the remote peer must send a
163 * Source. Otherwise a Target must be sent by the remote
164 * peer. We only check the required behaviour and not
165 * the optional one.
166 */
167 if (status->type == SML_COMMAND_TYPE_ADD ||
168 session->sessionType == SML_SESSION_TYPE_CLIENT) {
169 /* FIXME: How do we handle remote peers which are clients
170 * FIXME: and only support replace? The assembler will
171 * FIXME: send a replace command with a target instead of
172 * FIXME: an add command with a source.
173 */
174 if (!status->sourceRef) {
175 smlTrace(TRACE_EXIT_ERROR, "%s: Received add status or change reply from an OMA DS server without sourceRef", __func__);
176 return;
177 }
178 } else {
179 if (!status->targetRef) {
180 smlTrace(TRACE_EXIT_ERROR, "%s: Received delete or modify status or change reply from an OMA DS client without targetRef", __func__);
181 return;
182 }
183 }
184
185 ctx->status = status;
186 smlStatusRef(status);
187 _write_context_dispatch(dsession, ctx);
188
189 smlTrace(TRACE_EXIT, "%s", __func__);
190 }
191
192 SmlDsServer *smlDsServerNew(const char *type, SmlLocation *location, SmlError **error)
193 {
194 smlTrace(TRACE_ENTRY, "%s(%s, %p, %p)", __func__, VA_STRING(type), location, error);
195 smlAssert(location);
196 CHECK_ERROR_REF
197
198 SmlDsServer *server = smlTryMalloc0(sizeof(SmlDsServer), error);
199 if (!server)
200 goto error;
201
202 server->location = location;
203 smlLocationRef(location);
204
205 server->contenttype = g_strdup(type);
206 server->servertype = SML_DS_SERVER;
207
208 smlTrace(TRACE_EXIT, "%s: %p", __func__, server);
209 return server;
210
211 error:
212 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
213 return NULL;
214 }
215
216 SmlDsServer *smlDsClientNew(const char *type, SmlLocation *location, SmlLocation *target, SmlError **error)
217 {
218 smlTrace(TRACE_ENTRY, "%s(%s, %p, %p, %p)", __func__, VA_STRING(type), location, target, error);
219 smlAssert(location);
220 smlAssert(target);
221 CHECK_ERROR_REF
222
223 SmlDsServer *server = smlTryMalloc0(sizeof(SmlDsServer), error);
224 if (!server)
225 goto error;
226
227 server->location = location;
228 smlLocationRef(location);
229
230 server->target = target;
231 smlLocationRef(target);
232
233 server->contenttype = g_strdup(type);
234 server->servertype = SML_DS_CLIENT;
235
236 smlTrace(TRACE_EXIT, "%s: %p", __func__, server);
237 return server;
238
239 error:
240 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
241 return NULL;
242 }
243
244 SmlDsServerType smlDsServerGetServerType(SmlDsServer *server)
245 {
246 smlAssert(server);
247 return server->servertype;
248 }
249
250 void smlDsServerFree(SmlDsServer *server)
251 {
252 smlTrace(TRACE_ENTRY, "%s(%p)", __func__, server);
253 smlAssert(server);
254
255 if (server->location)
256 smlLocationUnref(server->location);
257
258 if (server->target)
259 smlLocationUnref(server->target);
260
261 if (server->contenttype)
262 smlSafeCFree(&(server->contenttype));
263
264 smlSafeFree((gpointer *)&server);
265
266 smlTrace(TRACE_EXIT, "%s", __func__);
267 }
268
279 void smlDsServerSetConnectCallback(SmlDsServer *server, SmlDsSessionConnectCb callback, void *userdata)
280 {
281 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, server, callback, userdata);
282 smlAssert(server);
283
284 server->connectCallback = callback;
285 server->connectCallbackUserdata = userdata;
286
287 smlTrace(TRACE_EXIT, "%s", __func__);
288 }
289
290 void smlDsServerSetSanCallback(SmlDsServer *server, SmlDsServerSanCb callback, void *userdata)
291 {
292 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, server, callback, userdata);
293 smlAssert(server);
294 smlAssert(server->servertype == SML_DS_CLIENT);
295
296 server->sanCallback = callback;
297 server->sanCallbackUserdata = userdata;
298
299 smlTrace(TRACE_EXIT, "%s", __func__);
300 }
301
302 void smlDsServerSetSanSessionCallback(SmlDsServer *server, SmlDsServerSanSessionCb callback, void *userdata)
303 {
304 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, server, callback, userdata);
305 smlAssert(server);
306 smlAssert(server->servertype == SML_DS_CLIENT);
307
308 server->sanSessionCallback = callback;
309 server->sanSessionCallbackUserdata = userdata;
310
311 smlTrace(TRACE_EXIT, "%s", __func__);
312 }
313
314 const char *smlDsServerGetLocation(SmlDsServer *server)
315 {
316 smlAssert(server);
317 if (server->location)
318 return server->location->locURI;
319 return NULL;
320 }
321
322 const char *smlDsServerGetContentType(SmlDsServer *server)
323 {
324 smlAssert(server);
325 return server->contenttype;
326 }
327
328 SmlBool smlDsServerAddSan(SmlDsServer *server, SmlNotification *san, SmlError **error)
329 {
330 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, server, san, error);
331 smlAssert(server);
332 smlAssert(san);
333 CHECK_ERROR_REF
334
335 if (!smlNotificationNewAlert(san, SML_ALERT_TWO_WAY_BY_SERVER, server->contenttype, smlLocationGetURI(server->location), error))
336 goto error;
337
338 smlTrace(TRACE_EXIT, "%s", __func__);
339 return TRUE;
340
341 error:
342 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
343 return FALSE;
344 }
345
346 SmlDsSession *smlDsServerRecvAlert(SmlDsServer *server, SmlSession *session, SmlCommand *cmd)
347 {
348 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, server, session, cmd);
349 SmlError *error = NULL;
350
351 SmlDsSession *dsession = smlDsSessionNew(server, session, &error);
352 if (!dsession)
353 goto error;
354
355 smlDsSessionRecvAlert(session, cmd, dsession);
356
357 if (server->connectCallback)
358 server->connectCallback(dsession, server->connectCallbackUserdata);
359
360 smlDsSessionUnref(dsession);
361
362 smlTrace(TRACE_EXIT, "%s", __func__);
363 return dsession;
364
365 error:
366 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(&error));
367 smlErrorDeref(&error);
368 return NULL;
369 }
370
371 SmlDsSession *smlDsServerSendAlert(SmlDsServer *server, SmlSession *session, SmlAlertType type, const char *last, const char *next, SmlStatusReplyCb callback, void *userdata, SmlError **error)
372 {
373 smlTrace(TRACE_ENTRY, "%s(%p, %p, %i, %s, %s, %p)", __func__, server, session, type, VA_STRING(last), VA_STRING(next), error);
374 smlAssert(server);
375 smlAssert(session);
376 CHECK_ERROR_REF
377
378 SmlDsSession *dsession = smlDsSessionNew(server, session, error);
379 if (!dsession)
380 goto error;
381
382 if (server->manager) {
383 if (!smlManagerObjectRegister(server->manager, SML_COMMAND_TYPE_SYNC, session, server->location, NULL, NULL, smlDsSessionRecvSync, smlDsSessionRecvChange, dsession, error))
384 goto error_free_dsession;
385
386 if (!smlManagerObjectRegister(server->manager, SML_COMMAND_TYPE_MAP, session, server->location, NULL, NULL, smlDsSessionRecvMap, NULL, dsession, error))
387 goto error_free_dsession;
388
389 if (!smlManagerObjectRegister(server->manager, SML_COMMAND_TYPE_ALERT, session, server->location, NULL, NULL, smlDsSessionRecvAlert, NULL, dsession, error))
390 goto error_free_dsession;
391 }
392
393 if (!smlDsSessionSendAlert(dsession, type, last, next, callback, userdata, error))
394 goto error_free_dsession;
395
396 smlTrace(TRACE_EXIT, "%s", __func__);
397 return dsession;
398
399 error_free_dsession:
400 smlSafeFree((gpointer *)&dsession);
401 error:
402 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
403 return NULL;
404 }
405
406 SmlDsSession *smlDsSessionNew(SmlDsServer *server, SmlSession *session, SmlError **error)
407 {
408 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, server, session, error);
409 smlAssert(server);
410 CHECK_ERROR_REF
411
412 SmlDsSession *dsession = smlTryMalloc0(sizeof(SmlDsSession), error);
413 if (!dsession)
414 goto error;
415
416 dsession->server = server;
417 dsession->session = session;
418 dsession->write_lock = g_mutex_new();
419 dsession->lock = g_mutex_new();
420 dsession->syncReply = SML_ERROR_UNKNOWN;
421 dsession->refCount = 1;
422
423 if (server->servertype == SML_DS_CLIENT) {
424 dsession->target = server->target;
425 smlLocationRef(dsession->target);
426 }
427
428 dsession->location = server->location;
429 smlLocationRef(dsession->location);
430
431 dsession->pendingMapsLock = g_mutex_new();
432
433 smlTrace(TRACE_EXIT, "%s: %p", __func__, dsession);
434 return dsession;
435
436 error:
437 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
438 return NULL;
439 }
440
441 SmlDsSession *smlDsSessionRef(SmlDsSession *dsession)
442 {
443 smlTrace(TRACE_ENTRY, "%s(%p)", __func__, dsession);
444 smlAssert(dsession);
445
446 g_atomic_int_inc(&(dsession->refCount));
447
448 smlTrace(TRACE_EXIT, "%s: New refcount: %i", __func__, dsession->refCount);
449 return dsession;
450 }
451
452 void smlDsSessionUnref(SmlDsSession *dsession)
453 {
454 smlTrace(TRACE_ENTRY, "%s(%p)", __func__, dsession);
455 smlAssert(dsession);
456
457 if (g_atomic_int_dec_and_test(&(dsession->refCount))) {
458 smlTrace(TRACE_INTERNAL, "%s: Refcount == 0!", __func__);
459
460 if (dsession->target)
461 smlLocationUnref(dsession->target);
462
463 if (dsession->location)
464 smlLocationUnref(dsession->location);
465
466 if (dsession->alertCommand)
467 smlCommandUnref(dsession->alertCommand);
468
469 while (dsession->recvSync) {
470 SmlCommand *cmd = dsession->recvSync->data;
471 smlCommandUnref(cmd);
472 dsession->recvSync = g_list_delete_link(dsession->recvSync, dsession->recvSync);
473 }
474
475 while (dsession->recvChanges) {
476 SmlCommand *cmd = dsession->recvChanges->data;
477 smlCommandUnref(cmd);
478 dsession->recvChanges = g_list_delete_link(dsession->recvChanges, dsession->recvChanges);
479 }
480
481 if (dsession->syncCommand)
482 smlCommandUnref(dsession->syncCommand);
483
484 if (!g_mutex_trylock(dsession->pendingMapsLock)) {
485 smlTrace(TRACE_ERROR,
486 "%s: somebody still uses this object", __func__);
487 g_mutex_lock(dsession->pendingMapsLock);
488 }
489 while (dsession->pendingMaps) {
490 SmlWriteContext *ctx = dsession->pendingMaps->data;
491 _write_context_free(ctx);
492 dsession->pendingMaps = g_list_delete_link(dsession->pendingMaps, dsession->pendingMaps);
493 }
494 g_mutex_unlock(dsession->pendingMapsLock);
495 g_mutex_free(dsession->pendingMapsLock);
496
497 while (dsession->mapItems) {
498 SmlMapItem *item = dsession->mapItems->data;
499 smlMapItemUnref(item);
500 dsession->mapItems = g_list_delete_link(dsession->mapItems, dsession->mapItems);
501 }
502
503 if (dsession->lock)
504 g_mutex_free(dsession->lock);
505 if (dsession->write_lock)
506 g_mutex_free(dsession->write_lock);
507
508 smlSafeFree((gpointer *)&dsession);
509 }
510
511 smlTrace(TRACE_EXIT, "%s", __func__);
512 }
513
514 void smlDsSessionDispatch(SmlDsSession *dsession)
515 {
516 smlTrace(TRACE_ENTRY, "%s(%p)", __func__, dsession);
517 SmlError *error = NULL;
518 SmlStatus *reply = NULL;
519
520 /* A dispatch function should never block on a
521 * locked resource. This is like a busy wait
522 * because the thread is not available for this
523 * time which can block the whole system if two
524 * dispatchers use the same thread.
525 */
526 if (!g_mutex_trylock(dsession->lock))
527 {
528 smlTrace(TRACE_EXIT, "%s - DsSession is already locked", __func__);
529 return;
530 }
531 smlTrace(TRACE_INTERNAL, "%s - locked DsSession successfully", __func__);
532
533 if (dsession->alertCommand && dsession->recvAlertCallback) {
534 smlTrace(TRACE_INTERNAL, "%s: Dispatching alert", __func__);
535
536 SmlErrorType type = SML_NO_ERROR;
537 if (!dsession->recvAlertCallback(dsession, dsession->alertCommand->private.alert.type, dsession->alertCommand->private.alert.anchor->last, dsession->alertCommand->private.alert.anchor->next, dsession->recvAlertCallbackUserdata))
538 type = SML_ERROR_REQUIRE_REFRESH;
539 dsession->recvAlertCallback = NULL;
540
541 reply = smlCommandNewReply(dsession->alertCommand, type, &error);
542 if (!reply)
543 goto error;
544
545 if (!smlSessionSendReply(dsession->session, reply, &error))
546 goto error;
547
548
549 smlStatusUnref(reply);
550
551 smlCommandUnref(dsession->alertCommand);
552 dsession->alertCommand = NULL;
553
554 /* unlock the final event at the manager
555 *
556 * If this is called from a test case then the datastore
557 * is sometimes not registered at a SmlManager.
558 */
559 if (dsession->server->manager && dsession->finalLock)
560 {
561 dsession->finalLock = FALSE;
562 smlManagerSessionFinalLockUnref(dsession->server->manager, dsession->session);
563 }
564
565 } else if (dsession->recvSync && dsession->recvSyncCallback) {
566 smlTrace(TRACE_INTERNAL, "%s: Dispatching sync", __func__);
567
568 dsession->recvSyncCallback(dsession, ((SmlCommand *)(dsession->recvSync->data))->private.sync.numChanged, dsession->recvSyncCallbackUserdata);
569 dsession->recvSyncCallback = NULL;
570
571 while (dsession->recvSync) {
572 SmlCommand *cmd = dsession->recvSync->data;
573
574 smlTrace(TRACE_INTERNAL, "%s: answering sync command with cmdRef %i and msgRef %i", __func__, cmd->cmdID, cmd->msgID);
575 reply = smlCommandNewReply(cmd, SML_NO_ERROR, &error);
576 if (!reply)
577 goto error;
578
579 if (!smlSessionSendReply(dsession->session, reply, &error))
580 goto error;
581
582 smlStatusUnref(reply);
583
584 smlCommandUnref(cmd);
585 dsession->recvSync = g_list_delete_link(dsession->recvSync, dsession->recvSync);
586 }
587
588 dsession->syncReply = SML_NO_ERROR;
589
590 if (!dsession->recvChanges) {
591 /* There are no changes. */
592
593 /* ... do some fancy callback. Some applications will love it ;) */
594 if (dsession->recvEventCallback) {
595 dsession->recvEventCallback(dsession, SML_DS_EVENT_GOTCHANGES, dsession->recvEventCallbackUserdata);
596 smlTrace(TRACE_INTERNAL, "%s: recvEventCallback no changes in recvSync callback", __func__);
597 }
598 /* unlock the final event at the manager
599 *
600 * If this is called from a test case then the datastore
601 * is sometimes not registered at a SmlManager.
602 */
603 if (dsession->server->manager && dsession->finalLock)
604 {
605 dsession->finalLock = FALSE;
606 smlManagerSessionFinalLockUnref(dsession->server->manager, dsession->session);
607 }
608 smlTrace(TRACE_INTERNAL, "%s: final handling done", __func__);
609 }
610 } else if (dsession->recvChanges && dsession->changesCallback) {
611 smlTrace(TRACE_INTERNAL, "%s: Dispatching changes", __func__);
612
613 while (dsession->recvChanges) {
614
615 SmlCommand *cmd = dsession->recvChanges->data;
616
617 if (cmd) {
618 if (!cmd->private.change.items ||
619 !g_list_length(cmd->private.change.items))
620 {
621 smlErrorSet(&error, SML_ERROR_GENERIC, "No items found in command.");
622 goto error;
623 }
624
625 /* All items handled at once because libsyncml
626 * only supports one status code for all items.
627 * So one failed item means that the complete
628 * command is aborted.
629 */
630
631 guint i;
632 for (i=0; i < g_list_length(cmd->private.change.items); i++)
633 {
634 SmlItem *item = g_list_nth_data(cmd->private.change.items, i);
635 if (!item)
636 {
637 smlErrorSet(&error, SML_ERROR_GENERIC,
638 "Item %i of the command's item list is NULL.", i);
639 goto error;
640 }
641 /* We'd rather use the target of the change since it already the mapped
642 * uid (if we are a client for example). If it is not given we use the
643 * source uri. This has then to be translated by the sync engine of course */
644 if ((!item->source && !item->target)) {
645 smlErrorSet(&error, SML_ERROR_GENERIC,
646 "Cannot determine UID because source an target are missing on item %i.", i);
647 goto error;
648 }
649
650 char *data = NULL;
651 unsigned int size = 0;
652 if (!smlItemStealData(item, &data, &size, &error))
653 goto error;
654
655 if (!dsession->changesCallback(dsession, cmd->private.change.type, item->target ? item->target->locURI : item->source->locURI, data, size, item->contenttype, dsession->changesCallbackUserdata, &error))
656 goto error;
657 }
658
659 if (cmd->private.change.type == SML_CHANGE_ADD)
660 reply = smlCommandNewReply(cmd, SML_ITEM_ADDED, &error);
661 else
662 reply = smlCommandNewReply(cmd, SML_NO_ERROR, &error);
663
664 if (!reply)
665 goto error;
666
667 if (!smlSessionSendReply(dsession->session, reply, &error))
668 goto error;
669
670 smlStatusUnref(reply);
671
672 smlCommandUnref(cmd);
673 }
674
675 dsession->recvChanges = g_list_delete_link(dsession->recvChanges, dsession->recvChanges);
676 }
677
678 // Now there are no more changes... do some fancy callback. Some applications will love it ;)
679 if (dsession->recvEventCallback) {
680 dsession->recvEventCallback(dsession, SML_DS_EVENT_GOTCHANGES, dsession->recvEventCallbackUserdata);
681 smlTrace(TRACE_INTERNAL, "%s: recvEventCallback all changes sent in recvChanges callback", __func__);
682 }
683 /* unlock the final event at the manager
684 *
685 * If this is called from a test case then the datastore
686 * is sometimes not registered at a SmlManager.
687 */
688 if (dsession->server->manager)
689 {
690 dsession->finalLock = FALSE;
691 smlManagerSessionFinalLockUnref(dsession->server->manager, dsession->session);
692 }
693 else
694 smlTrace(TRACE_INTERNAL, "%s - no manager so should be a test", __func__);
695 } else {
696
697 smlTrace(TRACE_INTERNAL, "%s: recvChanges: %p changesCallback: %p", __func__, dsession->recvChanges, dsession->changesCallback);
698 }
699
700 smlTrace(TRACE_EXIT, "%s()", __func__);
701 g_mutex_unlock(dsession->lock);
702
703 return;
704
705 error:
706 if (reply)
707 smlStatusUnref(reply);
708 g_mutex_unlock(dsession->lock);
709 smlTrace(TRACE_EXIT_ERROR, "%s: Unable to dispatch: %s", __func__, smlErrorPrint(&error));
710 smlErrorDeref(&error);
711 }
712
713 SmlBool smlDsSessionCheck(SmlDsSession *dsession)
714 {
715 if ((dsession->alertCommand && dsession->recvAlertCallback) || \
716 (dsession->recvSync && dsession->recvSyncCallback) || \
717 (dsession->recvChanges && dsession->changesCallback))
718 return TRUE;
719 return FALSE;
720 }
721
722 void smlDsSessionRecvAlert(SmlSession *session, SmlCommand *cmd, void *userdata)
723 {
724 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, session, cmd, userdata);
725 SmlDsSession *dsession = userdata;
726 SmlError *error = NULL;
727 smlAssert(dsession->location);
728
729 g_mutex_lock(dsession->lock);
730
731 if (!cmd->target || !cmd->source) {
732 SmlStatus *reply = smlCommandNewReply(cmd, SML_ERROR_BAD_REQUEST, &error);
733 if (!reply)
734 goto error;
735
736 if (!smlSessionSendReply(session, reply, &error)) {
737 smlStatusUnref(reply);
738 goto error;
739 }
740
741 smlStatusUnref(reply);
742
743 smlTrace(TRACE_EXIT, "%s: Alert had no target or source", __func__);
744 return;
745 }
746
747 if (!smlLocationCompare(NULL, dsession->location, NULL, cmd->target)) {
748 SmlStatus *reply = smlCommandNewReply(cmd, SML_ERROR_NOT_FOUND, &error);
749 if (!reply)
750 goto error;
751
752 if (!smlSessionSendReply(session, reply, &error)) {
753 smlStatusUnref(reply);
754 goto error;
755 }
756
757 smlStatusUnref(reply);
758
759 smlTrace(TRACE_EXIT, "%s: Alert does not match our location", __func__);
760 return;
761 }
762
763 smlCommandRef(cmd);
764
765 if (!dsession->target) {
766 dsession->target = cmd->source;
767 smlLocationRef(cmd->source);
768 }
769
770 dsession->alertCommand = cmd;
771
772 /* Lock the final event at the manager.
773 *
774 * If this is called from a test case then the datastore
775 * is sometimes not registered at a SmlManager.
776 */
777 if (dsession->server->manager)
778 {
779 smlManagerSessionFinalLockRef(dsession->server->manager, session);
780 dsession->finalLock = TRUE;
781 }
782 else
783 smlTrace(TRACE_INTERNAL, "%s - no manager so should be a test", __func__);
784
785 g_mutex_unlock(dsession->lock);
786
787 smlTrace(TRACE_EXIT, "%s", __func__);
788 return;
789
790 error:
791 g_mutex_unlock(dsession->lock);
792 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(&error));
793 smlErrorDeref(&error);
794 return;
795 }
796
797 void smlDsSessionRecvSync(SmlSession *session, SmlCommand *cmd, void *userdata)
798 {
799 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, session, cmd, userdata);
800 SmlDsSession *dsession = userdata;
801 SmlError *error = NULL;
802
803 /* Create a write lock on the complete DsSession object to avoid race
804 * conditions. If the write lock is already present then this is the
805 * end of the sync block and the write lock must only be removed.
806 */
807 if (g_mutex_trylock(dsession->write_lock))
808 {
809 /* write lock succeeded so lock the complete DsSession */
810 g_mutex_lock(dsession->lock);
811 smlTrace(TRACE_INTERNAL, "%s - write lock enabled", __func__);
812 /* Lock the final event at the manager.
813 *
814 * If this is called from a test case then the datastore
815 * is sometimes not registered at a SmlManager.
816 */
817 if (dsession->server->manager)
818 {
819 smlManagerSessionFinalLockRef(dsession->server->manager, session);
820 dsession->finalLock = TRUE;
821 dsession->emptySync = TRUE;
822 }
823 else
824 smlTrace(TRACE_INTERNAL, "%s - no manager so should be a test", __func__);
825 } else {
826 /* detected an old write lock so this is the closing sync call */
827 if (dsession->finalLock && dsession->emptySync)
828 {
829 smlTrace(TRACE_INTERNAL, "%s - empty sync of moreData ?", __func__);
830 dsession->finalLock = FALSE;
831 smlManagerSessionFinalLockUnref(dsession->server->manager, session);
832 }
833 g_mutex_unlock(dsession->lock);
834 g_mutex_unlock(dsession->write_lock);
835 smlTrace(TRACE_EXIT, "%s - removed write lock", __func__);
836 return;
837 }
838
839 if (dsession->syncReply == SML_ERROR_UNKNOWN) {
840 smlTrace(TRACE_INTERNAL, "%s: Storing sync command with cmdRef %i and msgRef %i", __func__, cmd->cmdID, cmd->msgID);
841 smlCommandRef(cmd);
842 dsession->recvSync = g_list_append(dsession->recvSync, cmd);
843 } else {
844 smlTrace(TRACE_INTERNAL, "%s: Using stored sync reply on cmd with cmdRef %i and msgRef %i", __func__, cmd->cmdID, cmd->msgID);
845 SmlStatus *reply = smlCommandNewReply(cmd, dsession->syncReply, &error);
846 if (!reply)
847 goto error;
848
849 if (!smlSessionSendReply(dsession->session, reply, &error))
850 goto error;
851
852 smlStatusUnref(reply);
853 }
854
855 smlTrace(TRACE_EXIT, "%s", __func__);
856 return;
857
858 error:
859 g_mutex_unlock(dsession->lock);
860 g_mutex_unlock(dsession->write_lock);
861 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(&error));
862 smlErrorDeref(&error);
863 }
864
865 void smlDsSessionRecvChange(SmlSession *session, SmlCommand *cmd, void *userdata)
866 {
867 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, session, cmd, userdata);
868 SmlDsSession *dsession = userdata;
869
870 /* It is not necessary to lock the DsSesion object
871 * because RecvSync already enabled a global write_lock.
872 */
873 dsession->recvChanges = g_list_append(dsession->recvChanges, cmd);
874 smlCommandRef(cmd);
875
876 /* This is important for fast and consistent final signalling. */
877 dsession->emptySync = FALSE;
878
879 smlTrace(TRACE_EXIT, "%s", __func__);
880 }
881
882 void smlDsSessionRecvMap(SmlSession *session, SmlCommand *cmd, void *userdata)
883 {
884 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, session, cmd, userdata);
885 SmlDsSession *dsession = userdata;
886 SmlError *error = NULL;
887
888 g_mutex_lock(dsession->lock);
889
890 SmlStatus *reply = smlCommandNewReply(cmd, SML_NO_ERROR, &error);
891 if (!reply)
892 goto error;
893
894 if (!smlSessionSendReply(session, reply, &error))
895 goto error;
896
897 smlStatusUnref(reply);
898
899 GList *m = NULL;
900 for (m = cmd->private.map.items; m; m = m->next) {
901 SmlMapItem *item = m->data;
902
903 if (dsession->recvMappingCallback) {
904 dsession->recvMappingCallback(
905 dsession,
906 item->target,
907 item->source,
908 dsession->recvMappingCallbackUserdata);
909 } else {
910 SmlWriteContext *ctx = _write_context_find(dsession, item->target->locURI, SML_CHANGE_ADD);
911 if (ctx) {
912 ctx->newuid = g_strdup(item->source->locURI);
913 _write_context_dispatch(dsession, ctx);
914 } else {
915 smlTrace(TRACE_ERROR, "%s: Unknown map ... %s => %s",
916 __func__,
917 VA_STRING(item->target->locURI),
918 VA_STRING(item->source->locURI));
919 }
920 }
921 }
922
923 g_mutex_unlock(dsession->lock);
924
925 smlTrace(TRACE_EXIT, "%s", __func__);
926 return;
927
928 error:
929 g_mutex_unlock(dsession->lock);
930 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(&error));
931 smlErrorDeref(&error);
932 }
933
946 void smlDsSessionGetAlert(SmlDsSession *dsession, SmlDsSessionAlertCb callback, void *userdata)
947 {
948 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, dsession, callback, userdata);
949 smlAssert(dsession);
950 smlAssert(callback);
951
952 dsession->recvAlertCallback = callback;
953 dsession->recvAlertCallbackUserdata = userdata;
954
955 smlDsSessionDispatch(dsession);
956
957 smlTrace(TRACE_EXIT, "%s", __func__);
958 }
959
972 SmlBool smlDsSessionSendAlert(SmlDsSession *dsession, SmlAlertType type, const char *last, const char *next, SmlStatusReplyCb callback, void *userdata, SmlError **error)
973 {
974 smlTrace(TRACE_ENTRY, "%s(%p, %i, %s, %s, %p)", __func__, dsession, type, VA_STRING(last), VA_STRING(next), error);
975 smlAssert(dsession);
976 CHECK_ERROR_REF
977
978 SmlCommand *alert = smlCommandNewAlert(type, dsession->target, dsession->location, next, last, NULL, error);
979 if (!alert)
980 goto error;
981
982 dsession->sentAlertCallback = callback;
983 dsession->sentAlertCallbackUserdata = userdata;
984
985 if (!smlSessionSendCommand(dsession->session, alert, NULL, _alert_reply, dsession, error))
986 goto error;
987
988 smlCommandUnref(alert);
989
990 smlTrace(TRACE_EXIT, "%s", __func__);
991 return TRUE;
992
993 error:
994 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
995 return FALSE;
996 }
997
998 void smlDsSessionGetMapping(
999 SmlDsSession *dsession,
1000 SmlDsSessionMapCb mapCallback,
1001 void *userdata)
1002 {
1003 smlTrace(TRACE_ENTRY, "%s", __func__);
1004 dsession->recvMappingCallback = mapCallback;
1005 dsession->recvMappingCallbackUserdata = userdata;
1006 smlTrace(TRACE_EXIT, "%s", __func__);
1007 }
1008
1022 void smlDsSessionGetChanges(SmlDsSession *dsession, SmlDsSessionChangesCb chgCallback, void *userdata)
1023 {
1024 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, dsession, chgCallback, userdata);
1025 smlAssert(dsession);
1026 smlAssert(chgCallback);
1027
1028 dsession->changesCallback = chgCallback;
1029 dsession->changesCallbackUserdata = userdata;
1030
1031 smlDsSessionDispatch(dsession);
1032
1033 smlTrace(TRACE_EXIT, "%s", __func__);
1034 }
1035
1036 void smlDsSessionGetSync(SmlDsSession *dsession, SmlDsSessionSyncCb syncCallback, void *userdata)
1037 {
1038 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, dsession, syncCallback, userdata);
1039 smlAssert(dsession);
1040 smlAssert(syncCallback);
1041
1042 dsession->recvSyncCallback = syncCallback;
1043 dsession->recvSyncCallbackUserdata = userdata;
1044
1045 smlDsSessionDispatch(dsession);
1046
1047 smlTrace(TRACE_EXIT, "%s", __func__);
1048 }
1049
1050 void smlDsSessionGetEvent(SmlDsSession *dsession, SmlDsSessionEventCb eventCallback, void *userdata)
1051 {
1052 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, dsession, eventCallback, userdata);
1053 smlAssert(dsession);
1054 smlAssert(eventCallback);
1055
1056 dsession->recvEventCallback = eventCallback;
1057 dsession->recvEventCallbackUserdata = userdata;
1058
1059 smlDsSessionDispatch(dsession);
1060
1061 smlTrace(TRACE_EXIT, "%s", __func__);
1062 }
1063
1064
1077 SmlBool smlDsSessionSendSync(SmlDsSession *dsession, unsigned int num_changes, SmlStatusReplyCb callback, void *userdata, SmlError **error)
1078 {
1079 smlTrace(TRACE_ENTRY, "%s(%p, %i, %p, %p, %p)", __func__, dsession, num_changes, callback, userdata, error);
1080 smlAssert(dsession);
1081 CHECK_ERROR_REF
1082
1083 if (dsession->syncCommand) {
1084 smlErrorSet(error, SML_ERROR_GENERIC, "There already was a sync command started");
1085 goto error;
1086 }
1087
1088 dsession->sentSyncCallback = callback;
1089 dsession->sentSyncCallbackUserdata = userdata;
1090
1091 dsession->syncCommand = smlCommandNewSync(dsession->target, dsession->location, num_changes, error);
1092 if (!dsession->syncCommand)
1093 goto error;
1094
1095 if (!smlSessionStartCommand(dsession->session, dsession->syncCommand, NULL, _sync_reply, dsession, error))
1096 goto error;
1097
1098 smlTrace(TRACE_EXIT, "%s", __func__);
1099 return TRUE;
1100
1101 error:
1102 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
1103 return FALSE;
1104 }
1105
1106 //Send a change to the remote side
1107 SmlBool smlDsSessionQueueChange(SmlDsSession *dsession, SmlChangeType type, const char *uid, const char *data, unsigned int size, const char *contenttype, SmlDsSessionWriteCb callback, void *userdata, SmlError **error)
1108 {
1109 smlTrace(TRACE_ENTRY, "%s(%p, %i, %s, %p, %i, %s, %p, %p, %p)", __func__, dsession, type, VA_STRING(uid), data, size, VA_STRING(contenttype), callback, userdata, error);
1110 smlAssert(dsession);
1111 CHECK_ERROR_REF
1112
1113 if (!dsession->syncCommand) {
1114 smlErrorSet(error, SML_ERROR_GENERIC, "You have to start a sync command first");
1115 goto error;
1116 }
1117
1118 SmlCommand *cmd = smlCommandNewChange(type, uid, data, size, contenttype, error);
1119 if (!cmd)
1120 goto error;
1121
1122 SmlWriteContext *ctx = smlTryMalloc0(sizeof(SmlWriteContext), error);
1123 if (!ctx)
1124 goto error_free_cmd;
1125
1126 ctx->callback = callback;
1127 ctx->userdata = userdata;
1128 ctx->uid = g_strdup(uid);
1129 ctx->type = type;
1130 ctx->session = dsession;
1131
1132 g_mutex_lock(dsession->pendingMapsLock);
1133 dsession->pendingMaps = g_list_append(dsession->pendingMaps, ctx);
1134 g_mutex_unlock(dsession->pendingMapsLock);
1135
1136 if (!smlSessionSendCommand(dsession->session, cmd, dsession->syncCommand, _change_reply, ctx, error))
1137 goto error_free_ctx;
1138
1139 smlCommandUnref(cmd);
1140
1141 smlTrace(TRACE_EXIT, "%s", __func__);
1142 return TRUE;
1143
1144 error_free_ctx:
1145 smlSafeCFree(&(ctx->uid));
1146 smlSafeFree((gpointer *)&ctx);
1147 error_free_cmd:
1148 smlCommandUnref(cmd);
1149 error:
1150 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
1151 return FALSE;
1152 }
1153
1160 SmlBool smlDsSessionCloseSync(SmlDsSession *dsession, SmlError **error)
1161 {
1162 smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, dsession, error);
1163 smlAssert(dsession);
1164 CHECK_ERROR_REF
1165
1166 if (!dsession->syncCommand) {
1167 smlErrorSet(error, SML_ERROR_GENERIC, "There already was a sync command started");
1168 goto error;
1169 }
1170
1171 if (!smlSessionEndCommand(dsession->session, NULL, error))
1172 goto error;
1173
1174 smlCommandUnref(dsession->syncCommand);
1175 dsession->syncCommand = NULL;
1176
1177 smlTrace(TRACE_EXIT, "%s", __func__);
1178 return TRUE;
1179
1180 error:
1181 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
1182 return FALSE;
1183 }
1184
1185 SmlBool smlDsSessionQueueMap(SmlDsSession *dsession, const char *uid, const char *newuid, SmlError **error)
1186 {
1187 smlTrace(TRACE_ENTRY, "%s(%p, %s, %s, %p)", __func__, dsession, VA_STRING(uid), VA_STRING(newuid), error);
1188 smlAssert(dsession);
1189 CHECK_ERROR_REF
1190
1191 SmlMapItem *item = smlMapItemNew(uid, newuid, error);
1192 if (!item)
1193 goto error;
1194
1195 dsession->mapItems = g_list_append(dsession->mapItems, item);
1196
1197 smlTrace(TRACE_EXIT, "%s", __func__);
1198 return TRUE;
1199
1200 error:
1201 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
1202 return FALSE;
1203 }
1204
1214 SmlBool smlDsSessionCloseMap(SmlDsSession *dsession, SmlStatusReplyCb callback, void *userdata, SmlError **error)
1215 {
1216 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, dsession, callback, userdata, error);
1217 smlAssert(dsession);
1218 CHECK_ERROR_REF
1219
1220 if (!dsession->mapItems) {
1221 smlTrace(TRACE_EXIT, "%s: No mapitems", __func__);
1222 return TRUE;
1223 }
1224
1225 SmlCommand *cmd = smlCommandNewMap(dsession->server->target, dsession->server->location, error);
1226 if (!cmd)
1227 goto error;
1228
1229 while (dsession->mapItems) {
1230 SmlMapItem *item = dsession->mapItems->data;
1231 if (!smlCommandAddMapItem(cmd, item, error))
1232 goto error_free_cmd;
1233 smlMapItemUnref(item);
1234
1235 dsession->mapItems = g_list_remove(dsession->mapItems, item);
1236 }
1237
1238 if (!smlSessionSendCommand(dsession->session, cmd, NULL, callback, userdata, error))
1239 goto error_free_cmd;
1240
1241 smlCommandUnref(cmd);
1242
1243 smlTrace(TRACE_EXIT, "%s", __func__);
1244 return TRUE;
1245
1246 error_free_cmd:
1247 smlCommandUnref(cmd);
1248 error:
1249 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
1250 return FALSE;
1251 }
1252
1253 const char *smlDsSessionGetLocation(SmlDsSession *dsession)
1254 {
1255 smlAssert(dsession);
1256 return smlDsServerGetLocation(dsession->server);
1257 }
1258
1259 SmlDsServer *smlDsSessionGetServer(SmlDsSession *dsession)
1260 {
1261 smlAssert(dsession);
1262 return dsession->server;
1263 }
1264
1265 const char *smlDsSessionGetContentType(SmlDsSession *dsession)
1266 {
1267 smlAssert(dsession);
1268 return smlDsServerGetContentType(dsession->server);
1269 }
1270
1271 static void _recv_manager_alert(SmlSession *session, SmlCommand *cmd, void *userdata)
1272 {
1273 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, session, cmd, userdata);
1274 SmlDsServer *server = userdata;
1275 SmlError *error = NULL;
1276
1277 SmlDsSession *dsession = smlDsServerRecvAlert(server, session, cmd);
1278 if (!dsession)
1279 goto error;
1280
1281 if (!smlManagerObjectRegister(server->manager, SML_COMMAND_TYPE_SYNC, session, server->location, NULL, NULL, smlDsSessionRecvSync, smlDsSessionRecvChange, dsession, &error))
1282 goto error_free_dsession;
1283
1284 if (!smlManagerObjectRegister(server->manager, SML_COMMAND_TYPE_MAP, session, server->location, NULL, NULL, smlDsSessionRecvMap, NULL, dsession, &error))
1285 goto error_free_dsession;
1286
1287 smlTrace(TRACE_EXIT, "%s", __func__);
1288 return;
1289
1290 error_free_dsession:
1291 smlSafeFree((gpointer *)&dsession);
1292 error:
1293 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(&error));
1294 if (error)
1295 smlErrorDeref(&error);
1296 }
1297
1298 static void _recv_manager_san(SmlSession *session, SmlCommand *cmd, void *userdata)
1299 {
1300 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, session, cmd, userdata);
1301 SmlDsServer *server = userdata;
1302 SmlError *error = NULL;
1303
1304 /* ensure that the session is in client mode */
1305 session->sessionType = SML_SESSION_TYPE_CLIENT;
1306
1307 /* fix target */
1308 smlLocationUnref(server->target);
1309 server->target = cmd->source;
1310 smlLocationRef(server->target);
1311
1312 /* handle the SAN */
1313 if (server->sanSessionCallback) {
1314 SmlErrorType type = server->sanSessionCallback(
1315 server,
1316 session,
1317 cmd->private.alert.type,
1318 server->sanSessionCallbackUserdata);
1319
1320 SmlStatus *reply = smlCommandNewReply(cmd, type, &error);
1321 if (!reply)
1322 goto error;
1323
1324 if (!smlSessionSendReply(session, reply, &error))
1325 goto error;
1326
1327 smlStatusUnref(reply);
1328 } else if (server->sanCallback) {
1329 SmlErrorType type = server->sanCallback(server, cmd->private.alert.type, server->sanCallbackUserdata);
1330
1331 SmlStatus *reply = smlCommandNewReply(cmd, type, &error);
1332 if (!reply)
1333 goto error;
1334
1335 if (!smlSessionSendReply(session, reply, &error))
1336 goto error;
1337
1338 smlStatusUnref(reply);
1339 } else {
1340 smlTrace(TRACE_INTERNAL, "%s: SAN ignored", __func__);
1341
1342 SmlStatus *reply = smlCommandNewReply(cmd, SML_ERROR_NOT_IMPLEMENTED, &error);
1343 if (!reply)
1344 goto error;
1345
1346 if (!smlSessionSendReply(session, reply, &error))
1347 goto error;
1348
1349 smlStatusUnref(reply);
1350 }
1351
1352 smlTrace(TRACE_EXIT, "%s", __func__);
1353 return;
1354
1355 error:
1356 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(&error));
1357 if (error)
1358 smlErrorDeref(&error);
1359 }
1360
1361 SmlBool smlDsServerRegister(SmlDsServer *server, SmlManager *manager, SmlError **error)
1362 {
1363 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, server, manager, error);
1364 smlAssert(server);
1365 smlAssert(manager);
1366 CHECK_ERROR_REF
1367
1368 if (!smlManagerObjectRegister(manager, SML_COMMAND_TYPE_ALERT, NULL, server->location, NULL, NULL, _recv_manager_alert, NULL, server, error))
1369 goto error;
1370
1371 if (!smlManagerObjectRegister(manager, SML_COMMAND_TYPE_ALERT, NULL, NULL, NULL,server->contenttype, _recv_manager_san, NULL, server, error))
1372 goto error;
1373
1374 server->manager = manager;
1375
1376 smlTrace(TRACE_EXIT, "%s", __func__);
1377 return TRUE;
1378
1379 error:
1380 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
1381 return FALSE;
1382 }
1383
1384 SmlLocation *smlDsSessionGetTarget(SmlDsSession *dsession)
1385 {
1386 smlAssert(dsession);
1387 return dsession->target;
1388 }
1389