Windows Server 2019 - Windows socket receive timeout does not respect to the setting in the socket option.

S

Simon Guo

I am not sure if anyone had encounter this but this wasn't an issue in the previous version of Windows.


System Info: Windows Server 2019 V10.0.17763, Visual Studio 2017 Professional, Microsoft Visual C++ 2017 Redistributable



Issue: Socket receive timeout is 1000 times faster than the value was defined in the timeval struct (in WinSock2.h). The issue does not appear on Windows Server 2012 and Server 2016 with VS2017 installed.



Work Around: Passing integer value (in millisecond) instead of timeval struct on the setsockopt() call seems not a problem. However, it will require code change in my software.




The following code can reproduce this issue on Windows Server 2019. You will need a socket client to connect to the opening port.

The issue can be also seen by calling getsockopt() for retrieving timeout value. The tv_sec field of timeval structure is more like in millisecond instead of second.



#undef UNICODE


#define WIN32_LEAN_AND_MEAN


#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>


// Need to link with Ws2_32.lib
#pragma comment (lib, "Ws2_32.lib")
// #pragma comment (lib, "Mswsock.lib")


#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "27015"


int __cdecl main(void)
{
WSADATA wsaData;
int iResult;


SOCKET ListenSocket = INVALID_SOCKET;
SOCKET ClientSocket = INVALID_SOCKET;


struct addrinfo *result = NULL;
struct addrinfo hints;


int iSendResult;
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;


// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}


ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;


// Resolve the server address and port
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}


// Create a SOCKET for connecting to server
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}


// Setup the TCP listening socket
iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}


freeaddrinfo(result);


iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
printf("listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}


// Accept a client socket
ClientSocket = accept(ListenSocket, NULL, NULL);
if (ClientSocket == INVALID_SOCKET) {
printf("accept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}


// No longer need server socket
closesocket(ListenSocket);


// Receive until the peer shuts down the connection
do {


struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
int timeoutVal = 0;
int timeoutValSizeInInt = sizeof(int);
int timeoutValSizeInTimeVal = sizeof(timeval);
if (setsockopt(ClientSocket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, timeoutValSizeInTimeVal) != SOCKET_ERROR)
{
int lastError = WSAGetLastError();
printf("Error: %d\n", lastError);
}


//timeoutVal = 5000;
//if (setsockopt(ClientSocket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeoutVal, timeoutValSizeInInt) != SOCKET_ERROR)
//{
// int lastError = WSAGetLastError();
// printf("Error: %d\n", lastError);
//}


if (getsockopt(ClientSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, &timeoutValSizeInTimeVal) != SOCKET_ERROR)
{
int lastError = WSAGetLastError();
printf("Error: %d\n", lastError);
}
if (getsockopt(ClientSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeoutVal, &timeoutValSizeInInt) != SOCKET_ERROR)
{
int lastError = WSAGetLastError();
printf("Error: %d\n", lastError);
}


iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);


if (iResult > 0) {
printf("Bytes received: %d\n", iResult);


// Echo the buffer back to the sender
iSendResult = send(ClientSocket, recvbuf, iResult, 0);
if (iSendResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
printf("Bytes sent: %d\n", iSendResult);
}
else if (iResult == 0)
printf("Connection closing...\n");
else {
printf("recv failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}


} while (iResult > 0);


// shutdown the connection since we're done
iResult = shutdown(ClientSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}


// cleanup
closesocket(ClientSocket);
WSACleanup();


return 0;
}

Continue reading...
 
Back
Top Bottom