您的位置:首页 > 移动开发

retrive ip address list change event by EventSelect and Overlapped

2010-07-21 10:57 453 查看
上周遇到一个问题,需要检测FD_ADDRESS_LIST_CHANGE_BIT,是用来检测可绑定地址列表变化的事件。结果在网上搜来搜去只看到一些文字描述(好像都是来自MSDN),没有看到可用的代码。最后没办法自己写了一个,贴出来供以后参考。

I got two ipsec QFE last week for thread leak issues. An orphan thread will be left every L2TP connect/disconnect. 32kb memory will be lost because of this thread leak. The customer found the system crashed hours later due to out of memory issue.

The root cause of this bug was using overlapped mechanism unsafely on WinCE. IPsec module used overlapped structure to retrive FD_ADDRESS_LIST_CHANGE. It works ok except in these cases:

1) The last overpad request will never return after the monitoring socket was deleted. Because there never will be any address change again on that socket.

2) If failed to create L2TP connection. No address change happen at all in this case. So the overlapped thread will be waiting for the event forever.

We can fix the first bug by not setting overlap request without valid L2TP line. It works well according to our test.

But the second bug is not as easy as the first one. The thread leak was cause by the first overlap request, which waited for the FD_ADDRESS_LIST_CHANGE. But L2TP connection failed, so no L2TP adapter was created at all, and no address list change happened. So the overlap thread waited and waited and waited... How to deal with it then?

1) We can't avoid setting the overlap request, otherwise, IPsec won't get any FD_ADDRESS_LIST_CHANGE any more, even the general ones.

2) We have to terminate the orphan thread before IPsec shutdown. But I didn't found any method to do this in WinCE. The overlap mechanism seems not as strong as desktop version. There is not any method to terminate the waiting thread.

3) So, my last idea was to replace overlap with some other mechanism, EventSelect was a good choice.

I tried to search example codes for detecting adapter connect/disconnect notifications. But got only descriptions on how to XXX, no usful codes was gotten. At last, I wrote my demo codes like this.

For EventSelect mechanism:

1) calling WSAStartup() to initiate ws2.dll;

2) calling WSASocket() to create socket, which will be used to monitor FD_ADDRESS_LIST_CHANGE;

3) calling WSACreateEvent() to creat an event;

4) calling WSAEventSelect() to associate the event with FD_ADDRESS_LIST_CHANGE network event;

5) calling WSAIoctl() to register SIO_ADDRESS_LIST_CHANGE event;

6) calling WaitForMultipleObjects() to wait for the event be signaled.

For Overlapped mechanism:

1) calling WSAStartup() to initiate ws2.dll;

2) calling WSASocket() to create socket with WSA_FLAG_OVERLAPPED flag;

3) calling WSACreateEvent() to creat an event;

4) setting wsaOverlapped.hEvent with the just created event;

5) calling WSAIoctl() to register SIO_ADDRESS_LIST_CHANGE event, with overlapped parameter;

