From 830aa82e44381c85d8486e46de7ae0e26830457e Mon Sep 17 00:00:00 2001 From: Ben Summers Date: Mon, 13 Feb 2006 13:30:21 +0000 Subject: Merge chris/win32/vc2005-compile-fixes @ r455, add infrastructure/msvc to distribution --- bin/bbackupd/BackupClientContext.cpp | 14 +- bin/bbackupd/BackupClientContext.h | 5 - bin/bbackupd/BackupClientDirectoryRecord.cpp | 5 +- bin/bbackupd/BackupDaemon.cpp | 216 ++++++++++++++++++--------- bin/bbackupd/BackupDaemon.h | 5 +- bin/bbackupd/Win32ServiceFunctions.cpp | 69 +++++++-- bin/bbackupd/bbackupd.cpp | 12 +- 7 files changed, 223 insertions(+), 103 deletions(-) (limited to 'bin/bbackupd') diff --git a/bin/bbackupd/BackupClientContext.cpp b/bin/bbackupd/BackupClientContext.cpp index ae4e1cad..25852b19 100644 --- a/bin/bbackupd/BackupClientContext.cpp +++ b/bin/bbackupd/BackupClientContext.cpp @@ -57,9 +57,7 @@ BackupClientContext::BackupClientContext(BackupDaemon &rDaemon, TLSContext &rTLS mpExcludeFiles(0), mpExcludeDirs(0), mbIsManaged(false), - mTimeMgmtEpoch(0), - mMaximumDiffTime(600), - mKeepAliveTime(0) + mTimeMgmtEpoch(0) { } @@ -511,6 +509,9 @@ void BackupClientContext::ManageDiffProcess() #ifdef PLATFORM_CYGWIN ::signal(SIGALRM, TimerSigHandler); +#elif defined WIN32 + // no support for SIGVTALRM + SetTimerHandler(TimerSigHandler); #else ::signal(SIGVTALRM, TimerSigHandler); #endif // PLATFORM_CYGWIN @@ -599,7 +600,10 @@ void BackupClientContext::UnManageDiffProcess() void BackupClientContext::DoKeepAlive() { if (!mpConnection) + { + ::syslog(LOG_ERR, "DoKeepAlive() called with no connection!"); return; + } mpConnection->QueryGetIsAlive(); } @@ -620,10 +624,10 @@ time_t BackupClientContext::GetTimeMgmtEpoch() int BackupClientContext::GetMaximumDiffingTime() { - return mMaximumDiffTime; + return sMaximumDiffTime; } int BackupClientContext::GetKeepaliveTime() { - return mKeepAliveTime; + return sKeepAliveTime; } diff --git a/bin/bbackupd/BackupClientContext.h b/bin/bbackupd/BackupClientContext.h index 234868db..a0cf6e1f 100644 --- a/bin/bbackupd/BackupClientContext.h +++ b/bin/bbackupd/BackupClientContext.h @@ -208,11 +208,6 @@ private: bool mbIsManaged; // unix time when diff was started time_t mTimeMgmtEpoch; - // maximum time to spend diffing, in seconds - int mMaximumDiffTime; - // maximum time of SSL inactivity (keep-alive interval), in seconds - int mKeepAliveTime; - }; diff --git a/bin/bbackupd/BackupClientDirectoryRecord.cpp b/bin/bbackupd/BackupClientDirectoryRecord.cpp index 49193ccf..5a566d84 100644 --- a/bin/bbackupd/BackupClientDirectoryRecord.cpp +++ b/bin/bbackupd/BackupClientDirectoryRecord.cpp @@ -9,7 +9,10 @@ #include "Box.h" -#include +#ifdef HAVE_DIRENT_H + #include +#endif + #include #include diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index a6d25f0f..01e5bf36 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -11,8 +11,10 @@ #include #include -#include +#ifdef HAVE_UNISTD_H + #include +#endif #ifdef HAVE_SIGNAL_H #include #endif @@ -35,6 +37,9 @@ #include #include #endif +#ifdef HAVE_PROCESS_H + #include +#endif #include "Configuration.h" #include "IOStream.h" @@ -78,6 +83,25 @@ static const time_t MAX_SLEEP_TIME = 1024; // This prevents repetative cycles of load on the server #define SYNC_PERIOD_RANDOM_EXTRA_TIME_SHIFT_BY 6 +#ifdef WIN32 +// -------------------------------------------------------------------------- +// +// Function +// Name: HelperThread() +// Purpose: Background thread function, called by Windows, +// calls the BackupDaemon's RunHelperThread method +// to listen for and act on control communications +// Created: 18/2/04 +// +// -------------------------------------------------------------------------- +unsigned int WINAPI HelperThread(LPVOID lpParam) +{ + ((BackupDaemon *)lpParam)->RunHelperThread(); + + return 0; +} +#endif + // -------------------------------------------------------------------------- // // Function @@ -99,6 +123,20 @@ BackupDaemon::BackupDaemon() { mNotificationsSent[l] = false; } + +#ifdef WIN32 + // Create a thread to handle the named pipe + HANDLE hThread; + unsigned int dwThreadId; + + hThread = (HANDLE) _beginthreadex( + NULL, // default security attributes + 0, // use default stack size + HelperThread, // thread function + this, // argument to thread function + 0, // use default creation flags + &dwThreadId); // returns the thread identifier +#endif } // -------------------------------------------------------------------------- @@ -185,11 +223,12 @@ void BackupDaemon::SetupInInitialProcess() if(GetConfiguration().KeyExists("CommandSocket")) { printf( - "============================================================================================\n" \ - "SECURITY WARNING: This platform cannot check the credentials of connections to the\n" \ - "command socket. This is a potential DoS security problem.\n" \ - "Remove the CommandSocket directive from the bbackupd.conf file if bbackupctl is not used.\n" \ - "============================================================================================\n" + "==============================================================================\n" + "SECURITY WARNING: This platform cannot check the credentials of connections to\n" + "the command socket. This is a potential DoS security problem.\n" + "Remove the CommandSocket directive from the bbackupd.conf file if bbackupctl\n" + "is not used.\n" + "==============================================================================\n" ); } } @@ -221,30 +260,13 @@ void BackupDaemon::DeleteAllLocations() } #ifdef WIN32 -// -------------------------------------------------------------------------- -// -// Function -// Name: HelperThread() -// Purpose: Background thread function, called by Windows, -// calls the BackupDaemon's RunHelperThread method -// to listen for and act on control communications -// Created: 18/2/04 -// -// -------------------------------------------------------------------------- -unsigned int WINAPI HelperThread( LPVOID lpParam ) -{ - printf( "Parameter = %lu.\n", *(DWORD*)lpParam ); - ((BackupDaemon *)lpParam)->RunHelperThread(); - - return 0; -} - void BackupDaemon::RunHelperThread(void) { mpCommandSocketInfo = new CommandSocketInfo; this->mReceivedCommandConn = false; - while ( !IsTerminateWanted() ) + // loop until the parent process exits + while (TRUE) { try { @@ -359,24 +381,21 @@ void BackupDaemon::RunHelperThread(void) void BackupDaemon::Run() { #ifdef WIN32 - - // Create a thread to handle the named pipe - HANDLE hThread; - unsigned int dwThreadId; - - hThread = (HANDLE) _beginthreadex( - NULL, // default security attributes - 0, // use default stack size - HelperThread, // thread function - this, // argument to thread function - 0, // use default creation flags - &dwThreadId); // returns the thread identifier - // init our own timer for file diff timeouts InitTimer(); -#else // ! WIN32 + try + { + Run2(); + } + catch(...) + { + FiniTimer(); + throw; + } + FiniTimer(); +#else // ! WIN32 // Ignore SIGPIPE (so that if a command connection is broken, the daemon doesn't terminate) ::signal(SIGPIPE, SIG_IGN); @@ -390,8 +409,6 @@ void BackupDaemon::Run() ::unlink(socketName); mpCommandSocketInfo->mListeningSocket.Listen(Socket::TypeUNIX, socketName); } - -#endif // WIN32 // Handle things nicely on exceptions try @@ -402,23 +419,28 @@ void BackupDaemon::Run() { if(mpCommandSocketInfo != 0) { - delete mpCommandSocketInfo; + try + { + delete mpCommandSocketInfo; + } + catch(...) + { + ::syslog(LOG_WARNING, + "Error closing command socket " + "after exception, ignored."); + } mpCommandSocketInfo = 0; } throw; } - + // Clean up if(mpCommandSocketInfo != 0) { delete mpCommandSocketInfo; mpCommandSocketInfo = 0; } - -#ifdef WIN32 - // clean up windows specific stuff. - FiniTimer(); #endif } @@ -482,8 +504,8 @@ void BackupDaemon::Run2() BackupClientContext::ClientStoreMarker_NotKnown; // haven't contacted the store yet - DeserializeStoreObjectInfo(clientStoreMarker, lastSyncTime, - nextSyncTime); + bool deserialised = DeserializeStoreObjectInfo(clientStoreMarker, + lastSyncTime, nextSyncTime); // -------------------------------------------------------------------------------------------- @@ -585,6 +607,17 @@ void BackupDaemon::Run2() // but this should be OK, because the changes only upload should upload no data. syncPeriodEndExtended += SecondsToBoxTime((time_t)(356*24*3600)); } + + // Delete the serialised store object file, + // so that we don't try to reload it after a + // partially completed backup + if(deserialised && !DeleteStoreObjectInfo()) + { + ::syslog(LOG_ERR, "Failed to delete the " + "StoreObjectInfoFile, backup cannot " + "continue safely."); + continue; + } // Do sync bool errorOccurred = false; @@ -751,7 +784,12 @@ void BackupDaemon::Run2() "to retry...", errorString, errorCode, errorSubCode); - ::sleep(100); + ::sleep(10); + nextSyncTime = currentSyncStartTime + + SecondsToBoxTime(90) + + Random::RandomInt( + updateStoreInterval >> + SYNC_PERIOD_RANDOM_EXTRA_TIME_SHIFT_BY); } } @@ -863,7 +901,7 @@ void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFla #ifdef WIN32 // Really could use some interprocess protection, mutex etc // any side effect should be too bad???? :) - DWORD timeout = BoxTimeToMilliSeconds(RequiredDelay); + DWORD timeout = (DWORD)BoxTimeToMilliSeconds(RequiredDelay); while ( this->mReceivedCommandConn == false ) { @@ -1065,25 +1103,23 @@ void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFla // -------------------------------------------------------------------------- void BackupDaemon::CloseCommandConnection() { +#ifndef WIN32 try { TRACE0("Closing command connection\n"); -#ifdef WIN32 - mpCommandSocketInfo->mListeningSocket.Close(); -#else if(mpCommandSocketInfo->mpGetLine) { delete mpCommandSocketInfo->mpGetLine; mpCommandSocketInfo->mpGetLine = 0; } mpCommandSocketInfo->mpConnectedSocket.reset(); -#endif } catch(...) { // Ignore any errors } +#endif } @@ -1100,7 +1136,11 @@ void BackupDaemon::SendSyncStartOrFinish(bool SendStart) { // The bbackupctl program can't rely on a state change, because it may never // change if the server doesn't need to be contacted. - + +#ifdef __MINGW32__ +#warning race condition: what happens if socket is closed? +#endif + if (mpCommandSocketInfo != NULL && #ifdef WIN32 mpCommandSocketInfo->mListeningSocket.IsConnected() @@ -1114,7 +1154,7 @@ void BackupDaemon::SendSyncStartOrFinish(bool SendStart) { #ifdef WIN32 mpCommandSocketInfo->mListeningSocket.Write(message, - strlen(message)); + (int)strlen(message)); #else mpCommandSocketInfo->mpConnectedSocket->Write(message, strlen(message)); @@ -1711,7 +1751,10 @@ void BackupDaemon::SetState(int State) char newStateSize = sprintf(newState, "state %d\n", State); #ifdef WIN32 - #warning FIX ME: race condition + #ifndef _MSC_VER + #warning FIX ME: race condition + #endif + // what happens if the socket is closed by the other thread before // we can write to it? Null pointer deref at best. if (mpCommandSocketInfo && @@ -2196,7 +2239,7 @@ void BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time // Created: 2005/04/11 // // -------------------------------------------------------------------------- -void BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_time_t & theLastSyncTime, box_time_t & theNextSyncTime) +bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_time_t & theLastSyncTime, box_time_t & theNextSyncTime) { // // @@ -2208,7 +2251,7 @@ void BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ // if(!GetConfiguration().KeyExists("StoreObjectInfoFile")) { - return; + return false; } std::string StoreObjectInfoFile = @@ -2216,7 +2259,7 @@ void BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ if (StoreObjectInfoFile.size() <= 0) { - return; + return false; } try @@ -2236,7 +2279,7 @@ void BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ "is not a valid or compatible serialised " "archive. Will re-cache from store.", StoreObjectInfoFile.c_str()); - return; + return false; } // @@ -2251,7 +2294,7 @@ void BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ "is not a valid or compatible serialised " "archive. Will re-cache from store.", StoreObjectInfoFile.c_str()); - return; + return false; } // @@ -2264,11 +2307,11 @@ void BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ if (iVersion != STOREOBJECTINFO_VERSION) { ::syslog(LOG_WARNING, "Store object info file '%s' " - "version [%d] unsupported. " + "version %d unsupported. " "Will re-cache from store.", StoreObjectInfoFile.c_str(), iVersion); - return; + return false; } // @@ -2283,7 +2326,7 @@ void BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ ::syslog(LOG_WARNING, "Store object info file '%s' " "out of date. Will re-cache from store", StoreObjectInfoFile.c_str()); - return; + return false; } // @@ -2331,12 +2374,7 @@ void BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ "version [%d]", StoreObjectInfoFile.c_str(), iVersion); - if (::unlink(StoreObjectInfoFile.c_str()) != 0) - { - ::syslog(LOG_ERR, "Failed to delete the old " - "store object info file '%s': %s", - StoreObjectInfoFile.c_str(), strerror(errno)); - } + return true; } catch (...) { @@ -2352,4 +2390,38 @@ void BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ "Will re-cache from store.", StoreObjectInfoFile.c_str()); } + + return false; +} + +// -------------------------------------------------------------------------- +// +// Function +// Name: BackupDaemon::DeleteStoreObjectInfo() +// Purpose: Deletes the serialised state file, to prevent us +// from using it again if a backup is interrupted. +// +// Created: 2006/02/12 +// +// -------------------------------------------------------------------------- + +bool BackupDaemon::DeleteStoreObjectInfo() const +{ + if(!GetConfiguration().KeyExists("StoreObjectInfoFile")) + { + return false; + } + + std::string StoreObjectInfoFile = + GetConfiguration().GetKeyValue("StoreObjectInfoFile"); + + if (::unlink(StoreObjectInfoFile.c_str()) != 0) + { + ::syslog(LOG_ERR, "Failed to delete the old " + "store object info file '%s': %s", + StoreObjectInfoFile.c_str(), strerror(errno)); + return false; + } + + return true; } diff --git a/bin/bbackupd/BackupDaemon.h b/bin/bbackupd/BackupDaemon.h index 8693fe9e..3bd15fad 100644 --- a/bin/bbackupd/BackupDaemon.h +++ b/bin/bbackupd/BackupDaemon.h @@ -45,10 +45,11 @@ public: BackupDaemon(); ~BackupDaemon(); +private: // methods below do partial (specialized) serialization of client state only void SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time_t theLastSyncTime, box_time_t theNextSyncTime) const; - void DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_time_t & theLastSyncTime, box_time_t & theNextSyncTime); -private: + bool DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_time_t & theLastSyncTime, box_time_t & theNextSyncTime); + bool DeleteStoreObjectInfo() const; BackupDaemon(const BackupDaemon &); public: diff --git a/bin/bbackupd/Win32ServiceFunctions.cpp b/bin/bbackupd/Win32ServiceFunctions.cpp index 89f02f62..b74c7e09 100644 --- a/bin/bbackupd/Win32ServiceFunctions.cpp +++ b/bin/bbackupd/Win32ServiceFunctions.cpp @@ -14,10 +14,12 @@ #include "Box.h" -//#include -//#include -#include -//#include +#ifdef HAVE_UNISTD_H + #include +#endif +#ifdef HAVE_PROCESS_H + #include +#endif extern void TerminateService(void); extern unsigned int WINAPI RunService(LPVOID lpParameter); @@ -31,18 +33,23 @@ HANDLE gStopServiceEvent = 0; #define SERVICE_NAME "boxbackup" +void ShowMessage(char *s) +{ + MessageBox(0, s, "Box Backup Message", + MB_OK | MB_SETFOREGROUND | MB_DEFAULT_DESKTOP_ONLY); +} + void ErrorHandler(char *s, DWORD err) { char buf[256]; memset(buf, 0, sizeof(buf)); - snprintf(buf, sizeof(buf)-1, "%s (%d)", s, err); + _snprintf(buf, sizeof(buf)-1, "%s (%d)", s, err); ::syslog(LOG_ERR, "%s", buf); MessageBox(0, buf, "Error", MB_OK | MB_SETFOREGROUND | MB_DEFAULT_DESKTOP_ONLY); ExitProcess(err); } - void WINAPI ServiceControlHandler( DWORD controlCode ) { switch ( controlCode ) @@ -88,7 +95,7 @@ void WINAPI ServiceControlHandler( DWORD controlCode ) VOID ServiceMain(DWORD argc, LPTSTR *argv) { - // initialise service status + // initialise service status gServiceStatus.dwServiceType = SERVICE_WIN32; gServiceStatus.dwCurrentState = SERVICE_STOPPED; gServiceStatus.dwControlsAccepted = 0; @@ -178,14 +185,19 @@ void InstallService(void) scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE); - if (!scm) return; + if (!scm) + { + syslog(LOG_ERR, "Failed to open service control manager: " + "error %d", GetLastError()); + return; + } char cmd[MAX_PATH]; GetModuleFileName(NULL, cmd, sizeof(cmd)-1); cmd[sizeof(cmd)-1] = 0; char cmd_args[MAX_PATH]; - snprintf(cmd_args, sizeof(cmd_args)-1, "%s --service", cmd); + _snprintf(cmd_args, sizeof(cmd_args)-1, "%s --service", cmd); cmd_args[sizeof(cmd_args)-1] = 0; newService = CreateService( @@ -194,12 +206,31 @@ void InstallService(void) "Box Backup", SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, - SERVICE_DEMAND_START, + SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, cmd_args, 0,0,0,0,0); - if (newService) CloseServiceHandle(newService); + if (!newService) + { + ::syslog(LOG_ERR, "Failed to create Box Backup service: " + "error %d", GetLastError()); + return; + } + + ::syslog(LOG_INFO, "Created Box Backup service"); + + SERVICE_DESCRIPTION desc; + desc.lpDescription = "Backs up your data files over the Internet"; + + if (!ChangeServiceConfig2(newService, SERVICE_CONFIG_DESCRIPTION, + &desc)) + { + ::syslog(LOG_WARNING, "Failed to set description for " + "Box Backup service: error %d", GetLastError()); + } + + CloseServiceHandle(newService); CloseServiceHandle(scm); } @@ -210,23 +241,31 @@ void RemoveService(void) scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE); - if (!scm) return; + if (!scm) + { + syslog(LOG_ERR, "Failed to open service control manager: " + "error %d", GetLastError()); + return; + } service = OpenService(scm, SERVICE_NAME, SERVICE_ALL_ACCESS|DELETE); ControlService(service, SERVICE_CONTROL_STOP, &status); if (!service) { - printf("Failed to open service manager"); + syslog(LOG_ERR, "Failed to open Box Backup service: " + "error %d", GetLastError()); return; } + if (DeleteService(service)) { - printf("Service removed"); + syslog(LOG_INFO, "Box Backup service deleted"); } else { - printf("Failed to remove service"); + syslog(LOG_ERR, "Failed to remove Box Backup service: " + "error %d", GetLastError()); } CloseServiceHandle(service); diff --git a/bin/bbackupd/bbackupd.cpp b/bin/bbackupd/bbackupd.cpp index 1c870317..089b2d09 100644 --- a/bin/bbackupd/bbackupd.cpp +++ b/bin/bbackupd/bbackupd.cpp @@ -48,13 +48,19 @@ int main(int argc, const char *argv[]) InstallService(); return 0; } - + + bool runAsWin32Service = false; + if (argc == 2 && ::strcmp(argv[1], "--service") == 0) + { + runAsWin32Service = true; + } + // Under win32 we must initialise the Winsock library // before using sockets WSADATA info; - if (WSAStartup(MAKELONG(1, 1), &info) == SOCKET_ERROR) + if (WSAStartup(0x0101, &info) == SOCKET_ERROR) { // box backup will not run without sockets ::syslog(LOG_ERR, "Failed to initialise Windows Sockets"); @@ -65,7 +71,7 @@ int main(int argc, const char *argv[]) int ExitCode = 0; - if (argc == 2 && ::strcmp(argv[1], "--service") == 0) + if (runAsWin32Service) { syslog(LOG_INFO,"Starting Box Backup Service"); OurService(); -- cgit v1.2.3