libsyncml 0.5.4

- Main Page
- Modules
- Data Structures
- Files

- File List

data_sync_server.c
1 /*
2 * libsyncml - A syncml protocol implementation
3 * Copyright (C) 2008-2009 Michael Bell <michael.bell@opensync.org>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21 #include "data_sync_server.h"
22 #include "data_sync_common.h"
23 #include "libsyncml/sml_error_internals.h"
24 #include "data_sync_callbacks.h"
25 #include "libsyncml/objects/sml_ds_server.h"
26 #include "data_sync_devinf.h"
27 #include "libsyncml/sml_support.h"
28
29 static SmlBool smlDataSyncServerAlertCallback(
30 SmlDsSession *dsession,
31 SmlAlertType recvType,
32 const char *last,
33 const char *next,
34 void *userdata)
35 {
36 smlTrace(TRACE_ENTRY, "%s(%p, %i, %s, %s, %p)", __func__, dsession, recvType, VA_STRING(last), VA_STRING(next), userdata);
37
38 SmlDataSyncDatastore *datastore = userdata;
39 SmlDataSyncObject *dsObject = datastore->dsObject;
40 SmlBool ret = TRUE;
41 SmlError *error = NULL;
42 SmlAlertType sentType = recvType;
43
44 /* libsyncml only supports SML_ALERT_TWO_WAY and SML_ALERT_SLOW_SYNC
45 * but some old phones reply on a SAN alert 206 with a slow sync 201
46 * alert or a SAN alert 206 (insteed of a normal two way alert 200).
47 * Therefore it is necessary to check for TWO_WAY and TWO_WAY_BY_SERVER.
48 */
49
50 if (recvType != SML_ALERT_TWO_WAY &&
51 recvType != SML_ALERT_SLOW_SYNC &&
52 recvType != SML_ALERT_TWO_WAY_BY_SERVER)
53 {
54 smlErrorSet(&error, SML_ERROR_NOT_IMPLEMENTED, "Unsupported alert type %d.", recvType);
55 goto error;
56 }
57
58 char *remote_key = g_strdup_printf("remoteanchor%s", smlDsSessionGetLocation(dsession));
59 datastore->remoteNext = g_strdup(next);
60
61 /* We return FALSE if we need a special return code as answer:
62 * SML_ERROR_REQUIRE_REFRESH 508
63 * This return code enforces a SLOW-SYNC.
64 */
65 if (recvType == SML_ALERT_TWO_WAY || recvType == SML_ALERT_TWO_WAY_BY_SERVER)
66 {
67 if (!last)
68 {
69 smlTrace(TRACE_INTERNAL, "%s: TWO-WAY-SYNC but last is missing", __func__);
70 sentType = SML_ALERT_SLOW_SYNC;
71 ret = FALSE;
72 } else {
73 char *cached = NULL;
74 if (dsObject->getAnchorCallback)
75 cached = dsObject->getAnchorCallback(
76 dsObject,
77 remote_key,
78 dsObject->getAnchorUserdata,
79 &error);
80 if (!cached && error)
81 goto error;
82 if (!cached || strcmp(cached, last))
83 {
84 smlTrace(TRACE_INTERNAL,
85 "%s: TWO-WAY-SYNC but received LAST(%s) and cached LAST (%s) mismatch",
86 __func__, VA_STRING(last), VA_STRING(cached));
87 if (cached)
88 smlSafeCFree(&cached);
89 sentType = SML_ALERT_SLOW_SYNC;
90 ret = FALSE;
91 }
92 }
93 }
94
95 if (dsObject->getAlertTypeCallback)
96 {
97 SmlAlertType alertType;
98 alertType = dsObject->getAlertTypeCallback(
99 dsObject,
100 datastore->sourceUri,
101 sentType,
102 dsObject->getAlertTypeUserdata,
103 &error);
104 if (alertType == SML_ALERT_UNKNOWN || error)
105 goto error;
106 if (alertType == SML_ALERT_SLOW_SYNC &&
107 alertType != recvType)
108 ret = FALSE; /* REQUIRE REFRESH */
109 sentType = alertType;
110 }
111
112 smlSafeCFree(&remote_key);
113
114 /* If the getAnchorCallback and the getAlertTypeCallback
115 * return inconsistent data then this must be detected here.
116 * Inconsistent means that for example status 508 and alert
117 * type 200 are used together which is illegal.
118 */
119 if (
120 ( /* alert 200 => alert 200 + status 508 */
121 recvType != SML_ALERT_SLOW_SYNC &&
122 sentType != SML_ALERT_SLOW_SYNC &&
123 ret == FALSE
124 ) ||
125 ( /* alert 200 => alert 201 + status 200 */
126 recvType != SML_ALERT_SLOW_SYNC &&
127 sentType == SML_ALERT_SLOW_SYNC &&
128 ret != FALSE
129 ) ||
130 ( /* alert 201 => alert 200 */
131 recvType == SML_ALERT_SLOW_SYNC &&
132 sentType != SML_ALERT_SLOW_SYNC
133 ) ||
134 ( /* alert 201 => alert 201 + status 508 */
135 recvType == SML_ALERT_SLOW_SYNC &&
136 sentType == SML_ALERT_SLOW_SYNC &&
137 ret == FALSE
138 )
139 )
140 {
141 if (ret) {
142 smlErrorSet(&error, SML_ERROR_GENERIC,
143 "The library user tries to respond an alert %d " \
144 "with an alert %d and status 200 which is illegal.",
145 recvType, sentType);
146 } else {
147 smlErrorSet(&error, SML_ERROR_GENERIC,
148 "The library user tries to respond an alert %d " \
149 "with an alert %d and status 508 which is illegal.",
150 recvType, sentType);
151 }
152 goto error;
153 }
154
155 /* generate new timestamp for local anchors */
156 char *local_key = g_strdup_printf("localanchor%s", smlDsSessionGetLocation(dsession));
157 char *local_last = NULL;
158 if (dsObject->getAnchorCallback)
159 local_last = dsObject->getAnchorCallback(
160 dsObject,
161 local_key,
162 dsObject->getAnchorUserdata,
163 &error);
164 if (!local_last && error)
165 goto error;
166 if (datastore->localNext)
167 smlSafeCFree(&(datastore->localNext));
168 if (local_last == NULL || strlen(local_last) == 0)
169 {
170 /* this is the first sync
171 * let's respect the remote's anchor style
172 */
173 if (smlDataSyncIsTimestamp(next, dsObject->useTimestampAnchor) != dsObject->useTimestampAnchor)
174 {
175 /* Many users are confused by warnings which can be ignored.
176 * Therefore the issue is only traced.
177 */
178 smlTrace(TRACE_INTERNAL,
179 "%s: libsyncml uses different timestamp anchor modes.",
180 __func__);
181 }
182 }
183 datastore->localNext = smlDataSyncGetNextAnchor(datastore, local_last, &error);
184 if (!datastore->localNext)
185 goto error;
186
187 /* send alert */
188 if (!smlDsSessionSendAlert(
189 dsession, sentType,
190 local_last, datastore->localNext,
191 smlDataSyncAlertStatusCallback,
192 datastore, &error))
193 goto error;
194
195 /* free local anchor stuff */
196 smlSafeCFree(&local_key);
197 if (local_last)
198 smlSafeCFree(&local_last);
199
200 smlTrace(TRACE_EXIT, "%s: %i", __func__, ret);
201 return ret;
202 error:
203 smlErrorRef(&error);
204 smlDataSyncSendEvent(
205 dsObject, SML_DATA_SYNC_EVENT_ERROR,
206 dsObject->eventUserdata, error);
207 smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(&error));
208 smlErrorDeref(&error);
209 return FALSE;
210 }
211
212 SmlBool smlDataSyncServerInit(SmlDataSyncObject *dsObject, SmlError **error)
213 {
214 CHECK_ERROR_REF
215 /* The manager responsible for handling the other objects */
216 dsObject->manager = smlManagerNew(dsObject->tsp, error);
217 if (!dsObject->manager)
218 goto error;
219 smlManagerSetEventCallback(dsObject->manager, smlDataSyncEventCallback, dsObject);
220 smlManagerSetLocalMaxMsgSize(dsObject->manager, dsObject->maxMsgSize);
221 smlManagerSetLocalMaxObjSize(dsObject->manager, dsObject->maxObjSize);
222
223 /* set server specific callbacks */
224 dsObject->funcDatastoreAlert = smlDataSyncServerAlertCallback;
225
226 /* The authenticator */
227 dsObject->auth = smlAuthNew(error);
228 if (!dsObject->auth)
229 goto error;
230 smlAuthSetVerifyCallback(dsObject->auth, smlDataSyncVerifyUserCallback, dsObject);
231 if (!dsObject->username) {
232 smlAuthSetEnable(dsObject->auth, FALSE);
233 } else {
234 smlAuthSetEnable(dsObject->auth, TRUE);
235 smlAuthSetType(dsObject->auth, dsObject->authType);
236 }
237 if (!smlAuthRegister(dsObject->auth, dsObject->manager, error))
238 goto error;
239
240 /* prepare device info */
241 if (!smlDataSyncDevInfInit(dsObject, SML_DEVINF_DEVTYPE_SERVER, error))
242 goto error;
243
244 /* prepare datastore server */
245 GList *o = dsObject->datastores;
246 for (; o; o = o->next) {
247 SmlDataSyncDatastore *datastore = o->data;
248
249 /* We now create the ds server hat the given location */
250 SmlLocation *loc = smlLocationNew(datastore->sourceUri, NULL, error);
251 if (!loc)
252 goto error;
253
254 datastore->server = smlDsServerNew(datastore->contentType, loc, error);
255 if (!datastore->server) {
256 smlLocationUnref(loc);
257 goto error;
258 }
259 smlLocationUnref(loc);
260
261 if (!smlDsServerRegister(datastore->server, dsObject->manager, error))
262 goto error;
263
264 smlDsServerSetConnectCallback(
265 datastore->server,
266 smlDataSyncDatastoreConnectCallback,
267 datastore);
268
269 /* And we also add the devinfo to the devinf agent */
270 if (!smlDataSyncDevInfAddDatastore(dsObject->localDevInf, datastore, error))
271 goto error;
272 }
273
274 /* Run the manager */
275 if (!smlManagerStart(dsObject->manager, error))
276 goto error;
277
278 /* Initialize the Transport */
279 if (!smlTransportInitialize(dsObject->tsp, error))
280 goto error;
281
282 smlTrace(TRACE_EXIT, "%s - TRUE", __func__);
283 return TRUE;
284
285 error:
286 smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
287 return FALSE;
288 }
289