diff options
-rw-r--r-- | byterun/caml/osdeps.h | 12 | ||||
-rw-r--r-- | byterun/io.c | 64 | ||||
-rw-r--r-- | byterun/unix.c | 29 | ||||
-rw-r--r-- | byterun/win32.c | 30 | ||||
-rw-r--r-- | otherlibs/win32unix/accept.c | 16 | ||||
-rw-r--r-- | otherlibs/win32unix/socket.c | 16 |
6 files changed, 101 insertions, 66 deletions
diff --git a/byterun/caml/osdeps.h b/byterun/caml/osdeps.h index 8204205f74..dde9a114bb 100644 --- a/byterun/caml/osdeps.h +++ b/byterun/caml/osdeps.h @@ -18,6 +18,18 @@ #include "misc.h" +/* Read at most [n] bytes from file descriptor [fd] into buffer [buf]. + [is_socket] is true if [fd] refers to a socket. (This distinction + matters for Win32, but not for Unix.) Return number of bytes + read, or -1 if error. */ +extern int caml_read_fd(int fd, int is_socket, void * buf, int n); + +/* Write at most [n] bytes from buffer [buf] onto file descriptor [fd]. + [is_socket] is true if [fd] refers to a socket. (This distinction + matters for Win32, but not for Unix.) Return number of bytes + written, or -1 if error. */ +extern int caml_write_fd(int fd, int is_socket, void * buf, int n); + /* Decompose the given path into a list of directories, and add them to the given table. Return the block to be freed later. */ extern char * caml_decompose_path(struct ext_table * tbl, char * path); diff --git a/byterun/io.c b/byterun/io.c index 60504f5862..48c9c00542 100644 --- a/byterun/io.c +++ b/byterun/io.c @@ -33,6 +33,7 @@ #include "caml/memory.h" #include "caml/misc.h" #include "caml/mlvalues.h" +#include "caml/osdeps.h" #include "caml/signals.h" #include "caml/sys.h" @@ -158,25 +159,12 @@ CAMLexport int caml_channel_binary_mode(struct channel *channel) #define EWOULDBLOCK (-1) #endif -static int do_write(int fd, char *p, int n) +static int do_write(int fd, int flags, char *p, int n) { int retcode; - -again: caml_enter_blocking_section(); - retcode = write(fd, p, n); + retcode = caml_write_fd(fd, flags & CHANNEL_FLAG_FROM_SOCKET, p, n); caml_leave_blocking_section(); - if (retcode == -1) { - if (errno == EINTR) goto again; - if ((errno == EAGAIN || errno == EWOULDBLOCK) && n > 1) { - /* We couldn't do a partial write here, probably because - n <= PIPE_BUF and POSIX says that writes of less than - PIPE_BUF characters must be atomic. - We first try again with a partial write of 1 character. - If that fails too, we'll raise Sys_blocked_io below. */ - n = 1; goto again; - } - } if (retcode == -1) caml_sys_io_error(NO_ARG); CAMLassert (retcode > 0); return retcode; @@ -194,7 +182,7 @@ CAMLexport int caml_flush_partial(struct channel *channel) towrite = channel->curr - channel->buff; CAMLassert (towrite >= 0); if (towrite > 0) { - written = do_write(channel->fd, channel->buff, towrite); + written = do_write(channel->fd, channel->flags, channel->buff, towrite); channel->offset += written; if (written < towrite) memmove(channel->buff, channel->buff + written, towrite - written); @@ -238,7 +226,7 @@ CAMLexport int caml_putblock(struct channel *channel, char *p, intnat len) fits to buffer and write the buffer */ memmove(channel->curr, p, free); towrite = channel->end - channel->buff; - written = do_write(channel->fd, channel->buff, towrite); + written = do_write(channel->fd, channel->flags, channel->buff, towrite); if (written < towrite) memmove(channel->buff, channel->buff + written, towrite - written); channel->offset += written; @@ -277,30 +265,28 @@ CAMLexport file_offset caml_pos_out(struct channel *channel) /* Input */ -/* caml_do_read is exported for Cash */ -CAMLexport int caml_do_read(int fd, char *p, unsigned int n) +static int do_read(int fd, int flags, char *p, unsigned int n) { int retcode; - do { - caml_enter_blocking_section(); - retcode = read(fd, p, n); -#if defined(_WIN32) - if (retcode == -1 && errno == ENOMEM && n > 16384){ - retcode = read(fd, p, 16384); - } -#endif - caml_leave_blocking_section(); - } while (retcode == -1 && errno == EINTR); + caml_enter_blocking_section(); + retcode = caml_read_fd(fd, flags & CHANNEL_FLAG_FROM_SOCKET, p, n); if (retcode == -1) caml_sys_io_error(NO_ARG); return retcode; } +/* caml_do_read is exported for Cash */ +CAMLexport int caml_do_read(int fd, char *p, unsigned int n) +{ + return do_read(fd, 0, p, n); +} + CAMLexport unsigned char caml_refill(struct channel *channel) { int n; - n = caml_do_read(channel->fd, channel->buff, channel->end - channel->buff); + n = do_read(channel->fd, channel->flags, + channel->buff, channel->end - channel->buff); if (n == 0) caml_raise_end_of_file(); channel->offset += n; channel->max = channel->buff + n; @@ -337,8 +323,8 @@ CAMLexport int caml_getblock(struct channel *channel, char *p, intnat len) channel->curr += avail; return avail; } else { - nread = caml_do_read(channel->fd, channel->buff, - channel->end - channel->buff); + nread = do_read(channel->fd, channel->flags, channel->buff, + channel->end - channel->buff); channel->offset += nread; channel->max = channel->buff + nread; if (n > nread) n = nread; @@ -407,7 +393,8 @@ CAMLexport intnat caml_input_scan_line(struct channel *channel) return -(channel->max - channel->curr); } /* Fill the buffer as much as possible */ - n = caml_do_read(channel->fd, channel->max, channel->end - channel->max); + n = do_read(channel->fd, channel->flags, + channel->max, channel->end - channel->max); if (n == 0) { /* End-of-file encountered. Return the number of characters in the buffer, with negative sign since we haven't encountered @@ -603,6 +590,15 @@ CAMLprim value caml_ml_set_binary_mode(value vchannel, value mode) { #if defined(_WIN32) || defined(__CYGWIN__) struct channel * channel = Channel(vchannel); +#if defined(_WIN32) + /* The implementation of [caml_read_fd] and [caml_write_fd] in win32.c + doesn't support socket I/O with CRLF conversion. */ + if (channel->flags & CHANNEL_FLAG_FROM_SOCKET != 0 + && ! Bool_val(mode)) { + errno = EINVAL; + caml_sys_error(NO_ARG); + } +#endif if (setmode(channel->fd, Bool_val(mode) ? O_BINARY : O_TEXT) == -1) caml_sys_error(NO_ARG); #endif @@ -778,7 +774,7 @@ CAMLprim value caml_ml_input(value vchannel, value buff, value vstart, channel->curr += avail; n = avail; } else { - nread = caml_do_read(channel->fd, channel->buff, + nread = do_read(channel->fd, channel->flags, channel->buff, channel->end - channel->buff); channel->offset += nread; channel->max = channel->buff + nread; diff --git a/byterun/unix.c b/byterun/unix.c index 38ddee0056..c0fb1d8dcf 100644 --- a/byterun/unix.c +++ b/byterun/unix.c @@ -21,6 +21,7 @@ #include <string.h> #include <sys/types.h> #include <sys/stat.h> +#include <errno.h> #include <fcntl.h> #include "caml/config.h" #ifdef SUPPORT_DYNAMIC_LINKING @@ -46,6 +47,34 @@ #define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) #endif +int caml_read_fd(int fd, int is_socket, void * buf, int n) +{ + int retcode; + do { + retcode = read(fd, buf, n); + } while (retcode == -1 && errno == EINTR); + return retcode; +} + +int caml_write_fd(int fd, int is_socket, void * buf, int n) +{ + int retcode; + again: + retcode = write(fd, buf, n); + if (retcode == -1) { + if (errno == EINTR) goto again; + if ((errno == EAGAIN || errno == EWOULDBLOCK) && n > 1) { + /* We couldn't do a partial write here, probably because + n <= PIPE_BUF and POSIX says that writes of less than + PIPE_BUF characters must be atomic. + We first try again with a partial write of 1 character. + If that fails too, we'll return an error code. */ + n = 1; goto again; + } + } + return retcode; +} + char * caml_decompose_path(struct ext_table * tbl, char * path) { char * p, * q; diff --git a/byterun/win32.c b/byterun/win32.c index f26caf8fd7..13153c73bc 100644 --- a/byterun/win32.c +++ b/byterun/win32.c @@ -21,6 +21,7 @@ #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> +#include <winsock2.h> #include <ctype.h> #include <errno.h> #include <string.h> @@ -39,6 +40,35 @@ #define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) #endif +int caml_read_fd(int fd, int is_socket, void * buf, int n) +{ + int retcode; + if (! is_socket) { + retcode = read(fd, buf, n); + /* Large reads from console can fail with ENOMEM. Reduce requested size + and try again. */ + if (retcode == -1 && errno == ENOMEM && n > 16384) { + retcode = read(fd, p, 16384); + } + } else { + retcode = recv((SOCKET) _getosfhandle(fd), buf, n, 0); + if (ret == -1) _dosmaperr(WSAGetLastError()); + } + return retcode; +} + +int caml_write_fd(int fd, int is_socket, void * buf, int n) +{ + int retcode; + if (! is_socket) { + retcode = write(fd, buf, n); + } else { + retcode = send((SOCKET) _getosfhandle(fd), buf, n, 0); + if (ret == -1) _dosmaperr(WSAGetLastError()); + } + return retcode; +} + char * caml_decompose_path(struct ext_table * tbl, char * path) { char * p, * q; diff --git a/otherlibs/win32unix/accept.c b/otherlibs/win32unix/accept.c index f705f0f090..ab4747fbfd 100644 --- a/otherlibs/win32unix/accept.c +++ b/otherlibs/win32unix/accept.c @@ -16,7 +16,6 @@ #include <caml/memory.h> #include <caml/signals.h> #include "unixsupport.h" -#include <mswsock.h> // for SO_OPENTYPE and SO_SYNCHRONOUS_NONALERT #include "socketaddr.h" CAMLprim value unix_accept(sock) @@ -25,30 +24,15 @@ CAMLprim value unix_accept(sock) SOCKET sconn = Socket_val(sock); SOCKET snew; value fd = Val_unit, adr = Val_unit, res; - int oldvalue, oldvaluelen, newvalue, retcode; union sock_addr_union addr; socklen_param_type addr_len; DWORD err = 0; - oldvaluelen = sizeof(oldvalue); - retcode = getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, - (char *) &oldvalue, &oldvaluelen); - if (retcode == 0) { - /* Set sockets to synchronous mode */ - newvalue = SO_SYNCHRONOUS_NONALERT; - setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, - (char *) &newvalue, sizeof(newvalue)); - } addr_len = sizeof(sock_addr); enter_blocking_section(); snew = accept(sconn, &addr.s_gen, &addr_len); if (snew == INVALID_SOCKET) err = WSAGetLastError (); leave_blocking_section(); - if (retcode == 0) { - /* Restore initial mode */ - setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, - (char *) &oldvalue, oldvaluelen); - } if (snew == INVALID_SOCKET) { win32_maperr(err); uerror("accept", Nothing); diff --git a/otherlibs/win32unix/socket.c b/otherlibs/win32unix/socket.c index 9385e82e7e..29b3479b8e 100644 --- a/otherlibs/win32unix/socket.c +++ b/otherlibs/win32unix/socket.c @@ -13,7 +13,6 @@ #include <caml/mlvalues.h> #include "unixsupport.h" -#include <mswsock.h> // for SO_OPENTYPE and SO_SYNCHRONOUS_NONALERT int socket_domain_table[] = { PF_UNIX, PF_INET, @@ -32,7 +31,6 @@ CAMLprim value unix_socket(domain, type, proto) value domain, type, proto; { SOCKET s; - int oldvalue, oldvaluelen, newvalue, retcode; #ifndef HAS_IPV6 /* IPv6 requires WinSock2, we must raise an error on PF_INET6 */ @@ -42,23 +40,9 @@ CAMLprim value unix_socket(domain, type, proto) } #endif - oldvaluelen = sizeof(oldvalue); - retcode = getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, - (char *) &oldvalue, &oldvaluelen); - if (retcode == 0) { - /* Set sockets to synchronous mode */ - newvalue = SO_SYNCHRONOUS_NONALERT; - setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, - (char *) &newvalue, sizeof(newvalue)); - } s = socket(socket_domain_table[Int_val(domain)], socket_type_table[Int_val(type)], Int_val(proto)); - if (retcode == 0) { - /* Restore initial mode */ - setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, - (char *) &oldvalue, oldvaluelen); - } if (s == INVALID_SOCKET) { win32_maperr(WSAGetLastError()); uerror("socket", Nothing); |