server-1.12/server/win32.c

393 lines
9.8 KiB
C

/*
CrossFire, A Multiplayer game for X-windows
Copyright (C) 1992 Frank Tore Johansen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY 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., 675 Mass Ave, Cambridge, MA 02139, USA.
The author can be reached via e-mail to frankj@ifi.uio.no.
*/
/**
* @file
* Windows-related compatibility functions.
*
* This file should probably not be used apart under Windows.
*/
#include <global.h>
#include <stdarg.h>
#include <malloc.h>
#include <string.h>
#include <errno.h>
#include <mmsystem.h>
/** Timezone structure, for gettimeofday(). */
struct timezone {
int tz_minuteswest;
int tz_dsttime;
};
/**
* Gets the time of the day.
*
* @param[out] time_Info
* will receive the time of the day.
* @param[out] timezone_Info
* will receive the timezone info.
* @return
* 0.
*/
int gettimeofday(struct timeval *time_Info, struct timezone *timezone_Info) {
/* Get the time, if they want it */
if (time_Info != NULL) {
time_Info->tv_sec = time(NULL);
time_Info->tv_usec = timeGetTime()*1000;
}
/* Get the timezone, if they want it */
if (timezone_Info != NULL) {
_tzset();
timezone_Info->tz_minuteswest = _timezone;
timezone_Info->tz_dsttime = _daylight;
}
/* And return */
return 0;
}
/**
* Opens a directory for reading. The handle should be disposed through closedir().
*
* @param dir
* directory path.
* @return
* directory handle, NULL if failure.
*/
DIR *opendir(const char *dir) {
DIR *dp;
char *filespec;
long handle;
int index;
filespec = malloc(strlen(dir)+2+1);
strcpy(filespec, dir);
index = strlen(filespec)-1;
if (index >= 0 && (filespec[index] == '/' || filespec[index] == '\\'))
filespec[index] = '\0';
strcat(filespec, "/*");
dp = (DIR *)malloc(sizeof(DIR));
dp->offset = 0;
dp->finished = 0;
dp->dir = strdup(dir);
if ((handle = _findfirst(filespec, &(dp->fileinfo))) < 0) {
free(filespec);
free(dp);
return NULL;
}
dp->handle = handle;
free(filespec);
return dp;
}
/**
* Returns the next file/directory for specified directory handle, obtained through
* a call to opendir().
*
* @param dp
* handle.
* @return
* next file/directory, NULL if end reached.
*/
struct dirent *readdir(DIR *dp) {
if (!dp || dp->finished)
return NULL;
if (dp->offset != 0) {
if (_findnext(dp->handle, &(dp->fileinfo)) < 0) {
dp->finished = 1;
if (ENOENT == errno)
/* Clear error set to mean no more files else that breaks things */
errno = 0;
return NULL;
}
}
dp->offset++;
strncpy(dp->dent.d_name, dp->fileinfo.name, _MAX_FNAME);
dp->dent.d_name[_MAX_FNAME] = '\0';
dp->dent.d_ino = 1;
/* reclen is used as meaning the length of the whole record */
dp->dent.d_reclen = strlen(dp->dent.d_name)+sizeof(char)+sizeof(dp->dent.d_ino)+sizeof(dp->dent.d_reclen)+sizeof(dp->dent.d_off);
dp->dent.d_off = dp->offset;
return &(dp->dent);
}
/**
* Dispose of a directory handle.
*
* @param dp
* handle to free. Will become invalid.
* @return
* 0.
*/
int closedir(DIR *dp) {
if (!dp)
return 0;
_findclose(dp->handle);
if (dp->dir)
free(dp->dir);
if (dp)
free(dp);
return 0;
}
/**
* Restart a directory listing from the beginning.
*
* @param dir_Info
* handle to rewing.
*/
void rewinddir(DIR *dir_Info) {
/* Re-set to the beginning */
char *filespec;
long handle;
int index;
dir_Info->handle = 0;
dir_Info->offset = 0;
dir_Info->finished = 0;
filespec = malloc(strlen(dir_Info->dir)+2+1);
strcpy(filespec, dir_Info->dir);
index = strlen(filespec)-1;
if (index >= 0 && (filespec[index] == '/' || filespec[index] == '\\'))
filespec[index] = '\0';
strcat(filespec, "/*");
if ((handle = _findfirst(filespec, &(dir_Info->fileinfo))) < 0) {
if (errno == ENOENT) {
dir_Info->finished = 1;
}
}
dir_Info->handle = handle;
free(filespec);
}
/* Service-related stuff
Those functions are called while init is still being done, so no logging available.
Not useful for plugins, though.
*/
/** Will be set to FALSE when the server should stop running because the service is turned off. */
int bRunning;
#ifndef PYTHON_PLUGIN_EXPORTS
SERVICE_STATUS m_ServiceStatus;
SERVICE_STATUS_HANDLE m_ServiceStatusHandle;
/** Internal name of the service. */
#define SERVICE_NAME "Crossfire"
/** Name that will appear in the service list. */
#define SERVICE_DISPLAY "Crossfire server"
/** Description of the service. */
#define SERVICE_DESCRIPTION "Crossfire is a multiplayer online RPG game."
#include <winsvc.h>
/**
* Registers the server to the service manager.
* @sa service_unregister().
*/
void service_register() {
char strDir[1024];
HANDLE schSCManager, schService;
char *strDescription = SERVICE_DESCRIPTION;
GetModuleFileName(NULL, strDir, 1024);
strcat(strDir, " -srv");
schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (schSCManager == NULL) {
printf("openscmanager failed");
exit(1);
}
schService = CreateService(schSCManager,
SERVICE_NAME,
SERVICE_DISPLAY, /* service name to display */
SERVICE_ALL_ACCESS, /* desired access */
SERVICE_WIN32_OWN_PROCESS, /* service type */
SERVICE_DEMAND_START, /* start type */
SERVICE_ERROR_NORMAL, /* error control type */
strDir, /* service's binary */
NULL, /* no load ordering group */
NULL, /* no tag identifier */
NULL, /* no dependencies */
NULL, /* LocalSystem account */
NULL); /* no password */
if (schService == NULL) {
printf("createservice failed");
exit(1);
}
ChangeServiceConfig2(schService, SERVICE_CONFIG_DESCRIPTION, &strDescription);
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
exit(0);
}
/**
* Removes the Crossfire service from the service manager.
* @sa service_register().
*/
void service_unregister() {
HANDLE schSCManager;
SC_HANDLE hService;
schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (schSCManager == NULL) {
printf("open failed");
exit(1);
}
hService = OpenService(schSCManager, SERVICE_NAME, SERVICE_ALL_ACCESS);
if (hService == NULL) {
printf("openservice failed");
exit(1);
}
if (DeleteService(hService) == 0) {
printf("Delete failed");
exit(1);
}
if (CloseServiceHandle(hService) == 0) {
printf("close failed");
exit(1);
}
if (!CloseServiceHandle(schSCManager)) {
printf("close schSCManager failed");
exit(1);
}
exit(0);
}
/**
* Main service dispatch routine.
*
* @param Opcode
* service operation, like pause/start/stop.
*/
void WINAPI ServiceCtrlHandler(DWORD Opcode) {
switch (Opcode) {
case SERVICE_CONTROL_PAUSE:
m_ServiceStatus.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
m_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
break;
case SERVICE_CONTROL_STOP:
m_ServiceStatus.dwWin32ExitCode = 0;
m_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
m_ServiceStatus.dwCheckPoint = 0;
m_ServiceStatus.dwWaitHint = 0;
SetServiceStatus(m_ServiceStatusHandle, &m_ServiceStatus);
bRunning = 0;
LOG(llevInfo, "Service stopped.\n");
break;
case SERVICE_CONTROL_INTERROGATE:
break;
}
return;
}
extern int main(int argc, char **argv);
/**
* Main service entrypoint.
*
* @param argc
* @param argv
* arguments to the service.
*/
void WINAPI ServiceMain(DWORD argc, LPTSTR *argv) {
char strDir[1024];
char *strSlash;
GetModuleFileName(NULL, strDir, 1024);
strSlash = strrchr(strDir, '\\');
if (strSlash)
*strSlash = '\0';
chdir(strDir);
m_ServiceStatus.dwServiceType = SERVICE_WIN32;
m_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
m_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
m_ServiceStatus.dwWin32ExitCode = 0;
m_ServiceStatus.dwServiceSpecificExitCode = 0;
m_ServiceStatus.dwCheckPoint = 0;
m_ServiceStatus.dwWaitHint = 0;
m_ServiceStatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler);
if (m_ServiceStatusHandle == (SERVICE_STATUS_HANDLE)0) {
return;
}
m_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
m_ServiceStatus.dwCheckPoint = 0;
m_ServiceStatus.dwWaitHint = 0;
SetServiceStatus(m_ServiceStatusHandle, &m_ServiceStatus);
bRunning = 1;
main(0, NULL);
return;
}
/**
* Service entry point.
*/
void service_handle() {
SERVICE_TABLE_ENTRY DispatchTable[] = {
{ SERVICE_NAME, ServiceMain },
{ NULL, NULL }
};
StartServiceCtrlDispatcher(DispatchTable);
exit(0);
}
#endif /* PYTHON_PLUGIN_EXPORTS */