File: | libsynthesis/src/sysync/syncagent.cpp |
Warning: | line 2716, column 7 Value stored to 'aTryAgain' is never read |
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 |
Value stored to 'aTryAgain' is never read | |
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 |