Zack Weinberg <za...@panix.com> writes: > The least-POSIXy environment this program is ever likely to be ported to > is Windows -- advice on how to make code that assumes BSD socket headers > compile with Winsock would be significantly more useful to me.
Gnulib probably has a bunch of other functionality to help with this, but here are the core portability issues that I'm aware of: * Socket functions on Windows set a different error that you have to retrieve from WSAGetLastError() and set with WSASetLastError() rather than using errno. strerror obviously doesn't work also. * Socket file descriptors are an opaque type, not an int, and you have to check against INVALID_SOCKET rather than -1 for errors. * read/write cannot be used on sockets. You have to use recv/send. Similarly, you cannot use close on sockets; you have to use closesocket. * Applications using sockets have to do a one-time startup. * The header files are obviously different. Here's the core of portability for most TCP applications: #ifdef _WIN32 # include <winsock2.h> # include <ws2tcpip.h> #else # include <netinet/in.h> # include <arpa/inet.h> # include <netdb.h> # include <sys/socket.h> #endif #ifndef HAVE_SOCKLEN_T typedef int socklen_t; #endif #ifdef _WIN32 int socket_init(void); # define socket_shutdown() WSACleanup() # define socket_close(fd) closesocket(fd) # define socket_read(fd, b, s) recv((fd), (b), (s), 0) # define socket_write(fd, b, s) send((fd), (b), (s), 0) # define socket_errno WSAGetLastError() # define socket_set_errno(e) WSASetLastError(e) const char *socket_strerror(int); typedef SOCKET socket_type; #else # define socket_init() 1 # define socket_shutdown() /* empty */ # define socket_close(fd) close(fd) # define socket_read(fd, b, s) read((fd), (b), (s)) # define socket_write(fd, b, s) write((fd), (b), (s)) # define socket_errno errno # define socket_set_errno(e) errno = (e) # define socket_strerror(e) strerror(e) # define INVALID_SOCKET -1 typedef int socket_type; #endif and you then have to use socket_type and the above macros everywhere instead of using the regular functions directly. socket_init has to be called once and is: int socket_init(void) { WSADATA data; if (WSAStartup(MAKEWORD(2,2), &data)) return 0; return 1; } on Windows. socket_strerror is: const char * socket_strerror(err) { const char *message = NULL; if (err >= sys_nerr) { char *p; DWORD f = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; static char *buffer = NULL; if (buffer != NULL) LocalFree(buffer); if (FormatMessage(f, NULL, err, 0, (LPTSTR) &buffer, 0, NULL) != 0) { p = strchr(buffer, '\r'); if (p != NULL) *p = '\0'; } message = buffer; } if (message == NULL) message = strerror(err); return message; } on Windows (obviously not threadsafe; you have to do other things if you need to be threadsafe). -- Russ Allbery (r...@stanford.edu) <http://www.eyrie.org/~eagle/>