urbackup_backend/urbackupclient/ClientServiceCMD.cpp

899 lines
20 KiB
C++

#include "../Interface/Server.h"
#include "ClientService.h"
#include "ServerIdentityMgr.h"
#include "../urbackupcommon/fileclient/data.h"
#include "../urbackupcommon/capa_bits.h"
#include "../urbackupcommon/escape.h"
#include "client.h"
#include "database.h"
#include "../stringtools.h"
#ifdef _WIN32
#include "win_sysvol.h"
#else
std::wstring getSysVolume(std::wstring &mpath){ return L""; }
#endif
extern std::string time_format_str;
void ClientConnector::CMD_ADD_IDENTITY(const std::string &identity, const std::string &cmd, bool ident_ok)
{
if(identity.empty())
{
tcpstack.Send(pipe, "Identity empty");
}
else
{
if(Server->getServerParameter("restore_mode")=="true" && !ident_ok )
{
ServerIdentityMgr::addServerIdentity(identity);
tcpstack.Send(pipe, "OK");
}
else if( ident_ok )
{
tcpstack.Send(pipe, "OK");
}
else
{
if( ServerIdentityMgr::numServerIdentities()==0 )
{
ServerIdentityMgr::addServerIdentity(identity);
tcpstack.Send(pipe, "OK");
}
else
{
tcpstack.Send(pipe, "failed");
}
}
}
}
void ClientConnector::CMD_START_INCR_FILEBACKUP(const std::string &cmd)
{
if(cmd=="2START BACKUP") file_version=2;
state=CCSTATE_START_FILEBACKUP;
CWData data;
data.addChar(0);
data.addVoidPtr(mempipe);
data.addString(server_token);
IndexThread::getMsgPipe()->Write(data.getDataPtr(), data.getDataSize());
lasttime=Server->getTimeMS();
IScopedLock lock(backup_mutex);
backup_running=RUNNING_INCR_FILE;
last_pingtime=Server->getTimeMS();
pcdone=0;
backup_source_token=server_token;
}
void ClientConnector::CMD_START_FULL_FILEBACKUP(const std::string &cmd)
{
if(cmd=="2START FULL BACKUP") file_version=2;
state=CCSTATE_START_FILEBACKUP;
CWData data;
data.addChar(1);
data.addVoidPtr(mempipe);
data.addString(server_token);
IndexThread::getMsgPipe()->Write(data.getDataPtr(), data.getDataSize());
lasttime=Server->getTimeMS();
IScopedLock lock(backup_mutex);
backup_running=RUNNING_FULL_FILE;
last_pingtime=Server->getTimeMS();
pcdone=0;
backup_source_token=server_token;
}
void ClientConnector::CMD_START_SHADOWCOPY(const std::string &cmd)
{
#ifdef _WIN32
if(cmd[cmd.size()-1]=='"')
{
state=CCSTATE_SHADOWCOPY;
std::string dir=cmd.substr(10, cmd.size()-11);
CWData data;
data.addChar(2);
data.addVoidPtr(mempipe);
data.addString(dir);
data.addString(server_token);
IndexThread::getMsgPipe()->Write(data.getDataPtr(), data.getDataSize());
lasttime=Server->getTimeMS();
}
else
{
Server->Log("Invalid command", LL_ERROR);
}
#else
tcpstack.Send(pipe, "DONE");
#endif
}
void ClientConnector::CMD_STOP_SHADOWCOPY(const std::string &cmd)
{
#ifdef _WIN32
if(cmd[cmd.size()-1]=='"')
{
state=CCSTATE_SHADOWCOPY;
std::string dir=cmd.substr(9, cmd.size()-10);
CWData data;
data.addChar(3);
data.addVoidPtr(mempipe);
data.addString(dir);
data.addString(server_token);
IndexThread::getMsgPipe()->Write(data.getDataPtr(), data.getDataSize());
lasttime=Server->getTimeMS();
}
else
{
Server->Log("Invalid command", LL_ERROR);
}
#else
tcpstack.Send(pipe, "DONE");
#endif
}
void ClientConnector::CMD_SET_INCRINTERVAL(const std::string &cmd)
{
if(cmd[cmd.size()-1]=='"')
{
std::string intervall=cmd.substr(15, cmd.size()-16);
incr_update_intervall=atoi(intervall.c_str());
tcpstack.Send(pipe, "OK");
lasttime=Server->getTimeMS();
}
else
{
Server->Log("Invalid command", LL_ERROR);
}
}
void ClientConnector::CMD_GET_BACKUPDIRS(const std::string &cmd)
{
int version=0;
if(!cmd.empty() && cmd[0]=='1')
version=1;
IDatabase *db=Server->getDatabase(Server->getThreadID(), URBACKUPDB_CLIENT);
IQuery *q=db->Prepare("SELECT id,name,path FROM backupdirs");
int timeoutms=300;
db_results res=q->Read(&timeoutms);
if(timeoutms==0)
{
std::string msg;
for(size_t i=0;i<res.size();++i)
{
if(res[i][L"name"]==L"*") continue;
msg+=Server->ConvertToUTF8(res[i][L"id"])+"\n";
if(version!=0)
{
msg+=Server->ConvertToUTF8(res[i][L"name"])+"|";
}
msg+=Server->ConvertToUTF8(res[i][L"path"]);
if(i+1<res.size())
msg+="\n";
}
tcpstack.Send(pipe, msg);
}
else
{
pipe->shutdown();
}
db->destroyAllQueries();
lasttime=Server->getTimeMS();
}
void ClientConnector::CMD_SAVE_BACKUPDIRS(const std::string &cmd, str_map &params)
{
if(saveBackupDirs(params))
{
tcpstack.Send(pipe, "OK");
}
lasttime=Server->getTimeMS();
}
void ClientConnector::CMD_GET_INCRINTERVAL(const std::string &cmd)
{
if(incr_update_intervall==0 )
{
tcpstack.Send(pipe, nconvert(0));
}
else
{
tcpstack.Send(pipe, nconvert(incr_update_intervall+10*60) );
}
lasttime=Server->getTimeMS();
}
void ClientConnector::CMD_DID_BACKUP(const std::string &cmd)
{
updateLastBackup();
tcpstack.Send(pipe, "OK");
{
IScopedLock lock(backup_mutex);
if(backup_running==RUNNING_INCR_FILE || backup_running==RUNNING_FULL_FILE)
{
backup_running=RUNNING_NONE;
backup_done=true;
}
lasttime=Server->getTimeMS();
}
IndexThread::execute_postbackup_hook();
}
void ClientConnector::CMD_STATUS(const std::string &cmd)
{
IScopedLock lock(backup_mutex);
IDatabase *db=Server->getDatabase(Server->getThreadID(), URBACKUPDB_CLIENT);
IQuery *q=db->Prepare("SELECT strftime('"+time_format_str+"',last_backup, 'localtime') AS last_backup FROM status");
if(q==NULL)
return;
int timeoutms=300;
db_results res=q->Read(&timeoutms);
if(timeoutms==1)
{
res=cached_status;
}
else
{
cached_status=res;
}
std::string ret;
if(res.size()>0)
{
ret+=Server->ConvertToUTF8(res[0][L"last_backup"]);
}
if(backup_running==RUNNING_NONE)
{
if(backup_done)
ret+="#DONE";
else
ret+="#NOA";
backup_done=false;
}
else if(backup_running==RUNNING_INCR_FILE)
{
if(last_pingtime!=0 && Server->getTimeMS()-last_pingtime>x_pingtimeout )
ret+="#NOA";
else
ret+="#INCR";
}
else if(backup_running==RUNNING_FULL_FILE)
{
if(last_pingtime!=0 && Server->getTimeMS()-last_pingtime>x_pingtimeout )
ret+="#NOA";
else
ret+="#FULL";
}
else if(backup_running==RUNNING_FULL_IMAGE)
{
if(last_pingtime!=0 && Server->getTimeMS()-last_pingtime>x_pingtimeout )
ret+="#NOA";
else
ret+="#FULLI";
}
else if(backup_running==RUNNING_INCR_IMAGE)
{
if(last_pingtime!=0 && Server->getTimeMS()-last_pingtime>x_pingtimeout )
ret+="#NOA";
else
ret+="#INCRI";
}
if(backup_running!=RUNNING_INCR_IMAGE)
ret+="#"+nconvert(pcdone);
else
ret+="#"+nconvert(pcdone2);
if(IdleCheckerThread::getPause())
{
ret+="#P";
}
else
{
ret+="#NP";
}
int capa=0;
if(channel_capa.size()==0)
{
capa=last_capa;
capa|=DONT_ALLOW_STARTING_FILE_BACKUPS;
capa|=DONT_ALLOW_STARTING_IMAGE_BACKUPS;
}
else
{
capa=INT_MAX;
for(size_t i=0;i<channel_capa.size();++i)
{
capa=capa & channel_capa[i];
}
if(capa!=last_capa)
{
IQuery *cq=db->Prepare("UPDATE misc SET tvalue=? WHERE tkey='last_capa'");
if(cq!=NULL)
{
cq->Bind(capa);
cq->Write();
cq->Reset();
last_capa=capa;
}
}
}
ret+="#capa="+nconvert(capa);
tcpstack.Send(pipe, ret);
db->destroyAllQueries();
lasttime=Server->getTimeMS();
}
void ClientConnector::CMD_UPDATE_SETTINGS(const std::string &cmd)
{
std::string s_settings=cmd.substr(9);
unescapeMessage(s_settings);
updateSettings( s_settings );
tcpstack.Send(pipe, "OK");
lasttime=Server->getTimeMS();
}
void ClientConnector::CMD_PING_RUNNING(const std::string &cmd)
{
tcpstack.Send(pipe, "OK");
IScopedLock lock(backup_mutex);
lasttime=Server->getTimeMS();
last_pingtime=Server->getTimeMS();
int pcdone_new=atoi(getbetween("-","-", cmd).c_str());
if(backup_source_token.empty() || backup_source_token==server_token )
{
pcdone=pcdone_new;
}
last_token_times[server_token]=Server->getTimeSeconds();
#ifdef _WIN32
SetThreadExecutionState(ES_SYSTEM_REQUIRED);
#endif
}
void ClientConnector::CMD_CHANNEL(const std::string &cmd, IScopedLock *g_lock)
{
if(!img_download_running)
{
g_lock->relock(backup_mutex);
channel_pipe=pipe;
channel_pipes.push_back(pipe);
is_channel=true;
state=CCSTATE_CHANNEL;
last_channel_ping=Server->getTimeMS();
lasttime=Server->getTimeMS();
Server->Log("New channel: Number of Channels: "+nconvert((int)channel_pipes.size()), LL_DEBUG);
int capa=0;
if(cmd.find("1CHANNEL ")==0)
{
std::string s_params=cmd.substr(9);
str_map params;
ParseParamStr(s_params, &params);
capa=watoi(params[L"capa"]);
}
channel_capa.push_back(capa);
}
}
void ClientConnector::CMD_CHANNEL_PONG(const std::string &cmd)
{
lasttime=Server->getTimeMS();
IScopedLock lock(backup_mutex);
for(size_t i=0;i<channel_ping.size();++i)
{
if(channel_ping[i]==pipe)
{
channel_ping.erase(channel_ping.begin()+i);
break;
}
}
}
void ClientConnector::CMD_CHANNEL_PING(const std::string &cmd)
{
lasttime=Server->getTimeMS();
if(tcpstack.Send(pipe, "PONG")==0)
{
do_quit=true;
}
}
void ClientConnector::CMD_TOCHANNEL_START_INCR_FILEBACKUP(const std::string &cmd)
{
tochannelSendStartbackup(RUNNING_INCR_FILE);
}
void ClientConnector::CMD_TOCHANNEL_START_FULL_FILEBACKUP(const std::string &cmd)
{
tochannelSendStartbackup(RUNNING_FULL_FILE);
}
void ClientConnector::CMD_TOCHANNEL_START_FULL_IMAGEBACKUP(const std::string &cmd)
{
tochannelSendStartbackup(RUNNING_FULL_IMAGE);
}
void ClientConnector::CMD_TOCHANNEL_START_INCR_IMAGEBACKUP(const std::string &cmd)
{
tochannelSendStartbackup(RUNNING_INCR_IMAGE);
}
void ClientConnector::CMD_TOCHANNEL_UPDATE_SETTINGS(const std::string &cmd)
{
std::string s_settings=cmd.substr(16);
lasttime=Server->getTimeMS();
unescapeMessage(s_settings);
replaceSettings( s_settings );
IScopedLock lock(backup_mutex);
bool ok=false;
for(size_t o=0;o<channel_pipes.size();++o)
{
_u32 rc=(_u32)tcpstack.Send(channel_pipes[o], "UPDATE SETTINGS");
if(rc!=0)
ok=true;
}
if(!ok)
{
tcpstack.Send(pipe, "FAILED");
}
else
{
tcpstack.Send(pipe, "OK");
}
}
void ClientConnector::CMD_LOGDATA(const std::string &cmd)
{
std::string ldata=cmd.substr(9);
size_t cpos=ldata.find(" ");
std::string created=getuntil(" ", ldata);
lasttime=Server->getTimeMS();
saveLogdata(created, getafter(" ",ldata));
tcpstack.Send(pipe, "OK");
}
void ClientConnector::CMD_PAUSE(const std::string &cmd)
{
lasttime=Server->getTimeMS();
std::string b=cmd.substr(6);
bool ok=false;
if(b=="true")
{
ok=true;
IdleCheckerThread::setPause(true);
IndexThread::getFileSrv()->setPause(true);
}
else if(b=="false")
{
ok=true;
IdleCheckerThread::setPause(false);
IndexThread::getFileSrv()->setPause(false);
}
if(ok) tcpstack.Send(pipe, "OK");
else tcpstack.Send(pipe, "FAILED");
}
void ClientConnector::CMD_GET_LOGPOINTS(const std::string &cmd)
{
lasttime=Server->getTimeMS();
tcpstack.Send(pipe, getLogpoints() );
}
void ClientConnector::CMD_GET_LOGDATA(const std::string &cmd, str_map &params)
{
lasttime=Server->getTimeMS();
int logid=watoi(params[L"logid"]);
int loglevel=watoi(params[L"loglevel"]);
std::string ret;
getLogLevel(logid, loglevel, ret);
tcpstack.Send(pipe, ret);
}
void ClientConnector::CMD_FULL_IMAGE(const std::string &cmd, bool ident_ok)
{
if(ident_ok==true)
{
lasttime=Server->getTimeMS();
std::string s_params=cmd.substr(11);
str_map params;
ParseParamStr(s_params, &params);
server_token=Server->ConvertToUTF8(params[L"token"]);
image_inf.image_letter=Server->ConvertToUTF8(params[L"letter"]);
image_inf.shadowdrive=Server->ConvertToUTF8(params[L"shadowdrive"]);
if(params.find(L"start")!=params.end())
{
image_inf.startpos=(uint64)_atoi64(Server->ConvertToUTF8(params[L"start"]).c_str());
}
else
{
image_inf.startpos=0;
}
if(params.find(L"shadowid")!=params.end())
{
image_inf.shadow_id=watoi(params[L"shadowid"]);
}
else
{
image_inf.shadow_id=-1;
}
image_inf.no_shadowcopy=false;
if(image_inf.image_letter=="SYSVOL")
{
std::wstring mpath;
std::wstring sysvol=getSysVolume(mpath);
if(!mpath.empty())
{
image_inf.image_letter=Server->ConvertToUTF8(mpath);
}
else
{
image_inf.image_letter=Server->ConvertToUTF8(sysvol);
image_inf.no_shadowcopy=true;
}
}
if(image_inf.startpos==0 && !image_inf.no_shadowcopy)
{
CWData data;
data.addChar(2);
data.addVoidPtr(mempipe);
data.addString(image_inf.image_letter);
data.addString(server_token);
data.addUChar(1); //image backup
data.addUChar(0); //filesrv
IndexThread::getMsgPipe()->Write(data.getDataPtr(), data.getDataSize());
}
else if(image_inf.shadow_id!=-1)
{
image_inf.shadowdrive.clear();
CWData data;
data.addChar(4);
data.addVoidPtr(mempipe);
data.addInt(image_inf.shadow_id);
IndexThread::getMsgPipe()->Write(data.getDataPtr(), data.getDataSize());
}
if(image_inf.no_shadowcopy)
{
image_inf.shadowdrive=image_inf.image_letter;
if(!image_inf.shadowdrive.empty() && image_inf.shadowdrive[0]!='\\')
{
image_inf.shadowdrive="\\\\.\\"+image_inf.image_letter;
}
}
lasttime=Server->getTimeMS();
sendFullImage();
}
else
{
ImageErr("Ident reset (1)");
}
}
void ClientConnector::CMD_INCR_IMAGE(const std::string &cmd, bool ident_ok)
{
if(ident_ok==true)
{
lasttime=Server->getTimeMS();
std::string s_params=cmd.substr(11);
str_map params;
ParseParamStr(s_params, &params);
server_token=Server->ConvertToUTF8(params[L"token"]);
str_map::iterator f_hashsize=params.find(L"hashsize");
if(f_hashsize!=params.end())
{
hashdataok=false;
hashdataleft=watoi(f_hashsize->second);
image_inf.image_letter=Server->ConvertToUTF8(params[L"letter"]);
image_inf.shadowdrive=Server->ConvertToUTF8(params[L"shadowdrive"]);
if(params.find(L"start")!=params.end())
{
image_inf.startpos=(uint64)_atoi64(Server->ConvertToUTF8(params[L"start"]).c_str());
}
else
{
image_inf.startpos=0;
}
if(params.find(L"shadowid")!=params.end())
{
image_inf.shadow_id=watoi(params[L"shadowid"]);
}
else
{
image_inf.shadow_id=-1;
}
image_inf.no_shadowcopy=false;
if(image_inf.startpos==0)
{
CWData data;
data.addChar(2);
data.addVoidPtr(mempipe);
data.addString(image_inf.image_letter);
data.addString(server_token);
data.addUChar(1); //image backup
data.addUChar(0); //file serv?
IndexThread::getMsgPipe()->Write(data.getDataPtr(), data.getDataSize());
}
else if(image_inf.shadow_id!=-1)
{
image_inf.shadowdrive.clear();
CWData data;
data.addChar(4);
data.addVoidPtr(mempipe);
data.addInt(image_inf.shadow_id);
IndexThread::getMsgPipe()->Write(data.getDataPtr(), data.getDataSize());
}
hashdatafile=Server->openTemporaryFile();
if(hashdatafile==NULL)
{
Server->Log("Error creating temporary file in CMD_INCR_IMAGE", LL_ERROR);
do_quit=true;
return;
}
if(tcpstack.getBuffersize()>0)
{
if(hashdatafile->Write(tcpstack.getBuffer(), (_u32)tcpstack.getBuffersize())!=tcpstack.getBuffersize())
{
Server->Log("Error writing to hashdata temporary file in CMD_INCR_IMAGE", LL_ERROR);
do_quit=true;
return;
}
if(hashdataleft>=tcpstack.getBuffersize())
{
hashdataleft-=(_u32)tcpstack.getBuffersize();
//Server->Log("Hashdataleft: "+nconvert(hashdataleft), LL_DEBUG);
}
else
{
Server->Log("Too much hashdata - error in CMD_INCR_IMAGE", LL_ERROR);
}
if(hashdataleft==0)
{
hashdataok=true;
state=CCSTATE_IMAGE;
return;
}
}
lasttime=Server->getTimeMS();
sendIncrImage();
}
else
{
ImageErr("Ident reset (2)");
}
}
}
void ClientConnector::CMD_MBR(const std::string &cmd)
{
lasttime=Server->getTimeMS();
std::string s_params=cmd.substr(4);
str_map params;
ParseParamStr(s_params, &params);
std::wstring dl=params[L"driveletter"];
if(dl==L"SYSVOL")
{
std::wstring mpath;
dl=getSysVolume(mpath);
}
bool b=false;
if(!dl.empty())
{
b=sendMBR(dl);
}
if(!b)
{
CWData r;r.addChar(0);
tcpstack.Send(pipe, r);
}
}
void ClientConnector::CMD_RESTORE_GET_BACKUPCLIENTS(const std::string &cmd)
{
lasttime=Server->getTimeMS();
IScopedLock lock(backup_mutex);
waitForPings(&lock);
if(channel_pipes.size()==0)
{
tcpstack.Send(pipe, "0");
}
else
{
std::string clients;
for(size_t i=0;i<channel_pipes.size();++i)
{
tcpstack.Send(channel_pipes[i], "GET BACKUPCLIENTS");
if(channel_pipes[i]->hasError())
Server->Log("Channel has error after request -1", LL_DEBUG);
std::string nc=receivePacket(channel_pipes[i]);
if(channel_pipes[i]->hasError())
Server->Log("Channel has error after read -1", LL_DEBUG);
Server->Log("Client "+nconvert(i)+"/"+nconvert(channel_pipes.size())+": --"+nc+"--", LL_DEBUG);
if(!nc.empty())
{
clients+=nc+"\n";
}
}
tcpstack.Send(pipe, "1"+clients);
}
}
void ClientConnector::CMD_RESTORE_GET_BACKUPIMAGES(const std::string &cmd)
{
lasttime=Server->getTimeMS();
IScopedLock lock(backup_mutex);
waitForPings(&lock);
if(channel_pipes.size()==0)
{
tcpstack.Send(pipe, "0");
}
else
{
std::string imgs;
for(size_t i=0;i<channel_pipes.size();++i)
{
tcpstack.Send(channel_pipes[i], cmd);
std::string nc=receivePacket(channel_pipes[i]);
if(!nc.empty())
{
imgs+=nc+"\n";
}
}
tcpstack.Send(pipe, "1"+imgs);
}
}
void ClientConnector::CMD_RESTORE_DOWNLOAD_IMAGE(const std::string &cmd, str_map &params)
{
lasttime=Server->getTimeMS();
Server->Log("Downloading image...", LL_DEBUG);
IScopedLock lock(backup_mutex);
waitForPings(&lock);
Server->Log("In mutex...",LL_DEBUG);
img_download_running=true;
downloadImage(params);
img_download_running=false;
Server->Log("Donwload done -2", LL_DEBUG);
do_quit=true;
}
void ClientConnector::CMD_RESTORE_DOWNLOADPROGRESS(const std::string &cmd)
{
Server->Log("Sending progress...", LL_DEBUG);
lasttime=Server->getTimeMS();
if(img_download_running==false)
{
pipe->Write("100");
do_quit=true;
}
else
{
while(img_download_running)
{
{
int progress=0;
{
IScopedLock lock(progress_mutex);
progress=pcdone;
}
if(!pipe->Write(nconvert(progress)+"\n", 10000))
{
break;
}
}
{
Server->wait(1000);
}
}
do_quit=true;
}
}
void ClientConnector::CMD_VERSION_UPDATE(const std::string &cmd)
{
int n_version=atoi(cmd.substr(8).c_str());
std::string version_1=getFile("version.txt");
std::string version_2=getFile("curr_version.txt");
if(version_1.empty() ) version_1="0";
if(version_2.empty() ) version_2="0";
#ifdef _WIN32
if( atoi(version_1.c_str())<n_version && atoi(version_2.c_str())<n_version )
{
tcpstack.Send(pipe, "update");
}
else
{
#endif
tcpstack.Send(pipe, "noop");
#ifdef _WIN32
}
#endif
}
void ClientConnector::CMD_CLIENT_UPDATE(const std::string &cmd)
{
hashdatafile=Server->openTemporaryFile();
if(hashdatafile==NULL)
{
Server->Log("Error creating temporary file in CMD_CLIENT_UPDATE", LL_ERROR);
do_quit=true;
return;
}
hashdataleft=atoi(cmd.substr(13).c_str());
hashdataok=false;
state=CCSTATE_UPDATE_DATA;
if(tcpstack.getBuffersize()>0)
{
if(hashdatafile->Write(tcpstack.getBuffer(), (_u32)tcpstack.getBuffersize())!=tcpstack.getBuffersize())
{
Server->Log("Error writing to hashdata temporary file -1update", LL_ERROR);
do_quit=true;
return;
}
if(hashdataleft>=tcpstack.getBuffersize())
{
hashdataleft-=(_u32)tcpstack.getBuffersize();
}
else
{
Server->Log("Too much hashdata - error -1update", LL_ERROR);
}
if(hashdataleft==0)
{
hashdataok=true;
state=CCSTATE_UPDATE_FINISH;
return;
}
}
return;
}
void ClientConnector::CMD_CAPA(const std::string &cmd)
{
#ifdef _WIN32
tcpstack.Send(pipe, "FILE=2&IMAGE=1&UPDATE=1&MBR=1&FILESRV=2");
#else
tcpstack.Send(pipe, "FILE=2&FILESRV=2");
#endif
}