6) calling WaitForMultipleObjects() to wait for the event be signaled.

]/*
Retrive FD_ADDRESS_LIST_CHANGE event by overlap and eventselect mechanism
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <winsock2.h>
#include <winbase.h>
#include <math.h>
#include <tchar.h>

#define _EVENT_SELECT

enum {
INTERFACE_CHANGE_EVENT_SELECT = 0,
INTERFACE_CHANGE_OVERLAPPED,
WAIT_EVENT_COUNT,
};

int __cdecl
wmain(int argc, TCHAR **argvOriginal)
{
SOCKET sock;
DWORD dwRet;
WSANETWORKEVENTS wsaNetworkEvent;
BOOL bEventSelect = TRUE;
BOOL bOverlapped = TRUE;
unsigned long iBufSize;
struct WSAData dsaTemp;
WORD wsaVersion = MAKEWORD(2,0);
HANDLE wsaEventSelect = NULL;
HANDLE hOverlapEvent = NULL;
HANDLE hWaitEvent[WAIT_EVENT_COUNT];
WSAOVERLAPPED wsaOverlapped;

if ( WSAStartup(wsaVersion, &dsaTemp) != 0 ) {
RETAILMSG(1, (TEXT("WSAStartup failed/r/n")));
goto clean;
}

sock = WSASocket(
AF_INET,
SOCK_DGRAM,
0,
NULL,
0,
WSA_FLAG_OVERLAPPED
);

if (sock == INVALID_SOCKET) {
RETAILMSG(1, (TEXT("socket() failed, error = %d/r/n"), WSAGetLastError()));
ExitThread(-1);
}

// confit for EventSelect method
wsaEventSelect = WSACreateEvent();// NULL, TRUE, FALSE, NULL );
if (wsaEventSelect == NULL) {
RETAILMSG(1, (TEXT("WSACreateEvent failed/r/n")));
ExitThread(-1);
}

dwRet = WSAEventSelect(
sock,
wsaEventSelect,
FD_ADDRESS_LIST_CHANGE
);
if (dwRet == SOCKET_ERROR) {
RETAILMSG(1, (TEXT("WSAEventSelect failed/r/n")));
goto clean;
}

// config for Overlapped method
hOverlapEvent = WSACreateEvent();
if (hOverlapEvent == NULL) {
RETAILMSG(1, (TEXT("WSACreateEvent failed/r/n")));
ExitThread(-1);
}
wsaOverlapped.hEvent = hOverlapEvent;

// set hWaitEvent
hWaitEvent[INTERFACE_CHANGE_EVENT_SELECT] = wsaEventSelect;
hWaitEvent[INTERFACE_CHANGE_OVERLAPPED] = hOverlapEvent;

while(1){

#ifdef _EVENT_SELECT
if (bEventSelect) {
dwRet = WSAIoctl(
sock,
SIO_ADDRESS_LIST_CHANGE,
NULL,
0,
NULL,
0,
&iBufSize,
NULL,
NULL
);
if (dwRet == SOCKET_ERROR) {
if ( WSAGetLastError() != WSAEWOULDBLOCK) {
RETAILMSG(1,(TEXT("/tUnexpected error, exiting/r/n")));
goto clean;
}
}
bEventSelect = FALSE;
}
#else
if (bOverlapped) {
dwRet = WSAIoctl(
sock,
SIO_ADDRESS_LIST_CHANGE,
NULL,
0,
NULL,
0,
&iBufSize,
&wsaOverlapped,
NULL
);
if (dwRet == SOCKET_ERROR) {
if ( WSAGetLastError() != ERROR_IO_PENDING) {
RETAILMSG(1,(TEXT("/tUnexpected error, exiting/r/n")));
goto clean;
}
}
bOverlapped = FALSE;
}
#endif

RETAILMSG(1,(TEXT("calling WaitForSingleObject .../r/n")));
dwRet = WaitForMultipleObjects(
2,
hWaitEvent,
FALSE,
INFINITE
);
switch(dwRet) {

case INTERFACE_CHANGE_EVENT_SELECT:
RETAILMSG(1,(TEXT("INTERFACE_CHANGE_EVENT_SELECT/r/n")));
dwRet = WSAEnumNetworkEvents(
sock,
wsaEventSelect,
&wsaNetworkEvent
);
if (dwRet == SOCKET_ERROR) {
RETAILMSG(1,(TEXT("WSAEnumNetworkEvents failed/r/n")));
break;
}

if (wsaNetworkEvent.lNetworkEvents & FD_ADDRESS_LIST_CHANGE) {
RETAILMSG(1,(TEXT("Event: FD_ADDRESS_LIST_CHANGE/r/n")));
if (wsaNetworkEvent.iErrorCode[FD_ADDRESS_LIST_CHANGE_BIT]) {
// handle error condition
RETAILMSG(1,(TEXT("/twsaNetworkEvent.iErrorCode reported error result/r/n")));
}

bEventSelect = TRUE;
ResetEvent(wsaEventSelect);
RETAILMSG(1, (TEXT("get FD_ADDRESS_LIST_CHANGE by EventSelect successfully/n")));
}
break;

case INTERFACE_CHANGE_OVERLAPPED:
RETAILMSG(1,(TEXT("INTERFACE_CHANGE_OVERLAPPED/r/n")));
dwRet = WSAEnumNetworkEvents(
sock,
hOverlapEvent,
&wsaNetworkEvent
);
if (dwRet == SOCKET_ERROR) {
RETAILMSG(1,(TEXT("WSAEnumNetworkEvents failed/r/n")));
break;
}

if (wsaNetworkEvent.lNetworkEvents & FD_ADDRESS_LIST_CHANGE) {
RETAILMSG(1,(TEXT("Event: FD_ADDRESS_LIST_CHANGE/r/n")));
if (wsaNetworkEvent.iErrorCode[FD_ADDRESS_LIST_CHANGE_BIT]) {
// handle error condition
RETAILMSG(1,(TEXT("/twsaNetworkEvent.iErrorCode reported error result/r/n")));
}

bOverlapped = TRUE;
ResetEvent(hOverlapEvent);
RETAILMSG(1, (TEXT("get FD_ADDRESS_LIST_CHANGE by overlap successfully/n")));
}
break;

case WSA_WAIT_TIMEOUT:
break;

case WSA_WAIT_FAILED:
RETAILMSG(1,(TEXT("WaitForMultipleEvents failed/r/n")));
goto clean;

default:
RETAILMSG(1,(TEXT("WaitForMultipleEvents failed, unexpected return code = %d/r/n"), dwRet));
goto clean;
}
}

clean:

WSACloseEvent(wsaEventSelect);
WSACleanup();

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