Here's my code, I'd like to focus on the call to WSARecv
and WSAGetOverlappedResult
:
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <mswsock.h> // for ACCEPT_CONTEXT
#include <windows.h>
#include <stdio.h> // for wprintf
#include <assert.h>
static char buf[128];
static WSABUF recvBuf = {.len = 128, .buf = buf };
int WINAPI wWinMain(
HINSTANCE hInstance __attribute__((unused)),
HINSTANCE hPrevInstance __attribute__((unused)),
LPWSTR pCmdLine __attribute__((unused)),
int nCmdShow __attribute__((unused))
) {
WSADATA wsaData = {0};
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
wprintf(L"WSAStartup failed, quitting...\n");
abort();
}
SOCKET listenSock = socket(
AF_INET,
SOCK_STREAM,
IPPROTO_TCP
);
if (listenSock == INVALID_SOCKET) {
wprintf(L"Invalid socket, quitting...\n");
goto cleanupWsa;
}
struct sockaddr_in sockAddr = {
.sin_family = AF_INET,
.sin_port = htons(8080),
.sin_addr = INADDR_ANY,
};
wchar_t pretty[128];
DWORD len = sizeof pretty / sizeof(*pretty);
if (0 != WSAAddressToString(
(LPSOCKADDR) &sockAddr,
sizeof sockAddr,
NULL,
pretty,
&len)
) {
wprintf(L"Error during AddressToString, "
L"check needed address string length %ld, quitting...\n"
, len);
goto cleanupSocket;
}
wprintf(L"Binding to %ls\n", pretty);
if (bind(listenSock, (LPSOCKADDR) &sockAddr, sizeof sockAddr)
== SOCKET_ERROR) {
wprintf(L"Bind error, quitting...\n");
goto cleanupSocket;
}
if (listen(listenSock, SOMAXCONN) != 0) {
wprintf(L"Listen error, quitting...\n");
goto cleanupSocket;
}
struct sockaddr s;
int socklen = sizeof s;
SOCKET acceptSocket = accept(listenSock, &s, &socklen);
wprintf(L"ACCEPT\n");
if (SOCKET_ERROR == setsockopt(
acceptSocket,
SOL_SOCKET,
SO_UPDATE_ACCEPT_CONTEXT,
(char *)&listenSock,
sizeof listenSock
)) {
wprintf(L"setsockopt update_accept_context failure\n");
goto cleanupBothSockets;
}
DWORD flags = WSA_FLAG_OVERLAPPED;
WSAOVERLAPPED w;
memset(&w, 0, sizeof w);
if (WSARecv(
acceptSocket,
&recvBuf,
1,//dwBufferCount
NULL,//lpBytesReceived
&flags,
&w,
NULL
) != SOCKET_ERROR) {
wprintf(L"Recv: expected SOCKET_ERROR\n");
goto cleanupBothSockets;
}
int errnr = WSAGetLastError();
if (errnr != WSA_IO_PENDING) {
wprintf(L"RecvErr %d\n", errnr);
goto cleanupBothSockets;
}
wprintf(L"Running GetOverlappedResult\n");
DWORD bytes_transferred;
BOOL ret = WSAGetOverlappedResult(acceptSocket, &w, &bytes_transferred, TRUE, &flags);
if (ret == FALSE) {
wprintf(L"OverlappedResult: error\n");
} else {
wprintf(L"OverlappedResult: finished with no error, bytes transferred %d", bytes_transferred);
}
cleanupBothSockets:
closesocket(acceptSocket);
cleanupSocket:
closesocket(listenSock);
cleanupWsa:
WSACleanup();
return 0;
}
When I run the program, it listens for a connection. I connect with netcat. After connecting, it prints 'ACCEPT', as expected. It also prints 'Running GetOverlappedResult', but even though I write lots of gibberish on the netcat, neither of the "OverlappedResult:" lines appear, until I push Control-C on the netcat, and the connection dies. Then, I hit the success branch, and it says that 0 bytes were transferred.
What is wrong with this program? Why doesn't WSAGetOverlappedResult
return as soon as the 128 byte buffer is filled?
I scrutinized my calls to WSARecv
and WSAGetOverlappedResult
. Here are some details:
WSARecv
to acceptSocket
, since I want to read from the concrete connection that was established.recvBuf
as a one-sized array.lpNumberOfBytesRecvd
to null, since MSDN tells me to do that if I supply lpOverlapped
.You can't pass WSA_FLAG_OVERLAPPED
to WSARecv
. The socket itself is already either overlapped or not. If you pass 0
instead, the program notices the bytes from netcat
.
Furthermore, you cannot assume that WSARecv
will always generate the error ERROR_IO_PENDING
. The data may be available right away, in which case it will just return 0
. So you need to handle both these cases as success.
If you make the request with e.g. curl
, the data may be available right away, and the program will complain that it didn't get ERROR_IO_PENDING
, which you get when you manually type stuff into the socket with netcat
.