/*++ Copyright (c) 1995 Microsoft Corporation Module Name: net\routing\ipx\sap\svcsif.c Abstract: SAP interface with service controller (API for standalone SAP agent part of services.exe) Author: Vadim Eydelman 05-15-1995 Revision History: --*/ #include "sapp.h" // SAP service status (when operating standalone outside of router) SERVICE_STATUS_HANDLE ServiceStatusHandle; SERVICE_STATUS ServiceStatus; volatile HANDLE ServiceThreadHdl; VOID ServiceMain ( DWORD argc, LPTSTR argv[] ); VOID APIENTRY ResumeServiceThread ( ULONG_PTR param ) { return ; } VOID ServiceHandler ( DWORD fdwControl ) { ASSERT (ServiceStatusHandle!=0); EnterCriticalSection (&OperationalStateLock); switch (fdwControl) { case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: #if DBG DbgPrint ("IPXSAP: Service control stop/shutdown.\n"); #endif if (ServiceIfActive) { ServiceIfActive = FALSE; if (ServiceThreadHdl!=NULL) { BOOL res; HANDLE localHdl = ServiceThreadHdl; ServiceThreadHdl = NULL; #if DBG DbgPrint ("IPXSAP: Resuming service thread.\n"); #endif res = QueueUserAPC ( ResumeServiceThread, localHdl, 0); ASSERTMSG ("Could not queue APC to service thread ", res); CloseHandle (localHdl); } ServiceStatus.dwCheckPoint += 1; ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING; } else Trace (DEBUG_FAILURES, "SAP service has already been told to stop."); break; case SERVICE_CONTROL_INTERROGATE: #if DBG DbgPrint ("IPXSAP: Service control interrogate.\n"); #endif switch (OperationalState) { case OPER_STATE_UP: if (ServiceIfActive) ServiceStatus.dwCurrentState = SERVICE_RUNNING; else ServiceStatus.dwCurrentState = SERVICE_STOPPED; break; case OPER_STATE_STARTING: if (ServiceIfActive) { ServiceStatus.dwCheckPoint += 1; ServiceStatus.dwCurrentState = SERVICE_START_PENDING; } else ServiceStatus.dwCurrentState = SERVICE_STOPPED; break; case OPER_STATE_STOPPING: if (ServiceIfActive) // This is the case when router is being stopped // SAP will be restarted soon ServiceStatus.dwCurrentState = SERVICE_RUNNING; else { ServiceStatus.dwCheckPoint += 1; ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING; } break; case OPER_STATE_DOWN: if (ServiceIfActive) { // This is the case when service is being started ServiceStatus.dwCheckPoint += 1; ServiceStatus.dwCurrentState = SERVICE_START_PENDING; } else ServiceStatus.dwCurrentState = SERVICE_STOPPED; break; default: ASSERTMSG ("SAP is in unknown state ", FALSE); } break; default: Trace (DEBUG_FAILURES, "Service control handler called with unknown" " or unsupported code %d.", fdwControl); break; } #if DBG DbgPrint ("IPXSAP: Service control setting current state to %d.\n", ServiceStatus.dwCurrentState); #endif SetServiceStatus (ServiceStatusHandle, &ServiceStatus); LeaveCriticalSection (&OperationalStateLock); } /*++ ******************************************************************* S e r v i c e M a i n Routine Description: Entry point to be called by service controller to start SAP agent (when SAP is not part of the router but is a standalone service, though running in the router process) Arguments: argc - number of string arguments passed to service argv - array of string arguments passed to service Return Value: None ******************************************************************* --*/ VOID ServiceMain ( DWORD argc, LPWSTR argv[] ) { DWORD rc; ServiceStatusHandle = RegisterServiceCtrlHandler ( TEXT("nwsapagent"), ServiceHandler); if (!ServiceStatusHandle) { return; } ServiceStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS; ServiceStatus.dwCurrentState = SERVICE_START_PENDING; SetServiceStatus (ServiceStatusHandle, &ServiceStatus); rc = DuplicateHandle (GetCurrentProcess (), GetCurrentThread (), GetCurrentProcess (), (HANDLE *)&ServiceThreadHdl, 0, FALSE, DUPLICATE_SAME_ACCESS ); ASSERTMSG ("Could not duplicate service thread handle ", rc); EnterCriticalSection (&OperationalStateLock); ServiceIfActive = TRUE; if (RouterIfActive) { ServiceStatus.dwCurrentState = SERVICE_RUNNING; ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; SetServiceStatus (ServiceStatusHandle, &ServiceStatus); LeaveCriticalSection (&OperationalStateLock); #if DBG DbgPrint ("IPXSAP: Suspending service thread.\n"); #endif while (ServiceThreadHdl!=NULL) { SleepEx (INFINITE, TRUE); #if DBG DbgPrint ("IPXSAP: Service thread awakened.\n"); #endif } #if DBG DbgPrint ("IPXSAP: Service thread resumed.\n"); #endif EnterCriticalSection (&OperationalStateLock); if (!RouterIfActive) { if (OperationalState==OPER_STATE_UP) StopSAP (); LeaveCriticalSection (&OperationalStateLock); #if DBG DbgPrint ("IPXSAP: Waiting for main thread to exit.\n"); #endif rc = WaitForSingleObject (MainThreadHdl, INFINITE); ASSERTMSG ("Unexpected result from wait for sap main thread ", rc== WAIT_OBJECT_0); EnterCriticalSection (&OperationalStateLock); CloseHandle (MainThreadHdl); MainThreadHdl = NULL; } } else { BOOL bInternalNetNumOk; // [pmay] // We use this scheme to automatically select the internal network // number of the machine we're running on. If the net number is configured // as zero, this function will automatically select a random net num and // verify it's uniqueness on the net that this machine is attached to. DbgInitialize (hDLLInstance); if (AutoValidateInternalNetNum(&bInternalNetNumOk, DEBUG_ADAPTERS) == NO_ERROR) { if (!bInternalNetNumOk) { if (PnpAutoSelectInternalNetNumber(DEBUG_ADAPTERS) != NO_ERROR) Trace(DEBUG_ADAPTERS, "StartRouter: Auto selection of net number failed."); else AutoWaitForValidIntNetNum (10, NULL); } } ServiceStatus.dwWin32ExitCode = CreateAllComponents (NULL); if (ServiceStatus.dwWin32ExitCode==NO_ERROR) { // We use the thread that we were launched in // as IO thread ServiceStatus.dwWin32ExitCode = StartSAP (); if (ServiceStatus.dwWin32ExitCode==NO_ERROR) { LeaveCriticalSection (&OperationalStateLock); ServiceStatus.dwCurrentState = SERVICE_RUNNING; ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; SetServiceStatus (ServiceStatusHandle, &ServiceStatus); #if DBG DbgPrint ("IPXSAP: Suspending service thread.\n"); #endif while (ServiceThreadHdl!=NULL) { SleepEx (INFINITE, TRUE); #if DBG DbgPrint ("IPXSAP: Service thread awakened.\n"); #endif } #if DBG DbgPrint ("IPXSAP: Service thread resumed.\n"); #endif EnterCriticalSection (&OperationalStateLock); ServiceIfActive = FALSE; if (!RouterIfActive) { if (OperationalState==OPER_STATE_UP) StopSAP (); LeaveCriticalSection (&OperationalStateLock); #if DBG DbgPrint ("IPXSAP: Waiting for main thread to exit.\n"); #endif rc = WaitForSingleObject (MainThreadHdl, INFINITE); ASSERTMSG ("Unexpected result from wait for sap main thread ", rc== WAIT_OBJECT_0); EnterCriticalSection (&OperationalStateLock); } CloseHandle (MainThreadHdl); MainThreadHdl = NULL; } else { DeleteAllComponents (); } } } ServiceIfActive = FALSE; LeaveCriticalSection (&OperationalStateLock); #if DBG DbgPrint ("IPXSAP: Service stopped.\n"); #endif ServiceStatus.dwCurrentState = SERVICE_STOPPED; SetServiceStatus (ServiceStatusHandle, &ServiceStatus); }