// code for running the server as a background process/daemon/service struct servercontroller { virtual void start() = 0; virtual void keepalive() = 0; virtual void stop() = 0; virtual ~servercontroller() {} int argc; char **argv; }; #ifdef WIN32 struct winservice : servercontroller { SERVICE_STATUS_HANDLE statushandle; SERVICE_STATUS status; HANDLE stopevent; const char *name, *displayname; winservice() : name("assaultcubeserver"), displayname("AssaultCube Server") { callbacks::svc = this; }; ~winservice() { if(status.dwCurrentState != SERVICE_STOPPED) stop(); callbacks::svc = NULL; } void start() // starts the server again on a new thread and returns once the windows service has stopped { SERVICE_TABLE_ENTRY dispatchtable[] = { (LPSTR) name, (LPSERVICE_MAIN_FUNCTION)callbacks::main, NULL, NULL }; if(StartServiceCtrlDispatcher(dispatchtable)) exit(EXIT_SUCCESS); else fatal("an error occurred running the AC server as windows service. make sure you start the server from the service control manager and not from the command line."); } void keepalive() { report(SERVICE_RUNNING, 0); handleevents(); }; void stop() { report(SERVICE_STOP_PENDING, 0); if(stopevent) CloseHandle(stopevent); status.dwControlsAccepted &= ~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); report(SERVICE_STOPPED, 0); } void handleevents() { if(WaitForSingleObject(stopevent, 0) == WAIT_OBJECT_0) stop(); } void WINAPI requesthandler(DWORD ctrl) { switch(ctrl) { case SERVICE_CONTROL_STOP: report(SERVICE_STOP_PENDING, 0); SetEvent(stopevent); return; default: break; } report(status.dwCurrentState, 0); } void report(DWORD state, DWORD wait) { status.dwCurrentState = state; status.dwWaitHint = wait; status.dwWin32ExitCode = NO_ERROR; status.dwControlsAccepted = SERVICE_START_PENDING == state || SERVICE_STOP_PENDING == state ? 0 : SERVICE_ACCEPT_STOP; if(state == SERVICE_RUNNING || state == SERVICE_STOPPED) status.dwCheckPoint = 0; else status.dwCheckPoint++; SetServiceStatus(statushandle, &status); } int WINAPI svcmain() // new server thread's entry point { statushandle = RegisterServiceCtrlHandler(name, (LPHANDLER_FUNCTION)callbacks::requesthandler); if(!statushandle) return EXIT_FAILURE; status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; status.dwServiceSpecificExitCode = 0; report(SERVICE_START_PENDING, 3000); stopevent = CreateEvent(NULL, true, false, NULL); if(!stopevent) { stop(); return EXIT_FAILURE; } extern int main(int argc, char **argv); return main(0, NULL); // todo args } /*bool install() // provide install routine? { SC_HANDLE scm, svc; char path[MAX_PATH]; if(!GetModuleFileName(NULL, path, MAX_PATH)) return false; if((scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)) == NULL) return false; printf("checking if the service is already installed.."); svc = OpenService(scm, name, SC_MANAGER_CONNECT); if(svc) { printf("service already exists.."); return false; } printf("service not found, trying to install it.."); svc = CreateService(scm, name, displayname, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, path, NULL, NULL, NULL, NULL, NULL); if(svc == NULL) { printf("service installation failed"); CloseServiceHandle(scm); return false; } else { CloseServiceHandle(svc); CloseServiceHandle(scm); printf("service installation successfull\n"); return true; } }*/ struct callbacks { static winservice *svc; static int WINAPI main() { return svc->svcmain(); }; static void WINAPI requesthandler(DWORD request) { svc->requesthandler(request); }; }; /*void log(const char *msg, bool error) { HANDLE eventsrc = RegisterEventSource(NULL, "AC Server"); if(eventsrc) { int eventid = ((error ? 0x11 : 0x1) << 10) & (0x1 << 9) & (FACILITY_NULL << 6) & 0x1; // TODO: create event definitions LPCTSTR msgs[1] = { msg }; int r = ReportEvent(eventsrc, error ? EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE, 0, 4, NULL, 1, 0, msgs, NULL); DeregisterEventSource(eventsrc); } }*/ }; winservice *winservice::callbacks::svc = (winservice *)NULL; #elif __GNUC__ struct unixdaemon : servercontroller { // UNDONE, AH }; #endif