Revamp client's Windows POSIX compatibility code

Unlike POSIX sockets, Windows sockets are not file descriptors, but
"OS handles", with a completely separate set of functions.

However, Windows can create a file descriptor for a socket, and return
a file descriptor's underlying handle.  Use that instead of our gross
hacks to keep up the illusion that sockets are file descriptors.
Slightly dirty: we put file descriptors into fd_set.  Works because
both boil down to int.  Change w32_select(), w32_socket(),
w32_connect(), w32_recv(), w32_writev_socket(), w32_send() to take and
return only file descriptors, and map to sockets internally.  Replace
w32_close_socket() by w32_close(), and drop the close() macro hackery
that made tcp_connect(), host_connect() use w32_close_socket().  New
fd_is_socket().

Windows provides select()-like functions only for handles.  Because of
that, the client used a handle for reading script files, and stored it
in file descriptor input_fd.  Drop this dirty hack, use a file
descriptor instead.  Works because we can get its underlying handle.
Remove the dirty macro hackery that made play(), ring_from_file() and
doexecute() unwittingly work with a handle.  Remove w32_openhandle()
and w32_close_handle().  Replace w32_readv_handle() by w32_readv_fd().
Update w32_select().

Remove w32_openfd(), it's not really needed.

The old code stuffed WSA error codes into errno, which doesn't work.
Use new w32_set_winsock_errno() to convert & stuff.

Fix signed vs. unsigned warnings in Windows client.

Move the struct sigaction replacement next to the sigaction()
replacement.

Rename sysdep_init() to w32_sysdep_init() for consistency.
This commit is contained in:
Markus Armbruster 2009-04-13 15:08:13 +02:00
parent f4209f7ea9
commit 798af5b45b
8 changed files with 155 additions and 176 deletions

View file

@ -88,7 +88,7 @@ play.$O: linebuf.h misc.h sysdep_w32.h proto.h ringbuf.h secure.h
ringbuf.$O: misc.h sysdep_w32.h ringbuf.h
secure.$O: ringbuf.h secure.h
servcmd.$O: misc.h sysdep_w32.h proto.h secure.h
sysdep_w32.$O: misc.h sysdep_w32.h linebuf.h ringbuf.h secure.h
sysdep_w32.$O: misc.h sysdep_w32.h
termlib.$O: misc.h
version.$O: version.h
$(obj): config.h

View file

@ -47,8 +47,6 @@
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#else
#define close(fd) w32_close_socket((fd))
#endif
#include "misc.h"

View file

@ -31,7 +31,7 @@
* Dave Pare, 1986
* Steve McClure, 1998
* Ron Koenderink, 2004-2005
* Markus Armbruster, 2005-2008
* Markus Armbruster, 2005-2009
*/
#include <config.h>
@ -47,6 +47,7 @@
#ifdef _WIN32
#define getuid() 0
#define getpwuid(uid) ((void)(uid), w32_getpw())
#define sysdep_init() w32_sysdep_init()
#else
#define sysdep_init() ((void)0)
#endif

View file

