socket-win: Use non-overlapped I/O and socket event selection

The use of overlapped I/O was incorrect, as we passed stack based buffers, but
did not cancel/wait for pending completion on all sockets. Our receive-from-all
socket interface is actually tricky to implement using overlapped I/O. Switch
to WSAEventSelect() event management, which can be canceled properly while
working in a select()-like way.
This commit is contained in:
Martin Willi 2014-06-10 15:58:31 +02:00
parent 31f2696076
commit 2d846c2035
1 changed files with 13 additions and 31 deletions

View File

@ -88,10 +88,9 @@ struct private_socket_win_socket_t {
METHOD(socket_t, receiver, status_t,
private_socket_win_socket_t *this, packet_t **out)
{
WSAOVERLAPPED overlapped[SOCKET_COUNT] = {};
char buf[this->max_packet], cbuf[128];
bool old;
DWORD i, len, flags, err;
DWORD i, len, err;
WSAMSG msg;
WSABUF data;
WSACMSGHDR *cmsg;
@ -110,25 +109,7 @@ METHOD(socket_t, receiver, status_t,
msg.Control.buf = cbuf;
msg.Control.len = sizeof(cbuf);
for (i = 0; i < SOCKET_COUNT; i++)
{
overlapped[i].hEvent = this->events[i];
if (this->socks[i] != INVALID_SOCKET)
{
if (this->WSARecvMsg(this->socks[i], &msg, NULL,
&overlapped[i], NULL) == SOCKET_ERROR)
{
err = WSAGetLastError();
if (err != WSA_IO_PENDING)
{
DBG1(DBG_NET, "reading from socket failed: %d", err);
return FAILED;
}
}
}
}
/* wait for socket events */
old = thread_cancelability(TRUE);
i = WSAWaitForMultipleEvents(SOCKET_COUNT, this->events,
FALSE, INFINITE, TRUE);
@ -143,8 +124,8 @@ METHOD(socket_t, receiver, status_t,
/* WSAEvents must be reset manually */
WSAResetEvent(this->events[i]);
if (!WSAGetOverlappedResult(this->socks[i], &overlapped[i],
&len, FALSE, &flags))
if (this->WSARecvMsg(this->socks[i], &msg, &len,
NULL, NULL) == SOCKET_ERROR)
{
err = WSAGetLastError();
/* ignore WSAECONNRESET; this is returned for any ICMP port unreachable,
@ -152,16 +133,11 @@ METHOD(socket_t, receiver, status_t,
* we try to receive. */
if (err != WSAECONNRESET)
{
DBG1(DBG_NET, "getting socket result failed: %d", err);
DBG1(DBG_NET, "reading from socket failed: %d", WSAGetLastError());
}
return FAILED;
}
if (len >= sizeof(buf))
{
DBG1(DBG_NET, "receive buffer too small, packet discarded");
return FAILED;
}
DBG3(DBG_NET, "received packet %b", buf, (int)len);
for (cmsg = WSA_CMSG_FIRSTHDR(&msg); dst == NULL && cmsg != NULL;
@ -370,8 +346,7 @@ static SOCKET open_socket(private_socket_win_socket_t *this, int i)
DWORD dwon = TRUE;
SOCKET s;
s = WSASocket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP,
NULL, 0, WSA_FLAG_OVERLAPPED);
s = WSASocket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, 0);
if (s == INVALID_SOCKET)
{
DBG1(DBG_NET, "creating socket failed: %d", WSAGetLastError());
@ -501,6 +476,13 @@ socket_win_socket_t *socket_win_socket_create()
destroy(this);
return NULL;
}
if (WSAEventSelect(this->socks[i], this->events[i],
FD_READ) == SOCKET_ERROR)
{
DBG1(DBG_NET, "WSAEventSelect() failed: %d", WSAGetLastError());
destroy(this);
return NULL;
}
}
if (WSAIoctl(this->socks[0], SIO_GET_EXTENSION_FUNCTION_POINTER,