From 12f1e92c72a1f2b6dba6f22832ed9ee8ddd4f64f Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Wed, 11 Jan 2012 22:24:49 +0000 Subject: [PATCH] [DHCPCSVC] - Fix ipconfig hang with ipconfig /renew and ipconfig /release - Fix duplicate protocol entries being added for the same adapter - Use WSAEventSelect and WaitForMultipleObjects to manage waiting between timeouts, adapter state changes, and incoming packets svn path=/branches/wlan-bringup/; revision=54912 --- dll/win32/dhcpcsvc/dhcp/adapter.c | 9 ++- dll/win32/dhcpcsvc/dhcp/api.c | 33 ++++++++- dll/win32/dhcpcsvc/dhcp/dispatch.c | 109 ++++++++++++++++++----------- 3 files changed, 105 insertions(+), 46 deletions(-) diff --git a/dll/win32/dhcpcsvc/dhcp/adapter.c b/dll/win32/dhcpcsvc/dhcp/adapter.c index 78479f64e01..d79b76b112b 100644 --- a/dll/win32/dhcpcsvc/dhcp/adapter.c +++ b/dll/win32/dhcpcsvc/dhcp/adapter.c @@ -1,6 +1,6 @@ #include "rosdhcp.h" -static SOCKET DhcpSocket = INVALID_SOCKET; +SOCKET DhcpSocket = INVALID_SOCKET; static LIST_ENTRY AdapterList; static WSADATA wsd; @@ -209,6 +209,7 @@ DWORD WINAPI AdapterDiscoveryThread(LPVOID Context) { PDHCP_ADAPTER Adapter = NULL; HANDLE AdapterStateChangedEvent = (HANDLE)Context; struct interface_info *ifi = NULL; + struct protocol *proto; int i, AdapterCount = 0, Broadcast; /* FIXME: Kill this thread when the service is stopped */ @@ -245,6 +246,10 @@ DWORD WINAPI AdapterDiscoveryThread(LPVOID Context) { /* We're still active so we stay in the list */ ifi = &Adapter->DhclientInfo; } else { + proto = find_protocol_by_adapter(&Adapter->DhclientInfo); + if (proto) + remove_protocol(proto); + /* We've lost our link so out we go */ RemoveEntryList(&Adapter->ListEntry); free(Adapter); @@ -330,7 +335,7 @@ DWORD WINAPI AdapterDiscoveryThread(LPVOID Context) { Adapter->DhclientInfo.rfdesc, got_one, &Adapter->DhclientInfo); - state_init(&Adapter->DhclientInfo); + state_init(&Adapter->DhclientInfo); } ApiLock(); diff --git a/dll/win32/dhcpcsvc/dhcp/api.c b/dll/win32/dhcpcsvc/dhcp/api.c index 7623be382ac..02add5033d8 100644 --- a/dll/win32/dhcpcsvc/dhcp/api.c +++ b/dll/win32/dhcpcsvc/dhcp/api.c @@ -14,6 +14,8 @@ static CRITICAL_SECTION ApiCriticalSection; +extern HANDLE AdapterStateChangedEvent; + VOID ApiInit() { InitializeCriticalSection( &ApiCriticalSection ); } @@ -35,6 +37,7 @@ VOID ApiFree() { DWORD DSLeaseIpAddress( PipeSendFunc Send, COMM_DHCP_REQ *Req ) { COMM_DHCP_REPLY Reply; PDHCP_ADAPTER Adapter; + struct protocol* proto; ApiLock(); @@ -43,11 +46,19 @@ DWORD DSLeaseIpAddress( PipeSendFunc Send, COMM_DHCP_REQ *Req ) { Reply.Reply = Adapter ? 1 : 0; if( Adapter ) { + proto = find_protocol_by_adapter( &Adapter->DhclientInfo ); + if (proto) + remove_protocol(proto); + add_protocol( Adapter->DhclientInfo.name, Adapter->DhclientInfo.rfdesc, got_one, &Adapter->DhclientInfo ); - Adapter->DhclientInfo.client->state = S_INIT; - state_reboot(&Adapter->DhclientInfo); + + Adapter->DhclientInfo.client->state = S_INIT; + state_reboot(&Adapter->DhclientInfo); + + if (AdapterStateChangedEvent != NULL) + SetEvent(AdapterStateChangedEvent); } ApiUnlock(); @@ -95,6 +106,12 @@ DWORD DSReleaseIpAddressLease( PipeSendFunc Send, COMM_DHCP_REQ *Req ) { proto = find_protocol_by_adapter( &Adapter->DhclientInfo ); if (proto) remove_protocol(proto); + + Adapter->DhclientInfo.client->active = NULL; + Adapter->DhclientInfo.client->state = S_INIT; + + if (AdapterStateChangedEvent != NULL) + SetEvent(AdapterStateChangedEvent); } ApiUnlock(); @@ -105,6 +122,7 @@ DWORD DSReleaseIpAddressLease( PipeSendFunc Send, COMM_DHCP_REQ *Req ) { DWORD DSRenewIpAddressLease( PipeSendFunc Send, COMM_DHCP_REQ *Req ) { COMM_DHCP_REPLY Reply; PDHCP_ADAPTER Adapter; + struct protocol* proto; ApiLock(); @@ -118,12 +136,20 @@ DWORD DSRenewIpAddressLease( PipeSendFunc Send, COMM_DHCP_REQ *Req ) { Reply.Reply = 1; + proto = find_protocol_by_adapter( &Adapter->DhclientInfo ); + if (proto) + remove_protocol(proto); + add_protocol( Adapter->DhclientInfo.name, Adapter->DhclientInfo.rfdesc, got_one, &Adapter->DhclientInfo ); + Adapter->DhclientInfo.client->state = S_INIT; state_reboot(&Adapter->DhclientInfo); + if (AdapterStateChangedEvent != NULL) + SetEvent(AdapterStateChangedEvent); + ApiUnlock(); return Send( &Reply ); @@ -154,6 +180,9 @@ DWORD DSStaticRefreshParams( PipeSendFunc Send, COMM_DHCP_REQ *Req ) { &Adapter->NteContext, &Adapter->NteInstance ); Reply.Reply = NT_SUCCESS(Status); + + if (AdapterStateChangedEvent != NULL) + SetEvent(AdapterStateChangedEvent); } ApiUnlock(); diff --git a/dll/win32/dhcpcsvc/dhcp/dispatch.c b/dll/win32/dhcpcsvc/dhcp/dispatch.c index d3872d0d02f..013ef14b4af 100644 --- a/dll/win32/dhcpcsvc/dhcp/dispatch.c +++ b/dll/win32/dhcpcsvc/dhcp/dispatch.c @@ -47,6 +47,8 @@ //#include //#include +extern SOCKET DhcpSocket; +HANDLE AdapterStateChangedEvent = NULL; struct protocol *protocols = NULL; struct timeout *timeouts = NULL; static struct timeout *free_timeouts = NULL; @@ -63,17 +65,19 @@ void (*bootp_packet_handler)(struct interface_info *, void dispatch(void) { - int count, to_msec, err; + int count, to_msec; struct protocol *l; - fd_set fds; time_t howlong, cur_time; - struct timeval timeval; - HANDLE AdapterStateChangedEvent; + HANDLE Events[2]; + int EventCount = 1; - AdapterStateChangedEvent = StartAdapterDiscovery(); - if (!AdapterStateChangedEvent) + Events[0] = StartAdapterDiscovery(); + if (!Events[0]) return; - + AdapterStateChangedEvent = Events[0]; + + Events[1] = WSA_INVALID_EVENT; + ApiLock(); do { @@ -83,7 +87,8 @@ dispatch(void) */ time(&cur_time); - if (timeouts) { + if (timeouts) + { struct timeout *t; if (timeouts->when <= cur_time) { @@ -105,55 +110,75 @@ dispatch(void) if (howlong > INT_MAX / 1000) howlong = INT_MAX / 1000; to_msec = howlong * 1000; - - /* Set up the descriptors to be polled. */ - FD_ZERO(&fds); - - for (l = protocols; l; l = l->next) - FD_SET(l->fd, &fds); - - /* Wait for a packet or a timeout... XXX */ - timeval.tv_sec = to_msec / 1000; - timeval.tv_usec = to_msec % 1000; - - ApiUnlock(); - - count = select(0, &fds, NULL, NULL, &timeval); - - ApiLock(); } else { - ApiUnlock(); - WaitForSingleObject(AdapterStateChangedEvent, INFINITE); - ApiLock(); - - continue; + to_msec = INFINITE; } - DH_DbgPrint(MID_TRACE,("Select: %d\n", count)); + if (Events[1] == WSA_INVALID_EVENT && DhcpSocket != INVALID_SOCKET) + { + Events[1] = WSACreateEvent(); + if (Events[1] != WSA_INVALID_EVENT) + { + count = WSAEventSelect(DhcpSocket, Events[1], FD_READ | FD_CLOSE); + if (count != NO_ERROR) + { + WSACloseEvent(Events[1]); + Events[1] = WSA_INVALID_EVENT; + } + else + { + EventCount = 2; + } + } + } + else if (Events[1] != WSA_INVALID_EVENT && DhcpSocket == INVALID_SOCKET) + { + WSACloseEvent(Events[1]); + Events[1] = WSA_INVALID_EVENT; - /* Not likely to be transitory... */ - if (count == SOCKET_ERROR) { - err = WSAGetLastError(); - error("poll: %d", err); - break; + EventCount = 1; + } + + ApiUnlock(); + count = WaitForMultipleObjects(EventCount, + Events, + FALSE, + to_msec); + ApiLock(); + if (count == WAIT_OBJECT_0) + { + /* Adapter state change */ + continue; + } + else if (count == WAIT_OBJECT_0 + 1) + { + /* Packet received */ + + /* WSA events are manual reset events */ + WSAResetEvent(Events[1]); + } + else + { + /* Timeout */ + continue; } for (l = protocols; l; l = l->next) { struct interface_info *ip; ip = l->local; - if (FD_ISSET(l->fd, &fds)) { - if (ip && (l->handler != got_one || - !ip->dead)) { - DH_DbgPrint(MID_TRACE,("Handling %x\n", l)); - (*(l->handler))(l); - } + if (ip && (l->handler != got_one || + !ip->dead)) { + DH_DbgPrint(MID_TRACE,("Handling %x\n", l)); + (*(l->handler))(l); } } } while (1); - CloseHandle(AdapterStateChangedEvent); + AdapterStateChangedEvent = NULL; + CloseHandle(Events[0]); + WSACloseEvent(Events[1]); ApiUnlock(); }