bug-autoconf
[Top][All Lists]
Advanced

[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/>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]