libsyncml  0.5.4
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 */
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 
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 
This object represents an OMA DS datastore.
Definition: data_sync.h:93
const char * smlErrorPrint(SmlError **error)
Returns the message of the error.
Definition: sml_error.c:299
This is the central synchronization object.
Definition: data_sync.h:110
SmlBool smlDsSessionSendAlert(SmlDsSession *dsession, SmlAlertType type, const char *last, const char *next, SmlStatusReplyCb callback, void *userdata, SmlError **error)
Sends the alert to the remote side.
void smlDsServerSetConnectCallback(SmlDsServer *server, SmlDsSessionConnectCb callback, void *userdata)
Registers a callback that will get called once a client connects.
SmlBool smlTransportInitialize(SmlTransport *tsp, SmlError **error)
Initializes the transport with the given config.
void smlTrace(SmlTraceType type, const char *message,...)
Used for tracing the application.
Definition: sml_support.c:120
void smlErrorSet(SmlError **error, SmlErrorType type, const char *format,...)
Sets the error.
Definition: sml_error.c:355
Represent an error.