📄 syncmanager.cpp
字号:
/*
* Copyright (C) 2003-2007 Funambol, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY, TITLE, NONINFRINGEMENT or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
#include "base/fscapi.h"
#include "base/Log.h"
#include "base/debug.h"
#include "base/util/utils.h"
#include "base/base64.h"
#include "base/messages.h"
#include "http/TransportAgentFactory.h"
#include "spds/constants.h"
#include "spds/DataTransformer.h"
#include "spds/DataTransformerFactory.h"
#include "spds/SyncManagerConfig.h"
#include "spds/SyncManager.h"
#include "spds/SyncMLProcessor.h"
#include "spds/spdsutils.h"
#include "syncml/core/TagNames.h"
#include "syncml/core/ObjectDel.h"
#include "event/FireEvent.h"
#include <limits.h>
const char SyncManager::encodedKeyPrefix[] = "funambol-b64-";
char prevSourceName[64];
char prevSourceUri[64];
SyncMode prevSyncMode;
BOOL isFiredSyncEventBEGIN;
BOOL isFiredSyncEventEND;
void SyncManager::decodeItemKey(SyncItem *syncItem)
{
char *key;
if (syncItem &&
(key = toMultibyte(syncItem->getKey())) != NULL &&
!strncmp(key, encodedKeyPrefix, strlen(encodedKeyPrefix))) {
int len;
char *decoded = (char *)b64_decode(len, key + strlen(encodedKeyPrefix));
LOG.debug("replacing encoded key '%s' with unsafe key '%s'", key, decoded);
WCHAR* t = toWideChar(decoded);
syncItem->setKey(t);
delete [] decoded;
delete [] key;
delete [] t;
}
}
void SyncManager::encodeItemKey(SyncItem *syncItem)
{
char *key;
if (syncItem &&
(key = toMultibyte(syncItem->getKey())) != NULL &&
(strchr(key, '<') || strchr(key, '&'))) {
StringBuffer encoded;
b64_encode(encoded, key, strlen(key));
StringBuffer newkey(encodedKeyPrefix);
newkey += encoded;
LOG.debug("replacing unsafe key '%s' with encoded key '%s'", key, newkey.c_str());
WCHAR* t = toWideChar(newkey.c_str());
syncItem->setKey(t);
delete [] key;
delete [] t;
}
}
/**
* Is the given status code an error status code? Error codes are the ones
* outside the range 200-299.
*
* @param status the status code to check
*/
inline static bool isErrorStatus(int status) {
return (status) && ((status < 200) || (status > 299));
}
/**
* Return true if the status code is authentication failed
*
* @param status the status code to check
*/
inline static bool isAuthFailed(int status) {
return (status) && ((status == 401) || (status == 407));
}
/**
* Return true if there's no more work to do
* (if no source has a correct status)
*/
bool SyncManager::isToExit() {
for (int i = 0; i < sourcesNumber; i++) {
if (sources[i]->getReport()->checkState() == true) {
return false;
}
}
return true;
}
/*
* Utility to set a SyncSource state + errorCode + errorMsg.
*/
void SyncManager::setSourceStateAndError(unsigned int index, SourceState state,
unsigned int code, const char* msg) {
SyncSourceReport* report = sources[index]->getReport();
report->setState(state);
report->setLastErrorCode(code);
report->setLastErrorMsg(msg);
}
// Used to reserve some more space (DATA_SIZE_TOLERANCE) for incoming items.
// This is used to add a little tolerance to the data size of items sent by
// server in case of large object (item splitted in multiple chunks).
long SyncManager::getToleranceDataSize(long size) {
return (long)(size*DATA_SIZE_TOLERANCE + 0.5);
}
// Used to verify if data size of incoming item is different from the one declared.
bool SyncManager::testIfDataSizeMismatch(long allocatedSize, long receivedSize) {
long declaredSize = (long) (allocatedSize/DATA_SIZE_TOLERANCE + 0.5);
if (declaredSize != receivedSize) {
LOG.info("WARNING! Item size mismatch: real size = %d, declared size = %d", receivedSize, declaredSize);
return true;
}
return false;
}
SyncManager::SyncManager(SyncManagerConfig& c, SyncReport& report) : config(c), syncReport(report) {
initialize();
}
void SyncManager::initialize() {
// set all values which are checked by the destructor;
// previously some pointers were only set later, leading to
// uninitialized memory reads and potential crashes when
// constructing a SyncManager, but not using it
transportAgent = NULL;
mappings = NULL;
sources = NULL;
currentState = STATE_START;
sourcesNumber = 0;
count = 0;
commands = NULL;
devInf = NULL;
incomingItem = NULL;
AccessConfig& c = config.getAccessConfig();
DeviceConfig& dc = config.getDeviceConfig();
syncURL = c.getSyncURL();
deviceId = dc.getDevID();
credentialHandler.setUsername (c.getUsername());
credentialHandler.setPassword (c.getPassword());
credentialHandler.setClientNonce (c.getClientNonce());
credentialHandler.setClientAuthType (c.getClientAuthType());
credentialHandler.setServerID (c.getServerID());
credentialHandler.setServerPWD (c.getServerPWD());
credentialHandler.setServerNonce (c.getServerNonce());
credentialHandler.setServerAuthType (c.getServerAuthType());
credentialHandler.setServerAuthRequired (c.getServerAuthRequired());
commands = new ArrayList();
responseTimeout = c.getResponseTimeout();
if (responseTimeout <= 0) {
responseTimeout = DEFAULT_MAX_TIMEOUT;
}
maxMsgSize = c.getMaxMsgSize();
if (maxMsgSize <= 0) {
maxMsgSize = DEFAULT_MAX_MSG_SIZE;
}
maxObjSize = dc.getMaxObjSize();
loSupport = dc.getLoSupport();
readBufferSize = 5000; // default value
if (c.getReadBufferSize() > 0)
readBufferSize = c.getReadBufferSize();
syncMLBuilder.set(syncURL.c_str(), deviceId.c_str());
memset(credentialInfo, 0, 1024*sizeof(char));
sortedSourcesFromServer = NULL;
prevSourceName[0] = 0;
prevSourceUri[0] = 0;
prevSyncMode = SYNC_NONE;
isFiredSyncEventBEGIN = FALSE;
}
SyncManager::~SyncManager() {
if (transportAgent) {
delete transportAgent;
}
if (commands) {
commands->clear(); delete commands; commands = NULL;
}
if (mappings) {
for (int i=0; i<sourcesNumber; i++) {
deleteArrayList(&mappings[i]);
delete mappings[i];
}
delete [] mappings; mappings = NULL;
}
if (sources) {
// This deletes only SyncSource array
// We DON'T want to release SyncSource objects here!
delete [] sources;
}
if (devInf) {
delete devInf;
}
if (incomingItem) {
delete incomingItem;
}
if (sortedSourcesFromServer) {
int i=0;
while (sortedSourcesFromServer[i]) {
delete [] sortedSourcesFromServer[i];
i++;
}
delete [] sortedSourcesFromServer;
}
}
/*
* Modification to perform the sync of an array of sync sources.
*/
int SyncManager::prepareSync(SyncSource** s) {
char* initMsg = NULL;
const char* respURI = NULL;
char* responseMsg = NULL;
SyncML* syncml = NULL;
int ret = 0;
int serverRet = 0;
int count = 0;
const char* requestedAuthType = NULL;
ArrayList* list = new ArrayList();
ArrayList* alerts = new ArrayList();
// for authentication improvments
BOOL isServerAuthRequired = credentialHandler.getServerAuthRequired();
int clientAuthRetries = 1;
int serverAuthRetries = 1;
int authStatusCode = 200;
BOOL isClientAuthenticated = FALSE;
BOOL isServerAuthenticated = FALSE;
Chal* clientChal = NULL; // The chal of the server to the client
Chal* serverChal = NULL; // The chal of the client to the server
Status* status = NULL; // The status from the client to the server
Cred* cred = NULL;
Alert* alert = NULL;
SyncSource** buf = NULL;
StringBuffer* devInfStr = NULL;
BOOL putDevInf = FALSE;
char devInfHash[16 * 4 +1]; // worst case factor base64 is four
unsigned long timestamp = (unsigned long)time(NULL);
lastErrorCode = 0;
// Fire Sync Begin Event
fireSyncEvent(NULL, SYNC_BEGIN);
URL url(config.getAccessConfig().getSyncURL());
Proxy proxy;
LOG.info(MSG_SYNC_URL, syncURL.c_str());
// Copy and validate given
sourcesNumber = assignSources(s);
if (lastErrorCode) {
ret = lastErrorCode; // set when a source has an invalid config
}
if (isToExit()) {
if (!ret) {
// error: no source to sync
ret = lastErrorCode = ERR_NO_SOURCE_TO_SYNC;
sprintf(lastErrorMsg, ERRMSG_NO_SOURCE_TO_SYNC);
}
goto finally;
}
// Set proxy username/password if proxy is used.
if (config.getAccessConfig().getUseProxy()) {
//char* proxyHost = config.getAccessConfig().getProxyHost();
//int proxyPort = config.getAccessConfig().getProxyPort();
const char* proxyUser = config.getAccessConfig().getProxyUsername();
const char* proxyPwd = config.getAccessConfig().getProxyPassword();
proxy.setProxy(NULL, 0, proxyUser, proxyPwd);
}
mappings = new ArrayList*[sourcesNumber + 1];
for (count = 0; count < sourcesNumber; count++) {
mappings[count] = new ArrayList();
LOG.info(MSG_PREPARING_SYNC, _wcc(sources[count]->getName()));
}
syncMLBuilder.resetCommandID();
syncMLBuilder.resetMessageID();
config.getAccessConfig().setBeginSync(timestamp);
// Create the device informations.
devInf = createDeviceInfo();
// check device information for changes
if (devInf) {
char md5[16];
devInfStr = Formatter::getDevInf(devInf);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -