home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World 2001 August
/
PCWorld_2001-08_cd.bin
/
Komunikace
/
sambar
/
_setup.1
/
Ntmain.c
< prev
next >
Wrap
C/C++ Source or Header
|
2001-05-13
|
14KB
|
637 lines
/*
** NTMAIN
**
** This is the main driver for the Windows NT Service driver of
** the Sambar Server.
**
** Confidential Property of Tod Sambar
** (c) Copyright Tod Sambar 1997-2001
** All rights reserved.
**
**
** Syntax:
**
** ntserver [-i] [-u] [-d] [-s service-name] [-c config-dir ]
**
** -i Install the Sambar Server as an NT Service
** -u Uninstall the Sambar Server NT Service
** -d Start the Sambar Server in debug mode
** -s Optional service name argument (for installing multiple)
** -c Optional path to the config directory to use.
**
**
** History:
** Chg# Date Description Resp
** ---- ------- ------------------------------------------------------- ----
** 26JUL97 Created sambar
*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <direct.h>
#include <process.h>
#include <sambar.h>
/*
** Local Defines
*/
#define SERVICE_NAME "Sambar Server"
#define SERVICE_TITLE "Sambar Server"
#define NTSERVER_DEBUG (SA_INT)0x0001
#define NTSERVER_INSTALL (SA_INT)0x0002
#define NTSERVER_UNINSTALL (SA_INT)0x0004
#define CK_PIPE 1
/*
** Local Prototypes
*/
static SA_RETCODE get_args(int argc, char **argv, SA_INT *flagsp);
static void syntax_error(char *name, char *argv);
static SA_RETCODE install_service(void);
static SA_RETCODE uninstall_service(void);
VOID service_main(DWORD argc, LPTSTR *argv);
VOID service_ctrl(DWORD dwCtrlCode);
static SA_RETCODE service_cd(void);
static void service_status(int state, int exitCode, int waitHint);
static void HTTPLog(SA_CTX *ctx, SA_HTTPLOG *httplog);
static void create_pipe(void);
static void close_pipe(void);
/*
** Global Handles
*/
static SERVICE_STATUS_HANDLE hServiceStatus;
static int sState;
static boolean bConnected = FALSE;
static HANDLE hIOCP = NULL;
static HANDLE hPipe = NULL;
static OVERLAPPED o;
static SA_INIT SaInit;
static char ConfigDir[256];
static char ServiceName[256];
static char ServiceTitle[256];
int
main(int argc, char *argv[])
{
SA_INT flags;
/* Initialization */
memset(&SaInit, 0, sizeof(SA_INIT));
strcpy(ServiceName, SERVICE_NAME);
strcpy(ServiceTitle, SERVICE_TITLE);
ConfigDir[0] = '\0';
SaInit.i_logfunc = HTTPLog;
SaInit.i_servicename = ServiceName;
/*
** Read the command line arguments.
*/
if (get_args(argc, argv, &flags) != SA_SUCCEED)
return (0);
if (flags & NTSERVER_INSTALL)
{
if (install_service() != SA_SUCCEED)
return (-1);
fprintf(stdout,
"The %s NT Service can be started from the Service Panel.\n",
ServiceName);
return (0);
}
if (flags & NTSERVER_UNINSTALL)
{
if (uninstall_service() != SA_SUCCEED)
return (-1);
return (0);
}
/* Change to the appropriate working directory for execution */
if (service_cd() != SA_SUCCEED)
return (-1);
if (flags & NTSERVER_DEBUG)
{
create_pipe();
/* Execute the Sambar Server Shell */
if (sa_server2((SA_VOID *)&SaInit) != SA_SUCCEED)
{
close_pipe();
return (-1);
}
close_pipe();
}
else
{
SERVICE_TABLE_ENTRY ste[] =
{
{ ServiceName, (LPSERVICE_MAIN_FUNCTION)service_main },
{ NULL, NULL }
};
if (StartServiceCtrlDispatcher(ste) != TRUE)
{
fprintf(stderr, "Failed to start %s NT Service (%d)\n",
ServiceName, GetLastError());
return (-1);
}
}
return (0);
}
/*
** GET_ARGS
**
** This routine parses the command line arguments passed to the
** NT Server application.
**
*/
static SA_RETCODE
get_args(int argc, char **argv, SA_INT *flagsp)
{
int j;
SA_INT flags;
/* Initialization */
flags = 0;
/*
** Are there any arguments to parse?
*/
if (argc <= 1)
{
/*
** We don't have any arguments.
*/
*flagsp = 0;
return (SA_SUCCEED);
}
/* Loop through the arguments */
j = 1;
while (j < argc)
{
if (strcmp(argv[j], "-i") == 0)
{
flags |= NTSERVER_INSTALL;
}
else if (strcmp(argv[j], "-u") == 0)
{
flags |= NTSERVER_UNINSTALL;
}
else if (strcmp(argv[j], "-d") == 0)
{
flags |= NTSERVER_DEBUG;
}
else if (strcmp(argv[j], "-s") == 0)
{
j++;
if (j == argc)
{
syntax_error(argv[0], argv[j]);
return (SA_FAIL);
}
strcpy(ServiceName, argv[j]);
strcpy(ServiceTitle, argv[j]);
}
else if (strcmp(argv[j], "-c") == 0)
{
j++;
if (j == argc)
{
syntax_error(argv[0], argv[j]);
return (SA_FAIL);
}
strcpy(ConfigDir, argv[j]);
SaInit.i_configdir = ConfigDir;
}
else
{
syntax_error(argv[0], argv[j]);
return (SA_FAIL);
}
j++;
}
*flagsp = flags;
/*
** All done.
*/
return (SA_SUCCEED);
}
/*
** SYNTAX_ERROR
**
** This routine is used to inform the user that a command-line
** syntax error occurred.
*/
static void
syntax_error(char *name, char *argv)
{
/*
** Print the error string.
*/
if (argv != NULL)
fprintf(stderr, "\nUnexpected flag: %s\n", argv);
fprintf(stderr, "\nCorrect syntax is: %s\n", name);
fprintf(stderr,
" [-i] # Install the NT Service\n");
fprintf(stderr,
" [-u] # Unistall the NT Service\n");
fprintf(stderr,
" [-d] # Start the Sambar Server in debug mode\n");
fprintf(stderr,
" [-s servicename] # Optional NT Service name (default: Sambar Server)\n");
fprintf(stderr,
" [-c configdir] # Optional config directory (default: Sambar install dir)\n");
return;
}
static SA_RETCODE
install_service(void)
{
SC_HANDLE schService;
SC_HANDLE schSCManager;
TCHAR szPath[256];
TCHAR szCmd[512];
if (GetModuleFileName(NULL, szPath, 256) == 0)
{
fprintf(stderr, "Failed to get exe for service %s (%d)\n",
ServiceName, GetLastError());
return (SA_FAIL);
}
schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (schSCManager == NULL)
{
fprintf(stderr, "Failed to open the service manager.\n");
return (SA_FAIL);
}
if (ConfigDir[0] != '\0')
{
sprintf(szCmd, "\"%s\" -c \"%s\" -s \"%s\"", szPath, ConfigDir,
ServiceName);
}
else if (strcmp(ServiceName, SERVICE_NAME) != 0)
{
sprintf(szCmd, "\"%s\" -s \"%s\"", szPath, ServiceName);
}
else
{
strcpy(szCmd, szPath);
}
schService = CreateService(schSCManager, ServiceName, ServiceTitle,
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
szCmd, NULL, NULL, "Tcpip\0", NULL, NULL);
if (schService == NULL)
{
fprintf(stderr, "Failed to create service %s (%d)\n",
ServiceName, GetLastError());
CloseServiceHandle(schSCManager);
return (SA_FAIL);
}
fprintf(stdout, "Installed service %s.\n", ServiceName);
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return (SA_SUCCEED);
}
static SA_RETCODE
uninstall_service(void)
{
SC_HANDLE schService;
SC_HANDLE schSCManager;
SERVICE_STATUS status;
schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (schSCManager == NULL)
{
fprintf(stderr, "Failed to open the service manager.\n");
return (SA_FAIL);
}
schService = OpenService(schSCManager, ServiceName, SERVICE_ALL_ACCESS);
if (schService == NULL)
{
fprintf(stderr, "Failed to open service %s (%d).\n",
ServiceName, GetLastError());
CloseServiceHandle(schSCManager);
return (SA_FAIL);
}
/* Try to stop the service */
if (ControlService(schService, SERVICE_CONTROL_STOP, &status))
{
Sleep(1000);
while (QueryServiceStatus(schService, &status))
{
if (status.dwCurrentState == SERVICE_STOP_PENDING)
Sleep(1000);
else
break;
}
}
/* Delete the service */
if (DeleteService(schService) != TRUE)
{
fprintf(stderr, "Failed in attempt to delete service %s (%d).\n",
ServiceName, GetLastError());
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return (SA_FAIL);
}
fprintf(stdout, "Deleted service %s.\n", ServiceName);
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return (SA_SUCCEED);
}
VOID
service_main(DWORD argc, LPTSTR *argv)
{
SA_INT flags;
/* Get an configuration arguments */
(void)get_args(argc, argv, &flags);
hServiceStatus = RegisterServiceCtrlHandler(ServiceName,
(LPHANDLER_FUNCTION)service_ctrl);
if (!hServiceStatus)
{
fprintf(stderr, "Failed to register %s service control handler (%d).\n",
ServiceName, GetLastError());
return;
}
service_status(SERVICE_START_PENDING, NO_ERROR, 5000);
service_status(SERVICE_RUNNING, NO_ERROR, 0);
/* Start the Sambar Server */
create_pipe();
sa_server2((SA_VOID *)&SaInit);
close_pipe();
service_status(SERVICE_STOPPED, NO_ERROR, 0);
return;
}
VOID
service_ctrl(DWORD dwCtrlCode)
{
int state;
state = sState;
switch(dwCtrlCode)
{
// Stop the service.
//
case SERVICE_CONTROL_STOP:
case SERVICE_CONTROL_SHUTDOWN:
service_status(SERVICE_STOP_PENDING, NO_ERROR, 8000);
(SA_VOID)sa_shutdown(0);
return;
// Update the service status.
//
case SERVICE_CONTROL_INTERROGATE:
break;
// invalid control code
//
default:
break;
}
service_status(state, NO_ERROR, 0);
}
static void
service_status(int state, int exitCode, int waitHint)
{
SERVICE_STATUS status;
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
status.dwServiceSpecificExitCode = 0;
status.dwCheckPoint = 0;
if (state == SERVICE_START_PENDING)
{
status.dwControlsAccepted = 0;
}
else
{
status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_SHUTDOWN;
}
sState = state;
status.dwCurrentState = state;
status.dwWin32ExitCode = exitCode;
status.dwWaitHint = waitHint;
(VOID)SetServiceStatus(hServiceStatus, &status);
return;
}
static SA_RETCODE
service_cd(void)
{
int count;
DWORD len;
TCHAR szPath[512];
len = GetModuleFileName(NULL, szPath, 512);
if (len == 0)
{
fprintf(stderr, "Failed to get exe for service %s (%d)\n",
ServiceName, GetLastError());
return (SA_FAIL);
}
/*
** Change to the directory above the executable.
**
** The working directory for the Sambar Server application must
** be the installation directory.
*/
count = 0;
while ((len > 0) && (count < 2))
{
len--;
if (szPath[len] == '\\')
{
count++;
szPath[len] = '\0';
}
}
if (count != 2)
{
fprintf(stderr,
"Unable to change to the Sambar Server installation directory.\n");
return (SA_FAIL);
}
if (chdir(szPath) != 0)
{
fprintf(stderr,
"Unable to change to the Sambar Server installation directory.\n");
return (SA_FAIL);
}
return (SA_SUCCEED);
}
static void
create_pipe()
{
/* Create the completion port for named-pipe client connection */
hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, CK_PIPE, 0);
if (hIOCP == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "Failure creating I/O completion port [%d]",
GetLastError());
return;
}
/* Create a pipe that clients can connect to. */
hPipe = CreateNamedPipe("\\\\.\\pipe\\SambarServer",
PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED, PIPE_TYPE_MESSAGE,
1, 0, 1024, 1000, (LPSECURITY_ATTRIBUTES)NULL);
if (hPipe == INVALID_HANDLE_VALUE)
{
fprintf(stderr,
"Failure creating named pipe for interactive display [%d]",
GetLastError());
CloseHandle(hIOCP);
hIOCP = NULL;
}
/* Associate the pipe */
CreateIoCompletionPort(hPipe, hIOCP, CK_PIPE, 0);
/* Pend an asynchronous connect against the pipe. */
memset(&o, 0, sizeof(o));
ConnectNamedPipe(hPipe, &o);
}
static void
close_pipe()
{
if ((hIOCP != NULL) && (hIOCP != INVALID_HANDLE_VALUE))
{
CloseHandle(hIOCP);
hIOCP = NULL;
}
if ((hPipe != NULL) && (hPipe != INVALID_HANDLE_VALUE))
{
CloseHandle(hPipe);
hPipe = NULL;
}
}
static void
HTTPLog(SA_CTX *ctx, SA_HTTPLOG *httplog)
{
int i;
int n;
DWORD dwComp;
DWORD dwBytes;
OVERLAPPED *po;
char timestr[32];
char str[2048];
if ((!bConnected) && (hPipe != NULL) && (hPipe != INVALID_HANDLE_VALUE))
{
while (GetQueuedCompletionStatus(hIOCP, &dwBytes, &dwComp, &po, 0))
{
if (dwComp == CK_PIPE)
{
bConnected = TRUE;
}
}
}
if (!bConnected)
return;
i = 0;
while ((httplog->timestamp[i] != '\0') && (httplog->timestamp[i] != ':'))
i++;
n = 0;
while ((httplog->timestamp[i] != '\0') &&
(httplog->timestamp[i] != ' ') &&
(n < 16))
{
timestr[n] = httplog->timestamp[i];
n++;
i++;
}
timestr[0] = '[';
timestr[n] = ']';
timestr[n+1] = '\0';
sprintf(str, "[%s] %s %s %ld %s %s %ld",
httplog->vhost, timestr, httplog->user, httplog->status,
httplog->method, httplog->request, httplog->size);
if (!WriteFile(hPipe, str, strlen(str), &n, NULL))
{
/* Error occurred writing on pipe, client disconnected. */
bConnected = FALSE;
DisconnectNamedPipe(hPipe);
memset(&o, 0, sizeof(o));
ConnectNamedPipe(hPipe, &o);
}
else
{
FlushFileBuffers(hPipe);
}
return;
}