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