@ -28,7 +28,7 @@
* play.c: Playing the game
*
* Known contributors to this file:
* Markus Armbruster, 2007
* Markus Armbruster, 2007-2009
* Ron Koenderink, 2007-2009
*/
@ -71,6 +71,11 @@ static HANDLE bounce_full;
static HANDLE ctrl_c_event;
static int bounce_status, bounce_error;
struct sigaction {
int sa_flags;
void (*sa_handler)(int sig);
};
#define SIGPIPE -1
static void (*ctrl_handler)(int sig) = { SIG_DFL };
@ -170,45 +175,45 @@ sysdep_stdin_init(void)
/*
* This function uses to WaitForMultipleObjects to wait for both
* stdin and socket reading or writing.
* Stdin is treated special in WIN32. Waiting for stdin is done
* Stdin is treated special in WIN32. Waiting for stdin is done
* via a bounce_full event which is set in the stdin thread.
* Execute command file reading is done via handle. Execute
* command is read via CreateFile/ReadFile instead open/read
* because a file descriptor is not waitable.
* WaitForMultipleObjects will only respond with one object
* Execute command file reading is done via handle.
* WaitForMultipleObjects will only respond with one object,
* so an additonal select is also done to determine
* which individual events are active for the sock.
* which individual events are active.
*/
static int
w32_select(int nfds, fd_set *rdfd, fd_set *wrfd, fd_set *errfd, struct timeval* time)
{
HANDLE handles[3];
SOCKET sock;
int inp, result, s_result, num_handles;
int inp, sockfd, result, s_result, num_handles;
struct timeval tv_time = {0, 0};
fd_set rdfd2;
fd_set rdsock, wrsock;
switch (rdfd->fd_count) {
case 1:
inp = -1;
sock = rdfd->fd_array[0];
sockfd = rdfd->fd_array[0];
break;
case 2:
inp = rdfd->fd_array[0];
sock = rdfd->fd_array[1];
sockfd = rdfd->fd_array[1];
break;
default:
assert(0);
}
sock = W32_FD_TO_SOCKET(sockfd);
assert(wrfd->fd_count == 0
|| (wrfd->fd_count == 1 && wrfd->fd_array[0] == sock));
|| (wrfd->fd_count == 1 && wrfd->fd_array[0] == (SOCKET)sockfd));
assert(inp < 0 || inp == input_fd);
num_handles = 0;
handles[num_handles++] = ctrl_c_event;
if (inp >= 0)
handles[num_handles++] = inp ? (HANDLE)inp : bounce_full;
handles[num_handles++]
= inp ? (HANDLE)_get_osfhandle(inp) : bounce_full;
/* always wait on the socket */
handles[num_handles++] = WSACreateEvent();
@ -232,20 +237,27 @@ w32_select(int nfds, fd_set *rdfd, fd_set *wrfd, fd_set *errfd, struct timeval*
return -1;
}
FD_ZERO(&rdfd2);
FD_SET(sock, &rdfd2);
s_result = select(sock + 1, &rdfd2, wrfd, NULL, &tv_time);
FD_ZERO(&rdsock);
FD_ZERO(&wrsock);
FD_SET(sock, &rdsock);
if (wrfd->fd_count)
FD_SET(sock, &wrsock);
s_result = select(sock + 1, &rdsock, &wrsock, NULL, &tv_time);
if (s_result < 0) {
errno = WSAGetLastError();
w32_set_winsock_errno();
return s_result;
}
*rdfd = rdfd2;
if (inp >= 0 && result == WAIT_OBJECT_0 + 1) {
FD_SET((SOCKET)inp, rdfd);
if (!FD_ISSET(sock, &rdsock))
FD_CLR((SOCKET)sockfd, rdfd);
if (!FD_ISSET(sock, &wrsock))
FD_CLR((SOCKET)sockfd, wrfd);
if (inp >= 0 && result == WAIT_OBJECT_0 + 1)
s_result++;
}
else
FD_CLR((SOCKET)inp, rdfd);
return s_result;
}
@ -282,7 +294,6 @@ w32_ring_from_file_or_bounce_buf(struct ring *r, int fd)
return res;
}
#define ring_from_file w32_ring_from_file_or_bounce_buf
#define close(fd) w32_close_handle((fd))
#define read(sock, buffer, buf_size) \
w32_recv((sock), (buffer), (buf_size), 0)
#define select(nfds, rd, wr, error, time) \

View file

@ -28,7 +28,7 @@
* ringbuf.c: Simple ring buffer
*
* Known contributors to this file:
* Markus Armbruster, 2007
* Markus Armbruster, 2007-2009
*/
#include <config.h>
@ -41,7 +41,7 @@
#include <unistd.h>
#else
#define readv(fd, iov, iovcnt) \
w32_readv_handle((fd), (iov), (iovcnt))
w32_readv_fd((fd), (iov), (iovcnt))
#define writev(fd, iov, iovcnt) \
w32_writev_socket((fd), (iov), (iovcnt))
#endif

View file

