Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you _close(), _read(), and _write() a socket on windows?

Tags:

sockets

winapi

MSDN says closesocket() is the function to use. However, I couldn't help wondering if _close() will work also?

MSDN appears to say no in their description of SOCKET type: (http://msdn.microsoft.com/en-us/windows/ms740516(v=vs.80)):

In Winsock applications, a socket descriptor is not a file descriptor and must be used with the Winsock functions.

and more specifically from its note on renamed socket functions:

Sockets are represented by standard file descriptors in Berkeley Sockets, so the close function can be used to close sockets as well as regular files. While nothing in Windows Sockets prevents an implementation from using regular file handles to identify sockets, nothing requires it either. On Windows, sockets must be closed by using the closesocket routine. On Windows, using the close function to close a socket is incorrect and the effects of doing so are undefined by this specification.

However, even despite the above, some of the Windows file functions might work with sockets in practice:

Given that ReadFile and WriteFile work on sockets, I suspect _read and _write, for instance, might also work with sockets as well as file handles.

MSDN's overview of socket handles states:

A socket handle can optionally be a file handle in Windows Sockets 2. A socket handle from a Winsock provider can be used with other non-Winsock functions such as ReadFile, WriteFile, ReadFileEx, and WriteFileEx.

like image 446
Tim Lovell-Smith Avatar asked Dec 30 '13 20:12

Tim Lovell-Smith


2 Answers

The short answer is no. Sockets handles on Windows are not file handles as they are on Unix. There's special support such that the low level Win32 APIs, ReadFile and WriteFile, can work with a socket handle. But that's likely where it ends.

With regards to _open_osfhandle, yes, that will possibly work in a very limited sense, but there's good reasons why you shouldn't do this. Most of the following I inferred just by browsing the sources of open, read,write, close, and open_osfhandle in the CRT sources (that comes with Visual Studio).

  • There's a lot of buffering that goes on with the CRT read/write calls. Any attempt to mix read/write with recv/send will be going into undefined behavior.

  • Performance. Just look at the source of read() and write() as seen in the CRT sources. A lot of wrapper code to eventually call ReadFile and WriteFile, which in turn have to forward to the actual socket API.

  • Socket error codes may not bubble to the file API as you think. Remember socket API errors get returned through WSAGetLastError. Win32 file IO calls get bubbled up through GetLastError. So if your call to write() hits a socket error, it might try to map the return value via GetLastError, which still returns success.

  • close() won't properly close the socket handle since it maps to CloseHandle, not closesocket.

like image 119
selbie Avatar answered Nov 15 '22 08:11

selbie


More insightful than MSDN: [http://tangentsoft.net/wskfaq/articles/bsd-compatibility.html]

No they are definitely different in Windows 3.x, 9x:

'In Windows 3.1 and 95 Windows sockets and file handles are completely distinct. In Windows NT, however, it appears they may usually be one and the same.'

And no, you can't use them together on Windows NT - at least not by default:

'The Visual C++ RTL emulates POSIX functions, except that they’re named with a leading underscore: for example, _read() instead of read(). The _read() function uses ReadFile() internally, so you’d think it would work with sockets. The problem is, the first argument is an RTL-specific handle, not an operating system file handle. If you pass a socket handle to _read() or _write(), the RTL will realize that it isn’t an RTL handle and the call will fail.

'Fortunately, there is a bridge function in Visual C++’s RTL: _open_osfhandle(). (If you’re not using Visual C++, you’ll have to check its RTL source for a similar function.) I’ve not tried it, but it appears to take an operating system file handle (including socket handles) and return a handle you can use with the POSIX emulation functions in the RTL. I’m told that this will work with sanely-coded non-Microsoft Winsock stacks, but since I haven’t tried it, you should if you want to support these alternate stacks.'

like image 24
3 revs, 2 users 86% Avatar answered Nov 15 '22 07:11

3 revs, 2 users 86%