[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
socket code on Windows (was: AC_INCLUDES_DEFAULT does not need to probe
From: |
Russ Allbery |
Subject: |
socket code on Windows (was: AC_INCLUDES_DEFAULT does not need to probe for headers that are part of C89 or POSIX.1 anymore) |
Date: |
Thu, 12 Apr 2012 10:36:40 -0700 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/23.4 (gnu/linux) |
Zack Weinberg <address@hidden> 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 (address@hidden) <http://www.eyrie.org/~eagle/>