<<

Winsock Programmer's FAQ
Section 7: Articles

>>

Winsock's Compatibility With BSD Sockets

by Warren Young

So you say you're a long-time Unix hacker who's new to Windows programming? And you've heard of this great API called Winsock that's compatibile with your beloved BSD sockets, but try as you might, you just can't find the readv() call? Well pardner, this is the article for you.

Introduction

In the beginning, there was chaos. This chaos was in the form of incompatible Windows TCP/IP APIs: a program written for, say, FTP Software's TCP/IP stack wouldn't run on JSB's stack.

Then, sometime in 1990, a bunch of people got together and decided to make one nice, big, compatible API called Windows Sockets that would allow a single program to run on any vendor's stack. They decided to base this API on the popular BSD sockets model of network programming, but for various reasons, they didn't include every BSD sockets feature. This article will tell you how to get similar behavior to several BSD features using other Winsock or Win32 facilities.

This article is still evolving. Each entry below has two dates after it: an "added" and an optional "modified" date. So, you can periodically come back to this document to see if any new BSD-like behaviors have been uncovered in the Winsock API. Changes to this document will be announced on the main Winsock Programmer's FAQ page, in the What's New section.

dup() (Added 1998.12.24)

The Unix dup() function duplicates a file handle, and of course also works for sockets. Under Winsock 2, you can do the same thing with WSADuplicateSocket(). It's a bit more involved, but the Winsock spec gives you a canned function call sequence you can use.

Incidentally, the Winsock method is somewhat more powerful than the Unix version, because you can pass the duplicated socket to an unrelated process without any extra steps, whereas a simple dup()'ed socket under Unix can only be accessed by the process's children.

dup2() (Added 1998.12.24, modified 1999.06.27)

There is partial support for this feature under Winsock, though the mechanism is dissimilar to the dup2() feature. Under Unix, dup2() takes a handle and duplicates it like dup() does, but with a twist: it assigns the new filehandle a value that you specify. This is usually used to map a socket to the C language's stdin or stdout file handles so that you can use standard I/O functions like printf() and fgets() with the socket.

Item Q190351 in the Microsoft Knowledge Base documents a method by which you can redirect a child process's standard handles to a socket. The limitations are that you cannot do this to your own process's handles, you cannot redirect arbitrary handles to a socket (i.e. you can only do it with stdin, stdout and stderr), and not all processes are fully compatible with this API feature. Still, it at least makes an inetd-like program possible under Win32.

errno vs. WSAGetLastError() (Added 1998.12.24)

WSAGetLastError() is essentially the same thing as Unix's errno global variable. There is one small difference, however: WSAGetLastError() is a function call because it works on a per-thread basis, whereas errno is global to the entire program. This implies that sockets can be used safely by multiple threads under Winsock, but not necessarily so under Unix. (See the main FAQ for more on thread safety under Winsock.)

Symbolic Error Values (Added 1999.09.25)

Most of the error values that WSAGetLastError() can return come from BSD, except that Winsock's versions begin with "WSA". For example, where a BSD system might use ECONNRESET, Winsock would use WSAECONNRESET. (Insert "gratuitous incompatibility" rant here.)

EAGAIN (Added 1998.12.24)

Many Unix programs, especially those with System V roots, check for the EAGAIN value in the global errno variable when a non-blocking call fails. This is the same thing as BSD's EWOULDBLOCK and Winsock's WSAEWOULDBLOCK errors. You'll have to check your system's header files, but all Unixes I've checked on this matter #define EAGAIN and EWOULDBLOCK to the same value, so you may want to get into the habit of using EWOULDBLOCK instead of EAGAIN under Unix, to make transitions to and from Winsock easier.

readv() and writev() (Added 1998.08.01)

BSD sockets' scatter/gather mechanism is very similar to parts of Winsock 2's overlapped I/O mechanism. Overlapped I/O allows you to pass several buffers to WSASend() for "gathering" before sending on the network, and allow incoming data to be "scattered" into several input buffers by WSARecv().

Equivalence of File and Socket Handles (Added 1998.08.01)

Under Winsock 1.1, socket handles are completely distinct from the file handles issued by Win16 and Win32's native I/O facilities. For example, under BSD Unix, you can pass a socket handle to a function that will read from a file. This won't work under Winsock 1.1.

Winsock 2, with its close ties to Win32, changes this. Under Winsock 2, a socket handle is now equivalent to a Win32 file handle. So, the Win32 ReadFile() API is roughly equivalent to good old Winsock's recv() function. The equivalence is not exact, and compiler-provided APIs that emulate POSIX APIs like open(), write() and read() may not work with socket handles, which can make porting some BSD code more difficult that you might think necessary. Still, it's not as bad as it once was.

Winsock's ioctlsocket() vs. BSD's ioctl() (Added 1998.08.01)

BSD Unix (and other flavors of Unix) provides the ioctl() call to allow you to set and get various options and behaviors on a socket or file handle. Winsock replicates much of this in its ioctlsocket() call, but not everything is present. However, many of the popular ioctl() options under BSD are avaiable in different forms under Win32 or Winsock.

  • SIOCGIFCONF -- This ioctl() option allows you to get information about the network interfaces available. Winsock 2 provides very similar functionality with its SIO_GET_INTERFACE_LIST option for ioctlsocket().

Detecting a Dropped Connection (Added 1999.09.25)

Under BSD Unixes, if the remote peer closes its connection and your program is blocking on recv(), you will get a 0 back from recv(). If you're blocking on send() and you've blocked the SIGPIPE signal, it will return with a -1, and errno will be EPIPE; otherwise your program will be terminated.

Things are different under Winsock. recv() behaves roughly the same, except that it can also return -1, with WSAGetLastError() returning WSAECONNRESET, WSAECONNABORTED or WSAESHUTDOWN, to signal the detectable flavors of abnormal disconnections. send() can return with these codes as well; unlike BSD, however, a broken connection never kills the process under Winsock, nor does it send your program a SIGPIPE signal.

A Cry For Updates

This article can always use more work. As it is, it gives a few good bits of info about BSD-like behavior under Winsock, but there are still many, many holes left to fill. If you can help me out, please drop me a line! In particular, the fcntl() call is not covered at all, and I'll bet that there are several other BSD-only ioctl() options that we can duplicate in other ways with Win32 facilities.

Copyright © 1998-1999 by Warren Young. All rights reserved.


<< Debugging TCP WsControl() Revealed >>
Last modified on 29 April 2000 at 15:52 UTC-7 Please send corrections to tangent@cyberport.com.
< Go to the main FAQ page
<< Go to my Programming pages
<<< Go to my Home Page