From 9febc82acf317ea16ddb04cda88e24051bacd8c4 Mon Sep 17 00:00:00 2001 From: Eric Kohl Date: Wed, 21 Mar 2018 21:07:26 +0100 Subject: [PATCH] [DHCPCSVC] Add the ability to stop the DHCP client - Use a stop event to terminate the dispatch loop. - Report to the services manager that the service can be stopped or shut-down while it is running. CORE-14390 --- base/services/dhcpcsvc/dhcp/dispatch.c | 48 +++++++++++++++----------- base/services/dhcpcsvc/dhcpcsvc.c | 44 +++++++++++------------ base/services/dhcpcsvc/include/dhcpd.h | 2 +- 3 files changed, 51 insertions(+), 43 deletions(-) diff --git a/base/services/dhcpcsvc/dhcp/dispatch.c b/base/services/dhcpcsvc/dhcp/dispatch.c index d9ef98271ad..d72e0928047 100644 --- a/base/services/dhcpcsvc/dhcp/dispatch.c +++ b/base/services/dhcpcsvc/dhcp/dispatch.c @@ -63,21 +63,23 @@ void (*bootp_packet_handler)(struct interface_info *, * bootp_packet_handler hook to try to do something with it. */ void -dispatch(void) +dispatch(HANDLE hStopEvent) { int count, to_msec; struct protocol *l; time_t howlong, cur_time; - HANDLE Events[2]; - int EventCount = 1; + HANDLE Events[3]; + int EventCount = 2; Events[0] = StartAdapterDiscovery(); if (!Events[0]) return; + AdapterStateChangedEvent = Events[0]; - - Events[1] = WSA_INVALID_EVENT; - + + Events[1] = hStopEvent; + Events[2] = WSA_INVALID_EVENT; + ApiLock(); do { @@ -116,29 +118,29 @@ dispatch(void) to_msec = INFINITE; } - if (Events[1] == WSA_INVALID_EVENT && DhcpSocket != INVALID_SOCKET) + if (Events[2] == WSA_INVALID_EVENT && DhcpSocket != INVALID_SOCKET) { - Events[1] = WSACreateEvent(); - if (Events[1] != WSA_INVALID_EVENT) + Events[2] = WSACreateEvent(); + if (Events[2] != WSA_INVALID_EVENT) { - count = WSAEventSelect(DhcpSocket, Events[1], FD_READ | FD_CLOSE); + count = WSAEventSelect(DhcpSocket, Events[2], FD_READ | FD_CLOSE); if (count != NO_ERROR) { - WSACloseEvent(Events[1]); - Events[1] = WSA_INVALID_EVENT; + WSACloseEvent(Events[2]); + Events[2] = WSA_INVALID_EVENT; } else { - EventCount = 2; + EventCount = 3; } } } - else if (Events[1] != WSA_INVALID_EVENT && DhcpSocket == INVALID_SOCKET) + else if (Events[2] != WSA_INVALID_EVENT && DhcpSocket == INVALID_SOCKET) { - WSACloseEvent(Events[1]); - Events[1] = WSA_INVALID_EVENT; + WSACloseEvent(Events[2]); + Events[2] = WSA_INVALID_EVENT; - EventCount = 1; + EventCount = 2; } ApiUnlock(); @@ -153,11 +155,16 @@ dispatch(void) continue; } else if (count == WAIT_OBJECT_0 + 1) + { + /* Stop event signalled */ + break; + } + else if (count == WAIT_OBJECT_0 + 2) { /* Packet received */ - + /* WSA events are manual reset events */ - WSAResetEvent(Events[1]); + WSAResetEvent(Events[2]); } else { @@ -178,7 +185,8 @@ dispatch(void) AdapterStateChangedEvent = NULL; CloseHandle(Events[0]); - WSACloseEvent(Events[1]); + CloseHandle(Events[1]); + WSACloseEvent(Events[2]); ApiUnlock(); } diff --git a/base/services/dhcpcsvc/dhcpcsvc.c b/base/services/dhcpcsvc/dhcpcsvc.c index a96e372fc87..bfd3dbf6a56 100644 --- a/base/services/dhcpcsvc/dhcpcsvc.c +++ b/base/services/dhcpcsvc/dhcpcsvc.c @@ -16,6 +16,7 @@ static WCHAR ServiceName[] = L"DHCP"; SERVICE_STATUS_HANDLE ServiceStatusHandle = 0; SERVICE_STATUS ServiceStatus; +HANDLE hStopEvent = NULL; static HANDLE PipeHandle = INVALID_HANDLE_VALUE; @@ -328,17 +329,18 @@ UpdateServiceStatus(DWORD dwState) ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; ServiceStatus.dwCurrentState = dwState; - ServiceStatus.dwControlsAccepted = 0; + if (dwState == SERVICE_RUNNING) + ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP; + else + ServiceStatus.dwControlsAccepted = 0; ServiceStatus.dwWin32ExitCode = 0; ServiceStatus.dwServiceSpecificExitCode = 0; ServiceStatus.dwCheckPoint = 0; if (dwState == SERVICE_START_PENDING || - dwState == SERVICE_STOP_PENDING || - dwState == SERVICE_PAUSE_PENDING || - dwState == SERVICE_CONTINUE_PENDING) - ServiceStatus.dwWaitHint = 10000; + dwState == SERVICE_STOP_PENDING) + ServiceStatus.dwWaitHint = 1000; else ServiceStatus.dwWaitHint = 0; @@ -355,17 +357,10 @@ ServiceControlHandler(DWORD dwControl, switch (dwControl) { case SERVICE_CONTROL_STOP: + case SERVICE_CONTROL_SHUTDOWN: UpdateServiceStatus(SERVICE_STOP_PENDING); - UpdateServiceStatus(SERVICE_STOPPED); - return ERROR_SUCCESS; - - case SERVICE_CONTROL_PAUSE: - UpdateServiceStatus(SERVICE_PAUSED); - return ERROR_SUCCESS; - - case SERVICE_CONTROL_CONTINUE: - UpdateServiceStatus(SERVICE_START_PENDING); - UpdateServiceStatus(SERVICE_RUNNING); + if (hStopEvent != NULL) + SetEvent(hStopEvent); return ERROR_SUCCESS; case SERVICE_CONTROL_INTERROGATE: @@ -373,12 +368,7 @@ ServiceControlHandler(DWORD dwControl, &ServiceStatus); return ERROR_SUCCESS; - case SERVICE_CONTROL_SHUTDOWN: - UpdateServiceStatus(SERVICE_STOP_PENDING); - UpdateServiceStatus(SERVICE_STOPPED); - return ERROR_SUCCESS; - - default : + default: return ERROR_CALL_NOT_IMPLEMENTED; } } @@ -397,6 +387,16 @@ ServiceMain(DWORD argc, LPWSTR* argv) UpdateServiceStatus(SERVICE_START_PENDING); + /* Create the stop event */ + hStopEvent = CreateEventW(NULL, FALSE, FALSE, NULL); + if (hStopEvent == NULL) + { + UpdateServiceStatus(SERVICE_STOPPED); + return; + } + + UpdateServiceStatus(SERVICE_START_PENDING); + if (!init_client()) { DPRINT1("DHCPCSVC: init_client() failed!\n"); @@ -411,7 +411,7 @@ ServiceMain(DWORD argc, LPWSTR* argv) DH_DbgPrint(MID_TRACE,("Going into dispatch()\n")); DH_DbgPrint(MID_TRACE,("DHCPCSVC: DHCP service is starting up\n")); - dispatch(); + dispatch(hStopEvent); DH_DbgPrint(MID_TRACE,("DHCPCSVC: DHCP service is shutting down\n")); stop_client(); diff --git a/base/services/dhcpcsvc/include/dhcpd.h b/base/services/dhcpcsvc/include/dhcpd.h index d6a2fa405b8..b7b01b4e005 100644 --- a/base/services/dhcpcsvc/include/dhcpd.h +++ b/base/services/dhcpcsvc/include/dhcpd.h @@ -351,7 +351,7 @@ extern void (*bootp_packet_handler)(struct interface_info *, struct dhcp_packet *, int, unsigned int, struct iaddr, struct hardware *); void discover_interfaces(struct interface_info *); void reinitialize_interfaces(void); -void dispatch(void); +void dispatch(HANDLE hStopEvent); void got_one(struct protocol *); void add_timeout(time_t, void (*)(void *), void *); void cancel_timeout(void (*)(void *), void *);