@ -31,7 +31,7 @@
* Dave Pare, 1989
* Steve McClure, 1998
* Ron Koenderink, 2005
* Markus Armbruster, 2005-2007
* Markus Armbruster, 2005-2009
*/
#include <config.h>
@ -46,13 +46,6 @@
#include "proto.h"
#include "secure.h"
#ifdef _WIN32
#define open(filename, flags, ...) \
((flags & O_CREAT) \
? w32_openfd((filename), (flags), ## __VA_ARGS__) \
: w32_openhandle((filename), (flags)))
#endif
int eight_bit_clean;
FILE *auxfp;

View file

@ -29,18 +29,58 @@
*
* Known contributors to this file:
* Ron Koenderink, 2007
* Markus Armbruster, 2009
*/
#ifdef _WIN32
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <io.h>
#include <sys/stat.h>
#include "misc.h"
#include "linebuf.h"
#include "ringbuf.h"
#include "secure.h"
static int
fd_is_socket(int fd, SOCKET *sockp)
{
SOCKET sock;
WSANETWORKEVENTS ev;
sock = W32_FD_TO_SOCKET(fd);
if (sockp)
*sockp = sock;
return WSAEnumNetworkEvents(sock, NULL, &ev) == 0;
}
void
w32_set_winsock_errno(void)
{
int err = WSAGetLastError();
WSASetLastError(0);
/* Map some WSAE* errors to the runtime library's error codes. */
switch (err)
{
case WSA_INVALID_HANDLE:
errno = EBADF;
break;
case WSA_NOT_ENOUGH_MEMORY:
errno = ENOMEM;
break;
case WSA_INVALID_PARAMETER:
errno = EINVAL;
break;
case WSAEWOULDBLOCK:
errno = EAGAIN;
break;
case WSAENAMETOOLONG:
errno = ENAMETOOLONG;
break;
case WSAENOTEMPTY:
errno = ENOTEMPTY;
break;
default:
errno = (err > 10000 && err < 10025) ? err - 10000 : err;
break;
}
}
/*
* Get user name in the WIN32 environment
@ -50,12 +90,12 @@ w32_getpw(void)
{
static char unamebuf[128];
static struct passwd pwd;
long unamesize;
DWORD unamesize;
unamesize = sizeof(unamebuf);
if (GetUserName(unamebuf, &unamesize)) {
pwd.pw_name = unamebuf;
if ((unamesize <= 0 ) || (strlen(unamebuf) <= 0))
if (unamesize == 0 || strlen(unamebuf) == 0)
pwd.pw_name = "nobody";
} else
pwd.pw_name = "nobody";
@ -67,7 +107,7 @@ w32_getpw(void)
* set up stdout to work around bugs
*/
void
sysdep_init(void)
w32_sysdep_init(void)
{
int err;
WSADATA WsaData;
@ -92,16 +132,20 @@ sysdep_init(void)
*/
#undef socket
int
w32_socket(int family, int sock_type, int protocol)
w32_socket(int domain, int type, int protocol)
{
SOCKET result;
SOCKET sock;
result = socket(family, sock_type, protocol);
if (result == INVALID_SOCKET) {
errno = WSAGetLastError();
/*
* We have to use WSASocket() to create non-overlapped IO sockets.
* Overlapped IO sockets cannot be used with read/write.
*/
sock = WSASocket(domain, type, protocol, NULL, 0, 0);
if (sock == INVALID_SOCKET) {
w32_set_winsock_errno();
return -1;
}
return (int)result;
return W32_SOCKET_TO_FD(sock);
}
/*
@ -109,13 +153,15 @@ w32_socket(int family, int sock_type, int protocol)
*/
#undef connect
int
w32_connect(int sock, struct sockaddr *addr, int addrlen)
w32_connect(int sockfd, const struct sockaddr *addr, int addrlen)
{
SOCKET sock = W32_FD_TO_SOCKET(sockfd);
int result;
result = connect(sock, addr, addrlen);
result = connect(sock, addr, addrlen);
if (result == SOCKET_ERROR) {
errno = WSAGetLastError();
/* FIXME map WSAEWOULDBLOCK to EINPROGRESS */
w32_set_winsock_errno();
return -1;
}
return result;
@ -126,13 +172,14 @@ w32_connect(int sock, struct sockaddr *addr, int addrlen)
*/
#undef recv
int
w32_recv(int socket, char *buffer, size_t buf_size, int flags)
w32_recv(int sockfd, void *buffer, size_t buf_size, int flags)
{
SOCKET socket = W32_FD_TO_SOCKET(sockfd);
int result;
result = recv(socket, buffer, buf_size, flags);
if (result == SOCKET_ERROR) {
errno = WSAGetLastError();
w32_set_winsock_errno();
return -1;
}
return result;
@ -143,10 +190,11 @@ w32_recv(int socket, char *buffer, size_t buf_size, int flags)
* Modelled after the GNU's libc/sysdeps/posix/writev.c
*/
ssize_t
w32_writev_socket(int fd, const struct iovec *iov, int iovcnt)
w32_writev_socket(int sockfd, const struct iovec *iov, int iovcnt)
{
SOCKET sock = W32_FD_TO_SOCKET(sockfd);
int i;
unsigned char *buffer, *buffer_location;
char *buffer, *buffer_location;
size_t total_bytes = 0;
int bytes_written;
@ -165,12 +213,10 @@ w32_writev_socket(int fd, const struct iovec *iov, int iovcnt)
buffer_location += iov[i].iov_len;
}
bytes_written = send(fd, buffer, total_bytes, 0);
bytes_written = send(sock, buffer, total_bytes, 0);
free(buffer);
if (bytes_written == SOCKET_ERROR) {
errno = WSAGetLastError();
w32_set_winsock_errno();
return -1;
}
return bytes_written;
@ -180,87 +226,38 @@ w32_writev_socket(int fd, const struct iovec *iov, int iovcnt)
* POSIX compatible send() replacement
*/
int
w32_send(int socket, char *buffer, size_t buf_size, int flags)
{
int result;
result = send(socket, buffer, buf_size, flags);
if (result == SOCKET_ERROR)
errno = WSAGetLastError();
return result;
}
/*
* POSIX compatible close() replacement specialized to sockets.
*/
int
w32_close_socket(int fd)
w32_send(int sockfd, const void *buffer, size_t buf_size, int flags)
{
SOCKET socket = W32_FD_TO_SOCKET(sockfd);
int result;
result = closesocket(fd);
result = send(socket, buffer, buf_size, flags);
if (result == SOCKET_ERROR)
errno = WSAGetLastError();
w32_set_winsock_errno();
return result;
}
/*
* POSIX compatible open() replacement
* POSIX compatible close() replacement
*/
int
w32_openfd(const char *fname, int oflag, ...)
w32_close(int fd)
{
va_list ap;
int pmode = 0;
int fd;
int create_permission = 0;
SOCKET sock;
if (oflag & O_CREAT) {
va_start(ap, oflag);
pmode = va_arg(ap, int);
va_end(ap);
if (pmode & 0400)
create_permission |= _S_IREAD;
if (pmode & 0200)
create_permission |= _S_IWRITE;
}
fd = _open(fname, oflag, create_permission);
return fd;
}
/*
* Open a file for reading, return its handle.
* This can be used in place of open() when a handle is desired for
* waiting on it with WaitForMultipleObjects() or similar.
* Ensure the handle is not zero in order to prevent a problem
* input_fd.
*/
int
w32_openhandle(const char *fname, int oflag)
{
HANDLE handle;
handle = CreateFile(fname, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (handle == INVALID_HANDLE_VALUE) {
errno = GetLastError();
return -1;
}
if (handle == 0) {
HANDLE dup_handle;
if (!DuplicateHandle(GetCurrentProcess(), handle,
GetCurrentProcess(), &dup_handle,
0, FALSE, DUPLICATE_SAME_ACCESS)) {
errno = GetLastError();
if (fd_is_socket(fd, &sock)) {
if (closesocket(sock)) {
w32_set_winsock_errno();
return -1;
} else {
CloseHandle(handle);
handle = dup_handle;
}
/*
* This always fails because the underlying handle is already
* gone, but it closes the fd just fine.
*/
_close(fd);
return 0;
}
return (int)handle;
return _close(fd);
}
/*
@ -268,12 +265,12 @@ w32_openhandle(const char *fname, int oflag)
* Modelled after the GNU's libc/sysdeps/posix/readv.c
*/
ssize_t
w32_readv_handle(int fd, const struct iovec *iov, int iovcnt)
w32_readv_fd(int fd, const struct iovec *iov, int iovcnt)
{
int i;
unsigned char *buffer, *buffer_location;
char *buffer, *buffer_location;
size_t total_bytes = 0;
DWORD bytes_read;
int bytes_read;
size_t bytes_left;
for (i = 0; i < iovcnt; i++) {
@ -286,11 +283,9 @@ w32_readv_handle(int fd, const struct iovec *iov, int iovcnt)
return -1;
}
if (!ReadFile((HANDLE)fd, buffer, total_bytes, &bytes_read, NULL)) {
free(buffer);
errno = GetLastError();
bytes_read = read(fd, buffer, total_bytes);
if (bytes_read < 0)
return -1;
}
bytes_left = bytes_read;
buffer_location = buffer;
@ -306,23 +301,7 @@ w32_readv_handle(int fd, const struct iovec *iov, int iovcnt)
}
free(buffer);
return bytes_read;
}
/*
* POSIX compatible close() replacement specialized to files.
* Hack: expects a handle, cannot be used with a file descriptor.
*/
int
w32_close_handle(int fd)
{
int result;
result = CloseHandle((HANDLE)fd);
if (!result)
errno = GetLastError();
return result;
}
#endif /* _WIN32 */

View file

@ -29,13 +29,13 @@
*
* Known contributors to this file:
* Ron Koenderink, 2007
* Markus Armbruster, 2009
*/
#ifndef _SYSDEF_W32_H
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <signal.h>
extern int getopt(int, char * const[], const char *);
extern char *optarg;
@ -54,35 +54,32 @@ struct iovec {
size_t iov_len;
};
struct sigaction {
int sa_flags;
void (*sa_handler)(int sig);
};
#define W32_FD_TO_SOCKET(fd) ((SOCKET)_get_osfhandle((fd)))
#define W32_SOCKET_TO_FD(fh) (_open_osfhandle((long)(fh), O_RDWR | O_BINARY))
extern int w32_recv(int socket, char *buffer,
size_t buf_size, int flags);
extern int w32_send(int socket, char *buffer,
size_t buf_size, int flags);
extern int w32_close_socket(int fd);
extern int w32_socket(int family, int sock_type, int protocol);
extern int w32_connect(int sock, struct sockaddr *addr, int addrlen);
extern int w32_close_handle(int fd);
extern ssize_t w32_readv_handle(int fd, const struct iovec *iov,
int iovcnt);
extern ssize_t w32_writev_socket(int fd, const struct iovec *iov,
extern void w32_set_winsock_errno(void);
extern int w32_recv(int sockfd, void *, size_t, int flags);
extern int w32_send(int sockfd, const void *, size_t, int flags);
extern int w32_close(int fd);
extern int w32_socket(int domain, int type, int protocol);
extern int w32_connect(int sockfd, const struct sockaddr *, int addrlen);
extern ssize_t w32_readv_fd(int fd, const struct iovec *iov,
int iovcnt);
extern ssize_t w32_writev_socket(int sockfd, const struct iovec *iov,
int iovcnt);
extern int w32_openfd(const char *fname, int oflag, ...);
extern int w32_openhandle(const char *fname, int oflag);
extern struct passwd *w32_getpw(void);
extern void sysdep_init(void);
extern void w32_sysdep_init(void);
#define recv(sock, buffer, buf_size, flags) \
w32_recv((sock), (buffer), (buf_size), (flags))
#define socket(family, sock_type, protocol) \
w32_socket((family), (sock_type), (protocol))
#define connect(sock, addr, addrlen) \
w32_connect((sock), (addr), (addrlen))
#define recv(sockfd, buffer, buf_size, flags) \
w32_recv((sockfd), (buffer), (buf_size), (flags))
#define close(fd) \
w32_close((fd))
#define socket(domain, type, protocol) \
w32_socket((domain), (type), (protocol))
#define connect(sockfd, addr, addrlen) \
w32_connect((sockfd), (addr), (addrlen))
#define pclose _pclose
#define popen _popen