Defining TCP socket blocking mode for Windows

Those who work with TCP sockets know that a socket can work in blocking or non-blocking (nonblocking) mode. Windows sockets, after creation, are in blocking mode, but they can be turned into non-blocking function ioctlsocket ().

When working on one project, I had a task to determine in what mode the socket provided by the DLL function works for me. Those. except for the socket itself, I had no information and they came in unpredictable mode.

Under * nix, blocking mode is defined without problems by calling the fcntl () function, but under WinSock2 nothing of the kind was found, and on the forums nothing but “Windows does not offer any way to query whether a socket is currently set to blocking or non-blocking” nobody answered.

But there is still a way to determine:

// GetBlockingMode возвращает: 1 - nonblocking | 0 - blocking | -1 - error | -2 - timeout reseted!
int GetBlockingMode(int Sock)
{
	int iSize, iValOld, iValNew, retgso;
	iSize = sizeof(iValOld);
	retgso = getsockopt(Sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&iValOld, &iSize); // Save current timeout value
	if (retgso == SOCKET_ERROR) return (-1);
	iValNew = 1;
	retgso = setsockopt(Sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&iValNew, iSize); // Set new timeout to 1 ms
	if (retgso == SOCKET_ERROR) return (-1);
	// Ok! Try read 0 bytes.
	char buf[1]; // 1 - why not :)
	int retrcv = recv(Sock, buf, 0, MSG_OOB); // try read MSG_OOB
	int werr = WSAGetLastError();
	retgso = setsockopt(Sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&iValOld, iSize); // Set timeout to initial value
	if (retgso == SOCKET_ERROR) return (-2);
	if (werr == WSAENOTCONN) return (-1);
	if (werr == WSAEWOULDBLOCK) return 1;
	return 0;
}

The function accepts the socket number and returns 1 if the socket is in nonblocking mode, 0 - blocking, -1 if a detection error occurred, and -2 if the socket remained with a small timeout after determining the mode.

In short, the sequence of actions is as follows:

1. We save the value of the socket timeout (by default there is 0 - “wait forever”).
2. Set the timeout to 1 millisecond.
3. Read from the socket 0 (zero) bytes of Out of Band data. An explanation is needed here: If OOB data is transmitted, the function may lie, but I have never encountered OOB since Windows NT4 crashed into a blue screen when trying to accept this ( WinNuke ).
4. We get an error that occurred as a result of reading.
5. Restore the old socket timeout value.
6. We look at the reading error we had: if WSAEWOULDBLOCK, then the socket is in nonblocking mode, which was to be determined.

The disadvantages of this method, in addition to the already mentioned MSG_OOB, include a 1-millisecond detection delay and a non-zero probability of spoiling the socket read timeout (although the load test has never revealed such a behavior).

Also popular now: