You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

741 lines
27 KiB

/***************************************************************************/
/* */
/* Project: OpenSLP - OpenSource implementation of Service Location */
/* Protocol Version 2 */
/* */
/* File: slpd_win32.c */
/* */
/* Abstract: Win32 specific part, to make SLPD run as a "service" */
/* */
/*-------------------------------------------------------------------------*/
/* */
/* Please submit patches to http://www.openslp.org */
/* */
/*-------------------------------------------------------------------------*/
/* */
/* Copyright (C) 2000 Caldera Systems, Inc */
/* All rights reserved. */
/* */
/* Redistribution and use in source and binary forms, with or without */
/* modification, are permitted provided that the following conditions are */
/* met: */
/* */
/* Redistributions of source code must retain the above copyright */
/* notice, this list of conditions and the following disclaimer. */
/* */
/* Redistributions in binary form must reproduce the above copyright */
/* notice, this list of conditions and the following disclaimer in */
/* the documentation and/or other materials provided with the */
/* distribution. */
/* */
/* Neither the name of Caldera Systems nor the names of its */
/* contributors may be used to endorse or promote products derived */
/* from this software without specific prior written permission. */
/* */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
/* `AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */
/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE CALDERA */
/* SYSTEMS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */
/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
/* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */
/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
/* */
/***************************************************************************/
#include "slpd.h"
/*=========================================================================*/
/* slpd includes */
/*=========================================================================*/
#include "slpd_cmdline.h"
#include "slpd_log.h"
#include "slpd_property.h"
#include "slpd_database.h"
#include "slpd_socket.h"
#include "slpd_incoming.h"
#include "slpd_outgoing.h"
#include "slpd_knownda.h"
/*=========================================================================*/
/* common code includes */
/*=========================================================================*/
#include "slp_linkedlist.h"
#include "slp_xid.h"
SERVICE_STATUS ssStatus; /* current status of the service */
SERVICE_STATUS_HANDLE sshStatusHandle;
BOOL bDebug = FALSE;
TCHAR szErr[256];
/*-------------------------------------------------------------------------*/
extern int G_SIGTERM;
/* see slpd_main.c */
/*-------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
void LoadFdSets(SLPList* socklist,
int* highfd,
fd_set* readfds,
fd_set* writefds);
/* see slpd_main.c */
/*-------------------------------------------------------------------------*/
/*------------------------------------------------------------------------*/
void HandleSigTerm();
/* see slpd_main.c */
/*------------------------------------------------------------------------*/
/*------------------------------------------------------------------------*/
void HandleSigAlrm();
/* see slpd_main.c */
/*------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
DWORD dwWin32ExitCode,
DWORD dwWaitHint)
/* */
/* PURPOSE: Sets the current status of the service and */
/* reports it to the Service Control Manager */
/* */
/* PARAMETERS: */
/* dwCurrentState - the state of the service */
/* dwWin32ExitCode - error code to report */
/* dwWaitHint - worst case estimate to next checkpoint */
/* */
/* RETURN VALUE: */
/* TRUE - success */
/* FALSE - failure */
/* */
/*--------------------------------------------------------------------------*/
{
static DWORD dwCheckPoint = 1;
BOOL fResult = TRUE;
/* when debugging we don't report to the SCM */
if(G_SlpdCommandLine.action != SLPD_DEBUG)
{
if(dwCurrentState == SERVICE_START_PENDING)
{
ssStatus.dwControlsAccepted = 0;
}
else
{
ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
}
ssStatus.dwCurrentState = dwCurrentState;
ssStatus.dwWin32ExitCode = dwWin32ExitCode;
ssStatus.dwWaitHint = dwWaitHint;
if(( dwCurrentState == SERVICE_RUNNING ) ||
( dwCurrentState == SERVICE_STOPPED ))
{
ssStatus.dwCheckPoint = 0;
}
else
{
ssStatus.dwCheckPoint = dwCheckPoint++;
}
/* Report the status of the service to the service control manager.*/
if(!(fResult = SetServiceStatus( sshStatusHandle, &ssStatus)))
{
SLPDLog("SetServiceStatus failed");
}
}
return fResult;
}
/*--------------------------------------------------------------------------*/
LPTSTR GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize )
/* */
/* PURPOSE: copies error message text to string */
/* */
/* PARAMETERS: */
/* lpszBuf - destination buffer */
/* dwSize - size of buffer */
/* */
/* RETURN VALUE: */
/* destination buffer */
/* */
/*--------------------------------------------------------------------------*/
{
DWORD dwRet;
LPTSTR lpszTemp = NULL;
dwRet = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_ARGUMENT_ARRAY,
NULL,
GetLastError(),
LANG_NEUTRAL,
(LPTSTR)&lpszTemp,
0,
NULL );
/* supplied buffer is not long enough */
if(!dwRet || ( (long)dwSize < (long)dwRet+14 ))
{
lpszBuf[0] = TEXT('\0');
}
else
{
lpszTemp[lstrlen(lpszTemp)-2] = TEXT('\0');
sprintf( lpszBuf, "%s (0x%x)", lpszTemp, GetLastError() );
}
if(lpszTemp)
{
LocalFree((HLOCAL) lpszTemp );
}
return lpszBuf;
}
/*--------------------------------------------------------------------------*/
void ServiceStop()
/*--------------------------------------------------------------------------*/
{
G_SIGTERM = 1;
ReportStatusToSCMgr(SERVICE_STOPPED, /* service state */
NO_ERROR, /* exit code */
3000); /* wait hint */
}
/*--------------------------------------------------------------------------*/
void ServiceStart (int argc, char **argv)
/*--------------------------------------------------------------------------*/
{
fd_set readfds;
fd_set writefds;
int highfd;
int fdcount = 0;
time_t curtime;
time_t alarmtime;
struct timeval timeout;
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(1,1);
/*------------------------*/
/* Service initialization */
/*------------------------*/
if(!ReportStatusToSCMgr(SERVICE_START_PENDING, /* service state*/
NO_ERROR, /* exit code */
3000)) /* wait hint */
{
goto cleanup;
}
if(WSAStartup(wVersionRequested, &wsaData) != 0)
{
(void)ReportStatusToSCMgr(SERVICE_STOP_PENDING,
NO_ERROR,
0);
goto cleanup;
}
/*------------------------*/
/* Parse the command line */
/*------------------------*/
if(SLPDParseCommandLine(argc,argv))
{
ReportStatusToSCMgr(SERVICE_STOP_PENDING, /* service state */
NO_ERROR, /* exit code */
0); /* wait hint */
goto cleanup_winsock;
}
if(!ReportStatusToSCMgr(SERVICE_START_PENDING, /* service state */
NO_ERROR, /* exit code */
3000)) /* wait hint */
{
goto cleanup_winsock;
}
/*------------------------------*/
/* Initialize the log file */
/*------------------------------*/
if(SLPDLogFileOpen(G_SlpdCommandLine.logfile, 1))
{
SLPDLog("Could not open logfile %s\n",G_SlpdCommandLine.logfile);
goto cleanup_winsock;
}
/*------------------------*/
/* Seed the XID generator */
/*------------------------*/
SLPXidSeed();
/*---------------------*/
/* Log startup message */
/*---------------------*/
SLPDLog("****************************************\n");
SLPDLogTime();
SLPDLog("SLPD daemon started\n");
SLPDLog("****************************************\n");
SLPDLog("Command line = %s\n",argv[0]);
SLPDLog("Using configuration file = %s\n",G_SlpdCommandLine.cfgfile);
SLPDLog("Using registration file = %s\n",G_SlpdCommandLine.regfile);
if(!ReportStatusToSCMgr(SERVICE_START_PENDING, /* service state */
NO_ERROR, /* exit code */
3000)) /* wait hint */
{
goto cleanup_winsock;
}
/*--------------------------------------------------*/
/* Initialize for the first time */
/*--------------------------------------------------*/
if(SLPDPropertyInit(G_SlpdCommandLine.cfgfile) ||
SLPDDatabaseInit(G_SlpdCommandLine.regfile) ||
SLPDIncomingInit() ||
SLPDOutgoingInit() ||
SLPDKnownDAInit())
{
SLPDLog("slpd initialization failed\n");
goto cleanup_winsock;
}
SLPDLog("Agent Interfaces = %s\n",G_SlpdProperty.interfaces);
SLPDLog("Agent URL = %s\n",G_SlpdProperty.myUrl);
/* Service is now running, perform work until shutdown */
if(!ReportStatusToSCMgr(SERVICE_RUNNING, /* service state */
NO_ERROR, /* exit code */
0)) /* wait hint */
{
goto cleanup_winsock;
}
/*-----------*/
/* Main loop */
/*-----------*/
SLPDLog("Startup complete entering main run loop ...\n\n");
G_SIGTERM = 0;
curtime = time(&alarmtime);
alarmtime = curtime + SLPD_AGE_INTERVAL;
while(G_SIGTERM == 0)
{
/*--------------------------------------------------------*/
/* Load the fdsets up with all valid sockets in the list */
/*--------------------------------------------------------*/
highfd = 0;
FD_ZERO(&readfds);
FD_ZERO(&writefds);
LoadFdSets(&G_IncomingSocketList, &highfd, &readfds,&writefds);
LoadFdSets(&G_OutgoingSocketList, &highfd, &readfds,&writefds);
/*--------------------------------------------------*/
/* Before select(), check to see if we got a signal */
/*--------------------------------------------------*/
if(G_SIGALRM)
{
goto HANDLE_SIGNAL;
}
/*-------------*/
/* Main select */
/*-------------*/
timeout.tv_sec = SLPD_AGE_INTERVAL;
timeout.tv_usec = 0;
fdcount = select(highfd+1,&readfds,&writefds,0,&timeout);
if(fdcount > 0) /* fdcount will be < 0 when timed out */
{
SLPDIncomingHandler(&fdcount,&readfds,&writefds);
SLPDOutgoingHandler(&fdcount,&readfds,&writefds);
}
/*----------------*/
/* Handle signals */
/*----------------*/
HANDLE_SIGNAL:
curtime = time(&curtime);
if(curtime >= alarmtime)
{
HandleSigAlrm();
alarmtime = curtime + SLPD_AGE_INTERVAL;
}
} /* End of main loop */
/* Got SIGTERM */
HandleSigTerm();
cleanup_winsock:
WSACleanup();
cleanup:
;
}
/*==========================================================================*/
BOOL WINAPI ControlHandler ( DWORD dwCtrlType )
/* */
/* PURPOSE: Handled console control events */
/* */
/* PARAMETERS: */
/* dwCtrlType - type of control event */
/* */
/* RETURN VALUE: */
/* True - handled */
/* False - unhandled */
/* */
/*==========================================================================*/
{
switch(dwCtrlType)
{
case CTRL_BREAK_EVENT: /* use Ctrl+C or Ctrl+Break to simulate */
case CTRL_C_EVENT: /* SERVICE_CONTROL_STOP in debug mode */
printf("Stopping %s.\n", G_SERVICEDISPLAYNAME);
ServiceStop();
return TRUE;
break;
}
return FALSE;
}
/*==========================================================================*/
VOID WINAPI ServiceCtrl(DWORD dwCtrlCode)
/* */
/* PURPOSE: This function is called by the SCM whenever */
/* ControlService() is called on this service. */
/* */
/* PARAMETERS: */
/* dwCtrlCode - type of control requested */
/* */
/* RETURN VALUE: */
/* none */
/* */
/*==========================================================================*/
{
/* Handle the requested control code. */
/* */
switch(dwCtrlCode)
{
/* Stop the service. */
case SERVICE_CONTROL_STOP:
ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 0);
ServiceStop();
return;
/* Update the service status. */
case SERVICE_CONTROL_INTERROGATE:
break;
/* invalid control code */
default:
break;
}
ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
}
/*==========================================================================*/
void WINAPI SLPDServiceMain(DWORD argc, LPTSTR *argv)
/*==========================================================================*/
{
/* register our service control handler: */
sshStatusHandle = RegisterServiceCtrlHandler( G_SERVICENAME, ServiceCtrl);
if(sshStatusHandle != 0)
{
/* SERVICE_STATUS members that don't change */
ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ssStatus.dwServiceSpecificExitCode = 0;
/* report the status to the service control manager. */
if(ReportStatusToSCMgr(SERVICE_START_PENDING, /* service state */
NO_ERROR, /* exit code */
3000)) /* wait hint */
{
ServiceStart(argc, argv);
}
}
/* try to report the stopped status to the service control manager. */
if(sshStatusHandle)
(void)ReportStatusToSCMgr(SERVICE_STOPPED,
0,
0);
}
/*--------------------------------------------------------------------------*/
void SLPDCmdInstallService(int automatic)
/*--------------------------------------------------------------------------*/
{
SC_HANDLE schService;
SC_HANDLE schSCManager;
DWORD start_type;
TCHAR szPath[512];
if(GetModuleFileName( NULL, szPath, 512 ) == 0)
{
printf("Unable to install %s - %s\n",
G_SERVICEDISPLAYNAME,
GetLastErrorText(szErr, 256));
return;
}
if(automatic)
{
start_type = SERVICE_AUTO_START;
}
else
{
start_type = SERVICE_DEMAND_START;
}
schSCManager = OpenSCManager(
NULL, /* machine (NULL == local) */
NULL, /* database (NULL == default) */
SC_MANAGER_ALL_ACCESS); /* access required */
if(schSCManager)
{
schService = CreateService(
schSCManager, /* SCManager database */
G_SERVICENAME, /* name of service */
G_SERVICEDISPLAYNAME, /* name to display */
SERVICE_ALL_ACCESS, /* desired access */
SERVICE_WIN32_OWN_PROCESS, /* service type */
start_type, /* start type */
SERVICE_ERROR_NORMAL, /* error control type */
szPath, /* service's binary */
NULL, /* no load ordering group */
NULL, /* no tag identifier */
"", /* dependencies */
NULL, /* LocalSystem account */
NULL); /* no password */
if(schService)
{
printf("%s installed.\n", G_SERVICEDISPLAYNAME );
CloseServiceHandle(schService);
}
else
{
printf("CreateService failed - %s\n", GetLastErrorText(szErr, 256));
}
CloseServiceHandle(schSCManager);
}
else
printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr,256));
}
static void SLPDHlpStopService(SC_HANDLE schService)
{
/* try to stop the service */
if(ControlService(schService, SERVICE_CONTROL_STOP, &ssStatus))
{
printf("Stopping %s.", G_SERVICEDISPLAYNAME);
Sleep(1000);
while(QueryServiceStatus(schService, &ssStatus))
{
if(ssStatus.dwCurrentState == SERVICE_STOP_PENDING)
{
printf(".");
Sleep(1000);
}
else
break;
}
if(ssStatus.dwCurrentState == SERVICE_STOPPED)
printf("\n%s stopped.\n", G_SERVICEDISPLAYNAME);
else
printf("\n%s failed to stop.\n", G_SERVICEDISPLAYNAME);
}
}
/*--------------------------------------------------------------------------*/
void SLPDCmdRemoveService()
/*--------------------------------------------------------------------------*/
{
SC_HANDLE schService;
SC_HANDLE schSCManager;
schSCManager = OpenSCManager(
NULL, /* machine (NULL == local) */
NULL, /* database (NULL == default) */
SC_MANAGER_ALL_ACCESS); /* access required */
if(schSCManager)
{
schService = OpenService(schSCManager, G_SERVICENAME, SERVICE_ALL_ACCESS);
if(schService)
{
SLPDHlpStopService(schService);
/* now remove the service */
if(DeleteService(schService))
printf("%s removed.\n", G_SERVICEDISPLAYNAME );
else
printf("DeleteService failed - %s\n", GetLastErrorText(szErr,256));
CloseServiceHandle(schService);
}
else
printf("OpenService failed - %s\n", GetLastErrorText(szErr,256));
CloseServiceHandle(schSCManager);
}
else
printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr,256));
}
/*--------------------------------------------------------------------------*/
void SLPDCmdStartService()
/*--------------------------------------------------------------------------*/
{
SC_HANDLE schService;
SC_HANDLE schSCManager;
schSCManager = OpenSCManager(
NULL, /* machine (NULL == local) */
NULL, /* database (NULL == default) */
SC_MANAGER_ALL_ACCESS); /* access required */
if(schSCManager)
{
schService = OpenService(schSCManager, G_SERVICENAME, SERVICE_ALL_ACCESS);
if(schService)
{
if( !StartService(schService, 0, NULL))
{
printf("OpenService failed - %s\n", GetLastErrorText(szErr,256));
}
CloseServiceHandle(schService);
}
else
{
printf("OpenService failed - %s\n", GetLastErrorText(szErr,256));
}
CloseServiceHandle(schSCManager);
}
else
{
printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr,256));
}
}
/*--------------------------------------------------------------------------*/
void SLPDCmdStopService()
/*--------------------------------------------------------------------------*/
{
SC_HANDLE schService;
SC_HANDLE schSCManager;
schSCManager = OpenSCManager(
NULL, /* machine (NULL == local) */
NULL, /* database (NULL == default) */
SC_MANAGER_ALL_ACCESS); /* access required */
if(schSCManager)
{
schService = OpenService(schSCManager, G_SERVICENAME, SERVICE_ALL_ACCESS);
if(schService)
{
SLPDHlpStopService(schService);
CloseServiceHandle(schService);
}
else
{
printf("OpenService failed - %s\n", GetLastErrorText(szErr,256));
}
CloseServiceHandle(schSCManager);
}
else
{
printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr,256));
}
}
/*--------------------------------------------------------------------------*/
void SLPDCmdDebugService(int argc, char ** argv)
/*--------------------------------------------------------------------------*/
{
printf("Debugging %s.\n", G_SERVICEDISPLAYNAME);
SetConsoleCtrlHandler( ControlHandler, TRUE );
ServiceStart( argc, argv );
}
/*==========================================================================*/
void __cdecl main(int argc, char **argv)
/*==========================================================================*/
{
SERVICE_TABLE_ENTRY dispatchTable[] =
{
{ G_SERVICENAME, (LPSERVICE_MAIN_FUNCTION)SLPDServiceMain},
{ NULL, NULL}
};
/*------------------------*/
/* Parse the command line */
/*------------------------*/
if(SLPDParseCommandLine(argc,argv))
{
SLPDFatal("Invalid command line\n");
}
switch(G_SlpdCommandLine.action)
{
case SLPD_DEBUG:
SLPDCmdDebugService(argc, argv);
break;
case SLPD_INSTALL:
SLPDCmdInstallService(G_SlpdCommandLine.autostart);
break;
case SLPD_REMOVE:
SLPDCmdRemoveService();
break;
case SLPD_START:
SLPDCmdStartService();
break;
case SLPD_STOP:
SLPDCmdStopService();
break;
default:
SLPDPrintUsage();
StartServiceCtrlDispatcher(dispatchTable);
break;
}
}