Bug Summary

File:libsynthesis/src/sysync/syncagent.cpp
Warning:line 2716, column 7
Value stored to 'aTryAgain' is never read

Annotated Source Code

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
40namespace sysync {
41
42
43#ifdef SYSYNC_TOOL
44
45// Support for SySync Diagnostic Tool
46// ==================================
47
48
49// test login into database
50int 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
107int 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
276TSyncReqConfig::TSyncReqConfig(TLocalDSConfig *aLocalDSCfg, TConfigElement *aParentElement) :
277 TConfigElement("syncrequest",aParentElement),
278 fLocalDSConfig(aLocalDSCfg)
279{
280 clear();
281} // TSyncReqConfig::TSyncReqConfig
282
283
284TSyncReqConfig::~TSyncReqConfig()
285{
286 // nop so far
287} // TSyncReqConfig::~TSyncReqConfig
288
289
290// init defaults
291void 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
313bool 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
342void 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
354TLocalEngineDS *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
379TAgentConfig::TAgentConfig(const char* aName, TConfigElement *aParentElement) :
380 inherited(aName,aParentElement)
381{
382 clear();
383} // TAgentConfig::TAgentConfig
384
385
386TAgentConfig::~TAgentConfig()
387{
388 clear();
389} // TAgentConfig::~TAgentConfig
390
391
392// init defaults
393void 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
464bool 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
585void 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
616TSyncAgent::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
690TSyncAgent::~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
722void 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
739void 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
777void 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
786bool 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
800void 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
817string 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
831string 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
839bool 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
866localstatus 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
896localstatus 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
944localstatus 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
960localstatus 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
996bool 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
1077localstatus 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
1520bool 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
1568void 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
1712SmlCredPtr_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
1732TSyncClientBase *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
1739bool 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)
1768void 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
1846SmlPcdataPtr_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
1877bool 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
2066void 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
2351void 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.
2376bool 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
2450Ret_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
2472void 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]
2484sInt32 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
2506bool 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
2585void 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
2609void 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
2640bool 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
2654TAgentConfig *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
2666TAuthTypes 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
2680bool 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
2694bool 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
2726bool 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)
2891bool 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
2988appPointer TSyncAgent::newSessionKey(TEngineInterface *aEngineInterfaceP)
2989{
2990 return new TAgentParamsKey(aEngineInterfaceP,this);
2991} // TSyncAgent::newSessionKey
2992
2993
2994#ifdef ENGINE_LIBRARY1
2995
2996TSyError 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
3072done:
3073 // return step status
3074 return fEngineSessionStatus;
3075} // TSyncAgent::SessionStep
3076
3077
3078#ifdef PROGRESS_EVENTS1
3079
3080bool 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
3119ENGINE_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.
3130TSyncAppBase *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
3149TSyError 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
3276TSyError 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
3340TSyError 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
3397TSyError 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
3549TSyError 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
3585TSyError 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
3657TAgentParamsKey::TAgentParamsKey(TEngineInterface *aEngineInterfaceP, TSyncAgent *aAgentP) :
3658 inherited(aEngineInterfaceP,aAgentP),
3659 fAgentP(aAgentP)
3660{
3661} // TAgentParamsKey::TAgentParamsKey
3662
3663
3664
3665// - read local session ID
3666static 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
3680static 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
3694static 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
3710TSyError 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
3725static 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
3741static 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
3754static 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
3768static 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
3790static 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
3812static 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
3824static 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)
3838static 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
3851static 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
3862static 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)
3880TSyError 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
3893static 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
3908static 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
3919static 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
3931TSyError 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
3945TSyError 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
3961static 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
3990const TStructFieldInfo *TAgentParamsKey::getFieldsTable(void)
3991{
3992 return ServerParamFieldInfos;
3993} // TAgentParamsKey::getFieldsTable
3994
3995sInt32 TAgentParamsKey::numFields(void)
3996{
3997 return sizeof(ServerParamFieldInfos)/sizeof(TStructFieldInfo);
3998} // TAgentParamsKey::numFields
3999
4000// get actual struct base address
4001uInt8P 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!)
4009TSyError 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