File: | libsynthesis/src/sysync/syncagent.cpp |
Warning: | line 2548, column 9 Access to field 'source' results in a dereference of a null pointer (loaded from field 'mapItem') |
1 | /* | |||||||
2 | * File: syncagent.cpp | |||||||
3 | * | |||||||
4 | * Author: Lukas Zeller (luz@plan44.ch) | |||||||
5 | * | |||||||
6 | * TSyncAgent: Provides functionality to run client or server | |||||||
7 | * sessions. | |||||||
8 | * Unifies former TSyncClient and TSyncServer | |||||||
9 | * | |||||||
10 | * Copyright (c) 2002-2011 by Synthesis AG + plan44.ch | |||||||
11 | * | |||||||
12 | * 2009-09-30 : luz : created from syncclient.cpp and syncserver.cpp | |||||||
13 | * | |||||||
14 | */ | |||||||
15 | ||||||||
16 | ||||||||
17 | // includes | |||||||
18 | #include "prefix_file.h" | |||||||
19 | #include "sysync.h" | |||||||
20 | #include "syncagent.h" | |||||||
21 | #include "syncappbase.h" | |||||||
22 | ||||||||
23 | #ifdef HARD_CODED_SERVER_URI | |||||||
24 | #include "syserial.h" | |||||||
25 | #endif | |||||||
26 | ||||||||
27 | // includes that can't be in .h due to circular references | |||||||
28 | #ifdef SYSYNC_SERVER1 | |||||||
29 | #include "syncsessiondispatch.h" | |||||||
30 | #endif | |||||||
31 | #ifdef SYSYNC_CLIENT1 | |||||||
32 | #include "syncclientbase.h" | |||||||
33 | #endif | |||||||
34 | ||||||||
35 | #ifdef SYSYNC_TOOL | |||||||
36 | #include <errno(*__errno_location ()).h> | |||||||
37 | #endif | |||||||
38 | ||||||||
39 | ||||||||
40 | namespace sysync { | |||||||
41 | ||||||||
42 | ||||||||
43 | #ifdef SYSYNC_TOOL | |||||||
44 | ||||||||
45 | // Support for SySync Diagnostic Tool | |||||||
46 | // ================================== | |||||||
47 | ||||||||
48 | ||||||||
49 | // test login into database | |||||||
50 | int testLogin(int argc, const char *argv[]) | |||||||
51 | { | |||||||
52 | if (argc<0) { | |||||||
53 | // help requested | |||||||
54 | CONSOLEPRINTF((" login [<username> <password>] [<deviceid>]"))SySync_ConsolePrintf(stderr, "SYSYNC " " login [<username> <password>] [<deviceid>]" "\n"); | |||||||
55 | CONSOLEPRINTF((" test login to database with syncml user/password and optional deviceid"))SySync_ConsolePrintf(stderr, "SYSYNC " " test login to database with syncml user/password and optional deviceid" "\n"); | |||||||
56 | return EXIT_SUCCESS0; | |||||||
57 | } | |||||||
58 | ||||||||
59 | TSyncSession *sessionP = NULL__null; | |||||||
60 | const char *username = NULL__null; | |||||||
61 | const char *password = NULL__null; | |||||||
62 | const char *deviceid = "sysytool_test"; | |||||||
63 | ||||||||
64 | // check for argument | |||||||
65 | if (argc<2) { | |||||||
66 | // no user/password, test anonymous login | |||||||
67 | if (argc>0) deviceid = argv[0]; | |||||||
68 | } | |||||||
69 | else { | |||||||
70 | // login with user/password | |||||||
71 | username = argv[0]; | |||||||
72 | password = argv[1]; | |||||||
73 | if (argc>2) { | |||||||
74 | // explicit device ID | |||||||
75 | deviceid = argv[2]; | |||||||
76 | } | |||||||
77 | } | |||||||
78 | ||||||||
79 | // get session to work with | |||||||
80 | sessionP = | |||||||
81 | static_cast<TSyncSessionDispatch *>(getSyncAppBase())->getSySyToolSession(); | |||||||
82 | ||||||||
83 | bool authok = false; | |||||||
84 | ||||||||
85 | // try login | |||||||
86 | if (username) { | |||||||
87 | // real login with user and password | |||||||
88 | authok = sessionP->SessionLogin(username, password, sectyp_clearpass, deviceid); | |||||||
89 | } | |||||||
90 | else { | |||||||
91 | // anonymous - do a "login" with empty credentials | |||||||
92 | authok = sessionP->SessionLogin("anonymous", NULL__null, sectyp_anonymous, deviceid); | |||||||
93 | } | |||||||
94 | ||||||||
95 | if (authok) { | |||||||
96 | CONSOLEPRINTF(("+++++ Successfully authorized"))SySync_ConsolePrintf(stderr, "SYSYNC " "+++++ Successfully authorized" "\n"); | |||||||
97 | } | |||||||
98 | else { | |||||||
99 | CONSOLEPRINTF(("----- Authorisation failed"))SySync_ConsolePrintf(stderr, "SYSYNC " "----- Authorisation failed" "\n"); | |||||||
100 | } | |||||||
101 | ||||||||
102 | return authok; | |||||||
103 | } // testLogin | |||||||
104 | ||||||||
105 | ||||||||
106 | // convert user data into internal format and back | |||||||
107 | int convertData(int argc, const char *argv[]) | |||||||
108 | { | |||||||
109 | if (argc<0) { | |||||||
110 | // help requested | |||||||
111 | CONSOLEPRINTF((" convert <datastore name> <data file, vcard or vcalendar etc.> [<explicit input type>] [<output type>]"))SySync_ConsolePrintf(stderr, "SYSYNC " " convert <datastore name> <data file, vcard or vcalendar etc.> [<explicit input type>] [<output type>]" "\n"); | |||||||
112 | CONSOLEPRINTF((" Convert data to internal format of specified datastore and back"))SySync_ConsolePrintf(stderr, "SYSYNC " " Convert data to internal format of specified datastore and back" "\n"); | |||||||
113 | return EXIT_SUCCESS0; | |||||||
114 | } | |||||||
115 | ||||||||
116 | TSyncSession *sessionP = NULL__null; | |||||||
117 | const char *datastore = NULL__null; | |||||||
118 | const char *rawfilename = NULL__null; | |||||||
119 | const char *inputtype = NULL__null; | |||||||
120 | const char *outputtype = NULL__null; | |||||||
121 | ||||||||
122 | // check for argument | |||||||
123 | if (argc<2) { | |||||||
124 | CONSOLEPRINTF(("required datatype name and raw file name arguments"))SySync_ConsolePrintf(stderr, "SYSYNC " "required datatype name and raw file name arguments" "\n"); | |||||||
125 | return EXIT_FAILURE1; | |||||||
126 | } | |||||||
127 | datastore = argv[0]; | |||||||
128 | rawfilename = argv[1]; | |||||||
129 | if (argc>=3) { | |||||||
130 | // third arg is explicit input type | |||||||
131 | inputtype=argv[2]; | |||||||
132 | } | |||||||
133 | outputtype=inputtype; // default to input type | |||||||
134 | if (argc>=4) { | |||||||
135 | // fourth arg is explicit output type | |||||||
136 | outputtype=argv[3]; | |||||||
137 | } | |||||||
138 | ||||||||
139 | // get session to work with | |||||||
140 | sessionP = | |||||||
141 | static_cast<TSyncSessionDispatch *>(getSyncAppBase())->getSySyToolSession(); | |||||||
142 | // configure session | |||||||
143 | sessionP->fRemoteCanHandleUTC = true; // run generator and parser in UTC enabled mode | |||||||
144 | ||||||||
145 | ||||||||
146 | // switch mimimal debugging on | |||||||
147 | sessionP->getDbgLogger()->setMask(sessionP->getDbgLogger()->getMask() | (DBG_PARSE0x00000200+DBG_GEN0x00000400)); | |||||||
148 | ||||||||
149 | // find datastore | |||||||
150 | TLocalEngineDS *datastoreP = sessionP->findLocalDataStore(datastore); | |||||||
151 | TSyncItemType *inputtypeP = NULL__null; | |||||||
152 | TSyncItemType *outputtypeP = NULL__null; | |||||||
153 | if (!datastoreP) { | |||||||
154 | CONSOLEPRINTF(("datastore type '%s' not found",datastore))SySync_ConsolePrintf(stderr, "SYSYNC " "datastore type '%s' not found" "\n",datastore); | |||||||
155 | return EXIT_FAILURE1; | |||||||
156 | } | |||||||
157 | ||||||||
158 | // find input type | |||||||
159 | if (inputtype) { | |||||||
160 | // search in datastore | |||||||
161 | inputtypeP=datastoreP->getReceiveType(inputtype,NULL__null); | |||||||
162 | } | |||||||
163 | else { | |||||||
164 | // use preferred rx type | |||||||
165 | inputtypeP=datastoreP->getPreferredRxItemType(); | |||||||
166 | } | |||||||
167 | if (!inputtypeP) { | |||||||
168 | CONSOLEPRINTF(("input type not found"))SySync_ConsolePrintf(stderr, "SYSYNC " "input type not found" "\n"); | |||||||
169 | return EXIT_FAILURE1; | |||||||
170 | } | |||||||
171 | // find output type | |||||||
172 | if (outputtype) { | |||||||
173 | // search in datastore | |||||||
174 | outputtypeP=datastoreP->getSendType(outputtype,NULL__null); | |||||||
175 | } | |||||||
176 | else { | |||||||
177 | // use preferred rx type | |||||||
178 | outputtypeP=datastoreP->getPreferredTxItemType(); | |||||||
179 | } | |||||||
180 | if (!outputtypeP) { | |||||||
181 | CONSOLEPRINTF(("output type not found"))SySync_ConsolePrintf(stderr, "SYSYNC " "output type not found" "\n"); | |||||||
182 | return EXIT_FAILURE1; | |||||||
183 | } | |||||||
184 | // prepare type usage | |||||||
185 | if (inputtypeP==outputtypeP) | |||||||
186 | inputtypeP->initDataTypeUse(datastoreP, true, true); | |||||||
187 | else { | |||||||
188 | inputtypeP->initDataTypeUse(datastoreP, false, true); | |||||||
189 | outputtypeP->initDataTypeUse(datastoreP, true, false); | |||||||
190 | } | |||||||
191 | ||||||||
192 | // now open file and read data item | |||||||
193 | FILE *infile; | |||||||
194 | size_t insize=0; | |||||||
195 | uInt8 *databuffer; | |||||||
196 | ||||||||
197 | infile = fopen(rawfilename,"rb"); | |||||||
198 | if (!infile) { | |||||||
199 | CONSOLEPRINTF(("Cannot open input file '%s' (%d)",rawfilename,errno))SySync_ConsolePrintf(stderr, "SYSYNC " "Cannot open input file '%s' (%d)" "\n",rawfilename,(*__errno_location ())); | |||||||
200 | return EXIT_FAILURE1; | |||||||
201 | } | |||||||
202 | // - get size of file | |||||||
203 | fseek(infile,0,SEEK_END2); | |||||||
204 | insize=ftell(infile); | |||||||
205 | fseek(infile,0,SEEK_SET0); | |||||||
206 | // - create buffer of appropriate size | |||||||
207 | databuffer = new uInt8[insize]; | |||||||
208 | if (!databuffer) { | |||||||
209 | CONSOLEPRINTF(("Not enough memory to read input file '%s' (%d)",rawfilename,errno))SySync_ConsolePrintf(stderr, "SYSYNC " "Not enough memory to read input file '%s' (%d)" "\n",rawfilename,(*__errno_location ())); | |||||||
210 | return EXIT_FAILURE1; | |||||||
211 | } | |||||||
212 | // - read data | |||||||
213 | if (fread(databuffer,1,insize,infile)<insize) { | |||||||
214 | CONSOLEPRINTF(("Error reading input file '%s' (%d)",rawfilename,errno))SySync_ConsolePrintf(stderr, "SYSYNC " "Error reading input file '%s' (%d)" "\n",rawfilename,(*__errno_location ())); | |||||||
215 | return EXIT_FAILURE1; | |||||||
216 | } | |||||||
217 | CONSOLEPRINTF(("\nNow converting into internal field representation\n"))SySync_ConsolePrintf(stderr, "SYSYNC " "\nNow converting into internal field representation\n" "\n"); | |||||||
218 | // create a sml item | |||||||
219 | TStatusCommand statusCmd(sessionP); | |||||||
220 | SmlItemPtr_t smlitemP = newItem(); | |||||||
221 | smlitemP->data=newPCDataStringX(databuffer,true,insize); | |||||||
222 | delete[] databuffer; | |||||||
223 | // create and fill a Sync item | |||||||
224 | TSyncItem *syncitemP = inputtypeP->newSyncItem( | |||||||
225 | smlitemP, // SyncML toolkit item Data to be converted into SyncItem | |||||||
226 | sop_replace, // the operation to be performed with this item | |||||||
227 | fmt_chr, // assume default (char) format | |||||||
228 | inputtypeP, // target myself | |||||||
229 | datastoreP, // local datastore | |||||||
230 | statusCmd // status command that might be modified in case of error | |||||||
231 | ); | |||||||
232 | // forget SyncML version | |||||||
233 | smlFreeItemPtr(smlitemP); | |||||||
234 | if (!syncitemP) { | |||||||
235 | CONSOLEPRINTF(("Error converting input file to internal format (SyncML status code=%hd)",statusCmd.getStatusCode()))SySync_ConsolePrintf(stderr, "SYSYNC " "Error converting input file to internal format (SyncML status code=%hd)" "\n",statusCmd.getStatusCode()); | |||||||
236 | return EXIT_FAILURE1; | |||||||
237 | } | |||||||
238 | ||||||||
239 | CONSOLEPRINTF(("\nNow copying item and convert back to transport format\n"))SySync_ConsolePrintf(stderr, "SYSYNC " "\nNow copying item and convert back to transport format\n" "\n"); | |||||||
240 | ||||||||
241 | // make new for output type | |||||||
242 | TSyncItem *outsyncitemP = outputtypeP->newSyncItem( | |||||||
243 | outputtypeP, // target myself | |||||||
244 | datastoreP // local datastore | |||||||
245 | ); | |||||||
246 | // copy data | |||||||
247 | outsyncitemP->replaceDataFrom(*syncitemP); | |||||||
248 | delete syncitemP; | |||||||
249 | // convert back | |||||||
250 | smlitemP=outputtypeP->newSmlItem( | |||||||
251 | outsyncitemP, // the syncitem to be represented as SyncML | |||||||
252 | datastoreP // local datastore | |||||||
253 | ); | |||||||
254 | if (!syncitemP) { | |||||||
255 | CONSOLEPRINTF(("Could not convert back item data"))SySync_ConsolePrintf(stderr, "SYSYNC " "Could not convert back item data" "\n"); | |||||||
256 | return EXIT_FAILURE1; | |||||||
257 | } | |||||||
258 | ||||||||
259 | // forget converted back item | |||||||
260 | smlFreeItemPtr(smlitemP); | |||||||
261 | ||||||||
262 | return EXIT_SUCCESS0; | |||||||
263 | } // convertData | |||||||
264 | ||||||||
265 | #endif // SYSYNC_TOOL | |||||||
266 | ||||||||
267 | ||||||||
268 | ||||||||
269 | ||||||||
270 | #ifdef PRECONFIGURED_SYNCREQUESTS | |||||||
271 | ||||||||
272 | // Implementation of TSyncReqConfig | |||||||
273 | // ================================ | |||||||
274 | ||||||||
275 | // config for databases to sync with | |||||||
276 | TSyncReqConfig::TSyncReqConfig(TLocalDSConfig *aLocalDSCfg, TConfigElement *aParentElement) : | |||||||
277 | TConfigElement("syncrequest",aParentElement), | |||||||
278 | fLocalDSConfig(aLocalDSCfg) | |||||||
279 | { | |||||||
280 | clear(); | |||||||
281 | } // TSyncReqConfig::TSyncReqConfig | |||||||
282 | ||||||||
283 | ||||||||
284 | TSyncReqConfig::~TSyncReqConfig() | |||||||
285 | { | |||||||
286 | // nop so far | |||||||
287 | } // TSyncReqConfig::~TSyncReqConfig | |||||||
288 | ||||||||
289 | ||||||||
290 | // init defaults | |||||||
291 | void TSyncReqConfig::clear(void) | |||||||
292 | { | |||||||
293 | // init defaults | |||||||
294 | // - local client datatstore subselection path or CGI (such as "test" in "contact/test") | |||||||
295 | fLocalPathExtension.erase(); | |||||||
296 | // - remote server DB layer auth | |||||||
297 | fDBUser.erase(); | |||||||
298 | fDBPassword.erase(); | |||||||
299 | // - remote server datastore path | |||||||
300 | fServerDBPath.erase(); | |||||||
301 | // - sync mode | |||||||
302 | fSyncMode=smo_twoway; | |||||||
303 | fSlowSync=false; // default to non-slow | |||||||
304 | // - DS 1.2 filtering parameters | |||||||
305 | fRecordFilterQuery.erase(); | |||||||
306 | fFilterInclusive=false; | |||||||
307 | // clear inherited | |||||||
308 | inherited::clear(); | |||||||
309 | } // TSyncReqConfig::clear | |||||||
310 | ||||||||
311 | ||||||||
312 | // config element parsing | |||||||
313 | bool TSyncReqConfig::localStartElement(const char *aElementName, const char **aAttributes, sInt32 aLine) | |||||||
314 | { | |||||||
315 | // checking the elements | |||||||
316 | if (strucmp(aElementName,"localpathextension")==0) | |||||||
317 | expectString(fLocalPathExtension); | |||||||
318 | else if (strucmp(aElementName,"dbuser")==0) | |||||||
319 | expectString(fDBUser); | |||||||
320 | else if (strucmp(aElementName,"dbpassword")==0) | |||||||
321 | expectString(fDBPassword); | |||||||
322 | else if (strucmp(aElementName,"dbpath")==0) | |||||||
323 | expectString(fServerDBPath); | |||||||
324 | else if (strucmp(aElementName,"syncmode")==0) | |||||||
325 | expectEnum(sizeof(fSyncMode),&fSyncMode,SyncModeNames,numSyncModes); | |||||||
326 | else if (strucmp(aElementName,"slowsync")==0) | |||||||
327 | expectBool(fSlowSync); | |||||||
328 | else if (strucmp(aElementName,"recordfilter")==0) | |||||||
329 | expectString(fRecordFilterQuery); | |||||||
330 | else if (strucmp(aElementName,"filterinclusive")==0) | |||||||
331 | expectBool(fFilterInclusive); | |||||||
332 | ||||||||
333 | // - none known here | |||||||
334 | else | |||||||
335 | return inherited::localStartElement(aElementName,aAttributes,aLine); | |||||||
336 | // ok | |||||||
337 | return true; | |||||||
338 | } // TSyncReqConfig::localStartElement | |||||||
339 | ||||||||
340 | ||||||||
341 | // resolve | |||||||
342 | void TSyncReqConfig::localResolve(bool aLastPass) | |||||||
343 | { | |||||||
344 | if (aLastPass) { | |||||||
345 | // check for required settings | |||||||
346 | // %%% tbd | |||||||
347 | } | |||||||
348 | // resolve inherited | |||||||
349 | inherited::localResolve(aLastPass); | |||||||
350 | } // TSyncReqConfig::localResolve | |||||||
351 | ||||||||
352 | ||||||||
353 | // create appropriate type of local datastore from config and init sync parameters | |||||||
354 | TLocalEngineDS *TSyncReqConfig::initNewLocalDataStore(TSyncSession *aSessionP) | |||||||
355 | { | |||||||
356 | // - create appropriate type of localdsP | |||||||
357 | TLocalEngineDS *localdsP = fLocalDSConfig->newLocalDataStore(aSessionP); | |||||||
358 | // - set parameters | |||||||
359 | localdsP->dsSetClientSyncParams( | |||||||
360 | fSyncMode, | |||||||
361 | fSlowSync, | |||||||
362 | fServerDBPath.c_str(), | |||||||
363 | fDBUser.c_str(), | |||||||
364 | fDBPassword.c_str(), | |||||||
365 | fLocalPathExtension.c_str(), | |||||||
366 | fRecordFilterQuery.c_str(), | |||||||
367 | fFilterInclusive | |||||||
368 | ); | |||||||
369 | return localdsP; | |||||||
370 | } // TSyncReqConfig::initNewLocalDataStore | |||||||
371 | ||||||||
372 | #endif // PRECONFIGURED_SYNCREQUESTS | |||||||
373 | ||||||||
374 | ||||||||
375 | // Implementation of TAgentConfig | |||||||
376 | // ============================== | |||||||
377 | ||||||||
378 | ||||||||
379 | TAgentConfig::TAgentConfig(const char* aName, TConfigElement *aParentElement) : | |||||||
380 | inherited(aName,aParentElement) | |||||||
381 | { | |||||||
382 | clear(); | |||||||
383 | } // TAgentConfig::TAgentConfig | |||||||
384 | ||||||||
385 | ||||||||
386 | TAgentConfig::~TAgentConfig() | |||||||
387 | { | |||||||
388 | clear(); | |||||||
389 | } // TAgentConfig::~TAgentConfig | |||||||
390 | ||||||||
391 | ||||||||
392 | // init defaults | |||||||
393 | void TAgentConfig::clear(void) | |||||||
394 | { | |||||||
395 | // clear inherited | |||||||
396 | inherited::clear(); | |||||||
397 | // Note: we always clear both client and server fields - even if we'll only use one set later | |||||||
398 | #ifdef SYSYNC_CLIENT1 | |||||||
399 | // init client auth defaults (note that these MUST correspond with the defaults set by loadRemoteParams() !!! | |||||||
400 | fAssumedServerAuth=auth_none; // start with no auth | |||||||
401 | fAssumedServerAuthEnc=fmt_chr; // start with char encoding | |||||||
402 | fAssumedNonce.erase(); // start with no nonce | |||||||
403 | fPreferSlowSync=true; | |||||||
404 | // auth retry options (mainly for stupid servers like SCTS) | |||||||
405 | #ifdef SCTS_COMPATIBILITY_HACKS | |||||||
406 | fNewSessionForAuthRetry=false; | |||||||
407 | fNoRespURIForAuthRetry=false; | |||||||
408 | #else | |||||||
409 | fNewSessionForAuthRetry=true; // all production Synthesis clients had it hardcoded (ifdeffed) this way until 2.9.8.7 | |||||||
410 | fNoRespURIForAuthRetry=true; // all production Synthesis clients had it hardcoded (ifdeffed) this way until 2.9.8.7 | |||||||
411 | #endif | |||||||
412 | fSmartAuthRetry=true; // try to be smart and try different auth retry (different from fNewSessionForAuthRetry/fNoRespURIForAuthRetry) if first attempts fail | |||||||
413 | // other defaults | |||||||
414 | fPutDevInfAtSlowSync=true; // smartner server needs it, and it does not harm so we have it on by default | |||||||
415 | #ifndef NO_LOCAL_DBLOGIN1 | |||||||
416 | fLocalDBUser.erase(); | |||||||
417 | fLocalDBPassword.erase(); | |||||||
418 | fNoLocalDBLogin=false; | |||||||
419 | #endif | |||||||
420 | #ifdef PRECONFIGURED_SYNCREQUESTS | |||||||
421 | fEncoding=SML_XML; // default to more readable XML | |||||||
422 | fServerUser.erase(); | |||||||
423 | fServerPassword.erase(); | |||||||
424 | fServerURI.erase(); | |||||||
425 | fTransportUser.erase(); | |||||||
426 | fTransportPassword.erase(); | |||||||
427 | fSocksHost.erase(); | |||||||
428 | fProxyHost.erase(); | |||||||
429 | fProxyUser.erase(); | |||||||
430 | fProxyPassword.erase(); | |||||||
431 | // remove sync db specifications | |||||||
432 | TSyncReqList::iterator pos; | |||||||
433 | for(pos=fSyncRequests.begin();pos!=fSyncRequests.end();pos++) | |||||||
434 | delete *pos; | |||||||
435 | fSyncRequests.clear(); | |||||||
436 | #endif | |||||||
437 | // clear inherited | |||||||
438 | inherited::clear(); | |||||||
439 | // modify timeout after inherited sets it | |||||||
440 | fSessionTimeout=DEFAULT_CLIENTSESSIONTIMEOUT20; | |||||||
441 | // SyncML version support | |||||||
442 | fAssumedServerVersion=MAX_SYNCML_VERSIONsyncml_vers_1_2; // try with highest version we support | |||||||
443 | fMaxSyncMLVersionSupported=MAX_SYNCML_VERSIONsyncml_vers_1_2; // support what we request (overrides session default) | |||||||
444 | #endif | |||||||
445 | #ifdef SYSYNC_SERVER1 | |||||||
446 | // init server defaults | |||||||
447 | fRequestedAuth = auth_md5; | |||||||
448 | fRequiredAuth = auth_md5; | |||||||
449 | fAutoNonce = true; | |||||||
450 | fConstantNonce.erase(); | |||||||
451 | fExternalURL.erase(); | |||||||
452 | fMaxGUIDSizeSent = 32; // reasonable size, but prevent braindamaged Exchange-size IDs to be sent | |||||||
453 | fUseRespURI = true; | |||||||
454 | fRespURIOnlyWhenDifferent = true; | |||||||
455 | // modify timeout after inherited sets it | |||||||
456 | fSessionTimeout=DEFAULT_SERVERSESSIONTIMEOUT(60*5); | |||||||
457 | #endif | |||||||
458 | } // TAgentConfig::clear | |||||||
459 | ||||||||
460 | ||||||||
461 | #ifndef HARDCODED_CONFIG | |||||||
462 | ||||||||
463 | // config element parsing | |||||||
464 | bool TAgentConfig::localStartElement(const char *aElementName, const char **aAttributes, sInt32 aLine) | |||||||
465 | { | |||||||
466 | if (IS_CLIENT(!getSyncAppBase()->isServer())) { | |||||||
467 | // check the client elements | |||||||
468 | #ifdef SYSYNC_CLIENT1 | |||||||
469 | // - defaults for starting a session | |||||||
470 | if (strucmp(aElementName,"defaultsyncmlversion")==0) | |||||||
471 | expectEnum(sizeof(fAssumedServerVersion),&fAssumedServerVersion,SyncMLVersionNames,numSyncMLVersions); | |||||||
472 | else if (strucmp(aElementName,"defaultauth")==0) | |||||||
473 | expectEnum(sizeof(fAssumedServerAuth),&fAssumedServerAuth,authTypeNames,numAuthTypes); | |||||||
474 | else if (strucmp(aElementName,"defaultauthencoding")==0) | |||||||
475 | expectEnum(sizeof(fAssumedServerAuthEnc),&fAssumedServerAuthEnc,encodingFmtSyncMLNames,numFmtTypes); | |||||||
476 | else if (strucmp(aElementName,"defaultauthnonce")==0) | |||||||
477 | expectString(fAssumedNonce); | |||||||
478 | else if (strucmp(aElementName,"preferslowsync")==0) | |||||||
479 | expectBool(fPreferSlowSync); | |||||||
480 | else if (strucmp(aElementName,"newsessionforretry")==0) | |||||||
481 | expectBool(fNewSessionForAuthRetry); | |||||||
482 | else if (strucmp(aElementName,"originaluriforretry")==0) | |||||||
483 | expectBool(fNoRespURIForAuthRetry); | |||||||
484 | else if (strucmp(aElementName,"smartauthretry")==0) | |||||||
485 | expectBool(fSmartAuthRetry); | |||||||
486 | // - other options | |||||||
487 | else if (strucmp(aElementName,"putdevinfatslowsync")==0) | |||||||
488 | expectBool(fPutDevInfAtSlowSync); | |||||||
489 | else if (strucmp(aElementName,"fakedeviceid")==0) | |||||||
490 | expectString(fFakeDeviceID); | |||||||
491 | else | |||||||
492 | #ifndef NO_LOCAL_DBLOGIN1 | |||||||
493 | if (strucmp(aElementName,"localdbuser")==0) | |||||||
494 | expectString(fLocalDBUser); | |||||||
495 | else if (strucmp(aElementName,"localdbpassword")==0) | |||||||
496 | expectString(fLocalDBPassword); | |||||||
497 | else if (strucmp(aElementName,"nolocaldblogin")==0) | |||||||
498 | expectBool(fNoLocalDBLogin); | |||||||
499 | else | |||||||
500 | #endif | |||||||
501 | // serverURL is always available to allow define fixed URL in config that can't be overridden in profiles | |||||||
502 | if (strucmp(aElementName,"serverurl")==0) | |||||||
503 | expectString(fServerURI); | |||||||
504 | else | |||||||
505 | #ifdef PRECONFIGURED_SYNCREQUESTS | |||||||
506 | if (strucmp(aElementName,"syncmlencoding")==0) | |||||||
507 | expectEnum(sizeof(fEncoding),&fEncoding,SyncMLEncodingNames,numSyncMLEncodings(SML_XML-SML_UNDEF+1)); | |||||||
508 | else if (strucmp(aElementName,"serveruser")==0) | |||||||
509 | expectString(fServerUser); | |||||||
510 | else if (strucmp(aElementName,"serverpassword")==0) | |||||||
511 | expectString(fServerPassword); | |||||||
512 | else if (strucmp(aElementName,"sockshost")==0) | |||||||
513 | expectString(fSocksHost); | |||||||
514 | else if (strucmp(aElementName,"proxyhost")==0) | |||||||
515 | expectString(fProxyHost); | |||||||
516 | else if (strucmp(aElementName,"proxyuser")==0) | |||||||
517 | expectString(fProxyUser); | |||||||
518 | else if (strucmp(aElementName,"proxypassword")==0) | |||||||
519 | expectString(fProxyPassword); | |||||||
520 | else if (strucmp(aElementName,"transportuser")==0) | |||||||
521 | expectString(fTransportUser); | |||||||
522 | else if (strucmp(aElementName,"transportpassword")==0) | |||||||
523 | expectString(fTransportPassword); | |||||||
524 | // - Sync DB specification | |||||||
525 | else if (strucmp(aElementName,"syncrequest")==0) { | |||||||
526 | // definition of a new datastore | |||||||
527 | const char* nam = getAttr(aAttributes,"datastore"); | |||||||
528 | if (!nam) { | |||||||
529 | ReportError(true,"syncrequest missing 'datastore' attribute"); | |||||||
530 | } | |||||||
531 | else { | |||||||
532 | // search datastore | |||||||
533 | TLocalDSConfig *localDSCfgP = getLocalDS(nam); | |||||||
534 | if (!localDSCfgP) | |||||||
535 | return fail("unknown local datastore '%s' specified",nam); | |||||||
536 | // create new syncDB config linked to that datastore | |||||||
537 | TSyncReqConfig *syncreqcfgP = new TSyncReqConfig(localDSCfgP,this); | |||||||
538 | // - save in list | |||||||
539 | fSyncRequests.push_back(syncreqcfgP); | |||||||
540 | // - let element handle parsing | |||||||
541 | expectChildParsing(*syncreqcfgP); | |||||||
542 | } | |||||||
543 | } | |||||||
544 | else | |||||||
545 | #endif | |||||||
546 | // - none known here | |||||||
547 | return inherited::localStartElement(aElementName,aAttributes,aLine); | |||||||
548 | #endif // SYSYNC_CLIENT | |||||||
549 | } | |||||||
550 | else { | |||||||
551 | #ifdef SYSYNC_SERVER1 | |||||||
552 | // check the server elements | |||||||
553 | if (strucmp(aElementName,"requestedauth")==0) | |||||||
554 | expectEnum(sizeof(fRequestedAuth),&fRequestedAuth,authTypeNames,numAuthTypes); | |||||||
555 | else if (strucmp(aElementName,"requiredauth")==0) | |||||||
556 | expectEnum(sizeof(fRequiredAuth),&fRequiredAuth,authTypeNames,numAuthTypes); | |||||||
557 | // here to maintain compatibility with old pre 1.0.5.3 config files | |||||||
558 | else if (strucmp(aElementName,"reqiredauth")==0) | |||||||
559 | expectEnum(sizeof(fRequiredAuth),&fRequiredAuth,authTypeNames,numAuthTypes); | |||||||
560 | else if (strucmp(aElementName,"autononce")==0) | |||||||
561 | expectBool(fAutoNonce); | |||||||
562 | else if (strucmp(aElementName,"constantnonce")==0) | |||||||
563 | expectString(fConstantNonce); | |||||||
564 | else if (strucmp(aElementName,"externalurl")==0) | |||||||
565 | expectString(fExternalURL); | |||||||
566 | else if (strucmp(aElementName,"maxguidsizesent")==0) | |||||||
567 | expectUInt16(fMaxGUIDSizeSent); | |||||||
568 | else if (strucmp(aElementName,"sendrespuri")==0) | |||||||
569 | expectBool(fUseRespURI); | |||||||
570 | else if (strucmp(aElementName,"respurionlywhendifferent")==0) | |||||||
571 | expectBool(fRespURIOnlyWhenDifferent); | |||||||
572 | // - none known here | |||||||
573 | else | |||||||
574 | return inherited::localStartElement(aElementName,aAttributes,aLine); | |||||||
575 | #endif // SYSYNC_SERVER | |||||||
576 | } | |||||||
577 | // ok | |||||||
578 | return true; | |||||||
579 | } // TAgentConfig::localStartElement | |||||||
580 | ||||||||
581 | #endif // HARDCODED_CONFIG | |||||||
582 | ||||||||
583 | ||||||||
584 | // resolve | |||||||
585 | void TAgentConfig::localResolve(bool aLastPass) | |||||||
586 | { | |||||||
587 | if (aLastPass) { | |||||||
588 | if (IS_CLIENT(!getSyncAppBase()->isServer())) { | |||||||
589 | #ifdef SYSYNC_CLIENT1 | |||||||
590 | #ifdef PRECONFIGURED_SYNCREQUESTS | |||||||
591 | // - resolve requests | |||||||
592 | TSyncReqList::iterator pos; | |||||||
593 | for(pos=fSyncRequests.begin();pos!=fSyncRequests.end();pos++) | |||||||
594 | (*pos)->Resolve(aLastPass); | |||||||
595 | #endif | |||||||
596 | #endif // SYSYNC_CLIENT | |||||||
597 | } | |||||||
598 | else { | |||||||
599 | #ifdef SYSYNC_SERVER1 | |||||||
600 | if (!fAutoNonce && fConstantNonce.empty()) | |||||||
601 | ReportError(false,"Warning: 'constantnonce' should be defined when 'autononce' is not set"); | |||||||
602 | #endif // SYSYNC_SERVER | |||||||
603 | } | |||||||
604 | } | |||||||
605 | // resolve inherited | |||||||
606 | inherited::localResolve(aLastPass); | |||||||
607 | } // TAgentConfig::localResolve | |||||||
608 | ||||||||
609 | ||||||||
610 | ||||||||
611 | // Implementation of TSyncAgent | |||||||
612 | // ============================= | |||||||
613 | ||||||||
614 | ||||||||
615 | // constructor | |||||||
616 | TSyncAgent::TSyncAgent( | |||||||
617 | TSyncAppBase *aAppBaseP, | |||||||
618 | TSyncSessionHandle *aSessionHandleP, | |||||||
619 | const char *aSessionID // a session ID | |||||||
620 | ) : | |||||||
621 | TSyncSession(aAppBaseP,aSessionID) | |||||||
622 | { | |||||||
623 | // General | |||||||
624 | #ifdef ENGINE_LIBRARY1 | |||||||
625 | // init the flags which are set by STEPCMD_SUSPEND, STEPCMD_ABORT and STEPCMD_TRANSPFAIL | |||||||
626 | fAbortRequested = false; | |||||||
627 | fSuspendRequested = false; | |||||||
628 | fEngineSessionStatus = LOCERR_WRONGUSAGE; | |||||||
629 | #ifdef NON_FULLY_GRANULAR_ENGINE1 | |||||||
630 | // - erase the list of queued progress events | |||||||
631 | fProgressInfoList.clear(); | |||||||
632 | fPendingStepCmd = 0; // none pending | |||||||
633 | #endif // NON_FULLY_GRANULAR_ENGINE | |||||||
634 | // - issue session start event here (in non-engine case this is done in TSyncSession constructor) | |||||||
635 | SESSION_PROGRESS_EVENT(this,pev_sessionstart,NULL,0,0,0)this->NotifySessionProgressEvent(pev_sessionstart,__null,0 ,0,0); | |||||||
636 | #endif // ENGINE_LIBRARY | |||||||
637 | #ifdef SYSYNC_SERVER1 | |||||||
638 | // reset data counts | |||||||
639 | fIncomingBytes = 0; | |||||||
640 | fOutgoingBytes = 0; | |||||||
641 | #endif | |||||||
642 | fRestartSyncOnce = false; | |||||||
643 | fRestartingSync = false; | |||||||
644 | ||||||||
645 | // Specific for Client or Server | |||||||
646 | if (IS_CLIENT(!getSyncAppBase()->isServer())) { | |||||||
647 | #ifdef SYSYNC_CLIENT1 | |||||||
648 | #ifdef HARD_CODED_SERVER_URI | |||||||
649 | fNoCRCPrefixLen = 0; | |||||||
650 | #endif | |||||||
651 | #ifdef ENGINE_LIBRARY1 | |||||||
652 | // engine | |||||||
653 | fClientEngineState = ces_idle; | |||||||
654 | #endif | |||||||
655 | // reset session now to get correct initial state | |||||||
656 | InternalResetSession(); | |||||||
657 | // restart with session numbering at 1 (incremented before use) | |||||||
658 | fClientSessionNo = 0; | |||||||
659 | #endif // SYSYNC_CLIENT | |||||||
660 | } | |||||||
661 | else { | |||||||
662 | #ifdef SYSYNC_SERVER1 | |||||||
663 | // init answer buffer | |||||||
664 | fBufferedAnswer = NULL__null; | |||||||
665 | fBufferedAnswerSize = 0; | |||||||
666 | #ifdef ENGINE_LIBRARY1 | |||||||
667 | // engine | |||||||
668 | fServerEngineState = ses_needdata; | |||||||
669 | fRequestSize = 0; | |||||||
670 | #endif | |||||||
671 | // init own stuff | |||||||
672 | InternalResetSession(); | |||||||
673 | // save session handle | |||||||
674 | fSessionHandleP = aSessionHandleP; // link to handle | |||||||
675 | // get config defaults | |||||||
676 | TAgentConfig *configP = static_cast<TAgentConfig *>(aAppBaseP->getRootConfig()->fAgentConfigP); | |||||||
677 | fUseRespURI = configP->fUseRespURI; | |||||||
678 | // create all locally available datastores from config | |||||||
679 | TLocalDSList::iterator pos; | |||||||
680 | for (pos=configP->fDatastores.begin(); pos!=configP->fDatastores.end(); pos++) { | |||||||
681 | // create the datastore | |||||||
682 | addLocalDataStore(*pos); | |||||||
683 | } | |||||||
684 | #endif // SYSYNC_SERVER | |||||||
685 | } | |||||||
686 | } // TSyncAgent::TSyncAgent | |||||||
687 | ||||||||
688 | ||||||||
689 | // destructor | |||||||
690 | TSyncAgent::~TSyncAgent() | |||||||
691 | { | |||||||
692 | if (IS_CLIENT(!getSyncAppBase()->isServer())) { | |||||||
693 | // make sure everything is terminated BEFORE destruction of hierarchy begins | |||||||
694 | TerminateSession(); | |||||||
695 | } | |||||||
696 | else { | |||||||
697 | #ifdef SYSYNC_SERVER1 | |||||||
698 | // forget any buffered answers | |||||||
699 | bufferAnswer(NULL__null,0); | |||||||
700 | // reset session | |||||||
701 | InternalResetSession(); | |||||||
702 | // show session data transfer | |||||||
703 | PDEBUGPRINTFX(DBG_HOT,({ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Session data transfer statistics: incoming bytes=%ld, outgoing bytes=%ld" , (long)fIncomingBytes, (long)fOutgoingBytes ); } | |||||||
704 | "Session data transfer statistics: incoming bytes=%ld, outgoing bytes=%ld",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Session data transfer statistics: incoming bytes=%ld, outgoing bytes=%ld" , (long)fIncomingBytes, (long)fOutgoingBytes ); } | |||||||
705 | (long)fIncomingBytes,{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Session data transfer statistics: incoming bytes=%ld, outgoing bytes=%ld" , (long)fIncomingBytes, (long)fOutgoingBytes ); } | |||||||
706 | (long)fOutgoingBytes{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Session data transfer statistics: incoming bytes=%ld, outgoing bytes=%ld" , (long)fIncomingBytes, (long)fOutgoingBytes ); } | |||||||
707 | )){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Session data transfer statistics: incoming bytes=%ld, outgoing bytes=%ld" , (long)fIncomingBytes, (long)fOutgoingBytes ); }; | |||||||
708 | // DO NOT remove session from dispatcher here, | |||||||
709 | // this is the task of the dispatcher itself! | |||||||
710 | CONSOLEPRINTF(("Terminated SyncML session (server id=%s)\n",getLocalSessionID()))SySync_ConsolePrintf(stderr, "SYSYNC " "Terminated SyncML session (server id=%s)\n" "\n",getLocalSessionID()); | |||||||
711 | // show end of session in global level | |||||||
712 | POBJDEBUGPRINTFX(getSyncAppBase(),DBG_HOT,({ if ((getSyncAppBase()) && (((0x00000001) & (getSyncAppBase ())->getDbgMask()) == (0x00000001))) (getSyncAppBase())-> getDbgLogger()->setNextMask(0x00000001).DebugPrintfLastMask ( "TSyncAgent::~TSyncAgent: Deleted SyncML session (local session id=%s)" , getLocalSessionID() ); } | |||||||
713 | "TSyncAgent::~TSyncAgent: Deleted SyncML session (local session id=%s)",{ if ((getSyncAppBase()) && (((0x00000001) & (getSyncAppBase ())->getDbgMask()) == (0x00000001))) (getSyncAppBase())-> getDbgLogger()->setNextMask(0x00000001).DebugPrintfLastMask ( "TSyncAgent::~TSyncAgent: Deleted SyncML session (local session id=%s)" , getLocalSessionID() ); } | |||||||
714 | getLocalSessionID(){ if ((getSyncAppBase()) && (((0x00000001) & (getSyncAppBase ())->getDbgMask()) == (0x00000001))) (getSyncAppBase())-> getDbgLogger()->setNextMask(0x00000001).DebugPrintfLastMask ( "TSyncAgent::~TSyncAgent: Deleted SyncML session (local session id=%s)" , getLocalSessionID() ); } | |||||||
715 | )){ if ((getSyncAppBase()) && (((0x00000001) & (getSyncAppBase ())->getDbgMask()) == (0x00000001))) (getSyncAppBase())-> getDbgLogger()->setNextMask(0x00000001).DebugPrintfLastMask ( "TSyncAgent::~TSyncAgent: Deleted SyncML session (local session id=%s)" , getLocalSessionID() ); }; | |||||||
716 | #endif // SYSYNC_SERVER | |||||||
717 | } | |||||||
718 | } // TSyncAgent::~TSyncAgent | |||||||
719 | ||||||||
720 | ||||||||
721 | // Terminate session | |||||||
722 | void TSyncAgent::TerminateSession() | |||||||
723 | { | |||||||
724 | #ifdef SYSYNC_CLIENT1 | |||||||
725 | if (IS_CLIENT(!getSyncAppBase()->isServer()) && !fTerminated) { | |||||||
726 | InternalResetSession(); | |||||||
727 | #ifdef ENGINE_LIBRARY1 | |||||||
728 | // switch state to done to prevent any further activity via SessionStep() | |||||||
729 | fClientEngineState = ces_done; | |||||||
730 | #endif | |||||||
731 | } | |||||||
732 | #endif // SYSYNC_CLIENT | |||||||
733 | inherited::TerminateSession(); | |||||||
734 | } // TSyncAgent::TerminateSession | |||||||
735 | ||||||||
736 | ||||||||
737 | ||||||||
738 | ||||||||
739 | void TSyncAgent::InternalResetSession(void) | |||||||
740 | { | |||||||
741 | if (IS_CLIENT(!getSyncAppBase()->isServer())) { | |||||||
742 | #ifdef SYSYNC_CLIENT1 | |||||||
743 | // use remote URI as specified to start a session | |||||||
744 | fRespondURI = fRemoteURI; | |||||||
745 | #ifdef HARD_CODED_SERVER_URI | |||||||
746 | #if defined(CUSTOM_URI_SUFFIX) && !defined(HARD_CODED_SERVER_URI_LEN) | |||||||
747 | #error "HARD_CODED_SERVER_URI_LEN must be defined when using CUSTOM_URI_SUFFIX" | |||||||
748 | #endif | |||||||
749 | #ifdef HARD_CODED_SERVER_URI_LEN | |||||||
750 | // only part of URL must match (max HARD_CODED_SERVER_URI_LEN chars will be added, less if URI is shorter) | |||||||
751 | fServerURICRC = addNameToCRC(SYSER_CRC32_SEED((uInt32)4119203362LL), fRemoteURI.c_str()+fNoCRCPrefixLen, false, HARD_CODED_SERVER_URI_LEN); | |||||||
752 | #else | |||||||
753 | // entire URL (except prefix) must match | |||||||
754 | fServerURICRC = addNameToCRC(SYSER_CRC32_SEED((uInt32)4119203362LL), fRemoteURI.c_str()+fNoCRCPrefixLen, false); | |||||||
755 | #endif | |||||||
756 | #endif | |||||||
757 | // set SyncML version | |||||||
758 | // Note: will be overridden with call to loadRemoteParams() | |||||||
759 | fSyncMLVersion = syncml_vers_unknown; // unknown | |||||||
760 | // will be cleared to suppress automatic use of DS 1.2 SINCE/BEFORE filters | |||||||
761 | // (e.g. for date range in func_SetDaysRange()) | |||||||
762 | fServerHasSINCEBEFORE = true; | |||||||
763 | // no outgoing alert 222 sent so far | |||||||
764 | fOutgoingAlert222Count = 0; | |||||||
765 | #endif | |||||||
766 | } | |||||||
767 | else { | |||||||
768 | #ifdef SYSYNC_SERVER1 | |||||||
769 | // %%% remove this as soon as Server is 1.1 compliant | |||||||
770 | //fSyncMLVersion=syncml_vers_1_0; // only accepts 1.0 for now %%%% | |||||||
771 | #endif | |||||||
772 | } | |||||||
773 | } // TSyncAgent::InternalResetSession | |||||||
774 | ||||||||
775 | ||||||||
776 | // Virtual version | |||||||
777 | void TSyncAgent::ResetSession(void) | |||||||
778 | { | |||||||
779 | // let ancestor do its stuff | |||||||
780 | TSyncSession::ResetSession(); | |||||||
781 | // do my own stuff (and probably modify settings of ancestor!) | |||||||
782 | InternalResetSession(); | |||||||
783 | } // TSyncAgent::ResetSession | |||||||
784 | ||||||||
785 | ||||||||
786 | bool TSyncAgent::MessageStarted(SmlSyncHdrPtr_t aContentP, TStatusCommand &aStatusCommand, bool aBad) | |||||||
787 | { | |||||||
788 | if (IS_CLIENT(!getSyncAppBase()->isServer())) { | |||||||
789 | #ifdef SYSYNC_CLIENT1 | |||||||
790 | return ClientMessageStarted(aContentP,aStatusCommand,aBad); | |||||||
791 | #endif // SYSYNC_CLIENT | |||||||
792 | } | |||||||
793 | else { | |||||||
794 | #ifdef SYSYNC_SERVER1 | |||||||
795 | return ServerMessageStarted(aContentP,aStatusCommand,aBad); | |||||||
796 | #endif // SYSYNC_SERVER | |||||||
797 | } | |||||||
798 | } | |||||||
799 | ||||||||
800 | void TSyncAgent::MessageEnded(bool aIncomingFinal) | |||||||
801 | { | |||||||
802 | if (IS_CLIENT(!getSyncAppBase()->isServer())) { | |||||||
803 | #ifdef SYSYNC_CLIENT1 | |||||||
804 | ClientMessageEnded(aIncomingFinal); | |||||||
805 | #endif // SYSYNC_CLIENT | |||||||
806 | } | |||||||
807 | else { | |||||||
808 | #ifdef SYSYNC_SERVER1 | |||||||
809 | ServerMessageEnded(aIncomingFinal); | |||||||
810 | #endif // SYSYNC_SERVER | |||||||
811 | } | |||||||
812 | } | |||||||
813 | ||||||||
814 | ||||||||
815 | // starting with engine version 2.0.8.7 a client's device ID (in devinf) is no longer | |||||||
816 | // a constant string, but the device's unique ID | |||||||
817 | string TSyncAgent::getDeviceID(void) | |||||||
818 | { | |||||||
819 | if (fLocalURI.empty()) { | |||||||
820 | if (IS_SERVER(getSyncAppBase()->isServer())) | |||||||
821 | return SYSYNC_SERVER_DEVID"SySync Server"; // return default ID | |||||||
822 | else | |||||||
823 | return SYSYNC_CLIENT_DEVID"SySync Client"; // return default ID | |||||||
824 | } | |||||||
825 | else | |||||||
826 | return fLocalURI; | |||||||
827 | } // TSyncAgent::getDeviceID | |||||||
828 | ||||||||
829 | ||||||||
830 | // ask syncappbase for device type | |||||||
831 | string TSyncAgent::getDeviceType(void) | |||||||
832 | { | |||||||
833 | // taken from configuration or default for engine type (client/server) | |||||||
834 | return getSyncAppBase()->getDevTyp(); | |||||||
835 | } // TSyncAgent::getDeviceType | |||||||
836 | ||||||||
837 | ||||||||
838 | ||||||||
839 | bool TSyncAgent::checkAllFromClientOnly() | |||||||
840 | { | |||||||
841 | bool allFromClientOnly=false; | |||||||
842 | // Note: the map phase will not take place, if all datastores are in | |||||||
843 | // send-to-server-only mode and we are not in non-conformant old | |||||||
844 | // synthesis-compatible fCompleteFromClientOnly mode. | |||||||
845 | #ifdef SYSYNC_SERVER1 | |||||||
846 | if (!fCompleteFromClientOnly) | |||||||
847 | #endif | |||||||
848 | { | |||||||
849 | // let all local datastores know that message has ended | |||||||
850 | allFromClientOnly=true; | |||||||
851 | for (TLocalDataStorePContainer::iterator pos=fLocalDataStores.begin(); pos!=fLocalDataStores.end(); ++pos) { | |||||||
852 | // check sync modes | |||||||
853 | if ((*pos)->isActive() && (*pos)->getSyncMode()!=smo_fromclient) { | |||||||
854 | allFromClientOnly=false; | |||||||
855 | break; | |||||||
856 | } | |||||||
857 | } | |||||||
858 | } | |||||||
859 | return allFromClientOnly; | |||||||
860 | } | |||||||
861 | ||||||||
862 | ||||||||
863 | #ifdef SYSYNC_CLIENT1 | |||||||
864 | ||||||||
865 | // initialize the client session and link it with the SML toolkit | |||||||
866 | localstatus TSyncAgent::InitializeSession(uInt32 aProfileSelector, bool aAutoSyncSession) | |||||||
867 | { | |||||||
868 | localstatus sta; | |||||||
869 | ||||||||
870 | // Select profile now (before creating instance, as encoding is dependent on profile) | |||||||
871 | sta=SelectProfile(aProfileSelector, aAutoSyncSession); | |||||||
872 | if (sta) return sta; | |||||||
873 | // Start a SyncML toolkit instance now and set the encoding from config | |||||||
874 | InstanceID_t myInstance; | |||||||
875 | if (!getSyncAppBase()->newSmlInstance( | |||||||
876 | getEncoding(), | |||||||
877 | getRootConfig()->fLocalMaxMsgSize * 2, // twice the message size | |||||||
878 | myInstance | |||||||
879 | )) { | |||||||
880 | return LOCERR_SMLFATAL; | |||||||
881 | } | |||||||
882 | // let toolkit know the session pointer | |||||||
883 | if (getSyncAppBase()->setSmlInstanceUserData(myInstance,this)!=SML_ERR_OK0x00) // toolkit must know session (as userData) | |||||||
884 | return LOCERR_SMLFATAL; | |||||||
885 | // remember the instance myself | |||||||
886 | setSmlWorkspaceID(myInstance); // session must know toolkit workspace | |||||||
887 | // done | |||||||
888 | return LOCERR_OK; | |||||||
889 | } // TSyncAgent::InitializeSession | |||||||
890 | ||||||||
891 | ||||||||
892 | ||||||||
893 | // select a profile (returns false if profile not found) | |||||||
894 | // Note: base class just tries to retrieve information from | |||||||
895 | // config | |||||||
896 | localstatus TSyncAgent::SelectProfile(uInt32 aProfileSelector, bool aAutoSyncSession) | |||||||
897 | { | |||||||
898 | #ifndef PRECONFIGURED_SYNCREQUESTS | |||||||
899 | // no profile settings in config -> error | |||||||
900 | return LOCERR_NOCFG; | |||||||
901 | #else | |||||||
902 | // get profile settings from config | |||||||
903 | TAgentConfig *configP = static_cast<TAgentConfig *>(getRootConfig()->fAgentConfigP); | |||||||
904 | // - get encoding | |||||||
905 | fEncoding=configP->fEncoding; // SyncML encoding | |||||||
906 | // - set server access details | |||||||
907 | fRemoteURI=configP->fServerURI; // Remote URI = Server URI | |||||||
908 | fTransportUser=configP->fTransportUser; // transport layer user (e.g. HTTP auth) | |||||||
909 | fTransportPassword=configP->fTransportPassword; // transport layer password (e.g. HTTP auth) | |||||||
910 | fServerUser=configP->fServerUser; // Server layer authentification user name | |||||||
911 | fServerPassword=configP->fServerPassword; // Server layer authentification password | |||||||
912 | #ifndef NO_LOCAL_DBLOGIN1 | |||||||
913 | fLocalDBUser=configP->fLocalDBUser; // Local DB authentification user name (empty if local DB is single user) | |||||||
914 | fNoLocalDBLogin=configP->fNoLocalDBLogin; // if set, no local DB auth takes place, but fLocalDBUser is used as userkey (depending on DB implementation) | |||||||
915 | fLocalDBPassword=configP->fLocalDBPassword; // Local DB authentification password | |||||||
916 | #endif | |||||||
917 | fProxyHost=configP->fProxyHost; // Proxy host | |||||||
918 | fSocksHost=configP->fSocksHost; // Socks host | |||||||
919 | fProxyUser=configP->fProxyUser; | |||||||
920 | fProxyPassword=configP->fProxyPassword; | |||||||
921 | // Reset session after profile change | |||||||
922 | // and also remove any datastores we might have | |||||||
923 | ResetAndRemoveDatastores(); | |||||||
924 | // if tunnel, that's all for now | |||||||
925 | if (aProfileSelector==TUNNEL_PROFILE_ID0xFFFFFFFE) return LOCERR_OK; | |||||||
926 | // - create and init datastores needed for this session from config | |||||||
927 | // Note: probably config has no sync requests, but they are created later | |||||||
928 | // programmatically | |||||||
929 | TSyncReqList::iterator pos; | |||||||
930 | for (pos=configP->fSyncRequests.begin(); pos!=configP->fSyncRequests.end(); pos++) { | |||||||
931 | // create and init the datastore | |||||||
932 | fLocalDataStores.push_back( | |||||||
933 | (*pos)->initNewLocalDataStore(this) | |||||||
934 | ); | |||||||
935 | } | |||||||
936 | // create "new" session ID (derivates will do this better) | |||||||
937 | fClientSessionNo++; | |||||||
938 | return LOCERR_OK; | |||||||
939 | #endif | |||||||
940 | } // TSyncAgent::SelectProfile | |||||||
941 | ||||||||
942 | ||||||||
943 | // make sure we are logged in to local datastore | |||||||
944 | localstatus TSyncAgent::LocalLogin(void) | |||||||
945 | { | |||||||
946 | #ifndef NO_LOCAL_DBLOGIN1 | |||||||
947 | if (!fNoLocalDBLogin && !fLocalDBUser.empty()) { | |||||||
948 | // check authorisation (login to correct user) in local DB | |||||||
949 | if (!SessionLogin(fLocalDBUser.c_str(),fLocalDBPassword.c_str(),sectyp_clearpass,fRemoteURI.c_str())) { | |||||||
950 | return localError(401); // done & error | |||||||
951 | } | |||||||
952 | } | |||||||
953 | #endif | |||||||
954 | return LOCERR_OK; | |||||||
955 | } // TSyncAgent::LocalLogin | |||||||
956 | ||||||||
957 | ||||||||
958 | ||||||||
959 | // process message in the instance buffer | |||||||
960 | localstatus TSyncAgent::processAnswer(void) | |||||||
961 | { | |||||||
962 | InstanceID_t myInstance = getSmlWorkspaceID(); | |||||||
963 | Ret_t err; | |||||||
964 | ||||||||
965 | // now process data | |||||||
966 | DEBUGPRINTF(("===> now calling smlProcessData")){ if (((0x00008000) & getDbgMask()) == (0x00008000)) getDbgLogger ()->setNextMask(0x00008000).DebugPrintfLastMask ("===> now calling smlProcessData" ); }; | |||||||
967 | #ifdef SYDEBUG2 | |||||||
968 | MemPtr_t data = NULL__null; | |||||||
969 | MemSize_t datasize; | |||||||
970 | smlPeekMessageBuffer(getSmlWorkspaceID(), false, &data, &datasize); | |||||||
971 | #endif | |||||||
972 | fIgnoreMsgErrs=false; | |||||||
973 | err=smlProcessData( | |||||||
974 | myInstance, | |||||||
975 | SML_ALL_COMMANDS | |||||||
976 | ); | |||||||
977 | if (err) { | |||||||
978 | // dump the message that failed to process | |||||||
979 | #ifdef SYDEBUG2 | |||||||
980 | if (data) DumpSyncMLBuffer(data,datasize,false,err); | |||||||
981 | #endif | |||||||
982 | if (!fIgnoreMsgErrs) { | |||||||
983 | PDEBUGPRINTFX(DBG_ERROR,("===> smlProcessData failed, returned 0x%hX",(sInt16)err)){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("===> smlProcessData failed, returned 0x%hX" ,(sInt16)err); }; | |||||||
984 | // other problem or already using SyncML 1.0 --> error | |||||||
985 | return LOCERR_PROCESSMSG; | |||||||
986 | } | |||||||
987 | } | |||||||
988 | // now check if this is a session restart | |||||||
989 | if (isStarting()) { | |||||||
990 | // this is still the beginning of a session | |||||||
991 | return LOCERR_SESSIONRST; | |||||||
992 | } | |||||||
993 | return LOCERR_OK; | |||||||
994 | } // TSyncAgentBase::processAnswer | |||||||
995 | ||||||||
996 | bool TSyncAgent::restartSync() | |||||||
997 | { | |||||||
998 | if (IS_CLIENT(!getSyncAppBase()->isServer())) { | |||||||
999 | // Restarting needs to be done if: | |||||||
1000 | // - all datastores support restarting a sync (= multiple read/write cycles) | |||||||
1001 | // on client and server side (expected not be set if the engine itself on | |||||||
1002 | // either side doesn't support it, so that is not checked separately) | |||||||
1003 | // - no datastore has failed in current iteration | |||||||
1004 | // - client has pending changes: | |||||||
1005 | // - server temporarily rejected a change, queued for resending | |||||||
1006 | // - an item added by the server was merged with another | |||||||
1007 | // item locally (might have an updated queued, need to send delete) | |||||||
1008 | // - change on client failed temporarily | |||||||
1009 | // - the app or a datastore asked for a restart via the "restartsync" | |||||||
1010 | // session variable | |||||||
1011 | if (!getenv("LIBSYNTHESIS_NO_RESTART")) { | |||||||
1012 | bool restartPossible=true; // ... unless proven otherwise below | |||||||
1013 | bool restartNecessary=fRestartSyncOnce; // one reason for restarting: requested by app | |||||||
1014 | int numActive = 0; | |||||||
1015 | ||||||||
1016 | // clear the flag after we checked it | |||||||
1017 | fRestartSyncOnce=false; | |||||||
1018 | if (fRestartSyncOnce) | |||||||
1019 | PDEBUGPRINTFX(DBG_SESSION,("try to restart sync as requested by app")){ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ("try to restart sync as requested by app" ); }; | |||||||
1020 | ||||||||
1021 | for (TLocalDataStorePContainer::iterator pos=fLocalDataStores.begin(); | |||||||
1022 | pos!=fLocalDataStores.end(); | |||||||
1023 | ++pos) { | |||||||
1024 | TLocalEngineDS *localDS = *pos; | |||||||
1025 | if (localDS->isActive()) { | |||||||
1026 | numActive++; | |||||||
1027 | if (!localDS->canRestart()) { | |||||||
1028 | PDEBUGPRINTFX(DBG_SESSION,("cannot restart, %s does not support it",{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ("cannot restart, %s does not support it" , localDS->getName()); } | |||||||
1029 | localDS->getName())){ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ("cannot restart, %s does not support it" , localDS->getName()); }; | |||||||
1030 | restartPossible=false; | |||||||
1031 | break; | |||||||
1032 | } | |||||||
1033 | if (localDS->isAborted()) { | |||||||
1034 | PDEBUGPRINTFX(DBG_SESSION,("cannot restart, %s faileed",{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ("cannot restart, %s faileed" , localDS->getName()); } | |||||||
1035 | localDS->getName())){ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ("cannot restart, %s faileed" , localDS->getName()); }; | |||||||
1036 | restartPossible=false; | |||||||
1037 | break; | |||||||
1038 | } | |||||||
1039 | if (!localDS->getRemoteDatastore() || | |||||||
1040 | !localDS->getRemoteDatastore()->canRestart()) { | |||||||
1041 | PDEBUGPRINTFX(DBG_SESSION,("cannot restart, remote datastore %s matching with %s does not support it",{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ("cannot restart, remote datastore %s matching with %s does not support it" , localDS->getRemoteDatastore()->getName(), localDS-> getName()); } | |||||||
1042 | localDS->getRemoteDatastore()->getName(),{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ("cannot restart, remote datastore %s matching with %s does not support it" , localDS->getRemoteDatastore()->getName(), localDS-> getName()); } | |||||||
1043 | localDS->getName())){ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ("cannot restart, remote datastore %s matching with %s does not support it" , localDS->getRemoteDatastore()->getName(), localDS-> getName()); }; | |||||||
1044 | restartPossible=false; | |||||||
1045 | break; | |||||||
1046 | } | |||||||
1047 | } | |||||||
1048 | // check for pending local changes in the client | |||||||
1049 | if (localDS->numUnsentMaps() > 0) { | |||||||
1050 | PDEBUGPRINTFX(DBG_SESSION,("try to restart, %s has pending map entries",{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ("try to restart, %s has pending map entries" , localDS->getName()); } | |||||||
1051 | localDS->getName())){ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ("try to restart, %s has pending map entries" , localDS->getName()); }; | |||||||
1052 | restartNecessary=true; | |||||||
1053 | } | |||||||
1054 | // TODO: detect temporarily failed items (server sent an add/update/delete | |||||||
1055 | // that we had to reject temporarily and where we expect the server to | |||||||
1056 | // resend the request) | |||||||
1057 | // detect pending changes (for example, 409 handling in binfile client) | |||||||
1058 | if (localDS->hasPendingChangesForNextSync()) { | |||||||
1059 | PDEBUGPRINTFX(DBG_SESSION,("try to restart, %s has pending changes",{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ("try to restart, %s has pending changes" , localDS->getName()); } | |||||||
1060 | localDS->getName())){ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ("try to restart, %s has pending changes" , localDS->getName()); }; | |||||||
1061 | restartNecessary=true; | |||||||
1062 | } | |||||||
1063 | } | |||||||
1064 | ||||||||
1065 | return restartPossible && restartNecessary; | |||||||
1066 | } | |||||||
1067 | } | |||||||
1068 | ||||||||
1069 | return false; | |||||||
1070 | } | |||||||
1071 | ||||||||
1072 | // let session produce (or finish producing) next message into | |||||||
1073 | // SML workspace | |||||||
1074 | // - returns aDone if no answer needs to be sent (=end of session) | |||||||
1075 | // - returns 0 if successful | |||||||
1076 | // - returns SyncML status code if unsucessfully aborted session | |||||||
1077 | localstatus TSyncAgent::NextMessage(bool &aDone) | |||||||
1078 | { | |||||||
1079 | TLocalDataStorePContainer::iterator pos; | |||||||
1080 | TSyError status; | |||||||
1081 | ||||||||
1082 | TP_START(fTPInfo,TP_general); // could be new thread | |||||||
1083 | // default to not continuing | |||||||
1084 | aDone=true; | |||||||
1085 | #ifdef PROGRESS_EVENTS1 | |||||||
1086 | // check for user suspend | |||||||
1087 | if (!SESSION_PROGRESS_EVENT(this,pev_suspendcheck,NULL,0,0,0)this->NotifySessionProgressEvent(pev_suspendcheck,__null,0 ,0,0)) { | |||||||
1088 | SuspendSession(LOCERR_USERSUSPEND); | |||||||
1089 | } | |||||||
1090 | #endif | |||||||
1091 | // done if session was aborted by last received commands | |||||||
1092 | if (isAborted()) return getAbortReasonStatus(); // done & error | |||||||
1093 | // check package state | |||||||
1094 | if (fOutgoingState==psta_idle) { | |||||||
1095 | // if suspended here, we'll just stop - nothing has happened yet | |||||||
1096 | if (isSuspending()) { | |||||||
1097 | AbortSession(fAbortReasonStatus,true); | |||||||
1098 | return getAbortReasonStatus(); | |||||||
1099 | } | |||||||
1100 | // start of an entirely new client session | |||||||
1101 | #ifdef HARD_CODED_SERVER_URI | |||||||
1102 | // extra check to limit hacking | |||||||
1103 | if (fServerURICRC != SERVER_URI_CRC) { | |||||||
1104 | // someone has tried to change the URI | |||||||
1105 | DEBUGPRINTFX(DBG_ERROR,("hardcoded Server URI CRC mismatch")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("hardcoded Server URI CRC mismatch" ); }; | |||||||
1106 | return LOCERR_LIMITED; // user will not know what this means, but we will | |||||||
1107 | } | |||||||
1108 | #endif | |||||||
1109 | // - check if we have client requests | |||||||
1110 | if (fLocalDataStores.size()<1) { | |||||||
1111 | PDEBUGPRINTFX(DBG_ERROR,("No datastores defined to sync with")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("No datastores defined to sync with" ); }; | |||||||
1112 | return LOCERR_NOCFG; | |||||||
1113 | } | |||||||
1114 | // %%% later, we could probably load cached info about | |||||||
1115 | // server requested auth, devinf etc. here | |||||||
1116 | // use remote URI as specified to start a session | |||||||
1117 | fRespondURI=fRemoteURI; | |||||||
1118 | // get default params for sending first message to remote | |||||||
1119 | // Note: may include remote flag settings that influence creation of my own ID below, that's why we do it now here | |||||||
1120 | loadRemoteParams(); | |||||||
1121 | // get info about my own URI, whatever that is | |||||||
1122 | #ifndef HARDCODED_CONFIG | |||||||
1123 | if (!static_cast<TAgentConfig *>(getRootConfig()->fAgentConfigP)->fFakeDeviceID.empty()) { | |||||||
1124 | // return fake Device ID if we have one defined in the config file (useful for testing) | |||||||
1125 | fLocalURI = static_cast<TAgentConfig *>(getRootConfig()->fAgentConfigP)->fFakeDeviceID; | |||||||
1126 | } | |||||||
1127 | else | |||||||
1128 | #endif | |||||||
1129 | { | |||||||
1130 | if (!getSyncAppBase()->getMyDeviceID(fLocalURI) || devidWithUserHash()) { | |||||||
1131 | // Device ID is not really unique, make a hash including user name to make it pseudo-unique | |||||||
1132 | // create MD5 hash from non-unique ID and user name | |||||||
1133 | // Note: when compiled with GUARANTEED_UNIQUE_DEVICID, devidWithUserHash() is always false. | |||||||
1134 | md5::SYSYNC_MD5_CTX context; | |||||||
1135 | uInt8 digest[16]; // for MD5 digest | |||||||
1136 | md5::Init (&context); | |||||||
1137 | // - add what we got for ID | |||||||
1138 | md5::Update (&context, (uInt8 *)fLocalURI.c_str(), fLocalURI.size()); | |||||||
1139 | // - add user name, if any | |||||||
1140 | if (fLocalURI.size()>0) md5::Update (&context, (uInt8 *)fServerUser.c_str(), fServerUser.size()); | |||||||
1141 | // - done | |||||||
1142 | md5::Final (digest, &context); | |||||||
1143 | // now make hex string of that | |||||||
1144 | fLocalURI = devidWithUserHash() ? 'x' : 'X'; // start with X to document this special case (lowercase = forced by remoteFlag) | |||||||
1145 | for (int n=0; n<16; n++) { | |||||||
1146 | AppendHexByte(fLocalURI,digest[n]); | |||||||
1147 | } | |||||||
1148 | } | |||||||
1149 | } | |||||||
1150 | // get my own name (if any) | |||||||
1151 | getPlatformString(pfs_device_name,fLocalName); | |||||||
1152 | // override some of these if not set by loadRemoteParams() | |||||||
1153 | if (fSyncMLVersion==syncml_vers_unknown) | |||||||
1154 | fSyncMLVersion=static_cast<TAgentConfig *>(getRootConfig()->fAgentConfigP)->fAssumedServerVersion; | |||||||
1155 | if (fRemoteRequestedAuth==auth_none) | |||||||
1156 | fRemoteRequestedAuth=static_cast<TAgentConfig *>(getRootConfig()->fAgentConfigP)->fAssumedServerAuth; | |||||||
1157 | if (fRemoteRequestedAuthEnc==fmt_chr) | |||||||
1158 | fRemoteRequestedAuthEnc=static_cast<TAgentConfig *>(getRootConfig()->fAgentConfigP)->fAssumedServerAuthEnc; | |||||||
1159 | if (fRemoteNonce.empty()) | |||||||
1160 | fRemoteNonce=static_cast<TAgentConfig *>(getRootConfig()->fAgentConfigP)->fAssumedNonce; | |||||||
1161 | ||||||||
1162 | // we are not yet authenticated for the entire session | |||||||
1163 | fNeedAuth=true; | |||||||
1164 | // now ready for init | |||||||
1165 | fOutgoingState=psta_init; // %%%% could also set psta_initsync for combined init/sync | |||||||
1166 | fIncomingState=psta_idle; // remains idle until first answer SyncHdr with OK status is received | |||||||
1167 | fInProgress=true; // assume in progress | |||||||
1168 | // set session ID string | |||||||
1169 | StringObjPrintf(fSynchdrSessionID,"%hd",(sInt16)fClientSessionNo); | |||||||
1170 | // now we have a session id, can now display debug stuff | |||||||
1171 | #ifdef SYDEBUG2 | |||||||
1172 | string t; | |||||||
1173 | StringObjTimestamp(t,getSystemNowAs(TCTX_SYSTEM((timecontext_t) ((tctx_tz_system) | TCTX_SYMBOLIC_TZ)))); | |||||||
1174 | PDEBUGPRINTFX(DBG_HOT,("\n[%s] =================> Starting new client session",t.c_str())){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("\n[%s] =================> Starting new client session" ,t.c_str()); }; | |||||||
1175 | #endif | |||||||
1176 | // - make sure we are logged into the local database (if needed) | |||||||
1177 | status=LocalLogin(); | |||||||
1178 | if (status!=LOCERR_OK) return status; | |||||||
1179 | // create header for first message no noResp | |||||||
1180 | issueHeader(false); | |||||||
1181 | } | |||||||
1182 | else { | |||||||
1183 | // check for proper end of session (caused by MessageEnded analysis) | |||||||
1184 | if (!fInProgress) { | |||||||
1185 | // give an opportunity to let make outgoing message end and flush xml end message | |||||||
1186 | FinishMessage(true, false); | |||||||
1187 | // end sync in all datastores (save anchors etc.) | |||||||
1188 | PDEBUGPRINTFX(DBG_PROTO,("Successful end of session -> calling engFinishDataStoreSync() for datastores now")){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ("Successful end of session -> calling engFinishDataStoreSync() for datastores now" ); }; | |||||||
1189 | for (pos=fLocalDataStores.begin(); pos!=fLocalDataStores.end(); ++pos) | |||||||
1190 | (*pos)->engFinishDataStoreSync(); // successful end | |||||||
1191 | PDEBUGPRINTFX(DBG_PROTO,("Session not any more in progress: NextMessage() returns OK status=0")){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ("Session not any more in progress: NextMessage() returns OK status=0" ); }; | |||||||
1192 | return LOCERR_OK; // done & ok | |||||||
1193 | } | |||||||
1194 | } | |||||||
1195 | // check expired case | |||||||
1196 | #ifdef APP_CAN_EXPIRE | |||||||
1197 | if (getClientBase()->fAppExpiryStatus!=LOCERR_OK) { | |||||||
1198 | PDEBUGPRINTFX(DBG_ERROR,("Evaluation Version expired - Please contact Synthesis AG for release version")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Evaluation Version expired - Please contact Synthesis AG for release version" ); }; | |||||||
1199 | return getClientBase()->fAppExpiryStatus; // payment required, done & error | |||||||
1200 | } | |||||||
1201 | #endif | |||||||
1202 | if (fOutgoingState==psta_init || fOutgoingState==psta_initsync) { | |||||||
1203 | // - if suspended in init, nothing substantial has happened already, so just exit | |||||||
1204 | if (isSuspending() && fOutgoingState==psta_init) { | |||||||
1205 | AbortSession(fAbortReasonStatus,true); | |||||||
1206 | return getAbortReasonStatus(); | |||||||
1207 | } | |||||||
1208 | // - prepare Alert(s) for databases to sync | |||||||
1209 | bool anyfirstsyncs=false; | |||||||
1210 | bool anyslowsyncs=false; | |||||||
1211 | TLocalEngineDS *localDS; | |||||||
1212 | for (pos=fLocalDataStores.begin(); pos!=fLocalDataStores.end(); ++pos) { | |||||||
1213 | // prepare alert (Note: datastore may be run by a superdatastore) | |||||||
1214 | localDS = *pos; | |||||||
1215 | status=localDS->engPrepareClientSyncAlert(); | |||||||
1216 | if (status!=LOCERR_OK) { | |||||||
1217 | // local database error | |||||||
1218 | return localError(status); // not found | |||||||
1219 | } | |||||||
1220 | if (localDS->fFirstTimeSync) anyfirstsyncs=true; | |||||||
1221 | if (localDS->fSlowSync) anyslowsyncs=true; | |||||||
1222 | } | |||||||
1223 | // send devinf in Put command right away with init message if either... | |||||||
1224 | // - mustSendDevInf() returns true signalling an external condition that suggests sending devInf (like changed config) | |||||||
1225 | // - any datastore is doing first time sync | |||||||
1226 | // - fPutDevInfAtSlowSync is true and any datastore is doing slow sync | |||||||
1227 | // - not already sent (can be true here in later sync cycles) | |||||||
1228 | if (!fRemoteGotDevinf && | |||||||
1229 | (mustSendDevInf() || | |||||||
1230 | anyfirstsyncs || | |||||||
1231 | (anyslowsyncs && static_cast<TAgentConfig *>(getRootConfig()->fAgentConfigP)->fPutDevInfAtSlowSync)) | |||||||
1232 | ) { | |||||||
1233 | TDevInfPutCommand *putcmdP = new TDevInfPutCommand(this); | |||||||
1234 | issueRootPtr(putcmdP); | |||||||
1235 | } | |||||||
1236 | // try to load devinf from cache (only if we don't know it already) | |||||||
1237 | if (!fRemoteDataStoresKnown || !fRemoteDataTypesKnown) { | |||||||
1238 | SmlDevInfDevInfPtr_t devinfP; | |||||||
1239 | if (loadRemoteDevInf(getRemoteURI(),devinfP)) { | |||||||
1240 | // we have cached devinf, analyze it now | |||||||
1241 | analyzeRemoteDevInf(devinfP); | |||||||
1242 | } | |||||||
1243 | } | |||||||
1244 | // GET the server's info if server didn't send it and we haven't cached at least the datastores | |||||||
1245 | if (!fRemoteDataStoresKnown) { | |||||||
1246 | // if we know datastores here, but not types, this means that remote does not have | |||||||
1247 | // CTCap, so it makes no sense to issue a GET again. | |||||||
1248 | #ifndef NO_DEVINF_GET | |||||||
1249 | PDEBUGPRINTFX(DBG_REMOTEINFO,("Nothing known about server, request DevInf using GET command")){ if (((0x00000100) & getDbgMask()) == (0x00000100)) getDbgLogger ()->setNextMask(0x00000100).DebugPrintfLastMask ("Nothing known about server, request DevInf using GET command" ); }; | |||||||
1250 | TGetCommand *getcommandP = new TGetCommand(this); | |||||||
1251 | getcommandP->addTargetLocItem(SyncMLDevInfNames[fSyncMLVersion]); | |||||||
1252 | string devinftype=SYNCML_DEVINF_META_TYPE"application/vnd.syncml-devinf"; | |||||||
1253 | addEncoding(devinftype); | |||||||
1254 | getcommandP->setMeta(newMetaType(devinftype.c_str())); | |||||||
1255 | ISSUE_COMMAND_ROOT(this,getcommandP){ TSmlCommand* p=getcommandP; getcommandP=__null; this->issueRootPtr (p); }; | |||||||
1256 | #endif | |||||||
1257 | } | |||||||
1258 | // - create Alert(s) for databases to sync | |||||||
1259 | for (pos=fLocalDataStores.begin(); pos!=fLocalDataStores.end(); ++pos) { | |||||||
1260 | // create alert for non-subdatastores | |||||||
1261 | localDS = *pos; | |||||||
1262 | if (!localDS->isSubDatastore()) { | |||||||
1263 | TAlertCommand *alertcmdP; | |||||||
1264 | status = localDS->engGenerateClientSyncAlert(alertcmdP); | |||||||
1265 | if (status!=0) { | |||||||
1266 | // local database error | |||||||
1267 | return status; // not found | |||||||
1268 | } | |||||||
1269 | ///%%%% unneeded (probably got here by copy&paste accidentally): if (localDS->fFirstTimeSync) anyfirstsyncs=true; | |||||||
1270 | // issue alert | |||||||
1271 | issueRootPtr(alertcmdP); | |||||||
1272 | } | |||||||
1273 | } | |||||||
1274 | // append sync phase if we have combined init/sync | |||||||
1275 | if (fOutgoingState==psta_initsync) { | |||||||
1276 | fOutgoingState=psta_sync; | |||||||
1277 | fRestarting=false; | |||||||
1278 | } | |||||||
1279 | } | |||||||
1280 | // process sync/syncop/map generating phases after init | |||||||
1281 | if (!isSuspending()) { | |||||||
1282 | // normal, session continues | |||||||
1283 | if (fOutgoingState==psta_sync) { | |||||||
1284 | // hold back sync until server has finished first package (init or initsync) | |||||||
1285 | if (fIncomingState==psta_sync || fIncomingState==psta_initsync) { | |||||||
1286 | // start sync for alerted datastores | |||||||
1287 | for (pos=fLocalDataStores.begin(); pos!=fLocalDataStores.end(); ++pos) { | |||||||
1288 | // Note: some datastores might be aborted due to unsuccessful alert. | |||||||
1289 | if ((*pos)->isActive()) { | |||||||
1290 | // prepare engine for sync (%%% new routine in 3.2.0.3, summarizing engInitForSyncOps() and | |||||||
1291 | // switching to dssta_dataaccessstarted, i.e. loading sync set), but do in only once | |||||||
1292 | if (!((*pos)->testState(dssta_syncsetready))) { | |||||||
1293 | // not yet started | |||||||
1294 | status = (*pos)->engInitForClientSync(); | |||||||
1295 | if (status!=LOCERR_OK ) { | |||||||
1296 | // failed | |||||||
1297 | if (status!=LOCERR_DATASTORE_ABORT) { | |||||||
1298 | AbortSession(status,true); | |||||||
1299 | return getAbortReasonStatus(); | |||||||
1300 | } | |||||||
1301 | } | |||||||
1302 | } | |||||||
1303 | // start or continue (which is largely nop, as continuing works via unfinished sync command) | |||||||
1304 | // generating sync items | |||||||
1305 | (*pos)->engClientStartOfSyncMessage(); | |||||||
1306 | } | |||||||
1307 | } | |||||||
1308 | } | |||||||
1309 | } | |||||||
1310 | else if (fOutgoingState==psta_map) { | |||||||
1311 | // hold back map until server has started sync at least (incominstate >=psta_sync) | |||||||
1312 | // NOTE: This is according to the specs, which says that client can begin | |||||||
1313 | // with Map/update status package BEFORE sync package from server is | |||||||
1314 | // completely received. | |||||||
1315 | // NOTE: Starfish server expects this and generates a few 222 alerts | |||||||
1316 | // if we wait here, but then goes to map as well | |||||||
1317 | // (so (fIncomingState==psta_map)-version works as well here! | |||||||
1318 | // %%%% other version: wait until server has started map phase as well | |||||||
1319 | // %%%% if (fIncomingState==psta_map) { | |||||||
1320 | if (fIncomingState>=psta_sync) { | |||||||
1321 | // start map for synced datastores | |||||||
1322 | for (pos=fLocalDataStores.begin(); pos!=fLocalDataStores.end(); ++pos) { | |||||||
1323 | // Note: some datastores might be aborted due to unsuccessful alert. | |||||||
1324 | if ((*pos)->isActive()) { | |||||||
1325 | // now call datastore to generate map command if not already done | |||||||
1326 | (*pos)->engClientStartOfMapMessage(fIncomingState<psta_map); | |||||||
1327 | } | |||||||
1328 | } | |||||||
1329 | } | |||||||
1330 | } | |||||||
1331 | else if (fOutgoingState==psta_supplement) { | |||||||
1332 | // we are waiting for the server to complete a pending phase altough we are already done | |||||||
1333 | // with everything we want to send. | |||||||
1334 | // -> just generate a Alert 222 and wait for server to complete | |||||||
1335 | PDEBUGPRINTFX(DBG_PROTO+DBG_HOT,("Client finished so far, but needs to wait in supplement outgoing state until server finishes phase")){ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ("Client finished so far, but needs to wait in supplement outgoing state until server finishes phase" ); }; | |||||||
1336 | } | |||||||
1337 | else if (fOutgoingState!=psta_init) { | |||||||
1338 | // NOTE: can be psta_init because "if" begins again after psta_init checking | |||||||
1339 | // to allow psta_init appending psta_sync for combined init/sync | |||||||
1340 | // no known state | |||||||
1341 | return 9999; // %%%%% | |||||||
1342 | } | |||||||
1343 | } // if not suspended | |||||||
1344 | ||||||||
1345 | // security only: exit here if session got aborted in between | |||||||
1346 | if (isAborted()) | |||||||
1347 | return getAbortReasonStatus(); // done & error | |||||||
1348 | if (!fInProgress) | |||||||
1349 | return 9999; // that's fine with us | |||||||
1350 | // now, we know that we will (most probably) send a message, so default for aDone is false from now on | |||||||
1351 | aDone=false; | |||||||
1352 | bool outgoingfinal; | |||||||
1353 | ||||||||
1354 | // check for suspend | |||||||
1355 | if (isSuspending()) { | |||||||
1356 | // make sure we send a Suspend Alert | |||||||
1357 | TAlertCommand *alertCmdP = new TAlertCommand(this,NULL__null,(uInt16)224); | |||||||
1358 | // - we just put local and remote URIs here | |||||||
1359 | SmlItemPtr_t itemP = newItem(); | |||||||
1360 | itemP->target = newLocation(fRemoteURI.c_str()); | |||||||
1361 | itemP->source = newLocation(fLocalURI.c_str()); | |||||||
1362 | alertCmdP->addItem(itemP); | |||||||
1363 | ISSUE_COMMAND_ROOT(this,alertCmdP){ TSmlCommand* p=alertCmdP; alertCmdP=__null; this->issueRootPtr (p); }; | |||||||
1364 | // outgoing message is final, regardless of any session state | |||||||
1365 | outgoingfinal=true; | |||||||
1366 | MarkSuspendAlertSent(true); | |||||||
1367 | } | |||||||
1368 | else { | |||||||
1369 | // Determine if package can be final and if we need an 222 Alert | |||||||
1370 | // NOTE: if any commands were interruped or not sent due to outgoing message | |||||||
1371 | // size limits, FinishMessage() will prevent final anyway, so no | |||||||
1372 | // separate checking for enOfSync or endOfMap is needed. | |||||||
1373 | // - can finalize message when server has at least started answering current package | |||||||
1374 | // OR if this is the first message (probably repeatedly) sent | |||||||
1375 | outgoingfinal = fIncomingState >= fOutgoingState || fIncomingState==psta_idle; | |||||||
1376 | if (outgoingfinal) { | |||||||
1377 | // allow early success here in case of nothing to respond, and nothing pending | |||||||
1378 | // StarFish server does need this... | |||||||
1379 | if (!fNeedToAnswer) { | |||||||
1380 | if (hasPendingCommands()) { | |||||||
1381 | // we have pending commands, cannot be final message | |||||||
1382 | outgoingfinal=false; | |||||||
1383 | } | |||||||
1384 | else { | |||||||
1385 | // no pending commands -> we're done now | |||||||
1386 | PDEBUGPRINTFX(DBG_PROTO,("Early end of session (nothing to send to server any more) -> calling engFinishDataStoreSync() for datastores now")){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ("Early end of session (nothing to send to server any more) -> calling engFinishDataStoreSync() for datastores now" ); }; | |||||||
1387 | // - end sync in all datastores (save anchors etc.) | |||||||
1388 | for (pos=fLocalDataStores.begin(); pos!=fLocalDataStores.end(); ++pos) | |||||||
1389 | (*pos)->engFinishDataStoreSync(); // successful end | |||||||
1390 | PDEBUGPRINTFX(DBG_PROTO,("Session not any more in progress: NextMessage() returns OK status=0")){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ("Session not any more in progress: NextMessage() returns OK status=0" ); }; | |||||||
1391 | // done & ok | |||||||
1392 | aDone=true; | |||||||
1393 | return LOCERR_OK; | |||||||
1394 | } | |||||||
1395 | } | |||||||
1396 | } | |||||||
1397 | } | |||||||
1398 | /* A dummy alert indicates this is a message with only alert222 request*/ | |||||||
1399 | bool dummyAlert = false; | |||||||
1400 | if (!outgoingfinal) { | |||||||
1401 | // - send Alert 222 if we need to continue package but have nothing to send | |||||||
1402 | // (or ALWAYS_CONTINUE222 defined) | |||||||
1403 | #ifndef ALWAYS_CONTINUE222 | |||||||
1404 | if (!fNeedToAnswer) | |||||||
1405 | #endif | |||||||
1406 | { | |||||||
1407 | /* End-less loop detection | |||||||
1408 | * Some servers will never end and triggers client sends | |||||||
1409 | * ALERT222 forever. Detect this scenario and abort the session if | |||||||
1410 | * detected. | |||||||
1411 | * It is still valid for the server to use ALERT222 to "keep-alive" the | |||||||
1412 | * connection. | |||||||
1413 | * Therefore the loop detection criteria is: | |||||||
1414 | * - Nothing to send except the 222 Alert (!fNeedToAnswer) | |||||||
1415 | * - 5 adjacent 222 alerts within 20 seconds | |||||||
1416 | * - no status for an actual sync op command received (fOutgoingAlert222Count will be reset by those) | |||||||
1417 | * because a server sending pending status in small chunks could also trigger the detector otherwise | |||||||
1418 | */ | |||||||
1419 | if (!fNeedToAnswer) { | |||||||
1420 | dummyAlert = true; | |||||||
1421 | if (fOutgoingAlert222Count++ == 0) { | |||||||
1422 | // start of 222 loop detection time | |||||||
1423 | fLastOutgoingAlert222 = getSystemNowAs(TCTX_UTC((timecontext_t) ((tctx_tz_UTC) | TCTX_SYMBOLIC_TZ))); | |||||||
1424 | } else if (fOutgoingAlert222Count > 5) { | |||||||
1425 | lineartime_t curTime = getSystemNowAs(TCTX_UTC((timecontext_t) ((tctx_tz_UTC) | TCTX_SYMBOLIC_TZ))); | |||||||
1426 | if (curTime - fLastOutgoingAlert222 < 20*secondToLinearTimeFactor) { | |||||||
1427 | PDEBUGPRINTFX(DBG_ERROR,({ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Warning: More than 5 consecutive Alert 222 within 20 seconds- " "looks like endless loop, abort session" ); } | |||||||
1428 | "Warning: More than 5 consecutive Alert 222 within 20 seconds- "{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Warning: More than 5 consecutive Alert 222 within 20 seconds- " "looks like endless loop, abort session" ); } | |||||||
1429 | "looks like endless loop, abort session"{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Warning: More than 5 consecutive Alert 222 within 20 seconds- " "looks like endless loop, abort session" ); } | |||||||
1430 | )){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Warning: More than 5 consecutive Alert 222 within 20 seconds- " "looks like endless loop, abort session" ); }; | |||||||
1431 | AbortSession(400, false); | |||||||
1432 | return getAbortReasonStatus(); | |||||||
1433 | } else { | |||||||
1434 | fOutgoingAlert222Count = 0; | |||||||
1435 | } | |||||||
1436 | } | |||||||
1437 | } | |||||||
1438 | // not final, and nothing to answer otherwise: create alert-Command to request more info | |||||||
1439 | TAlertCommand *alertCmdP = new TAlertCommand(this,NULL__null,(uInt16)222); | |||||||
1440 | // %%% not clear from spec what has to be in item for 222 alert code | |||||||
1441 | // but there MUST be an Item for the Alert command according to SyncML TK | |||||||
1442 | // - we just put local and remote URIs here | |||||||
1443 | SmlItemPtr_t itemP = newItem(); | |||||||
1444 | itemP->target = newLocation(fRemoteURI.c_str()); | |||||||
1445 | itemP->source = newLocation(fLocalURI.c_str()); | |||||||
1446 | alertCmdP->addItem(itemP); | |||||||
1447 | ISSUE_COMMAND_ROOT(this,alertCmdP){ TSmlCommand* p=alertCmdP; alertCmdP=__null; this->issueRootPtr (p); }; | |||||||
1448 | } | |||||||
1449 | } | |||||||
1450 | // We send a response with no dummy alert, so reset the alert detector | |||||||
1451 | if (!dummyAlert) { | |||||||
1452 | fOutgoingAlert222Count = 0; | |||||||
1453 | } | |||||||
1454 | ||||||||
1455 | // Normally the package will be closed normally when the client is | |||||||
1456 | // ready. The exception is if we might want to restart the sync | |||||||
1457 | // session. This is checked below. | |||||||
1458 | bool finalprevented = false; | |||||||
1459 | ||||||||
1460 | // send custom end-of session puts or restart session | |||||||
1461 | if (!isSuspending() && outgoingfinal && fOutgoingState==psta_map) { | |||||||
1462 | // End of outgoing map package; let custom PUTs which may transmit some session statistics etc. happen now | |||||||
1463 | // TODO: this code is not reached when fOutgoingState==psta_map is skipped | |||||||
1464 | // by ClientMessageEnded() (see "All datastores in from-client-only mode, and no need to answer: skip map phase"). | |||||||
1465 | // A bug? For restarting a sync, the problem is avoided by | |||||||
1466 | // disabling the standard-compliant "skip map phase" in favor | |||||||
1467 | // of "let client enter map phase" mode (fCompleteFromClientOnly). | |||||||
1468 | issueCustomEndPut(); | |||||||
1469 | ||||||||
1470 | if (restartSync()) { | |||||||
1471 | // don't allow <Final> if we are going to restart sync in | |||||||
1472 | // ClientMessageEnded(), also remember that we did that | |||||||
1473 | finalprevented=true; | |||||||
1474 | // flag for TSyncAgent::ClientMessageEnded() | |||||||
1475 | fRestartingSync=true; | |||||||
1476 | } | |||||||
1477 | } | |||||||
1478 | // message complete, now finish it | |||||||
1479 | FinishMessage( | |||||||
1480 | outgoingfinal, // allowed if possible | |||||||
1481 | finalprevented // final not allowed when restarting sync | |||||||
1482 | ); | |||||||
1483 | // Note, now fNewOutgoingPackage is set (by FinishMessage()) | |||||||
1484 | // if next message will be responded to with a new package | |||||||
1485 | ||||||||
1486 | // debug info | |||||||
1487 | #ifdef SYDEBUG2 | |||||||
1488 | if (PDEBUGMASKgetDbgMask() & DBG_SESSION0x00000020) { | |||||||
1489 | PDEBUGPRINTFX(DBG_SESSION,({ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "---> NextMessage, outgoing state='%s', incoming state='%s'" , PackageStateNames[fOutgoingState], PackageStateNames[fIncomingState ] ); } | |||||||
1490 | "---> NextMessage, outgoing state='%s', incoming state='%s'",{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "---> NextMessage, outgoing state='%s', incoming state='%s'" , PackageStateNames[fOutgoingState], PackageStateNames[fIncomingState ] ); } | |||||||
1491 | PackageStateNames[fOutgoingState],{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "---> NextMessage, outgoing state='%s', incoming state='%s'" , PackageStateNames[fOutgoingState], PackageStateNames[fIncomingState ] ); } | |||||||
1492 | PackageStateNames[fIncomingState]{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "---> NextMessage, outgoing state='%s', incoming state='%s'" , PackageStateNames[fOutgoingState], PackageStateNames[fIncomingState ] ); } | |||||||
1493 | )){ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "---> NextMessage, outgoing state='%s', incoming state='%s'" , PackageStateNames[fOutgoingState], PackageStateNames[fIncomingState ] ); }; | |||||||
1494 | for (pos=fLocalDataStores.begin(); pos!=fLocalDataStores.end(); ++pos) { | |||||||
1495 | // Show state of local datastores | |||||||
1496 | PDEBUGPRINTFX(DBG_SESSION,({ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "Local Datastore '%s': %sState=%s, %s%s sync, %s%s" , (*pos)->getName(), (*pos)->isAborted() ? "ABORTED - " : "", (*pos)->getDSStateName(), (*pos)->isResuming() ? "RESUMED " : "", (*pos)->fSlowSync ? "SLOW" : "normal", SyncModeDescriptions [(*pos)->fSyncMode], (*pos)->fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
1497 | "Local Datastore '%s': %sState=%s, %s%s sync, %s%s",{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "Local Datastore '%s': %sState=%s, %s%s sync, %s%s" , (*pos)->getName(), (*pos)->isAborted() ? "ABORTED - " : "", (*pos)->getDSStateName(), (*pos)->isResuming() ? "RESUMED " : "", (*pos)->fSlowSync ? "SLOW" : "normal", SyncModeDescriptions [(*pos)->fSyncMode], (*pos)->fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
1498 | (*pos)->getName(),{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "Local Datastore '%s': %sState=%s, %s%s sync, %s%s" , (*pos)->getName(), (*pos)->isAborted() ? "ABORTED - " : "", (*pos)->getDSStateName(), (*pos)->isResuming() ? "RESUMED " : "", (*pos)->fSlowSync ? "SLOW" : "normal", SyncModeDescriptions [(*pos)->fSyncMode], (*pos)->fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
1499 | (*pos)->isAborted() ? "ABORTED - " : "",{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "Local Datastore '%s': %sState=%s, %s%s sync, %s%s" , (*pos)->getName(), (*pos)->isAborted() ? "ABORTED - " : "", (*pos)->getDSStateName(), (*pos)->isResuming() ? "RESUMED " : "", (*pos)->fSlowSync ? "SLOW" : "normal", SyncModeDescriptions [(*pos)->fSyncMode], (*pos)->fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
1500 | (*pos)->getDSStateName(),{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "Local Datastore '%s': %sState=%s, %s%s sync, %s%s" , (*pos)->getName(), (*pos)->isAborted() ? "ABORTED - " : "", (*pos)->getDSStateName(), (*pos)->isResuming() ? "RESUMED " : "", (*pos)->fSlowSync ? "SLOW" : "normal", SyncModeDescriptions [(*pos)->fSyncMode], (*pos)->fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
1501 | (*pos)->isResuming() ? "RESUMED " : "",{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "Local Datastore '%s': %sState=%s, %s%s sync, %s%s" , (*pos)->getName(), (*pos)->isAborted() ? "ABORTED - " : "", (*pos)->getDSStateName(), (*pos)->isResuming() ? "RESUMED " : "", (*pos)->fSlowSync ? "SLOW" : "normal", SyncModeDescriptions [(*pos)->fSyncMode], (*pos)->fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
1502 | (*pos)->fSlowSync ? "SLOW" : "normal",{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "Local Datastore '%s': %sState=%s, %s%s sync, %s%s" , (*pos)->getName(), (*pos)->isAborted() ? "ABORTED - " : "", (*pos)->getDSStateName(), (*pos)->isResuming() ? "RESUMED " : "", (*pos)->fSlowSync ? "SLOW" : "normal", SyncModeDescriptions [(*pos)->fSyncMode], (*pos)->fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
1503 | SyncModeDescriptions[(*pos)->fSyncMode],{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "Local Datastore '%s': %sState=%s, %s%s sync, %s%s" , (*pos)->getName(), (*pos)->isAborted() ? "ABORTED - " : "", (*pos)->getDSStateName(), (*pos)->isResuming() ? "RESUMED " : "", (*pos)->fSlowSync ? "SLOW" : "normal", SyncModeDescriptions [(*pos)->fSyncMode], (*pos)->fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
1504 | (*pos)->fServerAlerted ? ", Server-Alerted" : ""{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "Local Datastore '%s': %sState=%s, %s%s sync, %s%s" , (*pos)->getName(), (*pos)->isAborted() ? "ABORTED - " : "", (*pos)->getDSStateName(), (*pos)->isResuming() ? "RESUMED " : "", (*pos)->fSlowSync ? "SLOW" : "normal", SyncModeDescriptions [(*pos)->fSyncMode], (*pos)->fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
1505 | )){ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "Local Datastore '%s': %sState=%s, %s%s sync, %s%s" , (*pos)->getName(), (*pos)->isAborted() ? "ABORTED - " : "", (*pos)->getDSStateName(), (*pos)->isResuming() ? "RESUMED " : "", (*pos)->fSlowSync ? "SLOW" : "normal", SyncModeDescriptions [(*pos)->fSyncMode], (*pos)->fServerAlerted ? ", Server-Alerted" : "" ); }; | |||||||
1506 | } | |||||||
1507 | } | |||||||
1508 | PDEBUGENDBLOCK("SyncML_Outgoing")getDbgLogger()->DebugCloseBlock( "SyncML_Outgoing"); | |||||||
1509 | if (getLastIncomingMsgID()>0) { | |||||||
1510 | // we have already received an incoming message, so we have started an "SyncML_Incoming" blocks sometime | |||||||
1511 | PDEBUGENDBLOCK("SyncML_Incoming")getDbgLogger()->DebugCloseBlock( "SyncML_Incoming"); // terminate debug block of previous incoming message as well | |||||||
1512 | } | |||||||
1513 | #endif | |||||||
1514 | // ok | |||||||
1515 | return LOCERR_OK; // ok | |||||||
1516 | } // TSyncAgent::NextMessage | |||||||
1517 | ||||||||
1518 | ||||||||
1519 | // called after successful decoding of an incoming message | |||||||
1520 | bool TSyncAgent::ClientMessageStarted(SmlSyncHdrPtr_t aContentP, TStatusCommand &aStatusCommand, bool aBad) | |||||||
1521 | { | |||||||
1522 | // message not authorized by default | |||||||
1523 | fMessageAuthorized=false; | |||||||
1524 | ||||||||
1525 | // Check information from SyncHdr | |||||||
1526 | if ( | |||||||
1527 | aBad || | |||||||
1528 | (!(fSynchdrSessionID==smlPCDataToCharP(aContentP->sessionID))) || | |||||||
1529 | (!(fLocalURI==smlSrcTargLocURIToCharP(aContentP->target))) | |||||||
1530 | ) { | |||||||
1531 | // bad response | |||||||
1532 | PDEBUGPRINTFX(DBG_ERROR,({ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Bad SyncHeader from Server. Syntax %s, SessionID (rcvd/correct) = '%s' / '%s', LocalURI (rcvd/correct) = '%s' / '%s'" , aBad ? "ok" : "BAD", smlPCDataToCharP(aContentP->sessionID ), fSynchdrSessionID.c_str(), smlSrcTargLocURIToCharP(aContentP ->target), fLocalURI.c_str() ); } | |||||||
1533 | "Bad SyncHeader from Server. Syntax %s, SessionID (rcvd/correct) = '%s' / '%s', LocalURI (rcvd/correct) = '%s' / '%s'",{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Bad SyncHeader from Server. Syntax %s, SessionID (rcvd/correct) = '%s' / '%s', LocalURI (rcvd/correct) = '%s' / '%s'" , aBad ? "ok" : "BAD", smlPCDataToCharP(aContentP->sessionID ), fSynchdrSessionID.c_str(), smlSrcTargLocURIToCharP(aContentP ->target), fLocalURI.c_str() ); } | |||||||
1534 | aBad ? "ok" : "BAD",{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Bad SyncHeader from Server. Syntax %s, SessionID (rcvd/correct) = '%s' / '%s', LocalURI (rcvd/correct) = '%s' / '%s'" , aBad ? "ok" : "BAD", smlPCDataToCharP(aContentP->sessionID ), fSynchdrSessionID.c_str(), smlSrcTargLocURIToCharP(aContentP ->target), fLocalURI.c_str() ); } | |||||||
1535 | smlPCDataToCharP(aContentP->sessionID),{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Bad SyncHeader from Server. Syntax %s, SessionID (rcvd/correct) = '%s' / '%s', LocalURI (rcvd/correct) = '%s' / '%s'" , aBad ? "ok" : "BAD", smlPCDataToCharP(aContentP->sessionID ), fSynchdrSessionID.c_str(), smlSrcTargLocURIToCharP(aContentP ->target), fLocalURI.c_str() ); } | |||||||
1536 | fSynchdrSessionID.c_str(),{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Bad SyncHeader from Server. Syntax %s, SessionID (rcvd/correct) = '%s' / '%s', LocalURI (rcvd/correct) = '%s' / '%s'" , aBad ? "ok" : "BAD", smlPCDataToCharP(aContentP->sessionID ), fSynchdrSessionID.c_str(), smlSrcTargLocURIToCharP(aContentP ->target), fLocalURI.c_str() ); } | |||||||
1537 | smlSrcTargLocURIToCharP(aContentP->target),{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Bad SyncHeader from Server. Syntax %s, SessionID (rcvd/correct) = '%s' / '%s', LocalURI (rcvd/correct) = '%s' / '%s'" , aBad ? "ok" : "BAD", smlPCDataToCharP(aContentP->sessionID ), fSynchdrSessionID.c_str(), smlSrcTargLocURIToCharP(aContentP ->target), fLocalURI.c_str() ); } | |||||||
1538 | fLocalURI.c_str(){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Bad SyncHeader from Server. Syntax %s, SessionID (rcvd/correct) = '%s' / '%s', LocalURI (rcvd/correct) = '%s' / '%s'" , aBad ? "ok" : "BAD", smlPCDataToCharP(aContentP->sessionID ), fSynchdrSessionID.c_str(), smlSrcTargLocURIToCharP(aContentP ->target), fLocalURI.c_str() ); } | |||||||
1539 | )){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Bad SyncHeader from Server. Syntax %s, SessionID (rcvd/correct) = '%s' / '%s', LocalURI (rcvd/correct) = '%s' / '%s'" , aBad ? "ok" : "BAD", smlPCDataToCharP(aContentP->sessionID ), fSynchdrSessionID.c_str(), smlSrcTargLocURIToCharP(aContentP ->target), fLocalURI.c_str() ); }; | |||||||
1540 | aStatusCommand.setStatusCode(400); // bad response/request | |||||||
1541 | AbortSession(400,true); | |||||||
1542 | return false; | |||||||
1543 | } | |||||||
1544 | // check for suspend: if we are suspended at this point, this means that we have sent the Suspend Alert already | |||||||
1545 | // in the previous message (due to user suspend request), so we can now terminate the session | |||||||
1546 | if (isSuspending() && isSuspendAlertSent()) { | |||||||
1547 | AbortSession(514,true,LOCERR_USERSUSPEND); | |||||||
1548 | return false; | |||||||
1549 | } | |||||||
1550 | // - RespURI (remote URI to respond to) | |||||||
1551 | if (aContentP->respURI) { | |||||||
1552 | fRespondURI=smlPCDataToCharP(aContentP->respURI); | |||||||
1553 | DEBUGPRINTFX(DBG_PROTO,("RespURI set to = '%s'",fRespondURI.c_str())){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ("RespURI set to = '%s'" ,fRespondURI.c_str()); }; | |||||||
1554 | } | |||||||
1555 | // authorization check | |||||||
1556 | // Note: next message will be started not before status for last one | |||||||
1557 | // has been processed. Commands issued before will automatically | |||||||
1558 | // be queued by issuePtr() | |||||||
1559 | // %%% none for now | |||||||
1560 | fSessionAuthorized=true; | |||||||
1561 | fMessageAuthorized=true; | |||||||
1562 | // returns false on BAD header (but true on wrong/bad/missing cred) | |||||||
1563 | return true; | |||||||
1564 | } // TSyncAgent::ClientMessageStarted | |||||||
1565 | ||||||||
1566 | ||||||||
1567 | // determines new package states and sets fInProgress | |||||||
1568 | void TSyncAgent::ClientMessageEnded(bool aIncomingFinal) | |||||||
1569 | { | |||||||
1570 | TLocalDataStorePContainer::iterator pos; | |||||||
1571 | ||||||||
1572 | // show status before processing | |||||||
1573 | PDEBUGPRINTFX(DBG_SESSION,({ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "MessageEnded starts : old outgoing state='%s', old incoming state='%s', %sNeedToAnswer" , PackageStateNames[fOutgoingState], PackageStateNames[fIncomingState ], fNeedToAnswer ? "" : "NO " ); } | |||||||
1574 | "MessageEnded starts : old outgoing state='%s', old incoming state='%s', %sNeedToAnswer",{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "MessageEnded starts : old outgoing state='%s', old incoming state='%s', %sNeedToAnswer" , PackageStateNames[fOutgoingState], PackageStateNames[fIncomingState ], fNeedToAnswer ? "" : "NO " ); } | |||||||
1575 | PackageStateNames[fOutgoingState],{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "MessageEnded starts : old outgoing state='%s', old incoming state='%s', %sNeedToAnswer" , PackageStateNames[fOutgoingState], PackageStateNames[fIncomingState ], fNeedToAnswer ? "" : "NO " ); } | |||||||
1576 | PackageStateNames[fIncomingState],{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "MessageEnded starts : old outgoing state='%s', old incoming state='%s', %sNeedToAnswer" , PackageStateNames[fOutgoingState], PackageStateNames[fIncomingState ], fNeedToAnswer ? "" : "NO " ); } | |||||||
1577 | fNeedToAnswer ? "" : "NO "{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "MessageEnded starts : old outgoing state='%s', old incoming state='%s', %sNeedToAnswer" , PackageStateNames[fOutgoingState], PackageStateNames[fIncomingState ], fNeedToAnswer ? "" : "NO " ); } | |||||||
1578 | )){ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "MessageEnded starts : old outgoing state='%s', old incoming state='%s', %sNeedToAnswer" , PackageStateNames[fOutgoingState], PackageStateNames[fIncomingState ], fNeedToAnswer ? "" : "NO " ); }; | |||||||
1579 | bool allFromClientOnly=false; | |||||||
1580 | // process exceptions | |||||||
1581 | if (fAborted) { | |||||||
1582 | PDEBUGPRINTFX(DBG_ERROR,("***** Session is flagged 'aborted' -> MessageEnded ends package and session")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("***** Session is flagged 'aborted' -> MessageEnded ends package and session" ); }; | |||||||
1583 | fOutgoingState=psta_idle; | |||||||
1584 | fIncomingState=psta_idle; | |||||||
1585 | fInProgress=false; | |||||||
1586 | } // if aborted | |||||||
1587 | else if (!fMessageAuthorized) { | |||||||
1588 | // not authorized messages will just be ignored, so | |||||||
1589 | // nothing changes in states | |||||||
1590 | // %%% this will probably not really work, as we would need to repeat the last | |||||||
1591 | // message in this (unlikely) case that fMessageAuthorized is not set for | |||||||
1592 | // a non-first message (first message case is handled in handleHeaderStatus) | |||||||
1593 | DEBUGPRINTFX(DBG_ERROR,("***** received Message not authorized, ignore and DONT end package")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("***** received Message not authorized, ignore and DONT end package" ); }; | |||||||
1594 | fInProgress=true; | |||||||
1595 | } | |||||||
1596 | else { | |||||||
1597 | fInProgress=true; // assume we need to continue | |||||||
1598 | allFromClientOnly=checkAllFromClientOnly(); | |||||||
1599 | // new outgoing state is determined by the incomingState of this message | |||||||
1600 | // (which is the answer to the <final/> message of the previous outgoing package) | |||||||
1601 | if (fNewOutgoingPackage && fIncomingState!=psta_idle) { | |||||||
1602 | // last message sent was an end-of-package, so next will be a new package | |||||||
1603 | if (fIncomingState==psta_init) { | |||||||
1604 | // server has responded (or is still responding) to our finished init, | |||||||
1605 | // so client enters sync state now (but holds back sync until server | |||||||
1606 | // has finished init) | |||||||
1607 | fOutgoingState=psta_sync; | |||||||
1608 | fRestarting=false; | |||||||
1609 | } | |||||||
1610 | else if (fIncomingState==psta_sync || fIncomingState==psta_initsync) { | |||||||
1611 | // server has started (or already finished) sending statuses for our | |||||||
1612 | // <sync> or its own <sync> | |||||||
1613 | // client can enter map state (but holds back maps until server | |||||||
1614 | // has finished sync/initsync). In case of allFromClientOnly, we skip the map phase | |||||||
1615 | // but only if there is no need to answer. | |||||||
1616 | // Otherwise, this is most probably an old (pre 2.9.8.2) Synthesis server that has | |||||||
1617 | // sent an empty <sync> (and the status for it has set fNeedToAnswer), so we still | |||||||
1618 | // go to map phase. | |||||||
1619 | if (allFromClientOnly && !fNeedToAnswer) { | |||||||
1620 | fOutgoingState=psta_supplement; // all datastores are from-client-only, skip map phase | |||||||
1621 | PDEBUGPRINTFX(DBG_PROTO+DBG_HOT,("All datastores in from-client-only mode, and no need to answer: skip map phase")){ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ("All datastores in from-client-only mode, and no need to answer: skip map phase" ); }; | |||||||
1622 | } | |||||||
1623 | else { | |||||||
1624 | fOutgoingState=psta_map; // Some datastores do from-server-only or twoway, so we need a map phase | |||||||
1625 | allFromClientOnly=false; // do not skip map phase | |||||||
1626 | } | |||||||
1627 | } | |||||||
1628 | else { | |||||||
1629 | // map is finished as well, we might need extra packages just to | |||||||
1630 | // finish getting results for map commands | |||||||
1631 | fOutgoingState=psta_supplement; | |||||||
1632 | } | |||||||
1633 | } | |||||||
1634 | // New incoming state is simply derived from the incoming state of | |||||||
1635 | // this message | |||||||
1636 | if (fRestartingSync) { | |||||||
1637 | PDEBUGPRINTFX(DBG_HOT,("MessageEnded: restart sync")){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("MessageEnded: restart sync" ); }; | |||||||
1638 | fOutgoingState=psta_init; | |||||||
1639 | fIncomingState=psta_init; | |||||||
1640 | } else if (aIncomingFinal && fIncomingState!=psta_idle) { | |||||||
1641 | if (fIncomingState==psta_init) { | |||||||
1642 | // switch to sync | |||||||
1643 | fIncomingState=psta_sync; | |||||||
1644 | } | |||||||
1645 | else if (fIncomingState==psta_sync || fIncomingState==psta_initsync) { | |||||||
1646 | // check what to do | |||||||
1647 | if (allFromClientOnly) { | |||||||
1648 | // no need to answer and allFromClientOnly -> this is the end of the session | |||||||
1649 | fIncomingState=psta_supplement; | |||||||
1650 | fInProgress=false; // normally, at end of map answer, we are done | |||||||
1651 | } | |||||||
1652 | else { | |||||||
1653 | fIncomingState=psta_map; | |||||||
1654 | } | |||||||
1655 | } | |||||||
1656 | else { | |||||||
1657 | // end of a map phase - end of session (if no fNeedToAnswer) | |||||||
1658 | fIncomingState=psta_supplement; | |||||||
1659 | // this only ALLOWS ending the session, but it will continue as long | |||||||
1660 | // as more than OK for SyncHdr (fNeedToAnswer) must be sent | |||||||
1661 | fInProgress=false; // normally, at end of map answer, we are done | |||||||
1662 | } | |||||||
1663 | } | |||||||
1664 | // continue anyway as long as we need to answer | |||||||
1665 | if (fNeedToAnswer) fInProgress=true; | |||||||
1666 | } | |||||||
1667 | // show states | |||||||
1668 | PDEBUGPRINTFX(DBG_HOT,({ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "MessageEnded finishes : new outgoing state='%s', new incoming state='%s', %sNeedToAnswer" , PackageStateNames[fOutgoingState], PackageStateNames[fIncomingState ], fNeedToAnswer ? "" : "NO " ); } | |||||||
1669 | "MessageEnded finishes : new outgoing state='%s', new incoming state='%s', %sNeedToAnswer",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "MessageEnded finishes : new outgoing state='%s', new incoming state='%s', %sNeedToAnswer" , PackageStateNames[fOutgoingState], PackageStateNames[fIncomingState ], fNeedToAnswer ? "" : "NO " ); } | |||||||
1670 | PackageStateNames[fOutgoingState],{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "MessageEnded finishes : new outgoing state='%s', new incoming state='%s', %sNeedToAnswer" , PackageStateNames[fOutgoingState], PackageStateNames[fIncomingState ], fNeedToAnswer ? "" : "NO " ); } | |||||||
1671 | PackageStateNames[fIncomingState],{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "MessageEnded finishes : new outgoing state='%s', new incoming state='%s', %sNeedToAnswer" , PackageStateNames[fOutgoingState], PackageStateNames[fIncomingState ], fNeedToAnswer ? "" : "NO " ); } | |||||||
1672 | fNeedToAnswer ? "" : "NO "{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "MessageEnded finishes : new outgoing state='%s', new incoming state='%s', %sNeedToAnswer" , PackageStateNames[fOutgoingState], PackageStateNames[fIncomingState ], fNeedToAnswer ? "" : "NO " ); } | |||||||
1673 | )){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "MessageEnded finishes : new outgoing state='%s', new incoming state='%s', %sNeedToAnswer" , PackageStateNames[fOutgoingState], PackageStateNames[fIncomingState ], fNeedToAnswer ? "" : "NO " ); }; | |||||||
1674 | // let all local datastores know that message has ended | |||||||
1675 | for (pos=fLocalDataStores.begin(); pos!=fLocalDataStores.end(); ++pos) { | |||||||
1676 | TLocalEngineDS *localDS = *pos; | |||||||
1677 | // let them know | |||||||
1678 | localDS->engEndOfMessage(); | |||||||
1679 | if (fRestartingSync) { | |||||||
1680 | // finish current session as far as the datastore is concerned | |||||||
1681 | localDS->engFinishDataStoreSync(LOCERR_OK); | |||||||
1682 | ||||||||
1683 | // and start again | |||||||
1684 | localDS->changeState(dssta_adminready); | |||||||
1685 | localDS->fFirstTimeSync = false; | |||||||
1686 | ||||||||
1687 | // unsetting flow sync leads to new sync mode: | |||||||
1688 | // - slow sync -> two-way sync or one-way if data direction was limited | |||||||
1689 | // - refresh sync -> one-way sync in same direction | |||||||
1690 | // - one-way sync -> do it again | |||||||
1691 | localDS->fSlowSync = false; | |||||||
1692 | } | |||||||
1693 | // Show state of local datastores | |||||||
1694 | PDEBUGPRINTFX(DBG_HOT,({ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Local Datastore '%s': %sState=%s, %s%s sync, %s%s" , localDS->getName(), localDS->isAborted() ? "ABORTED - " : "", localDS->getDSStateName(), localDS->isResuming() ? "RESUMED " : "", localDS->isSlowSync() ? "SLOW" : "normal" , SyncModeDescriptions[localDS->getSyncMode()], localDS-> fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
1695 | "Local Datastore '%s': %sState=%s, %s%s sync, %s%s",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Local Datastore '%s': %sState=%s, %s%s sync, %s%s" , localDS->getName(), localDS->isAborted() ? "ABORTED - " : "", localDS->getDSStateName(), localDS->isResuming() ? "RESUMED " : "", localDS->isSlowSync() ? "SLOW" : "normal" , SyncModeDescriptions[localDS->getSyncMode()], localDS-> fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
1696 | localDS->getName(),{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Local Datastore '%s': %sState=%s, %s%s sync, %s%s" , localDS->getName(), localDS->isAborted() ? "ABORTED - " : "", localDS->getDSStateName(), localDS->isResuming() ? "RESUMED " : "", localDS->isSlowSync() ? "SLOW" : "normal" , SyncModeDescriptions[localDS->getSyncMode()], localDS-> fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
1697 | localDS->isAborted() ? "ABORTED - " : "",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Local Datastore '%s': %sState=%s, %s%s sync, %s%s" , localDS->getName(), localDS->isAborted() ? "ABORTED - " : "", localDS->getDSStateName(), localDS->isResuming() ? "RESUMED " : "", localDS->isSlowSync() ? "SLOW" : "normal" , SyncModeDescriptions[localDS->getSyncMode()], localDS-> fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
1698 | localDS->getDSStateName(),{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Local Datastore '%s': %sState=%s, %s%s sync, %s%s" , localDS->getName(), localDS->isAborted() ? "ABORTED - " : "", localDS->getDSStateName(), localDS->isResuming() ? "RESUMED " : "", localDS->isSlowSync() ? "SLOW" : "normal" , SyncModeDescriptions[localDS->getSyncMode()], localDS-> fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
1699 | localDS->isResuming() ? "RESUMED " : "",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Local Datastore '%s': %sState=%s, %s%s sync, %s%s" , localDS->getName(), localDS->isAborted() ? "ABORTED - " : "", localDS->getDSStateName(), localDS->isResuming() ? "RESUMED " : "", localDS->isSlowSync() ? "SLOW" : "normal" , SyncModeDescriptions[localDS->getSyncMode()], localDS-> fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
1700 | localDS->isSlowSync() ? "SLOW" : "normal",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Local Datastore '%s': %sState=%s, %s%s sync, %s%s" , localDS->getName(), localDS->isAborted() ? "ABORTED - " : "", localDS->getDSStateName(), localDS->isResuming() ? "RESUMED " : "", localDS->isSlowSync() ? "SLOW" : "normal" , SyncModeDescriptions[localDS->getSyncMode()], localDS-> fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
1701 | SyncModeDescriptions[localDS->getSyncMode()],{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Local Datastore '%s': %sState=%s, %s%s sync, %s%s" , localDS->getName(), localDS->isAborted() ? "ABORTED - " : "", localDS->getDSStateName(), localDS->isResuming() ? "RESUMED " : "", localDS->isSlowSync() ? "SLOW" : "normal" , SyncModeDescriptions[localDS->getSyncMode()], localDS-> fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
1702 | localDS->fServerAlerted ? ", Server-Alerted" : ""{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Local Datastore '%s': %sState=%s, %s%s sync, %s%s" , localDS->getName(), localDS->isAborted() ? "ABORTED - " : "", localDS->getDSStateName(), localDS->isResuming() ? "RESUMED " : "", localDS->isSlowSync() ? "SLOW" : "normal" , SyncModeDescriptions[localDS->getSyncMode()], localDS-> fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
1703 | )){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Local Datastore '%s': %sState=%s, %s%s sync, %s%s" , localDS->getName(), localDS->isAborted() ? "ABORTED - " : "", localDS->getDSStateName(), localDS->isResuming() ? "RESUMED " : "", localDS->isSlowSync() ? "SLOW" : "normal" , SyncModeDescriptions[localDS->getSyncMode()], localDS-> fServerAlerted ? ", Server-Alerted" : "" ); }; | |||||||
1704 | } | |||||||
1705 | fRestartingSync = false; | |||||||
1706 | // thread might end here, so stop profiling | |||||||
1707 | TP_STOP(fTPInfo); | |||||||
1708 | } // TSyncAgent::ClientMessageEnded | |||||||
1709 | ||||||||
1710 | ||||||||
1711 | // get credentials/username to authenticate with remote party, NULL if none | |||||||
1712 | SmlCredPtr_t TSyncAgent::newCredentialsForRemote(void) | |||||||
1713 | { | |||||||
1714 | if (fNeedAuth) { | |||||||
1715 | // generate cretentials from username/password | |||||||
1716 | PDEBUGPRINTFX(DBG_PROTO+DBG_USERDATA,("Authenticating with server as user '%s'", fServerUser.c_str())){ if (((0x00000010 +0x01000000) & getDbgMask()) == (0x00000010 +0x01000000)) getDbgLogger()->setNextMask(0x00000010 +0x01000000 ).DebugPrintfLastMask ("Authenticating with server as user '%s'" , fServerUser.c_str()); }; | |||||||
1717 | PDEBUGPRINTFX(DBG_PROTO+DBG_USERDATA+DBG_EXOTIC,("- using nonce '%s'", fRemoteNonce.c_str())){ if (((0x00000010 +0x01000000 +0x80000000) & getDbgMask( )) == (0x00000010 +0x01000000 +0x80000000)) getDbgLogger()-> setNextMask(0x00000010 +0x01000000 +0x80000000).DebugPrintfLastMask ("- using nonce '%s'", fRemoteNonce.c_str()); }; | |||||||
1718 | // NOTE: can be NULL when fServerRequestedAuth is auth_none | |||||||
1719 | return newCredentials( | |||||||
1720 | fServerUser.c_str(), | |||||||
1721 | fServerPassword.c_str() | |||||||
1722 | ); | |||||||
1723 | } | |||||||
1724 | else { | |||||||
1725 | // already authorized, no auth needed | |||||||
1726 | return NULL__null; | |||||||
1727 | } | |||||||
1728 | } // TSyncAgent::newCredentialsForRemote | |||||||
1729 | ||||||||
1730 | ||||||||
1731 | // get client base | |||||||
1732 | TSyncClientBase *TSyncAgent::getClientBase(void) | |||||||
1733 | { | |||||||
1734 | return static_cast<TSyncClientBase *>(getSyncAppBase()); | |||||||
1735 | } // TSyncAgent::getClientBase | |||||||
1736 | ||||||||
1737 | ||||||||
1738 | // retry older protocol, returns false if no older protocol to try | |||||||
1739 | bool TSyncAgent::retryOlderProtocol(bool aSameVersionRetry, bool aOldMessageInBuffer) | |||||||
1740 | { | |||||||
1741 | if (fIncomingState==psta_idle) { | |||||||
1742 | // if we have not started a session yet and not using oldest protocol already, | |||||||
1743 | // we want to retry with next older SyncML version | |||||||
1744 | if (aSameVersionRetry) { | |||||||
1745 | // just retry same version | |||||||
1746 | PDEBUGPRINTFX(DBG_PROTO,("Retrying session start with %s",SyncMLVerProtoNames[fSyncMLVersion])){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ("Retrying session start with %s" ,SyncMLVerProtoNames[fSyncMLVersion]); }; | |||||||
1747 | } | |||||||
1748 | else if (fSyncMLVersion>getSessionConfig()->fMinSyncMLVersionSupported) { | |||||||
1749 | // next lower | |||||||
1750 | fSyncMLVersion=(TSyncMLVersions)(((uInt16)fSyncMLVersion)-1); | |||||||
1751 | PDEBUGPRINTFX(DBG_PROTO,("Server does not support our SyncML version, trying with %s",SyncMLVerProtoNames[fSyncMLVersion])){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ("Server does not support our SyncML version, trying with %s" ,SyncMLVerProtoNames[fSyncMLVersion]); }; | |||||||
1752 | } | |||||||
1753 | else { | |||||||
1754 | // cannot retry | |||||||
1755 | return false; | |||||||
1756 | } | |||||||
1757 | // retry | |||||||
1758 | retryClientSessionStart(aOldMessageInBuffer); | |||||||
1759 | return true; | |||||||
1760 | } | |||||||
1761 | // session already started or no older protocol to try | |||||||
1762 | return false; | |||||||
1763 | } // TSyncAgent::retryOlderProtocol | |||||||
1764 | ||||||||
1765 | ||||||||
1766 | // prepares client session such that it will do a retry to start a session | |||||||
1767 | // (but keeping already received auth/nonce/syncML-Version state) | |||||||
1768 | void TSyncAgent::retryClientSessionStart(bool aOldMessageInBuffer) | |||||||
1769 | { | |||||||
1770 | TAgentConfig *configP = static_cast<TAgentConfig *>(getRootConfig()->fAgentConfigP); | |||||||
1771 | ||||||||
1772 | // now restarting | |||||||
1773 | PDEBUGPRINTFX(DBG_HOT,("=================> Retrying Client Session Start")){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("=================> Retrying Client Session Start" ); }; | |||||||
1774 | bool newSessionForAuthRetry = configP->fNewSessionForAuthRetry; | |||||||
1775 | bool noRespURIForAuthRetry = configP->fNoRespURIForAuthRetry; | |||||||
1776 | // check if we should use modified behaviour (smart retries) | |||||||
1777 | if (configP->fSmartAuthRetry && fAuthRetries>MAX_NORMAL_AUTH_RETRIES2) { | |||||||
1778 | if (newSessionForAuthRetry) { | |||||||
1779 | // if we had new session for retry, switch to in-session retry now | |||||||
1780 | newSessionForAuthRetry = false; | |||||||
1781 | noRespURIForAuthRetry = false; | |||||||
1782 | } | |||||||
1783 | else { | |||||||
1784 | // if we had in-session retry, try new session retry now | |||||||
1785 | newSessionForAuthRetry = true; | |||||||
1786 | noRespURIForAuthRetry = true; | |||||||
1787 | } | |||||||
1788 | PDEBUGPRINTFX(DBG_PROTO,("Smart retry with modified behaviour: newSessionForAuthRetry=%d, noRespURIForAuthRetry=%d",newSessionForAuthRetry,noRespURIForAuthRetry)){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ("Smart retry with modified behaviour: newSessionForAuthRetry=%d, noRespURIForAuthRetry=%d" ,newSessionForAuthRetry,noRespURIForAuthRetry); }; | |||||||
1789 | } | |||||||
1790 | // now retry | |||||||
1791 | if (newSessionForAuthRetry) { | |||||||
1792 | // Notes: | |||||||
1793 | // - must apparently be disabled for SCTS 3.1.2 and possibly Mightyphone | |||||||
1794 | // - must be enabled e.g for for Magically Server | |||||||
1795 | // Create new session ID | |||||||
1796 | StringObjPrintf(fSynchdrSessionID,"%hd",(sInt16)++fClientSessionNo); | |||||||
1797 | // restart message counting at 1 | |||||||
1798 | fIncomingMsgID=0; | |||||||
1799 | fOutgoingMsgID=0; | |||||||
1800 | // we must terminate the block here when we reset fIncomingMsgID, as NextMessage | |||||||
1801 | // only closes the incoming block when fIncomingMsgID>0 | |||||||
1802 | PDEBUGENDBLOCK("SyncML_Incoming")getDbgLogger()->DebugCloseBlock( "SyncML_Incoming"); | |||||||
1803 | } | |||||||
1804 | if (noRespURIForAuthRetry) { | |||||||
1805 | // Notes: | |||||||
1806 | // - must apparently be switched on for Starfish. | |||||||
1807 | // - must apparently be switched off for SCTS 3.1.2. | |||||||
1808 | // make sure we send next msg to the original URL | |||||||
1809 | fRespondURI=fRemoteURI; | |||||||
1810 | } | |||||||
1811 | // - make sure status for SyncHdr will not be generated! | |||||||
1812 | forgetHeaderWaitCommands(); | |||||||
1813 | // check if we have already started next outgoing message | |||||||
1814 | if (!fOutgoingStarted) { | |||||||
1815 | if (aOldMessageInBuffer) { | |||||||
1816 | // make sure we start with a fresh output buffer | |||||||
1817 | // Note: This usually only occur when we are not currently parsing | |||||||
1818 | // part of the buffer. If we are parsing, the remaining incoming | |||||||
1819 | // message gets cleared as well. | |||||||
1820 | getClientBase()->clrUnreadSmlBufferdata(); | |||||||
1821 | } | |||||||
1822 | // start a new message | |||||||
1823 | issueHeader(false); | |||||||
1824 | } | |||||||
1825 | else { | |||||||
1826 | if (aOldMessageInBuffer) { | |||||||
1827 | PDEBUGPRINTFX(DBG_ERROR,("Warning - restarting session with old message in output buffer")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Warning - restarting session with old message in output buffer" ); }; | |||||||
1828 | } | |||||||
1829 | } | |||||||
1830 | // - make sure subsequent commands (most probably statuses for Alerts) | |||||||
1831 | // don't get processed | |||||||
1832 | AbortCommandProcessing(0); // silently discard all further commands | |||||||
1833 | // - make sure possible processing errors do not abort the session | |||||||
1834 | fIgnoreMsgErrs = true; | |||||||
1835 | } // TSyncAgent::retryClientSessionStart | |||||||
1836 | ||||||||
1837 | ||||||||
1838 | #endif // SYSYNC_CLIENT | |||||||
1839 | ||||||||
1840 | #ifdef SYSYNC_SERVER1 | |||||||
1841 | ||||||||
1842 | // undefine these only for tests. Introduced to find problem with T68i | |||||||
1843 | #define RESPURI_ONLY_WHEN_NEEDED | |||||||
1844 | ||||||||
1845 | // create a RespURI string. If none needed, return NULL | |||||||
1846 | SmlPcdataPtr_t TSyncAgent::newResponseURIForRemote(void) | |||||||
1847 | { | |||||||
1848 | if (IS_CLIENT(!getSyncAppBase()->isServer())) { | |||||||
1849 | return NULL__null; | |||||||
1850 | } | |||||||
1851 | // do it in a transport-independent way, therefore let dispatcher do it | |||||||
1852 | string respURI; // empty string | |||||||
1853 | if (fUseRespURI) { | |||||||
1854 | getSyncAppBase()->generateRespURI( | |||||||
1855 | respURI, // remains unaffected if no RespURI could be calculated | |||||||
1856 | fInitialLocalURI.c_str(), // initial URI used by remote to send first message | |||||||
1857 | fLocalSessionID.c_str() // server generated unique session ID | |||||||
1858 | ); | |||||||
1859 | // Omit RespURI if local URI as seen by client is identical | |||||||
1860 | if (getServerConfig()->fRespURIOnlyWhenDifferent) { | |||||||
1861 | // create RespURI only if different from original URI | |||||||
1862 | if (respURI==fLocalURI) { | |||||||
1863 | respURI.erase(); | |||||||
1864 | DEBUGPRINTFX(DBG_SESSION,({ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "Generated RespURI and sourceLocURI are equal (%s)-> RespURI omitted" , fLocalURI.c_str() ); } | |||||||
1865 | "Generated RespURI and sourceLocURI are equal (%s)-> RespURI omitted",{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "Generated RespURI and sourceLocURI are equal (%s)-> RespURI omitted" , fLocalURI.c_str() ); } | |||||||
1866 | fLocalURI.c_str(){ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "Generated RespURI and sourceLocURI are equal (%s)-> RespURI omitted" , fLocalURI.c_str() ); } | |||||||
1867 | )){ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "Generated RespURI and sourceLocURI are equal (%s)-> RespURI omitted" , fLocalURI.c_str() ); }; | |||||||
1868 | } | |||||||
1869 | } | |||||||
1870 | } | |||||||
1871 | // Note: returns NULL if respURI is empty string | |||||||
1872 | return newPCDataOptString(respURI.c_str()); | |||||||
1873 | } // newResponseURIForRemote | |||||||
1874 | ||||||||
1875 | ||||||||
1876 | // called after successful decoding of an incoming message | |||||||
1877 | bool TSyncAgent::ServerMessageStarted(SmlSyncHdrPtr_t aContentP, TStatusCommand &aStatusCommand, bool aBad) | |||||||
1878 | { | |||||||
1879 | // message not authorized by default | |||||||
1880 | fMessageAuthorized=false; | |||||||
1881 | ||||||||
1882 | // Get information from SyncHdr which is needed for answers | |||||||
1883 | // - session ID to be used for responses | |||||||
1884 | fSynchdrSessionID=smlPCDataToCharP(aContentP->sessionID); | |||||||
1885 | // - local URI (as seen by remote client) | |||||||
1886 | fLocalURI=smlSrcTargLocURIToCharP(aContentP->target); | |||||||
1887 | fLocalName=smlSrcTargLocNameToCharP(aContentP->target); | |||||||
1888 | // - also remember URI to which first message was sent | |||||||
1889 | // %%% note: incoming ID is not a criteria, because it might be >1 due to | |||||||
1890 | // client retrying something which it thinks is for the same session | |||||||
1891 | //if (fIncomingMsgID==1) { | |||||||
1892 | if (fOutgoingMsgID==0) { | |||||||
1893 | // this is the first message, remember first URI used to contact server | |||||||
1894 | // (or set preconfigured string from <externalurl>) | |||||||
1895 | if (getServerConfig()->fExternalURL.empty()) | |||||||
1896 | fInitialLocalURI=fLocalURI; // use what client sends to us | |||||||
1897 | else | |||||||
1898 | fInitialLocalURI=getServerConfig()->fExternalURL; // use preconfigured URL | |||||||
1899 | // Many clients, including SCTS send the second login attempt with a MsgID>1, | |||||||
1900 | // and depending on how they handle RespURI, they might get a new session for that | |||||||
1901 | // -> so, just handle the case that a new session does not start with MsgID=1 | |||||||
1902 | if (fIncomingMsgID>1) { | |||||||
1903 | PDEBUGPRINTFX(DBG_ERROR,({ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "New session gets first message with MsgID=%ld (should be 1). Might be due to retries, adjusting OutgoingID as well" , (long)fIncomingMsgID ); } | |||||||
1904 | "New session gets first message with MsgID=%ld (should be 1). Might be due to retries, adjusting OutgoingID as well",{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "New session gets first message with MsgID=%ld (should be 1). Might be due to retries, adjusting OutgoingID as well" , (long)fIncomingMsgID ); } | |||||||
1905 | (long)fIncomingMsgID{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "New session gets first message with MsgID=%ld (should be 1). Might be due to retries, adjusting OutgoingID as well" , (long)fIncomingMsgID ); } | |||||||
1906 | )){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "New session gets first message with MsgID=%ld (should be 1). Might be due to retries, adjusting OutgoingID as well" , (long)fIncomingMsgID ); }; | |||||||
1907 | fOutgoingMsgID=fIncomingMsgID-1; // to make it match what client expects | |||||||
1908 | } | |||||||
1909 | } | |||||||
1910 | // - remote URI | |||||||
1911 | fRemoteURI=smlSrcTargLocURIToCharP(aContentP->source); | |||||||
1912 | fRemoteName=smlSrcTargLocNameToCharP(aContentP->source); | |||||||
1913 | // - RespURI (remote URI to respond to, if different from source) | |||||||
1914 | fRespondURI.erase(); | |||||||
1915 | if (aContentP->respURI) { | |||||||
1916 | fRespondURI=smlPCDataToCharP(aContentP->respURI); | |||||||
1917 | DEBUGPRINTFX(DBG_PROTO,("RespURI specified = '%s'",fRespondURI.c_str())){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ("RespURI specified = '%s'" ,fRespondURI.c_str()); }; | |||||||
1918 | } | |||||||
1919 | if (fRespondURI==fRemoteURI) fRespondURI.erase(); // if specified but equal to remote: act as if not specified | |||||||
1920 | // More checking if header was ok | |||||||
1921 | if (aBad) { | |||||||
1922 | // bad header, only do what is needed to get a status back to client | |||||||
1923 | fSessionAuthorized=false; | |||||||
1924 | fIncomingState=psta_init; | |||||||
1925 | fOutgoingState=psta_init; | |||||||
1926 | fNewOutgoingPackage=true; | |||||||
1927 | // issue header to make sure status can be sent back to client | |||||||
1928 | if (!fMsgNoResp) | |||||||
1929 | issueHeader(false); // issue header, do not prevent responses | |||||||
1930 | } | |||||||
1931 | else { | |||||||
1932 | // check busy (or expired) case | |||||||
1933 | if (serverBusy()) { | |||||||
1934 | #ifdef APP_CAN_EXPIRE | |||||||
1935 | if (getSyncAppBase()->fAppExpiryStatus!=LOCERR_OK) { | |||||||
1936 | aStatusCommand.setStatusCode(511); // server failure (expired) | |||||||
1937 | aStatusCommand.addItemString("License expired or invalid"); | |||||||
1938 | PDEBUGPRINTFX(DBG_ERROR,("License expired or invalid - Please contact Synthesis AG to obtain license")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("License expired or invalid - Please contact Synthesis AG to obtain license" ); }; | |||||||
1939 | } | |||||||
1940 | else | |||||||
1941 | #endif | |||||||
1942 | { | |||||||
1943 | aStatusCommand.setStatusCode(101); // busy | |||||||
1944 | } | |||||||
1945 | issueHeader(false); // issue header, do not prevent responses | |||||||
1946 | AbortSession(0,true); // silently discard rest of commands | |||||||
1947 | return false; // header not ok | |||||||
1948 | } | |||||||
1949 | // now check what state we are in | |||||||
1950 | if (fIncomingState==psta_idle) { | |||||||
1951 | // Initialize | |||||||
1952 | // - session-wide authorization not yet there | |||||||
1953 | fSessionAuthorized=false; | |||||||
1954 | fMapSeen=false; | |||||||
1955 | // - session has started, we are processing first incoming | |||||||
1956 | // package and generating first outgoing package | |||||||
1957 | // (init, possibly changed to combined init/sync by <sync> in this package) | |||||||
1958 | fIncomingState=psta_init; | |||||||
1959 | fOutgoingState=psta_init; | |||||||
1960 | fNewOutgoingPackage=true; | |||||||
1961 | } | |||||||
1962 | // authorization check | |||||||
1963 | if (fIncomingState>=psta_init) { | |||||||
1964 | // now check authorization | |||||||
1965 | if (!fSessionAuthorized) { | |||||||
1966 | // started, but not yet permanently authorized | |||||||
1967 | fMessageAuthorized=checkCredentials( | |||||||
1968 | smlSrcTargLocNameToCharP(aContentP->source), // user name in clear text according to SyncML 1.0.1 | |||||||
1969 | aContentP->cred, // actual credentials | |||||||
1970 | aStatusCommand | |||||||
1971 | ); | |||||||
1972 | // NOTE: aStatusCommand has now the appropriate status and chal (set by checkCredentials()) | |||||||
1973 | // if credentials do not match, stop processing commands (but stay with the session) | |||||||
1974 | if (!fMessageAuthorized) { | |||||||
1975 | AbortCommandProcessing(aStatusCommand.getStatusCode()); | |||||||
1976 | PDEBUGPRINTFX(DBG_PROTO,("Authorization failed with status %hd, stop command processing",aStatusCommand.getStatusCode())){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ("Authorization failed with status %hd, stop command processing" ,aStatusCommand.getStatusCode()); }; | |||||||
1977 | } | |||||||
1978 | // now determine if authorization is permanent or not | |||||||
1979 | if (fMessageAuthorized) { | |||||||
1980 | fAuthFailures=0; // reset count | |||||||
1981 | if (messageAuthRequired()) { | |||||||
1982 | // each message needs autorisation again (or no auth at all) | |||||||
1983 | // - 200 ok, next message needs authorization again (or again: none) | |||||||
1984 | fSessionAuthorized=false; // no permanent authorization | |||||||
1985 | aStatusCommand.setStatusCode(200); | |||||||
1986 | // - add challenge for next auth (different nonce) | |||||||
1987 | aStatusCommand.setChallenge(newSessionChallenge()); | |||||||
1988 | PDEBUGPRINTFX(DBG_PROTO,("Authorization ok, but required again for subsequent messages: 200 + chal")){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ("Authorization ok, but required again for subsequent messages: 200 + chal" ); }; | |||||||
1989 | } | |||||||
1990 | else { | |||||||
1991 | // entire session is authorized | |||||||
1992 | fSessionAuthorized=true; // permanent authorization | |||||||
1993 | // - 212 authentication accepted (or 200 if none is reqired at all) | |||||||
1994 | aStatusCommand.setStatusCode(requestedAuthType()==auth_none ? 200 : 212); | |||||||
1995 | // - add challenge for next auth (in next session, but as we support carry | |||||||
1996 | // forward via using sessionID, we need to send one here as well) | |||||||
1997 | aStatusCommand.setChallenge(newSessionChallenge()); | |||||||
1998 | PDEBUGPRINTFX(DBG_PROTO,("Authorization accepted: 212")){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ("Authorization accepted: 212" ); }; | |||||||
1999 | } | |||||||
2000 | } | |||||||
2001 | } // authorisation check | |||||||
2002 | else { | |||||||
2003 | // already authorized from previous message | |||||||
2004 | PDEBUGPRINTFX(DBG_PROTO,("Authorization ok from previous request: 200")){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ("Authorization ok from previous request: 200" ); }; | |||||||
2005 | fMessageAuthorized=true; | |||||||
2006 | } | |||||||
2007 | // Start response message AFTER auth check, to allow issueHeader | |||||||
2008 | // to check auth state and customize the header accordingly (no | |||||||
2009 | // RespURI for failed auth for example) | |||||||
2010 | if (!fMsgNoResp) { | |||||||
2011 | issueHeader(false); // issue header, do not prevent responses | |||||||
2012 | } | |||||||
2013 | } // if started at least | |||||||
2014 | } // if not aBad | |||||||
2015 | // return startmessage status | |||||||
2016 | // debug info | |||||||
2017 | #ifdef SYDEBUG2 | |||||||
2018 | if (PDEBUGMASKgetDbgMask() & DBG_SESSION0x00000020) { | |||||||
2019 | PDEBUGPRINTFX(DBG_SESSION,({ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "---> MessageStarted, Message %sauthorized, incoming state='%s', outgoing state='%s'" , fMessageAuthorized ? "" : "NOT ", PackageStateNames[fIncomingState ], PackageStateNames[fOutgoingState] ); } | |||||||
2020 | "---> MessageStarted, Message %sauthorized, incoming state='%s', outgoing state='%s'",{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "---> MessageStarted, Message %sauthorized, incoming state='%s', outgoing state='%s'" , fMessageAuthorized ? "" : "NOT ", PackageStateNames[fIncomingState ], PackageStateNames[fOutgoingState] ); } | |||||||
2021 | fMessageAuthorized ? "" : "NOT ",{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "---> MessageStarted, Message %sauthorized, incoming state='%s', outgoing state='%s'" , fMessageAuthorized ? "" : "NOT ", PackageStateNames[fIncomingState ], PackageStateNames[fOutgoingState] ); } | |||||||
2022 | PackageStateNames[fIncomingState],{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "---> MessageStarted, Message %sauthorized, incoming state='%s', outgoing state='%s'" , fMessageAuthorized ? "" : "NOT ", PackageStateNames[fIncomingState ], PackageStateNames[fOutgoingState] ); } | |||||||
2023 | PackageStateNames[fOutgoingState]{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "---> MessageStarted, Message %sauthorized, incoming state='%s', outgoing state='%s'" , fMessageAuthorized ? "" : "NOT ", PackageStateNames[fIncomingState ], PackageStateNames[fOutgoingState] ); } | |||||||
2024 | )){ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "---> MessageStarted, Message %sauthorized, incoming state='%s', outgoing state='%s'" , fMessageAuthorized ? "" : "NOT ", PackageStateNames[fIncomingState ], PackageStateNames[fOutgoingState] ); }; | |||||||
2025 | TLocalDataStorePContainer::iterator pos; | |||||||
2026 | for (pos=fLocalDataStores.begin(); pos!=fLocalDataStores.end(); ++pos) { | |||||||
2027 | // Show state of local datastores | |||||||
2028 | PDEBUGPRINTFX(DBG_SESSION,({ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "Local Datastore '%s': State=%s, %s%s sync, %s%s" , (*pos)->getName(), (*pos)->getDSStateName(), (*pos)-> isResuming() ? "RESUMED " : "", (*pos)->fSlowSync ? "SLOW" : "normal", SyncModeDescriptions[(*pos)->fSyncMode], (*pos )->fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
2029 | "Local Datastore '%s': State=%s, %s%s sync, %s%s",{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "Local Datastore '%s': State=%s, %s%s sync, %s%s" , (*pos)->getName(), (*pos)->getDSStateName(), (*pos)-> isResuming() ? "RESUMED " : "", (*pos)->fSlowSync ? "SLOW" : "normal", SyncModeDescriptions[(*pos)->fSyncMode], (*pos )->fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
2030 | (*pos)->getName(),{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "Local Datastore '%s': State=%s, %s%s sync, %s%s" , (*pos)->getName(), (*pos)->getDSStateName(), (*pos)-> isResuming() ? "RESUMED " : "", (*pos)->fSlowSync ? "SLOW" : "normal", SyncModeDescriptions[(*pos)->fSyncMode], (*pos )->fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
2031 | (*pos)->getDSStateName(),{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "Local Datastore '%s': State=%s, %s%s sync, %s%s" , (*pos)->getName(), (*pos)->getDSStateName(), (*pos)-> isResuming() ? "RESUMED " : "", (*pos)->fSlowSync ? "SLOW" : "normal", SyncModeDescriptions[(*pos)->fSyncMode], (*pos )->fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
2032 | (*pos)->isResuming() ? "RESUMED " : "",{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "Local Datastore '%s': State=%s, %s%s sync, %s%s" , (*pos)->getName(), (*pos)->getDSStateName(), (*pos)-> isResuming() ? "RESUMED " : "", (*pos)->fSlowSync ? "SLOW" : "normal", SyncModeDescriptions[(*pos)->fSyncMode], (*pos )->fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
2033 | (*pos)->fSlowSync ? "SLOW" : "normal",{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "Local Datastore '%s': State=%s, %s%s sync, %s%s" , (*pos)->getName(), (*pos)->getDSStateName(), (*pos)-> isResuming() ? "RESUMED " : "", (*pos)->fSlowSync ? "SLOW" : "normal", SyncModeDescriptions[(*pos)->fSyncMode], (*pos )->fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
2034 | SyncModeDescriptions[(*pos)->fSyncMode],{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "Local Datastore '%s': State=%s, %s%s sync, %s%s" , (*pos)->getName(), (*pos)->getDSStateName(), (*pos)-> isResuming() ? "RESUMED " : "", (*pos)->fSlowSync ? "SLOW" : "normal", SyncModeDescriptions[(*pos)->fSyncMode], (*pos )->fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
2035 | (*pos)->fServerAlerted ? ", Server-Alerted" : ""{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "Local Datastore '%s': State=%s, %s%s sync, %s%s" , (*pos)->getName(), (*pos)->getDSStateName(), (*pos)-> isResuming() ? "RESUMED " : "", (*pos)->fSlowSync ? "SLOW" : "normal", SyncModeDescriptions[(*pos)->fSyncMode], (*pos )->fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
2036 | )){ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "Local Datastore '%s': State=%s, %s%s sync, %s%s" , (*pos)->getName(), (*pos)->getDSStateName(), (*pos)-> isResuming() ? "RESUMED " : "", (*pos)->fSlowSync ? "SLOW" : "normal", SyncModeDescriptions[(*pos)->fSyncMode], (*pos )->fServerAlerted ? ", Server-Alerted" : "" ); }; | |||||||
2037 | } | |||||||
2038 | } | |||||||
2039 | #endif | |||||||
2040 | // final check for too many auth failures | |||||||
2041 | if (!fMessageAuthorized) { | |||||||
2042 | #ifdef NO_NONCE_OLD_BEAHVIOUR | |||||||
2043 | AbortSession(aStatusCommand.getStatusCode(),true); // local error | |||||||
2044 | // avoid special treatment of non-authorized message, we have aborted, this is enough | |||||||
2045 | fMessageAuthorized=true; | |||||||
2046 | #else | |||||||
2047 | // Unsuccessful auth, count this | |||||||
2048 | fAuthFailures++; | |||||||
2049 | PDEBUGPRINTFX(DBG_ERROR,({ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Authorization failed %hd. time, (any reason), sending status %hd" , fAuthFailures, aStatusCommand.getStatusCode() ); } | |||||||
2050 | "Authorization failed %hd. time, (any reason), sending status %hd",{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Authorization failed %hd. time, (any reason), sending status %hd" , fAuthFailures, aStatusCommand.getStatusCode() ); } | |||||||
2051 | fAuthFailures,{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Authorization failed %hd. time, (any reason), sending status %hd" , fAuthFailures, aStatusCommand.getStatusCode() ); } | |||||||
2052 | aStatusCommand.getStatusCode(){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Authorization failed %hd. time, (any reason), sending status %hd" , fAuthFailures, aStatusCommand.getStatusCode() ); } | |||||||
2053 | )){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Authorization failed %hd. time, (any reason), sending status %hd" , fAuthFailures, aStatusCommand.getStatusCode() ); }; | |||||||
2054 | // - abort session after too many auth failures | |||||||
2055 | if (fAuthFailures>=MAX_AUTH_ATTEMPTS3) { | |||||||
2056 | PDEBUGPRINTFX(DBG_ERROR,("Too many (>=%d) failures, aborting session",MAX_AUTH_ATTEMPTS)){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Too many (>=%d) failures, aborting session" ,3); }; | |||||||
2057 | AbortSession(400,true); | |||||||
2058 | } | |||||||
2059 | #endif | |||||||
2060 | } | |||||||
2061 | // returns false on BAD header (but true on wrong/bad/missing cred) | |||||||
2062 | return true; | |||||||
2063 | } // TSyncAgent::ServerMessageStarted | |||||||
2064 | ||||||||
2065 | ||||||||
2066 | void TSyncAgent::ServerMessageEnded(bool aIncomingFinal) | |||||||
2067 | { | |||||||
2068 | bool alldone; | |||||||
2069 | TPackageStates newoutgoingstate,newincomingstate; | |||||||
2070 | TLocalDataStorePContainer::iterator pos; | |||||||
2071 | bool allFromClientOnly=false; | |||||||
2072 | ||||||||
2073 | // Incoming message ends here - what is following are commands initiated by the server | |||||||
2074 | // not directly related to a incoming command. | |||||||
2075 | PDEBUGENDBLOCK("SyncML_Incoming")getDbgLogger()->DebugCloseBlock( "SyncML_Incoming"); | |||||||
2076 | // assume that outgoing package is NOT finished, so outgoing state does not change | |||||||
2077 | newoutgoingstate=fOutgoingState; | |||||||
2078 | // new incoming state depends on whether this message is final or not | |||||||
2079 | if ((aIncomingFinal || (fIncomingState==psta_supplement)) && fMessageAuthorized) { | |||||||
2080 | // Note: in supplement state, incoming final is not relevant (may or may not be present, there is | |||||||
2081 | // no next phase anyway | |||||||
2082 | // find out if this is a shortened session (no map phase) due to | |||||||
2083 | // from-client-only in all datastores | |||||||
2084 | allFromClientOnly=checkAllFromClientOnly(); | |||||||
2085 | // determine what package comes next | |||||||
2086 | switch (fIncomingState) { | |||||||
2087 | case psta_init : | |||||||
2088 | newincomingstate=psta_sync; | |||||||
2089 | break; | |||||||
2090 | case psta_sync : | |||||||
2091 | case psta_initsync : | |||||||
2092 | // end of sync phase means end of session if all datastores are in from-client-only mode | |||||||
2093 | if (allFromClientOnly) { | |||||||
2094 | PDEBUGPRINTFX(DBG_PROTO+DBG_HOT,("All datastores in from-client-only mode: don't expect map phase from client")){ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ("All datastores in from-client-only mode: don't expect map phase from client" ); }; | |||||||
2095 | newincomingstate=psta_supplement; | |||||||
2096 | } | |||||||
2097 | else { | |||||||
2098 | newincomingstate=psta_map; | |||||||
2099 | } | |||||||
2100 | break; | |||||||
2101 | case psta_map : | |||||||
2102 | case psta_supplement : // supplement state does not exit automatically | |||||||
2103 | // after map, possibly some supplement status/alert 222 messages are needed from client | |||||||
2104 | newincomingstate=psta_supplement; | |||||||
2105 | break; | |||||||
2106 | default: | |||||||
2107 | // by default, back to idle | |||||||
2108 | newincomingstate=psta_idle; | |||||||
2109 | break; | |||||||
2110 | } // switch | |||||||
2111 | } | |||||||
2112 | else { | |||||||
2113 | // not final or not authorized: no change in state | |||||||
2114 | newincomingstate=fIncomingState; | |||||||
2115 | } | |||||||
2116 | // show status before processing | |||||||
2117 | PDEBUGPRINTFX(DBG_SESSION,({ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "---> MessageEnded starts : old incoming state='%s', old outgoing state='%s', %sNeedToAnswer" , PackageStateNames[fIncomingState], PackageStateNames[fOutgoingState ], fNeedToAnswer ? "" : "NO " ); } | |||||||
2118 | "---> MessageEnded starts : old incoming state='%s', old outgoing state='%s', %sNeedToAnswer",{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "---> MessageEnded starts : old incoming state='%s', old outgoing state='%s', %sNeedToAnswer" , PackageStateNames[fIncomingState], PackageStateNames[fOutgoingState ], fNeedToAnswer ? "" : "NO " ); } | |||||||
2119 | PackageStateNames[fIncomingState],{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "---> MessageEnded starts : old incoming state='%s', old outgoing state='%s', %sNeedToAnswer" , PackageStateNames[fIncomingState], PackageStateNames[fOutgoingState ], fNeedToAnswer ? "" : "NO " ); } | |||||||
2120 | PackageStateNames[fOutgoingState],{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "---> MessageEnded starts : old incoming state='%s', old outgoing state='%s', %sNeedToAnswer" , PackageStateNames[fIncomingState], PackageStateNames[fOutgoingState ], fNeedToAnswer ? "" : "NO " ); } | |||||||
2121 | fNeedToAnswer ? "" : "NO "{ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "---> MessageEnded starts : old incoming state='%s', old outgoing state='%s', %sNeedToAnswer" , PackageStateNames[fIncomingState], PackageStateNames[fOutgoingState ], fNeedToAnswer ? "" : "NO " ); } | |||||||
2122 | )){ if (((0x00000020) & getDbgMask()) == (0x00000020)) getDbgLogger ()->setNextMask(0x00000020).DebugPrintfLastMask ( "---> MessageEnded starts : old incoming state='%s', old outgoing state='%s', %sNeedToAnswer" , PackageStateNames[fIncomingState], PackageStateNames[fOutgoingState ], fNeedToAnswer ? "" : "NO " ); }; | |||||||
2123 | // process | |||||||
2124 | if (isAborted()) { | |||||||
2125 | // actual aborting has already taken place | |||||||
2126 | PDEBUGPRINTFX(DBG_ERROR,("***** Session is flagged 'aborted' -> MessageEnded ends package and session")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("***** Session is flagged 'aborted' -> MessageEnded ends package and session" ); }; | |||||||
2127 | newoutgoingstate=psta_idle; | |||||||
2128 | newincomingstate=psta_idle; | |||||||
2129 | fInProgress=false; | |||||||
2130 | } // if aborted | |||||||
2131 | else if (isSuspending()) { | |||||||
2132 | // only flagged for suspend - but datastores are not yet aborted, do it now | |||||||
2133 | AbortSession(514,true,getAbortReasonStatus()); | |||||||
2134 | PDEBUGPRINTFX(DBG_ERROR,("***** Session is flagged 'suspended' -> MessageEnded ends package and session")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("***** Session is flagged 'suspended' -> MessageEnded ends package and session" ); }; | |||||||
2135 | newoutgoingstate=psta_idle; | |||||||
2136 | newincomingstate=psta_idle; | |||||||
2137 | fInProgress=false; | |||||||
2138 | } | |||||||
2139 | else if (!fMessageAuthorized) { | |||||||
2140 | // not authorized messages will just be ignored, no matter if final or not, | |||||||
2141 | // so outgoing will NEVER be final on non-authorized messages | |||||||
2142 | // %%% before 1.0.4.9, this was fInProgress=true | |||||||
2143 | // DEBUGPRINTFX(DBG_ERROR,("***** Message not authorized, ignore and DONT end package, session continues")); | |||||||
2144 | // fInProgress=true; | |||||||
2145 | PDEBUGPRINTFX(DBG_ERROR,("***** Message not authorized, ignore msg and terminate session")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("***** Message not authorized, ignore msg and terminate session" ); }; | |||||||
2146 | fInProgress=false; | |||||||
2147 | } | |||||||
2148 | else { | |||||||
2149 | // determine if session continues living or not | |||||||
2150 | // - if in other than idle state, session will continue | |||||||
2151 | fInProgress = | |||||||
2152 | (newincomingstate!=psta_idle) || // if not idle, we'll continue | |||||||
2153 | !fMessageAuthorized; // if not authorized, we'll continue as well (retrying auth) | |||||||
2154 | // Check if we need to send an Alert 222 to get more messages of this package | |||||||
2155 | if (!aIncomingFinal) { | |||||||
2156 | // not end of incoming package | |||||||
2157 | #ifndef ALWAYS_CONTINUE222 | |||||||
2158 | if (!fNeedToAnswer) | |||||||
2159 | #endif | |||||||
2160 | { | |||||||
2161 | #ifdef COMBINE_SYNCANDMAP | |||||||
2162 | // %%% make sure session gets to an end in case combined sync/map was used | |||||||
2163 | if (fMapSeen && fIncomingState==psta_map && fOutgoingState==psta_map) { | |||||||
2164 | DEBUGPRINTFX(DBG_HOT,("********** Incoming, non-final message in (combined)map state needs no answer -> force end of outgoing package")){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("********** Incoming, non-final message in (combined)map state needs no answer -> force end of outgoing package" ); }; | |||||||
2165 | newoutgoingstate=psta_idle; | |||||||
2166 | } | |||||||
2167 | else | |||||||
2168 | #endif | |||||||
2169 | { | |||||||
2170 | // detected 222-loop on init here: when we have nothing to answer in init | |||||||
2171 | // and nothing is alerted -> break session | |||||||
2172 | // %%% not sure if this is always ok | |||||||
2173 | if (fIncomingState<=psta_init) { | |||||||
2174 | PDEBUGPRINTFX(DBG_ERROR,("############## Looks like if we were looping in an init-repeat loop -> force final")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("############## Looks like if we were looping in an init-repeat loop -> force final" ); }; | |||||||
2175 | fInProgress=false; | |||||||
2176 | fOutgoingState=psta_idle; | |||||||
2177 | } | |||||||
2178 | else { | |||||||
2179 | // not final, and nothing to answer otherwise: create alert-Command to request more info | |||||||
2180 | TAlertCommand *alertCmdP = new TAlertCommand(this,NULL__null,(uInt16)222); | |||||||
2181 | // %%% not clear from spec what has to be in item for 222 alert code | |||||||
2182 | // but there MUST be an Item for the Alert command according to SyncML TK | |||||||
2183 | // - we just put local and remote URIs here | |||||||
2184 | SmlItemPtr_t itemP = newItem(); | |||||||
2185 | itemP->target = newLocation(fRemoteURI.c_str()); | |||||||
2186 | itemP->source = newLocation(fLocalURI.c_str()); | |||||||
2187 | alertCmdP->addItem(itemP); | |||||||
2188 | ISSUE_COMMAND_ROOT(this,alertCmdP){ TSmlCommand* p=alertCmdP; alertCmdP=__null; this->issueRootPtr (p); }; | |||||||
2189 | } | |||||||
2190 | } | |||||||
2191 | } | |||||||
2192 | } | |||||||
2193 | else { | |||||||
2194 | // end of package, finish processing package | |||||||
2195 | if (fIncomingState==psta_init) { | |||||||
2196 | // - try to load devinf from cache (only if we don't have both datastores and type info already) | |||||||
2197 | if (!fRemoteDataStoresKnown || !fRemoteDataTypesKnown) { | |||||||
2198 | SmlDevInfDevInfPtr_t devinfP; | |||||||
2199 | TStatusCommand dummystatus(this); | |||||||
2200 | if (loadRemoteDevInf(getRemoteURI(),devinfP)) { | |||||||
2201 | // we have cached devinf, analyze it now | |||||||
2202 | localstatus sta = analyzeRemoteDevInf(devinfP); | |||||||
2203 | PDEBUGPRINTFX(DBG_ERROR,("devInf from Cache could not be analyzed: error=%hd",sta)){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("devInf from Cache could not be analyzed: error=%hd" ,sta); }; | |||||||
2204 | } | |||||||
2205 | } | |||||||
2206 | // - if no DevInf for remote datastores cached or received yet, | |||||||
2207 | // issue GET for it now | |||||||
2208 | if (!fRemoteDataStoresKnown) { | |||||||
2209 | // if we know datastores here, but not types, this means that remote does not have | |||||||
2210 | // CTCap, so it makes no sense to issue a GET again. | |||||||
2211 | #ifndef NO_DEVINF_GET | |||||||
2212 | // end of initialisation package, but datastores not known yet | |||||||
2213 | // (=no DevInf Put received) --> ask for devinf now | |||||||
2214 | PDEBUGPRINTFX(DBG_REMOTEINFO,("No DevInf received or cached, request DevInf using GET command")){ if (((0x00000100) & getDbgMask()) == (0x00000100)) getDbgLogger ()->setNextMask(0x00000100).DebugPrintfLastMask ("No DevInf received or cached, request DevInf using GET command" ); }; | |||||||
2215 | TGetCommand *getcommandP = new TGetCommand(this); | |||||||
2216 | getcommandP->addTargetLocItem(SyncMLDevInfNames[fSyncMLVersion]); | |||||||
2217 | string devinftype=SYNCML_DEVINF_META_TYPE"application/vnd.syncml-devinf"; | |||||||
2218 | addEncoding(devinftype); | |||||||
2219 | getcommandP->setMeta(newMetaType(devinftype.c_str())); | |||||||
2220 | ISSUE_COMMAND_ROOT(this,getcommandP){ TSmlCommand* p=getcommandP; getcommandP=__null; this->issueRootPtr (p); }; | |||||||
2221 | #endif | |||||||
2222 | } | |||||||
2223 | } | |||||||
2224 | } | |||||||
2225 | // make sure syncing local datastores get informed of end-of-<Sync>-message | |||||||
2226 | if (fIncomingState==psta_sync || fIncomingState==psta_initsync) { | |||||||
2227 | // end of an incoming message of the Sync Package | |||||||
2228 | // - let all local datastores know, this is now the time to generate | |||||||
2229 | // <sync> commands, if needed | |||||||
2230 | // Note: if there are SyncEnd commands delayed, this means that this is | |||||||
2231 | // not yet the time to start <sync> commands. Instead, when all | |||||||
2232 | // queued SyncEnd commands are executed later, engEndOfSyncFromRemote() | |||||||
2233 | // will be called with the endOfAllSyncCommands flag true instead | |||||||
2234 | // of now. | |||||||
2235 | for (pos=fLocalDataStores.begin(); pos!=fLocalDataStores.end(); ++pos) { | |||||||
2236 | (*pos)->engEndOfSyncFromRemote(aIncomingFinal && !delayedSyncEndsPending()); | |||||||
2237 | } | |||||||
2238 | } | |||||||
2239 | // Detect outgoing package state transitions | |||||||
2240 | // - init to sync | |||||||
2241 | if (fOutgoingState==psta_init && newincomingstate>psta_init) { | |||||||
2242 | // new outgoing state is sync. | |||||||
2243 | // Note: In combined init&sync mode, sync command received in init state | |||||||
2244 | // will set outgoing state from init to init-sync while processing message, | |||||||
2245 | // so no transition needs to be detected here | |||||||
2246 | newoutgoingstate=psta_sync; | |||||||
2247 | fRestarting=false; | |||||||
2248 | } | |||||||
2249 | // - sync to map | |||||||
2250 | else if ( | |||||||
2251 | (fOutgoingState==psta_sync || fOutgoingState==psta_initsync) && // outgoing is sync.. | |||||||
2252 | (newincomingstate>=psta_initsync) && // ..and incoming has finished sync | |||||||
2253 | !allFromClientOnly // ..and this is not a session with all datastores doing from-client-only | |||||||
2254 | ) { | |||||||
2255 | // outgoing message belongs to Sync package | |||||||
2256 | // - ask all local datastores if they are finished with sync command generation | |||||||
2257 | alldone=true; | |||||||
2258 | for (pos=fLocalDataStores.begin(); pos!=fLocalDataStores.end(); ++pos) { | |||||||
2259 | alldone = alldone && (*pos)->isSyncDone(); | |||||||
2260 | } | |||||||
2261 | if (alldone) { | |||||||
2262 | // outgoing state changes to map (or supplement if all datastores are from-client-only | |||||||
2263 | PDEBUGPRINTFX(DBG_HOT,("All datastores are done with generating <Sync>")){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("All datastores are done with generating <Sync>" ); }; | |||||||
2264 | newoutgoingstate=psta_map; | |||||||
2265 | #ifdef COMBINE_SYNCANDMAP | |||||||
2266 | // %%% it seems as if 9210 needs combined Sync/Map package and | |||||||
2267 | if (fMapSeen) { | |||||||
2268 | // prevent FINAL to be sent at end of message | |||||||
2269 | DEBUGPRINTFX(DBG_HOT,("********** Combining outgoing sync and map-response packages into one")){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("********** Combining outgoing sync and map-response packages into one" ); }; | |||||||
2270 | fOutgoingState=psta_map; | |||||||
2271 | } | |||||||
2272 | #endif | |||||||
2273 | } | |||||||
2274 | } | |||||||
2275 | // - map (or from-client-only sync) to idle | |||||||
2276 | else if ( | |||||||
2277 | (fOutgoingState==psta_map && newincomingstate==psta_supplement) || | |||||||
2278 | (allFromClientOnly && (fOutgoingState==psta_sync || fOutgoingState==psta_initsync)) | |||||||
2279 | ) { | |||||||
2280 | // we are going back to idle now | |||||||
2281 | newoutgoingstate=psta_idle; | |||||||
2282 | // session ends if it doesn't need to continue for session-level reasons | |||||||
2283 | if (!sessionMustContinue()) { | |||||||
2284 | PDEBUGPRINTFX(DBG_HOT,("Session completed, now let datastores terminate all sync operations")){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("Session completed, now let datastores terminate all sync operations" ); }; | |||||||
2285 | for (pos=fLocalDataStores.begin(); pos!=fLocalDataStores.end(); ++pos) { | |||||||
2286 | // finished with Map: end of sync | |||||||
2287 | (*pos)->engFinishDataStoreSync(); // successful | |||||||
2288 | } | |||||||
2289 | // session ends now | |||||||
2290 | fInProgress=false; | |||||||
2291 | // let custom PUTs which may transmit some session statistics etc. happen now | |||||||
2292 | issueCustomEndPut(); | |||||||
2293 | } | |||||||
2294 | } | |||||||
2295 | // - if no need to answer (e.g. nothing to send back except OK status for SyncHdr), | |||||||
2296 | // session is over now (as well) | |||||||
2297 | if (!fNeedToAnswer) fInProgress=false; | |||||||
2298 | } // else | |||||||
2299 | // Now finish outgoing message | |||||||
2300 | #ifdef DONT_FINAL_BAD_AUTH_ATTEMPTS | |||||||
2301 | // - PREVENT final flag after failed auth attempts | |||||||
2302 | if(FinishMessage( | |||||||
2303 | fOutgoingState!=newoutgoingstate || fOutgoingState==psta_idle, // final when state changed or idle | |||||||
2304 | !fMessageAuthorized || serverBusy() // busy or unauthorized prevent final flag at any rate | |||||||
2305 | )) | |||||||
2306 | #else | |||||||
2307 | // - DO set final flag after failed auth attempts | |||||||
2308 | if(FinishMessage( | |||||||
2309 | !fMessageAuthorized || fOutgoingState!=newoutgoingstate || fOutgoingState==psta_idle, // final when state changed or idle | |||||||
2310 | serverBusy() // busy prevents final flag at any rate | |||||||
2311 | )) | |||||||
2312 | #endif | |||||||
2313 | { | |||||||
2314 | // outgoing state HAS changed | |||||||
2315 | fOutgoingState=newoutgoingstate; | |||||||
2316 | } | |||||||
2317 | // Now update incoming state | |||||||
2318 | fIncomingState=newincomingstate; | |||||||
2319 | // show states | |||||||
2320 | PDEBUGPRINTFX(DBG_HOT,({ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "---> MessageEnded finishes : new incoming state='%s', new outgoing state='%s', %sNeedToAnswer" , PackageStateNames[fIncomingState], PackageStateNames[fOutgoingState ], fNeedToAnswer ? "" : "NO " ); } | |||||||
2321 | "---> MessageEnded finishes : new incoming state='%s', new outgoing state='%s', %sNeedToAnswer",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "---> MessageEnded finishes : new incoming state='%s', new outgoing state='%s', %sNeedToAnswer" , PackageStateNames[fIncomingState], PackageStateNames[fOutgoingState ], fNeedToAnswer ? "" : "NO " ); } | |||||||
2322 | PackageStateNames[fIncomingState],{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "---> MessageEnded finishes : new incoming state='%s', new outgoing state='%s', %sNeedToAnswer" , PackageStateNames[fIncomingState], PackageStateNames[fOutgoingState ], fNeedToAnswer ? "" : "NO " ); } | |||||||
2323 | PackageStateNames[fOutgoingState],{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "---> MessageEnded finishes : new incoming state='%s', new outgoing state='%s', %sNeedToAnswer" , PackageStateNames[fIncomingState], PackageStateNames[fOutgoingState ], fNeedToAnswer ? "" : "NO " ); } | |||||||
2324 | fNeedToAnswer ? "" : "NO "{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "---> MessageEnded finishes : new incoming state='%s', new outgoing state='%s', %sNeedToAnswer" , PackageStateNames[fIncomingState], PackageStateNames[fOutgoingState ], fNeedToAnswer ? "" : "NO " ); } | |||||||
2325 | )){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "---> MessageEnded finishes : new incoming state='%s', new outgoing state='%s', %sNeedToAnswer" , PackageStateNames[fIncomingState], PackageStateNames[fOutgoingState ], fNeedToAnswer ? "" : "NO " ); }; | |||||||
2326 | // let all local datastores know that message has ended | |||||||
2327 | for (pos=fLocalDataStores.begin(); pos!=fLocalDataStores.end(); ++pos) { | |||||||
2328 | // let them know | |||||||
2329 | (*pos)->engEndOfMessage(); | |||||||
2330 | // Show state of local datastores | |||||||
2331 | PDEBUGPRINTFX(DBG_HOT,({ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Local Datastore '%s': State=%s, %s%s sync, %s%s" , (*pos)->getName(), (*pos)->getDSStateName(), (*pos)-> isResuming() ? "RESUMED " : "", (*pos)->fSlowSync ? "SLOW" : "normal", SyncModeDescriptions[(*pos)->fSyncMode], (*pos )->fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
2332 | "Local Datastore '%s': State=%s, %s%s sync, %s%s",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Local Datastore '%s': State=%s, %s%s sync, %s%s" , (*pos)->getName(), (*pos)->getDSStateName(), (*pos)-> isResuming() ? "RESUMED " : "", (*pos)->fSlowSync ? "SLOW" : "normal", SyncModeDescriptions[(*pos)->fSyncMode], (*pos )->fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
2333 | (*pos)->getName(),{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Local Datastore '%s': State=%s, %s%s sync, %s%s" , (*pos)->getName(), (*pos)->getDSStateName(), (*pos)-> isResuming() ? "RESUMED " : "", (*pos)->fSlowSync ? "SLOW" : "normal", SyncModeDescriptions[(*pos)->fSyncMode], (*pos )->fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
2334 | (*pos)->getDSStateName(),{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Local Datastore '%s': State=%s, %s%s sync, %s%s" , (*pos)->getName(), (*pos)->getDSStateName(), (*pos)-> isResuming() ? "RESUMED " : "", (*pos)->fSlowSync ? "SLOW" : "normal", SyncModeDescriptions[(*pos)->fSyncMode], (*pos )->fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
2335 | (*pos)->isResuming() ? "RESUMED " : "",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Local Datastore '%s': State=%s, %s%s sync, %s%s" , (*pos)->getName(), (*pos)->getDSStateName(), (*pos)-> isResuming() ? "RESUMED " : "", (*pos)->fSlowSync ? "SLOW" : "normal", SyncModeDescriptions[(*pos)->fSyncMode], (*pos )->fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
2336 | (*pos)->fSlowSync ? "SLOW" : "normal",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Local Datastore '%s': State=%s, %s%s sync, %s%s" , (*pos)->getName(), (*pos)->getDSStateName(), (*pos)-> isResuming() ? "RESUMED " : "", (*pos)->fSlowSync ? "SLOW" : "normal", SyncModeDescriptions[(*pos)->fSyncMode], (*pos )->fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
2337 | SyncModeDescriptions[(*pos)->fSyncMode],{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Local Datastore '%s': State=%s, %s%s sync, %s%s" , (*pos)->getName(), (*pos)->getDSStateName(), (*pos)-> isResuming() ? "RESUMED " : "", (*pos)->fSlowSync ? "SLOW" : "normal", SyncModeDescriptions[(*pos)->fSyncMode], (*pos )->fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
2338 | (*pos)->fServerAlerted ? ", Server-Alerted" : ""{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Local Datastore '%s': State=%s, %s%s sync, %s%s" , (*pos)->getName(), (*pos)->getDSStateName(), (*pos)-> isResuming() ? "RESUMED " : "", (*pos)->fSlowSync ? "SLOW" : "normal", SyncModeDescriptions[(*pos)->fSyncMode], (*pos )->fServerAlerted ? ", Server-Alerted" : "" ); } | |||||||
2339 | )){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Local Datastore '%s': State=%s, %s%s sync, %s%s" , (*pos)->getName(), (*pos)->getDSStateName(), (*pos)-> isResuming() ? "RESUMED " : "", (*pos)->fSlowSync ? "SLOW" : "normal", SyncModeDescriptions[(*pos)->fSyncMode], (*pos )->fServerAlerted ? ", Server-Alerted" : "" ); }; | |||||||
2340 | } | |||||||
2341 | // End of outgoing message | |||||||
2342 | PDEBUGPRINTFX(DBG_HOT,({ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "=================> Finished generating outgoing message #%ld, request=%ld" , (long)fOutgoingMsgID, (long)getSyncAppBase()->requestCount () ); } | |||||||
2343 | "=================> Finished generating outgoing message #%ld, request=%ld",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "=================> Finished generating outgoing message #%ld, request=%ld" , (long)fOutgoingMsgID, (long)getSyncAppBase()->requestCount () ); } | |||||||
2344 | (long)fOutgoingMsgID,{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "=================> Finished generating outgoing message #%ld, request=%ld" , (long)fOutgoingMsgID, (long)getSyncAppBase()->requestCount () ); } | |||||||
2345 | (long)getSyncAppBase()->requestCount(){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "=================> Finished generating outgoing message #%ld, request=%ld" , (long)fOutgoingMsgID, (long)getSyncAppBase()->requestCount () ); } | |||||||
2346 | )){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "=================> Finished generating outgoing message #%ld, request=%ld" , (long)fOutgoingMsgID, (long)getSyncAppBase()->requestCount () ); }; | |||||||
2347 | PDEBUGENDBLOCK("SyncML_Outgoing")getDbgLogger()->DebugCloseBlock( "SyncML_Outgoing"); | |||||||
2348 | } // TSyncAgent::ServerMessageEnded | |||||||
2349 | ||||||||
2350 | ||||||||
2351 | void TSyncAgent::RequestEnded(bool &aHasData) | |||||||
2352 | { | |||||||
2353 | // to make sure, finish any unfinished message | |||||||
2354 | FinishMessage(true); // final allowed, as this is an out-of-normal-order case anyway | |||||||
2355 | // if we need to answer, we have data | |||||||
2356 | // - SyncML specs 1.0.1 says that server must always respond, even if message | |||||||
2357 | // contains of a Status for the SyncHdr only | |||||||
2358 | aHasData=true; | |||||||
2359 | // %%% first drafts of 1.0.1 said that SyncHdr Status only messages must not be sent... | |||||||
2360 | // aHasData=fNeedToAnswer; // %%% | |||||||
2361 | ||||||||
2362 | // now let all datastores know that request processing ends here (so they might | |||||||
2363 | // prepare for a thread switch) | |||||||
2364 | // terminate sync with all datastores | |||||||
2365 | TLocalDataStorePContainer::iterator pos; | |||||||
2366 | for (pos=fLocalDataStores.begin(); pos!=fLocalDataStores.end(); ++pos) { | |||||||
2367 | // now let them know that request has ended | |||||||
2368 | (*pos)->engRequestEnded(); | |||||||
2369 | } | |||||||
2370 | } // TSyncAgent::RequestEnded | |||||||
2371 | ||||||||
2372 | ||||||||
2373 | // Called at end of Request, returns true if session must be deleted | |||||||
2374 | // returns flag if data to be returned. If response URI was specified | |||||||
2375 | // different, it is returned in aRespURI, otherwise aRespURI is empty. | |||||||
2376 | bool TSyncAgent::EndRequest(bool &aHasData, string &aRespURI, uInt32 aReqBytes) | |||||||
2377 | { | |||||||
2378 | // count incoming data | |||||||
2379 | fIncomingBytes+=aReqBytes; | |||||||
2380 | // let client or server do what is needed | |||||||
2381 | if (fMessageRetried) { | |||||||
2382 | // Message processing cancelled | |||||||
2383 | CancelMessageProcessing(); | |||||||
2384 | // Nothing happened | |||||||
2385 | // - but count bytes | |||||||
2386 | fOutgoingBytes+=fBufferedAnswerSize; | |||||||
2387 | PDEBUGPRINTFX(DBG_HOT,({ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "========= Finished retried request with re-sending buffered answer (session %sin progress), incoming bytes=%ld, outgoing bytes=%ld" , fInProgress ? "" : "NOT ", (long)aReqBytes, (long)fBufferedAnswerSize ); } | |||||||
2388 | "========= Finished retried request with re-sending buffered answer (session %sin progress), incoming bytes=%ld, outgoing bytes=%ld",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "========= Finished retried request with re-sending buffered answer (session %sin progress), incoming bytes=%ld, outgoing bytes=%ld" , fInProgress ? "" : "NOT ", (long)aReqBytes, (long)fBufferedAnswerSize ); } | |||||||
2389 | fInProgress ? "" : "NOT ",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "========= Finished retried request with re-sending buffered answer (session %sin progress), incoming bytes=%ld, outgoing bytes=%ld" , fInProgress ? "" : "NOT ", (long)aReqBytes, (long)fBufferedAnswerSize ); } | |||||||
2390 | (long)aReqBytes,{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "========= Finished retried request with re-sending buffered answer (session %sin progress), incoming bytes=%ld, outgoing bytes=%ld" , fInProgress ? "" : "NOT ", (long)aReqBytes, (long)fBufferedAnswerSize ); } | |||||||
2391 | (long)fBufferedAnswerSize{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "========= Finished retried request with re-sending buffered answer (session %sin progress), incoming bytes=%ld, outgoing bytes=%ld" , fInProgress ? "" : "NOT ", (long)aReqBytes, (long)fBufferedAnswerSize ); } | |||||||
2392 | )){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "========= Finished retried request with re-sending buffered answer (session %sin progress), incoming bytes=%ld, outgoing bytes=%ld" , fInProgress ? "" : "NOT ", (long)aReqBytes, (long)fBufferedAnswerSize ); }; | |||||||
2393 | aHasData=false; // we do not have data in the sml instance (but we have/had some in the retry re-send buffer) | |||||||
2394 | } | |||||||
2395 | else { | |||||||
2396 | // end request | |||||||
2397 | RequestEnded(aHasData); | |||||||
2398 | // count bytes | |||||||
2399 | fOutgoingBytes+=getOutgoingMessageSize(); | |||||||
2400 | PDEBUGPRINTFX(DBG_HOT,({ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "========= Finished request (session %sin progress), processing time=%ld msec, incoming bytes=%ld, outgoing bytes=%ld" , fInProgress ? "" : "NOT ", (long)((getSystemNowAs(((timecontext_t ) ((tctx_tz_UTC) | TCTX_SYMBOLIC_TZ)))-getLastRequestStarted( )) * nanosecondsPerLinearTime / 1000000), (long)aReqBytes, (long )getOutgoingMessageSize() ); } | |||||||
2401 | "========= Finished request (session %sin progress), processing time=%ld msec, incoming bytes=%ld, outgoing bytes=%ld",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "========= Finished request (session %sin progress), processing time=%ld msec, incoming bytes=%ld, outgoing bytes=%ld" , fInProgress ? "" : "NOT ", (long)((getSystemNowAs(((timecontext_t ) ((tctx_tz_UTC) | TCTX_SYMBOLIC_TZ)))-getLastRequestStarted( )) * nanosecondsPerLinearTime / 1000000), (long)aReqBytes, (long )getOutgoingMessageSize() ); } | |||||||
2402 | fInProgress ? "" : "NOT ",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "========= Finished request (session %sin progress), processing time=%ld msec, incoming bytes=%ld, outgoing bytes=%ld" , fInProgress ? "" : "NOT ", (long)((getSystemNowAs(((timecontext_t ) ((tctx_tz_UTC) | TCTX_SYMBOLIC_TZ)))-getLastRequestStarted( )) * nanosecondsPerLinearTime / 1000000), (long)aReqBytes, (long )getOutgoingMessageSize() ); } | |||||||
2403 | (long)((getSystemNowAs(TCTX_UTC)-getLastRequestStarted()) * nanosecondsPerLinearTime / 1000000),{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "========= Finished request (session %sin progress), processing time=%ld msec, incoming bytes=%ld, outgoing bytes=%ld" , fInProgress ? "" : "NOT ", (long)((getSystemNowAs(((timecontext_t ) ((tctx_tz_UTC) | TCTX_SYMBOLIC_TZ)))-getLastRequestStarted( )) * nanosecondsPerLinearTime / 1000000), (long)aReqBytes, (long )getOutgoingMessageSize() ); } | |||||||
2404 | (long)aReqBytes,{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "========= Finished request (session %sin progress), processing time=%ld msec, incoming bytes=%ld, outgoing bytes=%ld" , fInProgress ? "" : "NOT ", (long)((getSystemNowAs(((timecontext_t ) ((tctx_tz_UTC) | TCTX_SYMBOLIC_TZ)))-getLastRequestStarted( )) * nanosecondsPerLinearTime / 1000000), (long)aReqBytes, (long )getOutgoingMessageSize() ); } | |||||||
2405 | (long)getOutgoingMessageSize(){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "========= Finished request (session %sin progress), processing time=%ld msec, incoming bytes=%ld, outgoing bytes=%ld" , fInProgress ? "" : "NOT ", (long)((getSystemNowAs(((timecontext_t ) ((tctx_tz_UTC) | TCTX_SYMBOLIC_TZ)))-getLastRequestStarted( )) * nanosecondsPerLinearTime / 1000000), (long)aReqBytes, (long )getOutgoingMessageSize() ); } | |||||||
2406 | )){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "========= Finished request (session %sin progress), processing time=%ld msec, incoming bytes=%ld, outgoing bytes=%ld" , fInProgress ? "" : "NOT ", (long)((getSystemNowAs(((timecontext_t ) ((tctx_tz_UTC) | TCTX_SYMBOLIC_TZ)))-getLastRequestStarted( )) * nanosecondsPerLinearTime / 1000000), (long)aReqBytes, (long )getOutgoingMessageSize() ); }; | |||||||
2407 | // return RespURI (is empty if none specified or equal to message source URI) | |||||||
2408 | aRespURI = fRespondURI; | |||||||
2409 | } | |||||||
2410 | if (!fInProgress) { | |||||||
2411 | // terminate datastores here already in case we are not in progress any more | |||||||
2412 | // here. If any of the datastores are in progress at this point, this is a | |||||||
2413 | // protocol violation, and therefore we return a 400. | |||||||
2414 | // Note: resetting the session later will also call TerminateDatastores, but then | |||||||
2415 | // with a 408 (which is misleading when the session ends here due to protocol | |||||||
2416 | // problem. | |||||||
2417 | TerminateDatastores(400); | |||||||
2418 | } | |||||||
2419 | //%%% moved to happen before end of SyncML_Outgoing | |||||||
2420 | //PDEBUGENDBLOCK("SyncML_Incoming"); | |||||||
2421 | if (fRequestMinTime>0) { | |||||||
2422 | // make sure we spent enough time with this request, if not, artificially extend time | |||||||
2423 | // - get number of seconds already spent | |||||||
2424 | sInt32 t = | |||||||
2425 | (sInt32)((getSystemNowAs(TCTX_UTC((timecontext_t) ((tctx_tz_UTC) | TCTX_SYMBOLIC_TZ)))-getLastRequestStarted()) / (lineartime_t)secondToLinearTimeFactor); | |||||||
2426 | // - delay if needed | |||||||
2427 | if (t<fRequestMinTime) { | |||||||
2428 | PDEBUGPRINTFX(DBG_HOT,({ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "requestmintime is set to %ld seconds, we have spent only %ld seconds so far -> sleeping %ld seconds" , (long)fRequestMinTime, (long)t, (long)fRequestMinTime-t ); } | |||||||
2429 | "requestmintime is set to %ld seconds, we have spent only %ld seconds so far -> sleeping %ld seconds",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "requestmintime is set to %ld seconds, we have spent only %ld seconds so far -> sleeping %ld seconds" , (long)fRequestMinTime, (long)t, (long)fRequestMinTime-t ); } | |||||||
2430 | (long)fRequestMinTime,{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "requestmintime is set to %ld seconds, we have spent only %ld seconds so far -> sleeping %ld seconds" , (long)fRequestMinTime, (long)t, (long)fRequestMinTime-t ); } | |||||||
2431 | (long)t,{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "requestmintime is set to %ld seconds, we have spent only %ld seconds so far -> sleeping %ld seconds" , (long)fRequestMinTime, (long)t, (long)fRequestMinTime-t ); } | |||||||
2432 | (long)fRequestMinTime-t{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "requestmintime is set to %ld seconds, we have spent only %ld seconds so far -> sleeping %ld seconds" , (long)fRequestMinTime, (long)t, (long)fRequestMinTime-t ); } | |||||||
2433 | )){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "requestmintime is set to %ld seconds, we have spent only %ld seconds so far -> sleeping %ld seconds" , (long)fRequestMinTime, (long)t, (long)fRequestMinTime-t ); }; | |||||||
2434 | CONSOLEPRINTF((" ...delaying response by %ld seconds because requestmintime is set to %ld",(long)fRequestMinTime,(long)(fRequestMinTime-t)))SySync_ConsolePrintf(stderr, "SYSYNC " " ...delaying response by %ld seconds because requestmintime is set to %ld" "\n",(long)fRequestMinTime,(long)(fRequestMinTime-t)); | |||||||
2435 | sleepLineartime((lineartime_t)(fRequestMinTime-t)*secondToLinearTimeFactor); | |||||||
2436 | } | |||||||
2437 | } | |||||||
2438 | // thread might end here, so stop profiling | |||||||
2439 | TP_STOP(fTPInfo); | |||||||
2440 | #ifdef SYDEBUG2 | |||||||
2441 | // we are not the main thread any longer | |||||||
2442 | getDbgLogger()->DebugThreadOutputDone(); | |||||||
2443 | #endif | |||||||
2444 | // return true if session is not in progress any more | |||||||
2445 | return(!fInProgress); | |||||||
2446 | } // TSyncAgent::EndRequest | |||||||
2447 | ||||||||
2448 | ||||||||
2449 | // buffer answer in the session's buffer if transport allows it | |||||||
2450 | Ret_t TSyncAgent::bufferAnswer(MemPtr_t aAnswer, MemSize_t aAnswerSize) | |||||||
2451 | { | |||||||
2452 | // get rid of previous buffered answer | |||||||
2453 | if (fBufferedAnswer) | |||||||
2454 | delete[] fBufferedAnswer; | |||||||
2455 | fBufferedAnswer=NULL__null; | |||||||
2456 | fBufferedAnswerSize=0; | |||||||
2457 | // save new answer (if not empty) | |||||||
2458 | if (aAnswer && aAnswerSize) { | |||||||
2459 | // allocate buffer | |||||||
2460 | fBufferedAnswer = new unsigned char[aAnswerSize]; | |||||||
2461 | // copy data | |||||||
2462 | if (!fBufferedAnswer) return SML_ERR_NOT_ENOUGH_SPACE0x11; | |||||||
2463 | memcpy(fBufferedAnswer,aAnswer,aAnswerSize); | |||||||
2464 | // save size | |||||||
2465 | fBufferedAnswerSize=aAnswerSize; | |||||||
2466 | } | |||||||
2467 | return SML_ERR_OK0x00; | |||||||
2468 | } // TSyncAgent::bufferAnswer | |||||||
2469 | ||||||||
2470 | ||||||||
2471 | // get buffered answer from the session's buffer if there is any | |||||||
2472 | void TSyncAgent::getBufferedAnswer(MemPtr_t &aAnswer, MemSize_t &aAnswerSize) | |||||||
2473 | { | |||||||
2474 | aAnswer=fBufferedAnswer; | |||||||
2475 | aAnswerSize=fBufferedAnswerSize; | |||||||
2476 | PDEBUGPRINTFX(DBG_HOT,({ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Buffered answer read from session: %ld bytes" , (long)fBufferedAnswerSize ); } | |||||||
2477 | "Buffered answer read from session: %ld bytes",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Buffered answer read from session: %ld bytes" , (long)fBufferedAnswerSize ); } | |||||||
2478 | (long)fBufferedAnswerSize{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Buffered answer read from session: %ld bytes" , (long)fBufferedAnswerSize ); } | |||||||
2479 | )){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Buffered answer read from session: %ld bytes" , (long)fBufferedAnswerSize ); }; | |||||||
2480 | } // TSyncAgent::getBufferedAnswer | |||||||
2481 | ||||||||
2482 | ||||||||
2483 | // returns remaining time for request processing [seconds] | |||||||
2484 | sInt32 TSyncAgent::RemainingRequestTime(void) | |||||||
2485 | { | |||||||
2486 | if (IS_CLIENT(!getSyncAppBase()->isServer())) { | |||||||
2487 | // clients don't process requests, so there's no limit | |||||||
2488 | return 0x7FFFFFFF; // "infinite" | |||||||
2489 | } | |||||||
2490 | else { | |||||||
2491 | // if no request timeout specified, use session timeout | |||||||
2492 | sInt32 t = fRequestMaxTime ? fRequestMaxTime : getSessionConfig()->fSessionTimeout; | |||||||
2493 | // calculate number of remaining seconds | |||||||
2494 | return | |||||||
2495 | t==0 ? | |||||||
2496 | 0x7FFFFFFF : // "infinite" | |||||||
2497 | t - (sInt32)((getSystemNowAs(TCTX_UTC((timecontext_t) ((tctx_tz_UTC) | TCTX_SYMBOLIC_TZ)))-getLastRequestStarted()) / (lineartime_t)secondToLinearTimeFactor); | |||||||
2498 | } | |||||||
2499 | } // TSyncAgent::RemainingRequestTime | |||||||
2500 | ||||||||
2501 | ||||||||
2502 | ||||||||
2503 | ||||||||
2504 | ||||||||
2505 | // process a Map command in context of server session | |||||||
2506 | bool TSyncAgent::processMapCommand( | |||||||
2507 | SmlMapPtr_t aMapCommandP, // the map command contents | |||||||
2508 | TStatusCommand &aStatusCommand, // pre-set 200 status, can be modified in case of errors | |||||||
2509 | bool &aQueueForLater | |||||||
2510 | ) | |||||||
2511 | { | |||||||
2512 | bool allok=false; // assume not ok | |||||||
2513 | localstatus sta; | |||||||
2514 | ||||||||
2515 | // remember that this session has seen a map command already | |||||||
2516 | fMapSeen=true; | |||||||
2517 | // Detecting a map command in supplement incomin state indicates a | |||||||
2518 | // client like funambol that send to many <final/> in pre-map phases | |||||||
2519 | // (such as in 222-Alert messages). So we reset the session state back | |||||||
2520 | // to incoming/outgoing map to correct this client bug | |||||||
2521 | if (fIncomingState==psta_supplement) { | |||||||
| ||||||||
2522 | // back to map phase, as client apparently IS still in map phase, despite too many | |||||||
2523 | // <final/> sent | |||||||
2524 | PDEBUGPRINTFX(DBG_ERROR,({ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Warning: detected <Map> command after end of Map phase - buggy client sent too many <final/>. Re-entering map phase to compensate" ); } | |||||||
2525 | "Warning: detected <Map> command after end of Map phase - buggy client sent too many <final/>. Re-entering map phase to compensate"{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Warning: detected <Map> command after end of Map phase - buggy client sent too many <final/>. Re-entering map phase to compensate" ); } | |||||||
2526 | )){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Warning: detected <Map> command after end of Map phase - buggy client sent too many <final/>. Re-entering map phase to compensate" ); }; | |||||||
2527 | fIncomingState=psta_map; | |||||||
2528 | fOutgoingState=psta_map; | |||||||
2529 | } | |||||||
2530 | // find database(s) | |||||||
2531 | // - get relative URI of requested database | |||||||
2532 | const char *targetdburi = smlSrcTargLocURIToCharP(aMapCommandP->target); | |||||||
2533 | TLocalEngineDS *datastoreP = findLocalDataStoreByURI(targetdburi); | |||||||
2534 | if (!datastoreP) { | |||||||
2535 | // no such local datastore | |||||||
2536 | aStatusCommand.setStatusCode(404); // not found | |||||||
2537 | } | |||||||
2538 | else { | |||||||
2539 | // local datastore found | |||||||
2540 | // - maps can be processed when we are at least ready for early (chached by client from previous session) maps | |||||||
2541 | if (datastoreP->testState(dssta_syncmodestable)) { | |||||||
2542 | // datastore is ready | |||||||
2543 | PDEBUGBLOCKFMT(("ProcessMap", "Processing items from Map command", "datastore=%s", targetdburi))getDbgLogger()->DebugOpenBlockExpanded ("ProcessMap", "Processing items from Map command" , "datastore=%s", targetdburi); | |||||||
2544 | allok=true; // assume all ok | |||||||
2545 | SmlMapItemListPtr_t nextnode = aMapCommandP->mapItemList; | |||||||
2546 | while (nextnode) { | |||||||
2547 | POINTERTEST(nextnode->mapItem,("MapItemList node w/o MapItem"))if (!nextnode->mapItem) getDbgLogger()->setNextMask(0x00000002 ).DebugPrintfLastMask ("MapItemList node w/o MapItem"); | |||||||
2548 | PDEBUGPRINTFX(DBG_HOT,({ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Mapping remoteID='%s' to localID='%s'" , smlSrcTargLocURIToCharP(nextnode->mapItem->source), smlSrcTargLocURIToCharP (nextnode->mapItem->target) ); } | |||||||
| ||||||||
2549 | "Mapping remoteID='%s' to localID='%s'",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Mapping remoteID='%s' to localID='%s'" , smlSrcTargLocURIToCharP(nextnode->mapItem->source), smlSrcTargLocURIToCharP (nextnode->mapItem->target) ); } | |||||||
2550 | smlSrcTargLocURIToCharP(nextnode->mapItem->source),{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Mapping remoteID='%s' to localID='%s'" , smlSrcTargLocURIToCharP(nextnode->mapItem->source), smlSrcTargLocURIToCharP (nextnode->mapItem->target) ); } | |||||||
2551 | smlSrcTargLocURIToCharP(nextnode->mapItem->target){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Mapping remoteID='%s' to localID='%s'" , smlSrcTargLocURIToCharP(nextnode->mapItem->source), smlSrcTargLocURIToCharP (nextnode->mapItem->target) ); } | |||||||
2552 | )){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Mapping remoteID='%s' to localID='%s'" , smlSrcTargLocURIToCharP(nextnode->mapItem->source), smlSrcTargLocURIToCharP (nextnode->mapItem->target) ); }; | |||||||
2553 | sta = datastoreP->engProcessMap( | |||||||
2554 | #ifdef DONT_STRIP_PATHPREFIX_FROM_REMOTEIDS1 | |||||||
2555 | smlSrcTargLocURIToCharP(nextnode->mapItem->source), | |||||||
2556 | #else | |||||||
2557 | relativeURI(smlSrcTargLocURIToCharP(nextnode->mapItem->source)), | |||||||
2558 | #endif | |||||||
2559 | relativeURI(smlSrcTargLocURIToCharP(nextnode->mapItem->target)) | |||||||
2560 | ); | |||||||
2561 | if (sta!=LOCERR_OK) { | |||||||
2562 | PDEBUGPRINTFX(DBG_ERROR,(" Mapping FAILED!")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask (" Mapping FAILED!" ); }; | |||||||
2563 | aStatusCommand.setStatusCode(sta); | |||||||
2564 | allok=false; | |||||||
2565 | break; | |||||||
2566 | } | |||||||
2567 | // next mapitem | |||||||
2568 | nextnode=nextnode->next; | |||||||
2569 | } // while more mapitems | |||||||
2570 | // terminate Map command | |||||||
2571 | allok=datastoreP->MapFinishAsServer(allok,aStatusCommand); | |||||||
2572 | PDEBUGENDBLOCK("ProcessMap")getDbgLogger()->DebugCloseBlock( "ProcessMap"); | |||||||
2573 | } | |||||||
2574 | else { | |||||||
2575 | // we must queue the command for later execution | |||||||
2576 | aQueueForLater=true; | |||||||
2577 | allok=true; // ok for now, we'll re-execute this later | |||||||
2578 | } | |||||||
2579 | } // database found | |||||||
2580 | return allok; | |||||||
2581 | } // TSyncAgent::processMapCommand | |||||||
2582 | ||||||||
2583 | ||||||||
2584 | // get next nonce string top be sent to remote party for subsequent MD5 auth | |||||||
2585 | void TSyncAgent::getNextNonce(const char *aDeviceID, string &aNextNonce) | |||||||
2586 | { | |||||||
2587 | fLastNonce.erase(); | |||||||
2588 | if (getServerConfig()->fAutoNonce) { | |||||||
2589 | // generate nonce out of source ref and session ID | |||||||
2590 | // This scheme can provide nonce carrying forward between | |||||||
2591 | // sessions by initializing lastNonce with the srcRef/sessionid-1 | |||||||
2592 | // assuming client to use nonce from last session. | |||||||
2593 | sInt32 sid; | |||||||
2594 | // use current day as nonce varying number | |||||||
2595 | sid = time(NULL__null) / 3600 / 24; | |||||||
2596 | generateNonce(fLastNonce,aDeviceID,sid); | |||||||
2597 | } | |||||||
2598 | else { | |||||||
2599 | // get constant nonce (if empty, this is NO nonce) | |||||||
2600 | fLastNonce=getServerConfig()->fConstantNonce; | |||||||
2601 | } | |||||||
2602 | // return new nonce | |||||||
2603 | DEBUGPRINTFX(DBG_PROTO,("getNextNonce: created nonce='%s'",fLastNonce.c_str())){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ("getNextNonce: created nonce='%s'" ,fLastNonce.c_str()); }; | |||||||
2604 | aNextNonce=fLastNonce; | |||||||
2605 | } // TSyncAgent::getNextNonce | |||||||
2606 | ||||||||
2607 | ||||||||
2608 | // - get nonce string for specified deviceID | |||||||
2609 | void TSyncAgent::getAuthNonce(const char *aDeviceID, string &aAuthNonce) | |||||||
2610 | { | |||||||
2611 | // if no device ID, use session default nonce | |||||||
2612 | if (!aDeviceID) { | |||||||
2613 | TSyncSession::getAuthNonce(aDeviceID,fLastNonce); | |||||||
2614 | } | |||||||
2615 | else { | |||||||
2616 | // Basic nonce mechanism needing no per-device storage: | |||||||
2617 | // - we have no stored last nonce, but we can re-create nonce used | |||||||
2618 | // for last session with this device by the used algorithm | |||||||
2619 | if (getServerConfig()->fAutoNonce) { | |||||||
2620 | if (fLastNonce.empty()) { | |||||||
2621 | // none available, produce new one | |||||||
2622 | sInt32 sid; | |||||||
2623 | // use current day as nonce varying number | |||||||
2624 | sid = time(NULL__null) / 3600 / 24; | |||||||
2625 | generateNonce(fLastNonce,aDeviceID,sid); | |||||||
2626 | } | |||||||
2627 | } | |||||||
2628 | else { | |||||||
2629 | // return constant nonce | |||||||
2630 | fLastNonce=getServerConfig()->fConstantNonce; | |||||||
2631 | } | |||||||
2632 | } | |||||||
2633 | DEBUGPRINTFX(DBG_PROTO,("getAuthNonce: current auth nonce='%s'",fLastNonce.c_str())){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ("getAuthNonce: current auth nonce='%s'" ,fLastNonce.c_str()); }; | |||||||
2634 | aAuthNonce=fLastNonce; | |||||||
2635 | } // TSyncAgent::getAuthNonce | |||||||
2636 | ||||||||
2637 | ||||||||
2638 | ||||||||
2639 | // info about server status | |||||||
2640 | bool TSyncAgent::serverBusy(void) | |||||||
2641 | { | |||||||
2642 | // return flag (which might have been set by some connection | |||||||
2643 | // limit code in sessiondispatch). | |||||||
2644 | // When app is expired, all server sessions are busy anyway | |||||||
2645 | #ifdef APP_CAN_EXPIRE | |||||||
2646 | return fSessionIsBusy || (getSyncAppBase()->fAppExpiryStatus!=LOCERR_OK); | |||||||
2647 | #else | |||||||
2648 | return fSessionIsBusy; | |||||||
2649 | #endif | |||||||
2650 | } // TSyncAgent::serverBusy | |||||||
2651 | ||||||||
2652 | ||||||||
2653 | // access to config | |||||||
2654 | TAgentConfig *TSyncAgent::getServerConfig(void) | |||||||
2655 | { | |||||||
2656 | TAgentConfig *scP; | |||||||
2657 | GET_CASTED_PTR(scP,TAgentConfig,getSyncAppBase()->getRootConfig()->fAgentConfigP,DEBUGTEXT("no TAgentConfig","ss1")){ scP = dynamic_cast<TAgentConfig *>(getSyncAppBase()-> getRootConfig()->fAgentConfigP); if (!scP) { throw TSyncException ("no TAgentConfig"); } }; | |||||||
2658 | return scP; | |||||||
2659 | } // TSyncAgent::getServerConfig | |||||||
2660 | ||||||||
2661 | ||||||||
2662 | #endif // SYSYNC_SERVER | |||||||
2663 | ||||||||
2664 | ||||||||
2665 | // info about requested auth type | |||||||
2666 | TAuthTypes TSyncAgent::requestedAuthType(void) | |||||||
2667 | { | |||||||
2668 | if (IS_SERVER(getSyncAppBase()->isServer())) { | |||||||
2669 | #ifdef SYSYNC_SERVER1 | |||||||
2670 | return getServerConfig()->fRequestedAuth; | |||||||
2671 | #endif | |||||||
2672 | } | |||||||
2673 | else { | |||||||
2674 | return auth_none; // client does not require auth | |||||||
2675 | } | |||||||
2676 | } // TSyncAgent::requestedAuthType | |||||||
2677 | ||||||||
2678 | ||||||||
2679 | // check if auth type is allowed | |||||||
2680 | bool TSyncAgent::isAuthTypeAllowed(TAuthTypes aAuthType) | |||||||
2681 | { | |||||||
2682 | if (IS_SERVER(getSyncAppBase()->isServer())) { | |||||||
2683 | #ifdef SYSYNC_SERVER1 | |||||||
2684 | return aAuthType>=getServerConfig()->fRequiredAuth; | |||||||
2685 | #endif | |||||||
2686 | } | |||||||
2687 | else { | |||||||
2688 | return true; // client accepts any auth | |||||||
2689 | } | |||||||
2690 | } // TSyncAgent::isAuthTypeAllowed | |||||||
2691 | ||||||||
2692 | ||||||||
2693 | // called when incoming SyncHdr fails to execute | |||||||
2694 | bool TSyncAgent::syncHdrFailure(bool aTryAgain) | |||||||
2695 | { | |||||||
2696 | if (IS_CLIENT(!getSyncAppBase()->isServer())) { | |||||||
2697 | // do not try to re-execute the header, just let message processing fail; | |||||||
2698 | // this will cause the client's main loop to try using an older protocol | |||||||
2699 | return false; | |||||||
2700 | } | |||||||
2701 | else { | |||||||
2702 | #ifdef SYSYNC_SERVER1 | |||||||
2703 | if (!aTryAgain) { | |||||||
2704 | // not already retried executing | |||||||
2705 | // special case: header failed to execute, this means that session must be reset | |||||||
2706 | // - Reset session (aborts all DB transactions etc.) | |||||||
2707 | ResetSession(); | |||||||
2708 | PDEBUGPRINTFX(DBG_ERROR,("Trying to recover SyncHdr failure: =========== Session restarted =====================")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Trying to recover SyncHdr failure: =========== Session restarted =====================" ); }; | |||||||
2709 | // - now all session infos are gone except this command which is owned by | |||||||
2710 | // this function alone. Execute it again. | |||||||
2711 | aTryAgain=true; | |||||||
2712 | } | |||||||
2713 | else { | |||||||
2714 | // special special case: header failed to execute the second time | |||||||
2715 | DEBUGPRINTFX(DBG_ERROR,("Fatal internal problem, SyncHdr execution failed twice")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Fatal internal problem, SyncHdr execution failed twice" ); }; | |||||||
2716 | aTryAgain=false; // just to make sure | |||||||
2717 | SYSYNC_THROW(TSyncException("SyncHdr fatal execution problem"))throw TSyncException("SyncHdr fatal execution problem"); | |||||||
2718 | } | |||||||
2719 | return aTryAgain; | |||||||
2720 | #endif | |||||||
2721 | } | |||||||
2722 | } // TSyncAgent::syncHdrFailure | |||||||
2723 | ||||||||
2724 | ||||||||
2725 | // handle status received for SyncHdr, returns false if not handled | |||||||
2726 | bool TSyncAgent::handleHeaderStatus(TStatusCommand *aStatusCmdP) | |||||||
2727 | { | |||||||
2728 | if (IS_CLIENT(!getSyncAppBase()->isServer())) { | |||||||
2729 | #ifdef SYSYNC_CLIENT1 | |||||||
2730 | TAgentConfig *configP = static_cast<TAgentConfig *>(getRootConfig()->fAgentConfigP); | |||||||
2731 | bool handled=true; | |||||||
2732 | const char *txt; | |||||||
2733 | SmlMetInfMetInfPtr_t chalmetaP=NULL__null; | |||||||
2734 | SmlChalPtr_t chalP; | |||||||
2735 | ||||||||
2736 | // first evaluate possible challenge in header status | |||||||
2737 | chalP = aStatusCmdP->getStatusElement()->chal; | |||||||
2738 | if (chalP) { | |||||||
2739 | chalmetaP = smlPCDataToMetInfP(chalP->meta); | |||||||
2740 | if (chalmetaP) { | |||||||
2741 | sInt16 ty; | |||||||
2742 | // - get auth type | |||||||
2743 | if (!chalmetaP->type) AbortSession(401,true); // missing auth, but no type | |||||||
2744 | txt = smlPCDataToCharP(chalmetaP->type); | |||||||
2745 | PDEBUGPRINTFX(DBG_PROTO,("Remote requests auth type='%s'",txt)){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ("Remote requests auth type='%s'" ,txt); }; | |||||||
2746 | if (StrToEnum(authTypeSyncMLNames,numAuthTypes,ty,txt)) | |||||||
2747 | fRemoteRequestedAuth=(TAuthTypes)ty; | |||||||
2748 | else { | |||||||
2749 | AbortSession(406,true); // unknown auth type, not supported | |||||||
2750 | goto donewithstatus; | |||||||
2751 | } | |||||||
2752 | // - get auth format | |||||||
2753 | if (!smlPCDataToFormat(chalmetaP->format, fRemoteRequestedAuthEnc)) { | |||||||
2754 | AbortSession(406,true); // unknown auth format, not supported | |||||||
2755 | goto donewithstatus; | |||||||
2756 | } | |||||||
2757 | // - get next nonce | |||||||
2758 | if (chalmetaP->nextnonce) { | |||||||
2759 | // decode B64 | |||||||
2760 | uInt32 l; | |||||||
2761 | uInt8 *nonce = b64::decode(smlPCDataToCharP(chalmetaP->nextnonce), 0, &l); | |||||||
2762 | fRemoteNonce.assign((char *)nonce,l); | |||||||
2763 | b64::free(nonce); | |||||||
2764 | } | |||||||
2765 | // - show | |||||||
2766 | PDEBUGPRINTFX(DBG_PROTO,({ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ( "Next Cred will have type='%s' and format='%s' and use nonce='%s'" , authTypeNames[fRemoteRequestedAuth], encodingFmtNames[fRemoteRequestedAuthEnc ], fRemoteNonce.c_str() ); } | |||||||
2767 | "Next Cred will have type='%s' and format='%s' and use nonce='%s'",{ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ( "Next Cred will have type='%s' and format='%s' and use nonce='%s'" , authTypeNames[fRemoteRequestedAuth], encodingFmtNames[fRemoteRequestedAuthEnc ], fRemoteNonce.c_str() ); } | |||||||
2768 | authTypeNames[fRemoteRequestedAuth],{ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ( "Next Cred will have type='%s' and format='%s' and use nonce='%s'" , authTypeNames[fRemoteRequestedAuth], encodingFmtNames[fRemoteRequestedAuthEnc ], fRemoteNonce.c_str() ); } | |||||||
2769 | encodingFmtNames[fRemoteRequestedAuthEnc],{ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ( "Next Cred will have type='%s' and format='%s' and use nonce='%s'" , authTypeNames[fRemoteRequestedAuth], encodingFmtNames[fRemoteRequestedAuthEnc ], fRemoteNonce.c_str() ); } | |||||||
2770 | fRemoteNonce.c_str(){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ( "Next Cred will have type='%s' and format='%s' and use nonce='%s'" , authTypeNames[fRemoteRequestedAuth], encodingFmtNames[fRemoteRequestedAuthEnc ], fRemoteNonce.c_str() ); } | |||||||
2771 | )){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ( "Next Cred will have type='%s' and format='%s' and use nonce='%s'" , authTypeNames[fRemoteRequestedAuth], encodingFmtNames[fRemoteRequestedAuthEnc ], fRemoteNonce.c_str() ); }; | |||||||
2772 | } | |||||||
2773 | /* %%% do not save here already, we don't know if SyncML version is ok | |||||||
2774 | moved to those status code cases below that signal | |||||||
2775 | // let descendant possibly save auth params | |||||||
2776 | saveRemoteParams(); | |||||||
2777 | */ | |||||||
2778 | } | |||||||
2779 | // now evaluate status code | |||||||
2780 | switch (aStatusCmdP->getStatusCode()) { | |||||||
2781 | case 101: // Busy | |||||||
2782 | // Abort | |||||||
2783 | AbortSession(101,false); | |||||||
2784 | break; | |||||||
2785 | case 212: // authentication accepted for entire session | |||||||
2786 | fNeedAuth=false; // no need for further auth | |||||||
2787 | PDEBUGPRINTFX(DBG_PROTO,("Remote accepted authentication for entire session")){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ("Remote accepted authentication for entire session" ); }; | |||||||
2788 | case 200: // authentication accepted for this message | |||||||
2789 | // if this is the first authorized message we get an OK for the synchdr, this is | |||||||
2790 | // also the first incoming message that is really processed as init message | |||||||
2791 | if (fIncomingState==psta_idle && fMessageAuthorized) { | |||||||
2792 | // first incoming is expected to be same as first outgoing (init or initsync) | |||||||
2793 | fIncomingState=fOutgoingState; | |||||||
2794 | PDEBUGPRINTFX(DBG_PROTO,("Authenticated successfully with remote server")){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ("Authenticated successfully with remote server" ); }; | |||||||
2795 | } | |||||||
2796 | else { | |||||||
2797 | PDEBUGPRINTFX(DBG_PROTO,("Authentication with server ok for this message")){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ("Authentication with server ok for this message" ); }; | |||||||
2798 | } | |||||||
2799 | // let descendant possibly save auth params | |||||||
2800 | saveRemoteParams(); | |||||||
2801 | break; | |||||||
2802 | case 501: // handle a "command not implemented" for the SyncHdr like 513 (indication that server does not like our header) | |||||||
2803 | case 400: // ..and 400 as well (sync4j case, as it seems) | |||||||
2804 | case 513: // bad protocol version | |||||||
2805 | case 505: // bad DTD version (NextHaus/DeskNow case) | |||||||
2806 | // try with next lower protocol | |||||||
2807 | PDEBUGENDBLOCK("processStatus")getDbgLogger()->DebugCloseBlock( "processStatus"); // done processing status | |||||||
2808 | if (!retryOlderProtocol()) { | |||||||
2809 | // no older SyncML protocol we can try --> abort | |||||||
2810 | AbortSession(513,false); // server does not know any of our SyncML versions | |||||||
2811 | } | |||||||
2812 | break; | |||||||
2813 | case 401: // bad authentication | |||||||
2814 | // Bad authorisation | |||||||
2815 | if (fAuthRetries==0) | |||||||
2816 | // if first attempt is rejected with "bad", we conclude that the | |||||||
2817 | // last attempt was carrying auth data and was not a attempt to get challenge | |||||||
2818 | // from server. Therefore we count this as two tries (one get chal, one really failing) | |||||||
2819 | fAuthRetries=2; | |||||||
2820 | else | |||||||
2821 | fAuthRetries++; // just count attempt to auth | |||||||
2822 | /* %%% no longer required, is tested below at authfail: | |||||||
2823 | if (fAuthRetries>MAX_AUTH_RETRIES) { | |||||||
2824 | AbortSession(401,false); // abort session, too many retries | |||||||
2825 | break; | |||||||
2826 | } | |||||||
2827 | */ | |||||||
2828 | // Treat no nonce like empty nonce to make sure that a server (like SySync old versions...) | |||||||
2829 | // that does not send a nonce at all does not get auth with some old, invalid nonce string included. | |||||||
2830 | if (chalmetaP && chalmetaP->nextnonce==NULL__null) fRemoteNonce.erase(); | |||||||
2831 | // otherwise treat like 407 | |||||||
2832 | goto authfail; | |||||||
2833 | case 407: // authentication required | |||||||
2834 | // new since 2.0.4.6: count this as well (normally this happens once when sending | |||||||
2835 | // no auth to the server to force it to send us auth chal first). | |||||||
2836 | fAuthRetries++; | |||||||
2837 | authfail: | |||||||
2838 | PDEBUGPRINTFX(DBG_ERROR,("Authentication failed (status=%hd) with remote server",aStatusCmdP->getStatusCode())){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Authentication failed (status=%hd) with remote server" ,aStatusCmdP->getStatusCode()); }; | |||||||
2839 | // Auth fail after we have received a valid response for the init message indicates protocol messed up | |||||||
2840 | if (fIncomingState!=psta_idle) { | |||||||
2841 | AbortSession(400,true); // error in protocol handling from remote | |||||||
2842 | break; | |||||||
2843 | } | |||||||
2844 | // Check if smart retries (with modified in-session vs out-of-session behaviour) are enabled | |||||||
2845 | if (!configP->fSmartAuthRetry && fAuthRetries>MAX_NORMAL_AUTH_RETRIES2) { | |||||||
2846 | fAuthRetries = MAX_SMART_AUTH_RETRIES4+1; // skip additional smart retries | |||||||
2847 | } | |||||||
2848 | // Missing or bad authorisation, evaluate chal | |||||||
2849 | if (!chalmetaP || fAuthRetries>MAX_SMART_AUTH_RETRIES4) { | |||||||
2850 | #ifdef SYDEBUG2 | |||||||
2851 | if (!chalmetaP) { | |||||||
2852 | PDEBUGPRINTFX(DBG_ERROR,("Bad auth but no challenge in response status -> can't work - no retry")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Bad auth but no challenge in response status -> can't work - no retry" ); }; | |||||||
2853 | } | |||||||
2854 | #endif | |||||||
2855 | AbortSession(aStatusCmdP->getStatusCode(),false); // retries exhausted or no retry possible (no chal) -> stop session | |||||||
2856 | break; | |||||||
2857 | } | |||||||
2858 | // let descendant possibly save auth params | |||||||
2859 | saveRemoteParams(); | |||||||
2860 | // modify session for re-start | |||||||
2861 | PDEBUGENDBLOCK("processStatus")getDbgLogger()->DebugCloseBlock( "processStatus"); // done processing status | |||||||
2862 | retryClientSessionStart(false); // no previously sent message in the buffer | |||||||
2863 | break; | |||||||
2864 | default: | |||||||
2865 | handled=false; // could not handle status | |||||||
2866 | } // switch | |||||||
2867 | donewithstatus: | |||||||
2868 | // Anyway, reception of status for header enables generation of next message header | |||||||
2869 | // (plus already generated commands such as status for response header) | |||||||
2870 | if (!fMsgNoResp && !isAborted()) { | |||||||
2871 | // issue header now if not already issued above | |||||||
2872 | if (!fOutgoingStarted) { | |||||||
2873 | // interrupt status processing block here as issueHeader will do a start-of-message PDEBUGBLOCK | |||||||
2874 | PDEBUGENDBLOCK("processStatus")getDbgLogger()->DebugCloseBlock( "processStatus"); | |||||||
2875 | issueHeader(false); | |||||||
2876 | PDEBUGBLOCKDESC("processStatus","finishing processing incoming SyncHdr Status")getDbgLogger()->DebugOpenBlock( "processStatus","finishing processing incoming SyncHdr Status" ); | |||||||
2877 | } | |||||||
2878 | } | |||||||
2879 | // return handled status | |||||||
2880 | return handled; | |||||||
2881 | #endif // SYSYNC_SERVER | |||||||
2882 | } | |||||||
2883 | else { | |||||||
2884 | // nothing special | |||||||
2885 | return inherited::handleHeaderStatus(aStatusCmdP); | |||||||
2886 | } | |||||||
2887 | } // TSyncAgent::handleHeaderStatus | |||||||
2888 | ||||||||
2889 | ||||||||
2890 | // - start sync group (called in client or server roles) | |||||||
2891 | bool TSyncAgent::processSyncStart( | |||||||
2892 | SmlSyncPtr_t aSyncP, // the Sync element | |||||||
2893 | TStatusCommand &aStatusCommand, // pre-set 200 status, can be modified in case of errors | |||||||
2894 | bool &aQueueForLater // will be set if command must be queued for later (re-)execution | |||||||
2895 | ) | |||||||
2896 | { | |||||||
2897 | if (IS_CLIENT(!getSyncAppBase()->isServer())) { | |||||||
2898 | #ifdef SYSYNC_CLIENT1 | |||||||
2899 | if (fIncomingState!=psta_sync && fIncomingState!=psta_initsync) { | |||||||
2900 | aStatusCommand.setStatusCode(403); // forbidden in this context | |||||||
2901 | PDEBUGPRINTFX(DBG_ERROR,("Sync command not allowed outside of sync phase (-> 403)")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Sync command not allowed outside of sync phase (-> 403)" ); }; | |||||||
2902 | AbortSession(400,true); | |||||||
2903 | return false; | |||||||
2904 | } | |||||||
2905 | // just find appropriate database, must be already initialized for sync! | |||||||
2906 | // determine local database to sync with (target) | |||||||
2907 | TLocalEngineDS *datastoreP = findLocalDataStoreByURI(smlSrcTargLocURIToCharP(aSyncP->target)); | |||||||
2908 | if (!datastoreP) { | |||||||
2909 | // no such local datastore | |||||||
2910 | PDEBUGPRINTFX(DBG_ERROR,("Sync command for unknown DS locURI '%s' (-> 404)",smlSrcTargLocURIToCharP(aSyncP->target))){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Sync command for unknown DS locURI '%s' (-> 404)" ,smlSrcTargLocURIToCharP(aSyncP->target)); }; | |||||||
2911 | aStatusCommand.setStatusCode(404); // not found | |||||||
2912 | return false; | |||||||
2913 | } | |||||||
2914 | else { | |||||||
2915 | // save the pointer, will e.g. be used to route subsequent server commands | |||||||
2916 | fLocalSyncDatastoreP=datastoreP; | |||||||
2917 | // let local datastore know | |||||||
2918 | return fLocalSyncDatastoreP->engProcessSyncCmd(aSyncP,aStatusCommand,aQueueForLater); | |||||||
2919 | } | |||||||
2920 | return true; | |||||||
2921 | #endif // SYSYNC_CLIENT | |||||||
2922 | } | |||||||
2923 | else { | |||||||
2924 | #ifdef SYSYNC_SERVER1 | |||||||
2925 | // Init datastores for sync | |||||||
2926 | localstatus sta = initSync( | |||||||
2927 | smlSrcTargLocURIToCharP(aSyncP->target), // local datastore | |||||||
2928 | smlSrcTargLocURIToCharP(aSyncP->source) // remote datastore | |||||||
2929 | ); | |||||||
2930 | if (sta!=LOCERR_OK) { | |||||||
2931 | aStatusCommand.setStatusCode(sta); | |||||||
2932 | return false; | |||||||
2933 | } | |||||||
2934 | // let local datastore prepare for sync as server | |||||||
2935 | // - let local process sync command | |||||||
2936 | bool ok=fLocalSyncDatastoreP->engProcessSyncCmd(aSyncP,aStatusCommand,aQueueForLater); | |||||||
2937 | // Note: ok means that the sync command is addressing existing datastores. However, | |||||||
2938 | // it does not mean that the actual processing is already executed; aQueueForLater | |||||||
2939 | // could be set! | |||||||
2940 | // if ok and not queued: update package states | |||||||
2941 | if (ok) { | |||||||
2942 | if (fIncomingState==psta_init || fIncomingState==psta_initsync) { | |||||||
2943 | // detected sync command in init package -> this is combined init/sync | |||||||
2944 | #ifdef SYDEBUG2 | |||||||
2945 | if (fIncomingState==psta_init) | |||||||
2946 | DEBUGPRINTFX(DBG_HOT,("<Sync> started init package -> switching to combined init/sync")){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("<Sync> started init package -> switching to combined init/sync" ); }; | |||||||
2947 | #endif | |||||||
2948 | // - set new incoming state | |||||||
2949 | fIncomingState=psta_initsync; | |||||||
2950 | // - also update outgoing state, if it is in init package | |||||||
2951 | if (fOutgoingState==psta_init) | |||||||
2952 | fOutgoingState=psta_initsync; | |||||||
2953 | } | |||||||
2954 | else if (fCmdIncomingState!=psta_sync) { | |||||||
2955 | DEBUGPRINTFX(DBG_ERROR,({ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "<Sync> found in wrong incoming package state '%s' -> aborting session" , PackageStateNames[fCmdIncomingState] ); } | |||||||
2956 | "<Sync> found in wrong incoming package state '%s' -> aborting session",{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "<Sync> found in wrong incoming package state '%s' -> aborting session" , PackageStateNames[fCmdIncomingState] ); } | |||||||
2957 | PackageStateNames[fCmdIncomingState]{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "<Sync> found in wrong incoming package state '%s' -> aborting session" , PackageStateNames[fCmdIncomingState] ); } | |||||||
2958 | )){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "<Sync> found in wrong incoming package state '%s' -> aborting session" , PackageStateNames[fCmdIncomingState] ); }; | |||||||
2959 | aStatusCommand.setStatusCode(403); // forbidden | |||||||
2960 | fLocalSyncDatastoreP->engAbortDataStoreSync(403,true); // abort, local problem | |||||||
2961 | ok=false; | |||||||
2962 | } | |||||||
2963 | else { | |||||||
2964 | // - show sync start | |||||||
2965 | DEBUGPRINTFX(DBG_HOT,({ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "<Sync> started, cmd-incoming state='%s', incoming state='%s', outgoing state='%s'" , PackageStateNames[fCmdIncomingState], PackageStateNames[fIncomingState ], PackageStateNames[fOutgoingState] ); } | |||||||
2966 | "<Sync> started, cmd-incoming state='%s', incoming state='%s', outgoing state='%s'",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "<Sync> started, cmd-incoming state='%s', incoming state='%s', outgoing state='%s'" , PackageStateNames[fCmdIncomingState], PackageStateNames[fIncomingState ], PackageStateNames[fOutgoingState] ); } | |||||||
2967 | PackageStateNames[fCmdIncomingState],{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "<Sync> started, cmd-incoming state='%s', incoming state='%s', outgoing state='%s'" , PackageStateNames[fCmdIncomingState], PackageStateNames[fIncomingState ], PackageStateNames[fOutgoingState] ); } | |||||||
2968 | PackageStateNames[fIncomingState],{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "<Sync> started, cmd-incoming state='%s', incoming state='%s', outgoing state='%s'" , PackageStateNames[fCmdIncomingState], PackageStateNames[fIncomingState ], PackageStateNames[fOutgoingState] ); } | |||||||
2969 | PackageStateNames[fOutgoingState]{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "<Sync> started, cmd-incoming state='%s', incoming state='%s', outgoing state='%s'" , PackageStateNames[fCmdIncomingState], PackageStateNames[fIncomingState ], PackageStateNames[fOutgoingState] ); } | |||||||
2970 | )){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "<Sync> started, cmd-incoming state='%s', incoming state='%s', outgoing state='%s'" , PackageStateNames[fCmdIncomingState], PackageStateNames[fIncomingState ], PackageStateNames[fOutgoingState] ); }; | |||||||
2971 | } | |||||||
2972 | } | |||||||
2973 | return ok; | |||||||
2974 | #endif // SYSYNC_SERVER | |||||||
2975 | } | |||||||
2976 | } // TSyncAgent::processSyncStart | |||||||
2977 | ||||||||
2978 | ||||||||
2979 | ||||||||
2980 | ||||||||
2981 | #ifdef ENGINEINTERFACE_SUPPORT1 | |||||||
2982 | ||||||||
2983 | // Support for EngineModule common interface | |||||||
2984 | // ========================================= | |||||||
2985 | ||||||||
2986 | ||||||||
2987 | /// @brief Get new session key to access details of this session | |||||||
2988 | appPointer TSyncAgent::newSessionKey(TEngineInterface *aEngineInterfaceP) | |||||||
2989 | { | |||||||
2990 | return new TAgentParamsKey(aEngineInterfaceP,this); | |||||||
2991 | } // TSyncAgent::newSessionKey | |||||||
2992 | ||||||||
2993 | ||||||||
2994 | #ifdef ENGINE_LIBRARY1 | |||||||
2995 | ||||||||
2996 | TSyError TSyncAgent::SessionStep(uInt16 &aStepCmd, TEngineProgressInfo *aInfoP) | |||||||
2997 | { | |||||||
2998 | #ifdef NON_FULLY_GRANULAR_ENGINE1 | |||||||
2999 | // pre-process step command and generate pseudo-steps to empty progress event queue | |||||||
3000 | // preprocess general step codes | |||||||
3001 | switch (aStepCmd) { | |||||||
3002 | case STEPCMD_TRANSPFAIL : | |||||||
3003 | // directly abort | |||||||
3004 | AbortSession(LOCERR_TRANSPFAIL,true); | |||||||
3005 | goto abort; | |||||||
3006 | case STEPCMD_ABORT : | |||||||
3007 | // directly abort | |||||||
3008 | AbortSession(LOCERR_USERABORT,true); | |||||||
3009 | abort: | |||||||
3010 | // also set the flag so subsequent progress events will result the abort status | |||||||
3011 | fAbortRequested=true; | |||||||
3012 | aStepCmd = STEPCMD_STEP; // convert to normal step | |||||||
3013 | goto step; | |||||||
3014 | case STEPCMD_SUSPEND : | |||||||
3015 | // directly suspend | |||||||
3016 | SuspendSession(LOCERR_USERSUSPEND); | |||||||
3017 | // also set the flag so subsequent pev_suspendcheck events will result the suspend status | |||||||
3018 | fSuspendRequested=true; | |||||||
3019 | aStepCmd = STEPCMD_OK; // this is a out-of-order step, and always just returns STEPCMD_OK. | |||||||
3020 | fEngineSessionStatus = 0; // ok for now, subsequent steps will perform the actual suspend | |||||||
3021 | goto done; // no more action for now | |||||||
3022 | case STEPCMD_STEP : | |||||||
3023 | step: | |||||||
3024 | // first just return all queued up progress events | |||||||
3025 | if (fProgressInfoList.size()>0) { | |||||||
3026 | // get first element in list | |||||||
3027 | TEngineProgressInfoList::iterator pos = fProgressInfoList.begin(); | |||||||
3028 | // pass it back to caller if caller is interested | |||||||
3029 | if (aInfoP) { | |||||||
3030 | *aInfoP = *pos; // copy progress event | |||||||
3031 | } | |||||||
3032 | // delete progress event from list | |||||||
3033 | fProgressInfoList.erase(pos); | |||||||
3034 | // that's it for now, engine state does not change, wait for next step | |||||||
3035 | aStepCmd = STEPCMD_PROGRESS; | |||||||
3036 | return LOCERR_OK; | |||||||
3037 | } | |||||||
3038 | else if (fPendingStepCmd != 0) { | |||||||
3039 | // now return previously generated step command | |||||||
3040 | // Note: engine is already in the new state matching fPendingStepCmd | |||||||
3041 | aStepCmd = fPendingStepCmd; | |||||||
3042 | fEngineSessionStatus = fPendingStatus; | |||||||
3043 | fPendingStepCmd=0; // none pending any more | |||||||
3044 | fPendingStatus=0; | |||||||
3045 | return fEngineSessionStatus; // return pending status now | |||||||
3046 | } | |||||||
3047 | // all progress events are delivered, now we can do the real work | |||||||
3048 | } | |||||||
3049 | #endif // NON_FULLY_GRANULAR_ENGINE | |||||||
3050 | // Now perform the actual step | |||||||
3051 | if (IS_CLIENT(!getSyncAppBase()->isServer())) { | |||||||
3052 | #ifdef SYSYNC_CLIENT1 | |||||||
3053 | fEngineSessionStatus = ClientSessionStep(aStepCmd,aInfoP); | |||||||
3054 | #endif // SYSYNC_CLIENT | |||||||
3055 | } | |||||||
3056 | else { | |||||||
3057 | #ifdef SYSYNC_SERVER1 | |||||||
3058 | fEngineSessionStatus = ServerSessionStep(aStepCmd,aInfoP); | |||||||
3059 | #endif // SYSYNC_SERVER | |||||||
3060 | } | |||||||
3061 | #ifdef NON_FULLY_GRANULAR_ENGINE1 | |||||||
3062 | // make sure caller issues STEPCMD_STEP to get all pending progress events | |||||||
3063 | if (fProgressInfoList.size()>0) { | |||||||
3064 | // save pending step command for returning later | |||||||
3065 | fPendingStepCmd = aStepCmd; | |||||||
3066 | fPendingStatus = fEngineSessionStatus; | |||||||
3067 | // return request for more steps instead | |||||||
3068 | aStepCmd = STEPCMD_OK; | |||||||
3069 | fEngineSessionStatus = LOCERR_OK; | |||||||
3070 | } | |||||||
3071 | #endif // NON_FULLY_GRANULAR_ENGINE | |||||||
3072 | done: | |||||||
3073 | // return step status | |||||||
3074 | return fEngineSessionStatus; | |||||||
3075 | } // TSyncAgent::SessionStep | |||||||
3076 | ||||||||
3077 | ||||||||
3078 | #ifdef PROGRESS_EVENTS1 | |||||||
3079 | ||||||||
3080 | bool TSyncAgent::HandleSessionProgressEvent(TEngineProgressInfo aProgressInfo) | |||||||
3081 | { | |||||||
3082 | // handle some events specially | |||||||
3083 | if (aProgressInfo.eventtype==pev_suspendcheck) | |||||||
3084 | return !(fSuspendRequested); | |||||||
3085 | else { | |||||||
3086 | // engine progress record that needs to be queued | |||||||
3087 | // - check for message | |||||||
3088 | if (aProgressInfo.eventtype==pev_display100) { | |||||||
3089 | // this is a pointer to a string, save it separately | |||||||
3090 | // extra1 is a pointer to the message text | |||||||
3091 | // - save it for retrieval via SessionKey | |||||||
3092 | fAlertMessage = (cAppCharP)(aProgressInfo.extra1); | |||||||
3093 | // - don't pass pointer | |||||||
3094 | aProgressInfo.extra1 = 0; | |||||||
3095 | } | |||||||
3096 | // queue progress event | |||||||
3097 | fProgressInfoList.push_back(aProgressInfo); | |||||||
3098 | } | |||||||
3099 | return !(fAbortRequested); | |||||||
3100 | } // TSyncAgent::HandleSessionProgressEvent | |||||||
3101 | ||||||||
3102 | #endif // PROGRESS_EVENTS | |||||||
3103 | ||||||||
3104 | #endif // ENGINE_LIBRARY | |||||||
3105 | ||||||||
3106 | ||||||||
3107 | #ifdef SYSYNC_SERVER1 | |||||||
3108 | ||||||||
3109 | // Server implementation | |||||||
3110 | // --------------------- | |||||||
3111 | ||||||||
3112 | #ifndef ENGINE_LIBRARY1 | |||||||
3113 | ||||||||
3114 | // dummy server engine support to allow AsKey from plugins | |||||||
3115 | ||||||||
3116 | #warning "using ENGINEINTERFACE_SUPPORT in old-style appbase-rooted environment. Should be converted to real engine usage later" | |||||||
3117 | ||||||||
3118 | // Engine factory function for non-Library case | |||||||
3119 | ENGINE_IF_CLASSTEngineModuleBase *newServerEngine(void) | |||||||
3120 | { | |||||||
3121 | // For real engine based targets, newServerEngine must create a target-specific derivate | |||||||
3122 | // of the server engine, which then has a suitable newSyncAppBase() method to create the | |||||||
3123 | // appBase. For old-style environment, a generic TServerEngineInterface is ok, as this | |||||||
3124 | // in turn calls the global newSyncAppBase() which then returns the appropriate | |||||||
3125 | // target specific appBase. Here we just return a dummy server engine base. | |||||||
3126 | return new TDummyServerEngineInterface; | |||||||
3127 | } // newServerEngine | |||||||
3128 | ||||||||
3129 | /// @brief returns a new application base. | |||||||
3130 | TSyncAppBase *TDummyServerEngineInterface::newSyncAppBase(void) | |||||||
3131 | { | |||||||
3132 | // For not really engine based targets, the appbase factory function is | |||||||
3133 | // a global routine (for real engine targets, it is a true virtual of | |||||||
3134 | // the engineInterface, implemented in the target's leaf engineInterface derivate. | |||||||
3135 | // - for now, use the global appBase creator routine | |||||||
3136 | return sysync::newSyncAppBase(); // use global factory function | |||||||
3137 | } // TDummyServerEngineInterface::newSyncAppBase | |||||||
3138 | ||||||||
3139 | #else // old style | |||||||
3140 | ||||||||
3141 | // Real server engine support | |||||||
3142 | ||||||||
3143 | /// @brief Executes next step of the session | |||||||
3144 | /// @param aStepCmd[in/out] step command (STEPCMD_xxx): | |||||||
3145 | /// - tells caller to send or receive data or end the session etc. | |||||||
3146 | /// - instructs engine to abort or time out the session etc. | |||||||
3147 | /// @param aInfoP[in] pointer to a TEngineProgressInfo structure, NULL if no progress info needed | |||||||
3148 | /// @return LOCERR_OK on success, SyncML or LOCERR_xxx error code on failure | |||||||
3149 | TSyError TSyncAgent::ServerSessionStep(uInt16 &aStepCmd, TEngineProgressInfo *aInfoP) | |||||||
3150 | { | |||||||
3151 | uInt16 stepCmdIn = aStepCmd; | |||||||
3152 | localstatus sta = LOCERR_WRONGUSAGE; | |||||||
3153 | ||||||||
3154 | // init default response | |||||||
3155 | aStepCmd = STEPCMD_ERROR; // error | |||||||
3156 | if (aInfoP) { | |||||||
3157 | aInfoP->eventtype=PEV_NOP; | |||||||
3158 | aInfoP->targetID=0; | |||||||
3159 | aInfoP->extra1=0; | |||||||
3160 | aInfoP->extra2=0; | |||||||
3161 | aInfoP->extra3=0; | |||||||
3162 | } | |||||||
3163 | ||||||||
3164 | // if session is already aborted, no more steps are required | |||||||
3165 | if (isAborted()) { | |||||||
3166 | fServerEngineState = ses_done; // we are done | |||||||
3167 | } | |||||||
3168 | ||||||||
3169 | // handle pre-processed step command according to current engine state | |||||||
3170 | switch (fServerEngineState) { | |||||||
3171 | ||||||||
3172 | // Almost done state | |||||||
3173 | case ses_almostdone: | |||||||
3174 | // everything done, except for termination of session | |||||||
3175 | // - do it now | |||||||
3176 | TerminateSession(); | |||||||
3177 | // - now done | |||||||
3178 | fServerEngineState = ses_done; | |||||||
3179 | // fall through to done state | |||||||
3180 | ||||||||
3181 | // Done state | |||||||
3182 | case ses_done : | |||||||
3183 | // session done, nothing happens any more | |||||||
3184 | aStepCmd = STEPCMD_DONE; | |||||||
3185 | sta = LOCERR_OK; | |||||||
3186 | break; | |||||||
3187 | ||||||||
3188 | // Waiting for SyncML request data | |||||||
3189 | case ses_needdata: | |||||||
3190 | switch (stepCmdIn) { | |||||||
3191 | case STEPCMD_GOTDATA : { | |||||||
3192 | // got data, check content type | |||||||
3193 | MemPtr_t data = NULL__null; | |||||||
3194 | smlPeekMessageBuffer(getSmlWorkspaceID(), false, &data, &fRequestSize); // get request size | |||||||
3195 | SmlEncoding_t enc = TSyncAppBase::encodingFromData(data, fRequestSize); | |||||||
3196 | if (getEncoding()==SML_UNDEF) { | |||||||
3197 | // no encoding known so far - use what we found from looking at data | |||||||
3198 | PDEBUGPRINTFX(DBG_ERROR,({ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Incoming data had no or invalid content type, Determined encoding by looking at data: %s" , SyncMLEncodingNames[enc] ); } | |||||||
3199 | "Incoming data had no or invalid content type, Determined encoding by looking at data: %s",{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Incoming data had no or invalid content type, Determined encoding by looking at data: %s" , SyncMLEncodingNames[enc] ); } | |||||||
3200 | SyncMLEncodingNames[enc]{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Incoming data had no or invalid content type, Determined encoding by looking at data: %s" , SyncMLEncodingNames[enc] ); } | |||||||
3201 | )){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Incoming data had no or invalid content type, Determined encoding by looking at data: %s" , SyncMLEncodingNames[enc] ); }; | |||||||
3202 | setEncoding(enc); | |||||||
3203 | } | |||||||
3204 | else if (getEncoding()!=enc) { | |||||||
3205 | // already known encoding does not match actual encoding | |||||||
3206 | PDEBUGPRINTFX(DBG_ERROR,({ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Warning: Incoming data encoding mismatch: expected=%s, found=%s" , SyncMLEncodingNames[getEncoding()], SyncMLEncodingNames[enc ] ); } | |||||||
3207 | "Warning: Incoming data encoding mismatch: expected=%s, found=%s",{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Warning: Incoming data encoding mismatch: expected=%s, found=%s" , SyncMLEncodingNames[getEncoding()], SyncMLEncodingNames[enc ] ); } | |||||||
3208 | SyncMLEncodingNames[getEncoding()],{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Warning: Incoming data encoding mismatch: expected=%s, found=%s" , SyncMLEncodingNames[getEncoding()], SyncMLEncodingNames[enc ] ); } | |||||||
3209 | SyncMLEncodingNames[enc]{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Warning: Incoming data encoding mismatch: expected=%s, found=%s" , SyncMLEncodingNames[getEncoding()], SyncMLEncodingNames[enc ] ); } | |||||||
3210 | )){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Warning: Incoming data encoding mismatch: expected=%s, found=%s" , SyncMLEncodingNames[getEncoding()], SyncMLEncodingNames[enc ] ); }; | |||||||
3211 | } | |||||||
3212 | if (getEncoding()==SML_UNDEF) { | |||||||
3213 | // if session encoding is still unknown at this point, reject data as non-SyncML | |||||||
3214 | PDEBUGPRINTFX(DBG_ERROR,("Incoming data is not SyncML")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Incoming data is not SyncML" ); }; | |||||||
3215 | sta = LOCERR_BADCONTENT; // bad content type | |||||||
3216 | aStepCmd = STEPCMD_ERROR; | |||||||
3217 | // Note: we do not abort the session here - app could have a retry strategy and re-enter | |||||||
3218 | // this step with better data | |||||||
3219 | break; | |||||||
3220 | } | |||||||
3221 | // content type ok - switch to processing mode | |||||||
3222 | fServerEngineState = ses_processing; | |||||||
3223 | aStepCmd = STEPCMD_OK; | |||||||
3224 | sta = LOCERR_OK; | |||||||
3225 | break; | |||||||
3226 | } | |||||||
3227 | } // switch stepCmdIn for ses_needdata | |||||||
3228 | break; | |||||||
3229 | ||||||||
3230 | // Waiting until SyncML answer data is sent | |||||||
3231 | // (only when session needs to continue, otherwise we are in ses_done) | |||||||
3232 | case ses_dataready: | |||||||
3233 | switch (stepCmdIn) { | |||||||
3234 | case STEPCMD_SENTDATA : | |||||||
3235 | // sent data, now wait for next request | |||||||
3236 | fServerEngineState = ses_needdata; | |||||||
3237 | aStepCmd = STEPCMD_NEEDDATA; | |||||||
3238 | sta = LOCERR_OK; | |||||||
3239 | break; | |||||||
3240 | } // switch stepCmdIn for ses_dataready | |||||||
3241 | break; | |||||||
3242 | ||||||||
3243 | ||||||||
3244 | // Ready for generation steps | |||||||
3245 | case ses_generating: | |||||||
3246 | switch (stepCmdIn) { | |||||||
3247 | case STEPCMD_STEP : | |||||||
3248 | sta = ServerGeneratingStep(aStepCmd,aInfoP); | |||||||
3249 | break; | |||||||
3250 | } // switch stepCmdIn for ses_generating | |||||||
3251 | break; | |||||||
3252 | ||||||||
3253 | // Ready for processing steps | |||||||
3254 | case ses_processing: | |||||||
3255 | switch (stepCmdIn) { | |||||||
3256 | case STEPCMD_STEP : | |||||||
3257 | sta = ServerProcessingStep(aStepCmd,aInfoP); | |||||||
3258 | break; | |||||||
3259 | } // switch stepCmdIn for ses_processing | |||||||
3260 | break; | |||||||
3261 | ||||||||
3262 | case numServerEngineStates: | |||||||
3263 | // invalid | |||||||
3264 | break; | |||||||
3265 | ||||||||
3266 | } // switch fServerEngineState | |||||||
3267 | ||||||||
3268 | // done | |||||||
3269 | return sta; | |||||||
3270 | } // TSyncAgent::ServerSessionStep | |||||||
3271 | ||||||||
3272 | ||||||||
3273 | ||||||||
3274 | ||||||||
3275 | // Step that processes SyncML request data | |||||||
3276 | TSyError TSyncAgent::ServerProcessingStep(uInt16 &aStepCmd, TEngineProgressInfo *aInfoP) | |||||||
3277 | { | |||||||
3278 | localstatus sta = LOCERR_WRONGUSAGE; | |||||||
3279 | InstanceID_t myInstance = getSmlWorkspaceID(); | |||||||
3280 | Ret_t rc; | |||||||
3281 | ||||||||
3282 | // now process next command | |||||||
3283 | PDEBUGPRINTFX(DBG_EXOTIC,("Calling smlProcessData(NEXT_COMMAND)")){ if (((0x80000000) & getDbgMask()) == (0x80000000)) getDbgLogger ()->setNextMask(0x80000000).DebugPrintfLastMask ("Calling smlProcessData(NEXT_COMMAND)" ); }; | |||||||
3284 | #ifdef SYDEBUG2 | |||||||
3285 | MemPtr_t data = NULL__null; | |||||||
3286 | MemSize_t datasize; | |||||||
3287 | smlPeekMessageBuffer(getSmlWorkspaceID(), false, &data, &datasize); | |||||||
3288 | #endif | |||||||
3289 | rc=smlProcessData( | |||||||
3290 | myInstance, | |||||||
3291 | SML_NEXT_COMMAND | |||||||
3292 | ); | |||||||
3293 | if (rc==SML_ERR_CONTINUE0x01) { | |||||||
3294 | // processed ok, but message not completely processed yet | |||||||
3295 | // - engine state remains as is | |||||||
3296 | aStepCmd = STEPCMD_OK; // ok w/o progress %%% for now, progress is delivered via queue in next step | |||||||
3297 | sta = LOCERR_OK; | |||||||
3298 | } | |||||||
3299 | else if (rc==SML_ERR_OK0x00) { | |||||||
3300 | // message completely processed | |||||||
3301 | // - switch engine state to generating answer message (if any) | |||||||
3302 | aStepCmd = STEPCMD_OK; | |||||||
3303 | fServerEngineState = ses_generating; | |||||||
3304 | sta = LOCERR_OK; | |||||||
3305 | } | |||||||
3306 | else if (rc==LOCERR_RETRYMSG) { | |||||||
3307 | // server has detected that this message is a retry - report this to the app such that app can | |||||||
3308 | // first discard the instance buffer (consume everything in it) | |||||||
3309 | if (smlLockReadBuffer(myInstance,&data,&datasize)==SML_ERR_OK0x00) | |||||||
3310 | smlUnlockReadBuffer(myInstance,datasize); | |||||||
3311 | // indicate that transport must resend the previous response | |||||||
3312 | PDEBUGPRINTFX(DBG_ERROR,({ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Incoming message was identified as a retry - report STEPCMD_RESENDDATA - caller must resent last response" ); } | |||||||
3313 | "Incoming message was identified as a retry - report STEPCMD_RESENDDATA - caller must resent last response"{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Incoming message was identified as a retry - report STEPCMD_RESENDDATA - caller must resent last response" ); } | |||||||
3314 | )){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Incoming message was identified as a retry - report STEPCMD_RESENDDATA - caller must resent last response" ); }; | |||||||
3315 | aStepCmd = STEPCMD_RESENDDATA; | |||||||
3316 | fServerEngineState = ses_dataready; | |||||||
3317 | } | |||||||
3318 | else { | |||||||
3319 | // processing failed | |||||||
3320 | PDEBUGPRINTFX(DBG_ERROR,("===> smlProcessData failed, returned 0x%hX",(sInt16)rc)){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("===> smlProcessData failed, returned 0x%hX" ,(sInt16)rc); }; | |||||||
3321 | // dump the message that failed to process | |||||||
3322 | #ifdef SYDEBUG2 | |||||||
3323 | if (data) DumpSyncMLBuffer(data,datasize,false,rc); | |||||||
3324 | #endif | |||||||
3325 | // abort the session (causing proper error events to be generated and reported back) | |||||||
3326 | AbortSession(LOCERR_PROCESSMSG, true); | |||||||
3327 | // session is now done | |||||||
3328 | fServerEngineState = ses_done; | |||||||
3329 | // step by itself is ok - let app continue stepping (to restart session or complete abort) | |||||||
3330 | aStepCmd = STEPCMD_OK; | |||||||
3331 | sta = LOCERR_OK; | |||||||
3332 | } | |||||||
3333 | // done | |||||||
3334 | return sta; | |||||||
3335 | } // TSyncAgent::ServerProcessingStep | |||||||
3336 | ||||||||
3337 | ||||||||
3338 | ||||||||
3339 | // Step that generates (rest of) SyncML answer data at end of request | |||||||
3340 | TSyError TSyncAgent::ServerGeneratingStep(uInt16 &aStepCmd, TEngineProgressInfo *aInfoP) | |||||||
3341 | { | |||||||
3342 | bool done, hasdata; | |||||||
3343 | string respURI; | |||||||
3344 | ||||||||
3345 | // finish request | |||||||
3346 | done = EndRequest(hasdata, respURI, fRequestSize); | |||||||
3347 | // check different exit points | |||||||
3348 | if (hasdata) { | |||||||
3349 | // there is data to be sent | |||||||
3350 | aStepCmd = STEPCMD_SENDDATA; | |||||||
3351 | fServerEngineState = ses_dataready; | |||||||
3352 | } | |||||||
3353 | else { | |||||||
3354 | // no more data to send | |||||||
3355 | aStepCmd = STEPCMD_OK; // need one more step to finish | |||||||
3356 | } | |||||||
3357 | // in any case, if done, subsequent steps will terminate the session and return STEPCMD_DONE | |||||||
3358 | if (done) { | |||||||
3359 | // subsequent steps will all return STEPCMD_DONE | |||||||
3360 | fServerEngineState = ses_almostdone; | |||||||
3361 | } | |||||||
3362 | // request reset | |||||||
3363 | fRequestSize = 0; | |||||||
3364 | ||||||||
3365 | // finished generating outgoing message | |||||||
3366 | // - make sure read pointer is set (advanced in case incoming | |||||||
3367 | // message had trailing garbage) to beginning of generated | |||||||
3368 | // answer. With incoming message being clean SyncML without | |||||||
3369 | // garbage, this call is not needed, however with garbage | |||||||
3370 | // it is important because otherwise outgoing message | |||||||
3371 | // would have that garbage inserted before actual message | |||||||
3372 | // start. | |||||||
3373 | smlReadOutgoingAgain(getSmlWorkspaceID()); | |||||||
3374 | ||||||||
3375 | // return status | |||||||
3376 | return LOCERR_OK; | |||||||
3377 | } // TSyncAgent::ServerGeneratingStep | |||||||
3378 | ||||||||
3379 | #endif // ENGINE_LIBRARY | |||||||
3380 | ||||||||
3381 | #endif // SYSYNC_SERVER | |||||||
3382 | ||||||||
3383 | ||||||||
3384 | #ifdef SYSYNC_CLIENT1 | |||||||
3385 | ||||||||
3386 | #ifdef ENGINE_LIBRARY1 | |||||||
3387 | ||||||||
3388 | // Client implementation | |||||||
3389 | // --------------------- | |||||||
3390 | ||||||||
3391 | /// @brief Executes next step of the session | |||||||
3392 | /// @param aStepCmd[in/out] step command (STEPCMD_xxx): | |||||||
3393 | /// - tells caller to send or receive data or end the session etc. | |||||||
3394 | /// - instructs engine to suspend or abort the session etc. | |||||||
3395 | /// @param aInfoP[in] pointer to a TEngineProgressInfo structure, NULL if no progress info needed | |||||||
3396 | /// @return LOCERR_OK on success, SyncML or LOCERR_xxx error code on failure | |||||||
3397 | TSyError TSyncAgent::ClientSessionStep(uInt16 &aStepCmd, TEngineProgressInfo *aInfoP) | |||||||
3398 | { | |||||||
3399 | uInt16 stepCmdIn = aStepCmd; | |||||||
3400 | localstatus sta = LOCERR_WRONGUSAGE; | |||||||
3401 | ||||||||
3402 | // init default response | |||||||
3403 | aStepCmd = STEPCMD_ERROR; // error | |||||||
3404 | if (aInfoP) { | |||||||
3405 | aInfoP->eventtype=PEV_NOP; | |||||||
3406 | aInfoP->targetID=0; | |||||||
3407 | aInfoP->extra1=0; | |||||||
3408 | aInfoP->extra2=0; | |||||||
3409 | aInfoP->extra3=0; | |||||||
3410 | } | |||||||
3411 | ||||||||
3412 | // if session is already aborted, no more steps are required | |||||||
3413 | if (isAborted()) { | |||||||
3414 | fClientEngineState = ces_done; // we are done | |||||||
3415 | } | |||||||
3416 | ||||||||
3417 | // handle pre-processed step command according to current engine state | |||||||
3418 | switch (fClientEngineState) { | |||||||
3419 | ||||||||
3420 | // Idle state | |||||||
3421 | case ces_done : { | |||||||
3422 | // session done, nothing happens any more | |||||||
3423 | aStepCmd = STEPCMD_DONE; | |||||||
3424 | sta = LOCERR_OK; | |||||||
3425 | break; | |||||||
3426 | } | |||||||
3427 | ||||||||
3428 | case ces_idle : { | |||||||
3429 | // in idle, we can only start a session | |||||||
3430 | switch (stepCmdIn) { | |||||||
3431 | case STEPCMD_CLIENTSTART: | |||||||
3432 | case STEPCMD_CLIENTAUTOSTART: | |||||||
3433 | // initialize a new session | |||||||
3434 | sta = InitializeSession(fProfileSelectorInternal,stepCmdIn==STEPCMD_CLIENTAUTOSTART); | |||||||
3435 | if (sta!=LOCERR_OK) break; | |||||||
3436 | // engine is now ready, start generating first request | |||||||
3437 | fClientEngineState = ces_generating; | |||||||
3438 | // ok with no status | |||||||
3439 | aStepCmd = STEPCMD_OK; | |||||||
3440 | break; | |||||||
3441 | } // switch stepCmdIn for ces_idle | |||||||
3442 | break; | |||||||
3443 | } | |||||||
3444 | ||||||||
3445 | // Ready for generation steps | |||||||
3446 | case ces_generating: { | |||||||
3447 | switch (stepCmdIn) { | |||||||
3448 | case STEPCMD_STEP : | |||||||
3449 | sta = ClientGeneratingStep(aStepCmd,aInfoP); | |||||||
3450 | break; | |||||||
3451 | } // switch stepCmdIn for ces_generating | |||||||
3452 | break; | |||||||
3453 | } | |||||||
3454 | ||||||||
3455 | // Ready for processing steps | |||||||
3456 | case ces_processing: { | |||||||
3457 | switch (stepCmdIn) { | |||||||
3458 | case STEPCMD_STEP : | |||||||
3459 | sta = ClientProcessingStep(aStepCmd,aInfoP); | |||||||
3460 | break; | |||||||
3461 | } // switch stepCmdIn for ces_processing | |||||||
3462 | break; | |||||||
3463 | } | |||||||
3464 | ||||||||
3465 | // Waiting for SyncML data | |||||||
3466 | case ces_needdata: { | |||||||
3467 | switch (stepCmdIn) { | |||||||
3468 | case STEPCMD_GOTDATA : { | |||||||
3469 | // got data, now start processing it | |||||||
3470 | SESSION_PROGRESS_EVENT(this,pev_recvend,NULL,0,0,0)this->NotifySessionProgressEvent(pev_recvend,__null,0,0,0); | |||||||
3471 | // check content type now | |||||||
3472 | MemPtr_t data = NULL__null; | |||||||
3473 | MemSize_t datasize; | |||||||
3474 | if (smlPeekMessageBuffer(getSmlWorkspaceID(), false, &data, &datasize) != SML_ERR_OK0x00) { | |||||||
3475 | // SyncML TK has a problem when asked to store an empty message: | |||||||
3476 | // it then returns SML_ERR_WRONG_USAGE in smlPeekMessageBuffer and | |||||||
3477 | // leaves datasize unset. Happened after an application bug. | |||||||
3478 | // | |||||||
3479 | // Avoid undefined behavior and proceed without data (easier than | |||||||
3480 | // introducing an additional, untested error path). | |||||||
3481 | data = NULL__null; | |||||||
3482 | datasize = 0; | |||||||
3483 | } | |||||||
3484 | ||||||||
3485 | // check content type | |||||||
3486 | SmlEncoding_t enc = TSyncAppBase::encodingFromData(data, datasize); | |||||||
3487 | if (enc!=getEncoding()) { | |||||||
3488 | PDEBUGPRINTFX(DBG_ERROR,("Incoming data is not SyncML")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Incoming data is not SyncML" ); }; | |||||||
3489 | sta = LOCERR_BADCONTENT; // bad content type | |||||||
3490 | #ifdef SYDEBUG2 | |||||||
3491 | if (data) DumpSyncMLBuffer(data,datasize,false,SML_ERR_UNSPECIFIC0x10); | |||||||
3492 | #endif | |||||||
3493 | // abort the session (causing proper error events to be generated and reported back) | |||||||
3494 | AbortSession(sta, true); | |||||||
3495 | // session is now done | |||||||
3496 | fClientEngineState = ces_done; | |||||||
3497 | aStepCmd = STEPCMD_ERROR; | |||||||
3498 | break; | |||||||
3499 | } | |||||||
3500 | // content type ok - switch to processing mode | |||||||
3501 | fIgnoreMsgErrs=false; // do not ignore errors by default | |||||||
3502 | fClientEngineState = ces_processing; | |||||||
3503 | aStepCmd = STEPCMD_OK; | |||||||
3504 | sta = LOCERR_OK; | |||||||
3505 | break; | |||||||
3506 | } | |||||||
3507 | case STEPCMD_RESENDDATA : | |||||||
3508 | // instead of having received new data, the network layer has found it needs to re-send the data. | |||||||
3509 | // performing the STEPCMD_RESENDDATA just generates a new send start event, but otherwise no engine action | |||||||
3510 | fClientEngineState = ces_resending; | |||||||
3511 | aStepCmd = STEPCMD_RESENDDATA; // return the same step command, to differentiate it from STEPCMD_SENDDATA | |||||||
3512 | SESSION_PROGRESS_EVENT(this,pev_sendstart,NULL,0,0,0)this->NotifySessionProgressEvent(pev_sendstart,__null,0,0, 0); | |||||||
3513 | sta = LOCERR_OK; | |||||||
3514 | break; | |||||||
3515 | } // switch stepCmdIn for ces_needdata | |||||||
3516 | break; | |||||||
3517 | } | |||||||
3518 | ||||||||
3519 | // Waiting until SyncML data is sent | |||||||
3520 | case ces_dataready: | |||||||
3521 | case ces_resending: { | |||||||
3522 | switch (stepCmdIn) { | |||||||
3523 | case STEPCMD_SENTDATA : | |||||||
3524 | // allowed in dataready or resending state | |||||||
3525 | // sent (or re-sent) data, now request answer data | |||||||
3526 | SESSION_PROGRESS_EVENT(this,pev_sendend,NULL,0,0,0)this->NotifySessionProgressEvent(pev_sendend,__null,0,0,0); | |||||||
3527 | fClientEngineState = ces_needdata; | |||||||
3528 | aStepCmd = STEPCMD_NEEDDATA; | |||||||
3529 | sta = LOCERR_OK; | |||||||
3530 | break; | |||||||
3531 | } // switch stepCmdIn for ces_dataready | |||||||
3532 | break; | |||||||
3533 | } | |||||||
3534 | ||||||||
3535 | case numClientEngineStates: { | |||||||
3536 | // invalid | |||||||
3537 | break; | |||||||
3538 | } | |||||||
3539 | ||||||||
3540 | } // switch fClientEngineState | |||||||
3541 | ||||||||
3542 | // done | |||||||
3543 | return sta; | |||||||
3544 | } // TSyncAgent::ClientSessionStep | |||||||
3545 | ||||||||
3546 | ||||||||
3547 | ||||||||
3548 | // Step that generates SyncML data | |||||||
3549 | TSyError TSyncAgent::ClientGeneratingStep(uInt16 &aStepCmd, TEngineProgressInfo *aInfoP) | |||||||
3550 | { | |||||||
3551 | localstatus sta = LOCERR_WRONGUSAGE; | |||||||
3552 | bool done; | |||||||
3553 | ||||||||
3554 | //%%% at this time, generate next message in one step | |||||||
3555 | sta = NextMessage(done); | |||||||
3556 | if (done) { | |||||||
3557 | // done with session, with or without error | |||||||
3558 | fClientEngineState = ces_done; // blocks any further activity with the session | |||||||
3559 | aStepCmd = STEPCMD_DONE; | |||||||
3560 | // terminate session to provoke all end-of-session progress events | |||||||
3561 | TerminateSession(); | |||||||
3562 | } | |||||||
3563 | else if (sta==LOCERR_OK) { | |||||||
3564 | // finished generating outgoing message | |||||||
3565 | // - make sure read pointer is set (advanced in case incoming | |||||||
3566 | // message had trailing garbage) to beginning of generated | |||||||
3567 | // answer. With incoming message being clean SyncML without | |||||||
3568 | // garbage, this call is not needed, however with garbage | |||||||
3569 | // it is important because otherwise outgoing message | |||||||
3570 | // would have that garbage inserted before actual message | |||||||
3571 | // start. | |||||||
3572 | smlReadOutgoingAgain(getSmlWorkspaceID()); | |||||||
3573 | // next is sending request to server | |||||||
3574 | fClientEngineState = ces_dataready; | |||||||
3575 | aStepCmd = STEPCMD_SENDDATA; | |||||||
3576 | SESSION_PROGRESS_EVENT(this,pev_sendstart,NULL,0,0,0)this->NotifySessionProgressEvent(pev_sendstart,__null,0,0, 0); | |||||||
3577 | } | |||||||
3578 | // return status | |||||||
3579 | return sta; | |||||||
3580 | } // TSyncAgent::ClientGeneratingStep | |||||||
3581 | ||||||||
3582 | ||||||||
3583 | ||||||||
3584 | // Step that processes SyncML data | |||||||
3585 | TSyError TSyncAgent::ClientProcessingStep(uInt16 &aStepCmd, TEngineProgressInfo *aInfoP) | |||||||
3586 | { | |||||||
3587 | InstanceID_t myInstance = getSmlWorkspaceID(); | |||||||
3588 | Ret_t rc; | |||||||
3589 | localstatus sta = LOCERR_WRONGUSAGE; | |||||||
3590 | ||||||||
3591 | // now process next command | |||||||
3592 | PDEBUGPRINTFX(DBG_EXOTIC,("Calling smlProcessData(NEXT_COMMAND)")){ if (((0x80000000) & getDbgMask()) == (0x80000000)) getDbgLogger ()->setNextMask(0x80000000).DebugPrintfLastMask ("Calling smlProcessData(NEXT_COMMAND)" ); }; | |||||||
3593 | #ifdef SYDEBUG2 | |||||||
3594 | MemPtr_t data = NULL__null; | |||||||
3595 | MemSize_t datasize; | |||||||
3596 | smlPeekMessageBuffer(getSmlWorkspaceID(), false, &data, &datasize); | |||||||
3597 | #endif | |||||||
3598 | rc=smlProcessData( | |||||||
3599 | myInstance, | |||||||
3600 | SML_NEXT_COMMAND | |||||||
3601 | ); | |||||||
3602 | if (rc==SML_ERR_CONTINUE0x01) { | |||||||
3603 | // processed ok, but message not completely processed yet | |||||||
3604 | // - engine state remains as is | |||||||
3605 | aStepCmd = STEPCMD_OK; // ok w/o progress %%% for now, progress is delivered via queue in next step | |||||||
3606 | sta = LOCERR_OK; | |||||||
3607 | } | |||||||
3608 | else if (rc==SML_ERR_OK0x00) { | |||||||
3609 | // message completely processed | |||||||
3610 | // - switch engine state to generating next message (if any) | |||||||
3611 | aStepCmd = STEPCMD_OK; | |||||||
3612 | fClientEngineState = ces_generating; | |||||||
3613 | sta = LOCERR_OK; | |||||||
3614 | } | |||||||
3615 | else { | |||||||
3616 | // processing failed | |||||||
3617 | PDEBUGPRINTFX(DBG_ERROR,("===> smlProcessData failed, returned 0x%hX",(sInt16)rc)){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("===> smlProcessData failed, returned 0x%hX" ,(sInt16)rc); }; | |||||||
3618 | // dump the message that failed to process | |||||||
3619 | #ifdef SYDEBUG2 | |||||||
3620 | if (data) DumpSyncMLBuffer(data,datasize,false,rc); | |||||||
3621 | #endif | |||||||
3622 | if (!fIgnoreMsgErrs) { | |||||||
3623 | // abort the session (causing proper error events to be generated and reported back) | |||||||
3624 | AbortSession(LOCERR_PROCESSMSG, true); | |||||||
3625 | // session is now done | |||||||
3626 | fClientEngineState = ces_done; | |||||||
3627 | } | |||||||
3628 | else { | |||||||
3629 | // we must ignore errors e.g. because of session restart and go back to generate next message | |||||||
3630 | fClientEngineState = ces_generating; | |||||||
3631 | } | |||||||
3632 | // anyway, step by itself is ok - let app continue stepping (to restart session or complete abort) | |||||||
3633 | aStepCmd = STEPCMD_OK; | |||||||
3634 | sta = LOCERR_OK; | |||||||
3635 | } | |||||||
3636 | // now check if this is a session restart | |||||||
3637 | if (sta==LOCERR_OK && isStarting()) { | |||||||
3638 | // this is still the beginning of a session, which means | |||||||
3639 | // that we are restarting the session and caller should close | |||||||
3640 | // possibly open communication with the server before sending the next message | |||||||
3641 | aStepCmd = STEPCMD_RESTART; | |||||||
3642 | } | |||||||
3643 | // done | |||||||
3644 | return sta; | |||||||
3645 | } // TSyncAgent::ClientProcessingStep | |||||||
3646 | ||||||||
3647 | #endif // ENGINE_LIBRARY | |||||||
3648 | ||||||||
3649 | #endif // SYSYNC_CLIENT | |||||||
3650 | ||||||||
3651 | ||||||||
3652 | ||||||||
3653 | // Session runtime settings key | |||||||
3654 | // --------------------------- | |||||||
3655 | ||||||||
3656 | // Constructor | |||||||
3657 | TAgentParamsKey::TAgentParamsKey(TEngineInterface *aEngineInterfaceP, TSyncAgent *aAgentP) : | |||||||
3658 | inherited(aEngineInterfaceP,aAgentP), | |||||||
3659 | fAgentP(aAgentP) | |||||||
3660 | { | |||||||
3661 | } // TAgentParamsKey::TAgentParamsKey | |||||||
3662 | ||||||||
3663 | ||||||||
3664 | ||||||||
3665 | // - read local session ID | |||||||
3666 | static TSyError readLocalSessionID( | |||||||
3667 | TStructFieldsKey *aStructFieldsKeyP, const TStructFieldInfo *aFldInfoP, | |||||||
3668 | appPointer aBuffer, memSize aBufSize, memSize &aValSize | |||||||
3669 | ) | |||||||
3670 | { | |||||||
3671 | TAgentParamsKey *mykeyP = static_cast<TAgentParamsKey *>(aStructFieldsKeyP); | |||||||
3672 | return TStructFieldsKey::returnString( | |||||||
3673 | mykeyP->fAgentP->getLocalSessionID(), | |||||||
3674 | aBuffer,aBufSize,aValSize | |||||||
3675 | ); | |||||||
3676 | } // readLocalSessionID | |||||||
3677 | ||||||||
3678 | ||||||||
3679 | // - read initial local URI | |||||||
3680 | static TSyError readInitialLocalURI( | |||||||
3681 | TStructFieldsKey *aStructFieldsKeyP, const TStructFieldInfo *aFldInfoP, | |||||||
3682 | appPointer aBuffer, memSize aBufSize, memSize &aValSize | |||||||
3683 | ) | |||||||
3684 | { | |||||||
3685 | TAgentParamsKey *mykeyP = static_cast<TAgentParamsKey *>(aStructFieldsKeyP); | |||||||
3686 | return TStructFieldsKey::returnString( | |||||||
3687 | mykeyP->fAgentP->getInitialLocalURI(), | |||||||
3688 | aBuffer,aBufSize,aValSize | |||||||
3689 | ); | |||||||
3690 | } // readInitialLocalURI | |||||||
3691 | ||||||||
3692 | ||||||||
3693 | // - read abort status | |||||||
3694 | static TSyError readAbortStatus( | |||||||
3695 | TStructFieldsKey *aStructFieldsKeyP, const TStructFieldInfo *aFldInfoP, | |||||||
3696 | appPointer aBuffer, memSize aBufSize, memSize &aValSize | |||||||
3697 | ) | |||||||
3698 | { | |||||||
3699 | TAgentParamsKey *mykeyP = static_cast<TAgentParamsKey *>(aStructFieldsKeyP); | |||||||
3700 | return TStructFieldsKey::returnInt( | |||||||
3701 | mykeyP->fAgentP->getAbortReasonStatus(), | |||||||
3702 | sizeof(TSyError), | |||||||
3703 | aBuffer,aBufSize,aValSize | |||||||
3704 | ); | |||||||
3705 | } // readAbortStatus | |||||||
3706 | ||||||||
3707 | ||||||||
3708 | ||||||||
3709 | // - write abort status, which means aborting a session | |||||||
3710 | TSyError writeAbortStatus( | |||||||
3711 | TStructFieldsKey *aStructFieldsKeyP, const TStructFieldInfo *aFldInfoP, | |||||||
3712 | cAppPointer aBuffer, memSize aValSize | |||||||
3713 | ) | |||||||
3714 | { | |||||||
3715 | TAgentParamsKey *mykeyP = static_cast<TAgentParamsKey *>(aStructFieldsKeyP); | |||||||
3716 | // abort the session | |||||||
3717 | TSyError sta = *((TSyError *)aBuffer); | |||||||
3718 | mykeyP->fAgentP->AbortSession(sta, true); | |||||||
3719 | return LOCERR_OK; | |||||||
3720 | } // writeAbortStatus | |||||||
3721 | ||||||||
3722 | ||||||||
3723 | ||||||||
3724 | // - read content type string | |||||||
3725 | static TSyError readContentType( | |||||||
3726 | TStructFieldsKey *aStructFieldsKeyP, const TStructFieldInfo *aFldInfoP, | |||||||
3727 | appPointer aBuffer, memSize aBufSize, memSize &aValSize | |||||||
3728 | ) | |||||||
3729 | { | |||||||
3730 | TAgentParamsKey *mykeyP = static_cast<TAgentParamsKey *>(aStructFieldsKeyP); | |||||||
3731 | string contentType = SYNCML_MIME_TYPE"application/vnd.syncml"; | |||||||
3732 | mykeyP->fAgentP->addEncoding(contentType); | |||||||
3733 | return TStructFieldsKey::returnString( | |||||||
3734 | contentType.c_str(), | |||||||
3735 | aBuffer,aBufSize,aValSize | |||||||
3736 | ); | |||||||
3737 | } // readContentType | |||||||
3738 | ||||||||
3739 | ||||||||
3740 | // - write content type string | |||||||
3741 | static TSyError writeContentType( | |||||||
3742 | TStructFieldsKey *aStructFieldsKeyP, const TStructFieldInfo *aFldInfoP, | |||||||
3743 | cAppPointer aBuffer, memSize aValSize | |||||||
3744 | ) | |||||||
3745 | { | |||||||
3746 | string contentType((cAppCharP)aBuffer,aValSize); | |||||||
3747 | TAgentParamsKey *mykeyP = static_cast<TAgentParamsKey *>(aStructFieldsKeyP); | |||||||
3748 | mykeyP->fAgentP->setEncoding(TSyncAppBase::encodingFromContentType(contentType.c_str())); | |||||||
3749 | return LOCERR_OK; | |||||||
3750 | } // writeContentType | |||||||
3751 | ||||||||
3752 | ||||||||
3753 | // - read connection URL | |||||||
3754 | static TSyError readConnectURI( | |||||||
3755 | TStructFieldsKey *aStructFieldsKeyP, const TStructFieldInfo *aFldInfoP, | |||||||
3756 | appPointer aBuffer, memSize aBufSize, memSize &aValSize | |||||||
3757 | ) | |||||||
3758 | { | |||||||
3759 | TAgentParamsKey *mykeyP = static_cast<TAgentParamsKey *>(aStructFieldsKeyP); | |||||||
3760 | return TStructFieldsKey::returnString( | |||||||
3761 | mykeyP->fAgentP->getSendURI(), | |||||||
3762 | aBuffer,aBufSize,aValSize | |||||||
3763 | ); | |||||||
3764 | } // readConnectURI | |||||||
3765 | ||||||||
3766 | ||||||||
3767 | // - read host part of connection URL | |||||||
3768 | static TSyError readConnectHost( | |||||||
3769 | TStructFieldsKey *aStructFieldsKeyP, const TStructFieldInfo *aFldInfoP, | |||||||
3770 | appPointer aBuffer, memSize aBufSize, memSize &aValSize | |||||||
3771 | ) | |||||||
3772 | { | |||||||
3773 | TAgentParamsKey *mykeyP = static_cast<TAgentParamsKey *>(aStructFieldsKeyP); | |||||||
3774 | string host, port; | |||||||
3775 | splitURL(mykeyP->fAgentP->getSendURI(),NULL__null,&host,NULL__null,NULL__null,NULL__null,&port,NULL__null); | |||||||
3776 | // old semantic of splitURL was to include port in host string, | |||||||
3777 | // continue doing that | |||||||
3778 | if (!port.empty()) { | |||||||
3779 | host += ':'; | |||||||
3780 | host += port; | |||||||
3781 | } | |||||||
3782 | return TStructFieldsKey::returnString( | |||||||
3783 | host.c_str(), | |||||||
3784 | aBuffer,aBufSize,aValSize | |||||||
3785 | ); | |||||||
3786 | } // readConnectHost | |||||||
3787 | ||||||||
3788 | ||||||||
3789 | // - read document part of connection URL | |||||||
3790 | static TSyError readConnectDoc( | |||||||
3791 | TStructFieldsKey *aStructFieldsKeyP, const TStructFieldInfo *aFldInfoP, | |||||||
3792 | appPointer aBuffer, memSize aBufSize, memSize &aValSize | |||||||
3793 | ) | |||||||
3794 | { | |||||||
3795 | TAgentParamsKey *mykeyP = static_cast<TAgentParamsKey *>(aStructFieldsKeyP); | |||||||
3796 | string doc, query; | |||||||
3797 | splitURL(mykeyP->fAgentP->getSendURI(),NULL__null,NULL__null,&doc,NULL__null,NULL__null,NULL__null,&query); | |||||||
3798 | // old semantic of splitURL was to include query in document string, | |||||||
3799 | // continue doing that | |||||||
3800 | if (!query.empty()) { | |||||||
3801 | doc += '?'; | |||||||
3802 | doc += query; | |||||||
3803 | } | |||||||
3804 | return TStructFieldsKey::returnString( | |||||||
3805 | doc.c_str(), | |||||||
3806 | aBuffer,aBufSize,aValSize | |||||||
3807 | ); | |||||||
3808 | } // readConnectDoc | |||||||
3809 | ||||||||
3810 | ||||||||
3811 | // - time when session was last used | |||||||
3812 | static TSyError readLastUsed( | |||||||
3813 | TStructFieldsKey *aStructFieldsKeyP, const TStructFieldInfo *aFldInfoP, | |||||||
3814 | appPointer aBuffer, memSize aBufSize, memSize &aValSize | |||||||
3815 | ) | |||||||
3816 | { | |||||||
3817 | TAgentParamsKey *mykeyP = static_cast<TAgentParamsKey *>(aStructFieldsKeyP); | |||||||
3818 | // return it | |||||||
3819 | return TStructFieldsKey::returnLineartime(mykeyP->fAgentP->getSessionLastUsed(), aBuffer, aBufSize, aValSize); | |||||||
3820 | } // readLastUsed | |||||||
3821 | ||||||||
3822 | ||||||||
3823 | // - server only: check session timeout | |||||||
3824 | static TSyError readTimedOut( | |||||||
3825 | TStructFieldsKey *aStructFieldsKeyP, const TStructFieldInfo *aFldInfoP, | |||||||
3826 | appPointer aBuffer, memSize aBufSize, memSize &aValSize | |||||||
3827 | ) | |||||||
3828 | { | |||||||
3829 | TAgentParamsKey *mykeyP = static_cast<TAgentParamsKey *>(aStructFieldsKeyP); | |||||||
3830 | // check if session has timed out | |||||||
3831 | bool timedout = mykeyP->fAgentP->getSessionLastUsed()+mykeyP->fAgentP->getSessionConfig()->getSessionTimeout() < mykeyP->fAgentP->getSystemNowAs(TCTX_UTC((timecontext_t) ((tctx_tz_UTC) | TCTX_SYMBOLIC_TZ))); | |||||||
3832 | // return it | |||||||
3833 | return TStructFieldsKey::returnInt(timedout, sizeof(bool), aBuffer, aBufSize, aValSize); | |||||||
3834 | } // readTimedOut | |||||||
3835 | ||||||||
3836 | ||||||||
3837 | // - show if this is a server (for DB plugins) | |||||||
3838 | static TSyError readIsServer( | |||||||
3839 | TStructFieldsKey *aStructFieldsKeyP, const TStructFieldInfo *aFldInfoP, | |||||||
3840 | appPointer aBuffer, memSize aBufSize, memSize &aValSize | |||||||
3841 | ) | |||||||
3842 | { | |||||||
3843 | TAgentParamsKey *mykeyP = static_cast<TAgentParamsKey *>(aStructFieldsKeyP); | |||||||
3844 | return TStructFieldsKey::returnInt(mykeyP->fAgentP->getSyncAppBase()->isServer(), sizeof(bool), aBuffer, aBufSize, aValSize); | |||||||
3845 | } // readIsServer | |||||||
3846 | ||||||||
3847 | ||||||||
3848 | #ifdef SYSYNC_SERVER1 | |||||||
3849 | ||||||||
3850 | // - server only: read respURI enable flag | |||||||
3851 | static TSyError readSendRespURI( | |||||||
3852 | TStructFieldsKey *aStructFieldsKeyP, const TStructFieldInfo *aFldInfoP, | |||||||
3853 | appPointer aBuffer, memSize aBufSize, memSize &aValSize | |||||||
3854 | ) | |||||||
3855 | { | |||||||
3856 | TAgentParamsKey *mykeyP = static_cast<TAgentParamsKey *>(aStructFieldsKeyP); | |||||||
3857 | return TStructFieldsKey::returnInt(mykeyP->fAgentP->fUseRespURI, sizeof(bool), aBuffer, aBufSize, aValSize); | |||||||
3858 | } // readSendRespURI | |||||||
3859 | ||||||||
3860 | ||||||||
3861 | // - write respURI enable flag | |||||||
3862 | static TSyError writeSendRespURI( | |||||||
3863 | TStructFieldsKey *aStructFieldsKeyP, const TStructFieldInfo *aFldInfoP, | |||||||
3864 | cAppPointer aBuffer, memSize aValSize | |||||||
3865 | ) | |||||||
3866 | { | |||||||
3867 | TAgentParamsKey *mykeyP = static_cast<TAgentParamsKey *>(aStructFieldsKeyP); | |||||||
3868 | mykeyP->fAgentP->fUseRespURI = *((uInt8P)aBuffer); | |||||||
3869 | return LOCERR_OK; | |||||||
3870 | } // writeSendRespURI | |||||||
3871 | ||||||||
3872 | ||||||||
3873 | #endif // SYSYNC_SERVER | |||||||
3874 | ||||||||
3875 | ||||||||
3876 | #ifdef SYSYNC_CLIENT1 | |||||||
3877 | ||||||||
3878 | // - write (volatile, write-only) password for running this session | |||||||
3879 | // (for cases where we don't want to rely on binfile storage for sensitive password data) | |||||||
3880 | TSyError writeSessionPassword( | |||||||
3881 | TStructFieldsKey *aStructFieldsKeyP, const TStructFieldInfo *aFldInfoP, | |||||||
3882 | cAppPointer aBuffer, memSize aValSize | |||||||
3883 | ) | |||||||
3884 | { | |||||||
3885 | TAgentParamsKey *mykeyP = static_cast<TAgentParamsKey *>(aStructFieldsKeyP); | |||||||
3886 | mykeyP->fAgentP->setServerPassword((cAppCharP)aBuffer, aValSize); | |||||||
3887 | return LOCERR_OK; | |||||||
3888 | } // writeSessionPassword | |||||||
3889 | ||||||||
3890 | ||||||||
3891 | #ifdef ENGINE_LIBRARY1 | |||||||
3892 | // - read display alert | |||||||
3893 | static TSyError readDisplayAlert( | |||||||
3894 | TStructFieldsKey *aStructFieldsKeyP, const TStructFieldInfo *aFldInfoP, | |||||||
3895 | appPointer aBuffer, memSize aBufSize, memSize &aValSize | |||||||
3896 | ) | |||||||
3897 | { | |||||||
3898 | TAgentParamsKey *mykeyP = static_cast<TAgentParamsKey *>(aStructFieldsKeyP); | |||||||
3899 | return TStructFieldsKey::returnString( | |||||||
3900 | mykeyP->fAgentP->fAlertMessage.c_str(), | |||||||
3901 | aBuffer,aBufSize,aValSize | |||||||
3902 | ); | |||||||
3903 | } // readDisplayAlert | |||||||
3904 | #endif | |||||||
3905 | ||||||||
3906 | #endif // SYSYNC_CLIENT | |||||||
3907 | ||||||||
3908 | static TSyError readRestartSync( | |||||||
3909 | TStructFieldsKey *aStructFieldsKeyP, const TStructFieldInfo *aFldInfoP, | |||||||
3910 | appPointer aBuffer, memSize aBufSize, memSize &aValSize | |||||||
3911 | ) | |||||||
3912 | { | |||||||
3913 | TAgentParamsKey *mykeyP = static_cast<TAgentParamsKey *>(aStructFieldsKeyP); | |||||||
3914 | return TStructFieldsKey::returnInt(mykeyP->fAgentP->fRestartSyncOnce, sizeof(bool), aBuffer, aBufSize, aValSize); | |||||||
3915 | } // readRestartsync | |||||||
3916 | ||||||||
3917 | ||||||||
3918 | // - write respURI enable flag | |||||||
3919 | static TSyError writeRestartSync( | |||||||
3920 | TStructFieldsKey *aStructFieldsKeyP, const TStructFieldInfo *aFldInfoP, | |||||||
3921 | cAppPointer aBuffer, memSize aValSize | |||||||
3922 | ) | |||||||
3923 | { | |||||||
3924 | TAgentParamsKey *mykeyP = static_cast<TAgentParamsKey *>(aStructFieldsKeyP); | |||||||
3925 | mykeyP->fAgentP->fRestartSyncOnce = *((uInt8P)aBuffer); | |||||||
3926 | return LOCERR_OK; | |||||||
3927 | } // writeRestartSync | |||||||
3928 | ||||||||
3929 | ||||||||
3930 | // - write error message into session log | |||||||
3931 | TSyError writeErrorMsg( | |||||||
3932 | TStructFieldsKey *aStructFieldsKeyP, const TStructFieldInfo *aFldInfoP, | |||||||
3933 | cAppPointer aBuffer, memSize aValSize | |||||||
3934 | ) | |||||||
3935 | { | |||||||
3936 | TAgentParamsKey *mykeyP = static_cast<TAgentParamsKey *>(aStructFieldsKeyP); | |||||||
3937 | string msg; | |||||||
3938 | msg.assign((cAppCharP)aBuffer, aValSize); | |||||||
3939 | POBJDEBUGPRINTFX(mykeyP->fAgentP,DBG_ERROR,("external Error: %s",msg.c_str())){ if ((mykeyP->fAgentP) && (((0x00000002) & (mykeyP ->fAgentP)->getDbgMask()) == (0x00000002))) (mykeyP-> fAgentP)->getDbgLogger()->setNextMask(0x00000002).DebugPrintfLastMask ("external Error: %s",msg.c_str()); }; | |||||||
3940 | return LOCERR_OK; | |||||||
3941 | } // writeErrorMsg | |||||||
3942 | ||||||||
3943 | ||||||||
3944 | // - write debug message into session log | |||||||
3945 | TSyError writeDebugMsg( | |||||||
3946 | TStructFieldsKey *aStructFieldsKeyP, const TStructFieldInfo *aFldInfoP, | |||||||
3947 | cAppPointer aBuffer, memSize aValSize | |||||||
3948 | ) | |||||||
3949 | { | |||||||
3950 | TAgentParamsKey *mykeyP = static_cast<TAgentParamsKey *>(aStructFieldsKeyP); | |||||||
3951 | string msg; | |||||||
3952 | msg.assign((cAppCharP)aBuffer, aValSize); | |||||||
3953 | POBJDEBUGPRINTFX(mykeyP->fAgentP,DBG_HOT,("external Message: %s",msg.c_str())){ if ((mykeyP->fAgentP) && (((0x00000001) & (mykeyP ->fAgentP)->getDbgMask()) == (0x00000001))) (mykeyP-> fAgentP)->getDbgLogger()->setNextMask(0x00000001).DebugPrintfLastMask ("external Message: %s",msg.c_str()); }; | |||||||
3954 | return LOCERR_OK; | |||||||
3955 | } // writeDebugMsg | |||||||
3956 | ||||||||
3957 | ||||||||
3958 | ||||||||
3959 | ||||||||
3960 | // accessor table for session key | |||||||
3961 | static const TStructFieldInfo ServerParamFieldInfos[] = | |||||||
3962 | { | |||||||
3963 | // valName, valType, writable, fieldOffs, valSiz | |||||||
3964 | { "localSessionID", VALTYPE_TEXT, false, 0, 0, &readLocalSessionID, NULL__null }, | |||||||
3965 | { "initialLocalURI", VALTYPE_TEXT, false, 0, 0, &readInitialLocalURI, NULL__null }, | |||||||
3966 | { "abortStatus", VALTYPE_INT16, true, 0, 0, &readAbortStatus, &writeAbortStatus }, | |||||||
3967 | { "contenttype", VALTYPE_TEXT, true, 0, 0, &readContentType, &writeContentType }, | |||||||
3968 | { "connectURI", VALTYPE_TEXT, false, 0, 0, &readConnectURI, NULL__null }, | |||||||
3969 | { "connectHost", VALTYPE_TEXT, false, 0, 0, &readConnectHost, NULL__null }, | |||||||
3970 | { "connectDoc", VALTYPE_TEXT, false, 0, 0, &readConnectDoc, NULL__null }, | |||||||
3971 | { "timedout", VALTYPE_INT8, false, 0, 0, &readTimedOut, NULL__null }, | |||||||
3972 | { "lastused", VALTYPE_TIME64, false, 0, 0, &readLastUsed, NULL__null }, | |||||||
3973 | { "isserver", VALTYPE_INT8, false, 0, 0, &readIsServer, NULL__null }, | |||||||
3974 | #ifdef SYSYNC_SERVER1 | |||||||
3975 | { "sendrespuri", VALTYPE_INT8, true, 0, 0, &readSendRespURI, &writeSendRespURI }, | |||||||
3976 | #endif | |||||||
3977 | #ifdef SYSYNC_CLIENT1 | |||||||
3978 | { "sessionPassword", VALTYPE_TEXT, true, 0, 0, NULL__null, &writeSessionPassword }, | |||||||
3979 | #ifdef ENGINE_LIBRARY1 | |||||||
3980 | { "displayalert", VALTYPE_TEXT, false, 0, 0, &readDisplayAlert, NULL__null }, | |||||||
3981 | #endif | |||||||
3982 | #endif | |||||||
3983 | { "restartsync", VALTYPE_INT8, true, 0, 0, &readRestartSync, &writeRestartSync }, | |||||||
3984 | // write into debug log | |||||||
3985 | { "errorMsg", VALTYPE_TEXT, true, 0, 0, NULL__null, &writeErrorMsg }, | |||||||
3986 | { "debugMsg", VALTYPE_TEXT, true, 0, 0, NULL__null, &writeDebugMsg }, | |||||||
3987 | }; | |||||||
3988 | ||||||||
3989 | // get table describing the fields in the struct | |||||||
3990 | const TStructFieldInfo *TAgentParamsKey::getFieldsTable(void) | |||||||
3991 | { | |||||||
3992 | return ServerParamFieldInfos; | |||||||
3993 | } // TAgentParamsKey::getFieldsTable | |||||||
3994 | ||||||||
3995 | sInt32 TAgentParamsKey::numFields(void) | |||||||
3996 | { | |||||||
3997 | return sizeof(ServerParamFieldInfos)/sizeof(TStructFieldInfo); | |||||||
3998 | } // TAgentParamsKey::numFields | |||||||
3999 | ||||||||
4000 | // get actual struct base address | |||||||
4001 | uInt8P TAgentParamsKey::getStructAddr(void) | |||||||
4002 | { | |||||||
4003 | // prepared for accessing fields in server session object | |||||||
4004 | return (uInt8P)fAgentP; | |||||||
4005 | } // TAgentParamsKey::getStructAddr | |||||||
4006 | ||||||||
4007 | ||||||||
4008 | // open subkey by name (not by path!) | |||||||
4009 | TSyError TAgentParamsKey::OpenSubKeyByName( | |||||||
4010 | TSettingsKeyImpl *&aSettingsKeyP, | |||||||
4011 | cAppCharP aName, stringSize aNameSize, | |||||||
4012 | uInt16 aMode | |||||||
4013 | ) { | |||||||
4014 | #ifdef DBAPI_TUNNEL_SUPPORT | |||||||
4015 | if (strucmp(aName,"tunnel",aNameSize)==0) { | |||||||
4016 | // get tunnel datastore pointer | |||||||
4017 | TLocalEngineDS *ds = fAgentP->getTunnelDS(); | |||||||
4018 | if (!ds) return LOCERR_WRONGUSAGE; | |||||||
4019 | // opens current session's tunnel key | |||||||
4020 | aSettingsKeyP = ds->newTunnelKey(fEngineInterfaceP); | |||||||
4021 | } | |||||||
4022 | else | |||||||
4023 | #endif | |||||||
4024 | return inherited::OpenSubKeyByName(aSettingsKeyP,aName,aNameSize,aMode); | |||||||
4025 | // opened a key | |||||||
4026 | return LOCERR_OK; | |||||||
4027 | } // TAgentParamsKey::OpenSubKeyByName | |||||||
4028 | ||||||||
4029 | ||||||||
4030 | #endif // ENGINEINTERFACE_SUPPORT | |||||||
4031 | ||||||||
4032 | } // namespace sysync | |||||||
4033 | ||||||||
4034 | // eof |