X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fio-layer%2Fsockets.c;h=c068f06281d7794ba5f88e7058b10a59a00883cc;hb=5b558abeeb255a3179d4ca6a85617e051c6abd38;hp=e4f35874692054fd3b4adb320d55874df5bc13cf;hpb=0bd4004c832f6c5a02c35cada2b6fdbedd1563a2;p=mono.git diff --git a/mono/io-layer/sockets.c b/mono/io-layer/sockets.c index e4f35874692..c068f06281d 100644 --- a/mono/io-layer/sockets.c +++ b/mono/io-layer/sockets.c @@ -8,16 +8,21 @@ */ #include + +#ifndef DISABLE_SOCKETS + #include #include #include #include #include #include +#ifdef HAVE_SYS_UIO_H +# include +#endif #ifdef HAVE_SYS_IOCTL_H # include #endif -#include #ifdef HAVE_SYS_FILIO_H #include /* defines FIONBIO and FIONREAD */ #endif @@ -36,11 +41,15 @@ #include #include #include +#include #include #include #include #include +#ifdef HAVE_SYS_SENDFILE_H +#include +#endif #undef DEBUG @@ -305,7 +314,7 @@ int _wapi_connect(guint32 fd, const struct sockaddr *serv_addr, } if (connect (fd, serv_addr, addrlen) == -1) { - struct pollfd fds; + mono_pollfd fds; int so_error; socklen_t len; @@ -346,7 +355,7 @@ int _wapi_connect(guint32 fd, const struct sockaddr *serv_addr, fds.fd = fd; fds.events = POLLOUT; - while (poll (&fds, 1, -1) == -1 && + while (mono_poll (&fds, 1, -1) == -1 && !_wapi_thread_cur_apc_pending ()) { if (errno != EINTR) { errnum = errno_to_WSA (errno, __func__); @@ -708,6 +717,15 @@ int _wapi_send(guint32 fd, const void *msg, size_t len, int send_flags) g_message ("%s: send error: %s", __func__, strerror (errno)); #endif +#ifdef O_NONBLOCK + /* At least linux returns EAGAIN/EWOULDBLOCK when the timeout has been set on + * a blocking socket. See bug #599488 */ + if (errnum == EAGAIN) { + ret = fcntl (fd, F_GETFL, 0); + if (ret != -1 && (ret & O_NONBLOCK) == 0) + errnum = ETIMEDOUT; + } +#endif /* O_NONBLOCK */ errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); @@ -1118,29 +1136,112 @@ static gboolean wapi_disconnectex (guint32 fd, WapiOverlapped *overlapped, return(socket_disconnect (fd)); } -/* NB only supports NULL file handle, NULL buffers and - * TF_DISCONNECT|TF_REUSE_SOCKET flags to disconnect the socket fd. - * Shouldn't actually ever need to be called anyway though, because we - * have DisconnectEx (). - */ -static gboolean wapi_transmitfile (guint32 fd, gpointer file, - guint32 num_write, guint32 num_per_send, - WapiOverlapped *overlapped, - WapiTransmitFileBuffers *buffers, - WapiTransmitFileFlags flags) +#define SF_BUFFER_SIZE 16384 +static gint +wapi_sendfile (guint32 socket, gpointer fd, guint32 bytes_to_write, guint32 bytes_per_send, guint32 flags) { -#ifdef DEBUG - g_message ("%s: called on socket %d!", __func__, fd); +#if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN)) + gint file = GPOINTER_TO_INT (fd); + gint n; + gint errnum; + gssize res; + struct stat statbuf; + + n = fstat (file, &statbuf); + if (n == -1) { + errnum = errno; + errnum = errno_to_WSA (errnum, __func__); + WSASetLastError (errnum); + return SOCKET_ERROR; + } + do { +#ifdef __linux__ + res = sendfile (socket, file, NULL, statbuf.st_size); +#elif defined(DARWIN) + /* TODO: header/tail could be sent in the 5th argument */ + /* TODO: Might not send the entire file for non-blocking sockets */ + res = sendfile (file, socket, 0, &statbuf.st_size, NULL, 0); +#endif + } while (res != -1 && (errno == EINTR || errno == EAGAIN) && !_wapi_thread_cur_apc_pending ()); + if (res == -1) { + errnum = errno; + errnum = errno_to_WSA (errnum, __func__); + WSASetLastError (errnum); + return SOCKET_ERROR; + } +#else + /* Default implementation */ + gint file = GPOINTER_TO_INT (fd); + gchar *buffer; + gint n; + + buffer = g_malloc (SF_BUFFER_SIZE); + do { + do { + n = read (file, buffer, SF_BUFFER_SIZE); + } while (n == -1 && errno == EINTR && !_wapi_thread_cur_apc_pending ()); + if (n == -1) + break; + if (n == 0) { + g_free (buffer); + return 0; /* We're done reading */ + } + do { + n = send (socket, buffer, n, 0); /* short sends? enclose this in a loop? */ + } while (n == -1 && errno == EINTR && !_wapi_thread_cur_apc_pending ()); + } while (n != -1); + + if (n == -1) { + gint errnum = errno; + errnum = errno_to_WSA (errnum, __func__); + WSASetLastError (errnum); + g_free (buffer); + return SOCKET_ERROR; + } + g_free (buffer); #endif + return 0; +} + +gboolean +TransmitFile (guint32 socket, gpointer file, guint32 bytes_to_write, guint32 bytes_per_send, WapiOverlapped *ol, + WapiTransmitFileBuffers *buffers, guint32 flags) +{ + gpointer sock = GUINT_TO_POINTER (socket); + gint ret; - g_assert (file == NULL); - g_assert (overlapped == NULL); - g_assert (buffers == NULL); - g_assert (num_write == 0); - g_assert (num_per_send == 0); - g_assert (flags == (TF_DISCONNECT | TF_REUSE_SOCKET)); + if (startup_count == 0) { + WSASetLastError (WSANOTINITIALISED); + return FALSE; + } + + if (_wapi_handle_type (sock) != WAPI_HANDLE_SOCKET) { + WSASetLastError (WSAENOTSOCK); + return FALSE; + } - return(socket_disconnect (fd)); + /* Write the header */ + if (buffers != NULL && buffers->Head != NULL && buffers->HeadLength > 0) { + ret = _wapi_send (socket, buffers->Head, buffers->HeadLength, 0); + if (ret == SOCKET_ERROR) + return FALSE; + } + + ret = wapi_sendfile (socket, file, bytes_to_write, bytes_per_send, flags); + if (ret == SOCKET_ERROR) + return FALSE; + + /* Write the tail */ + if (buffers != NULL && buffers->Tail != NULL && buffers->TailLength > 0) { + ret = _wapi_send (socket, buffers->Tail, buffers->TailLength, 0); + if (ret == SOCKET_ERROR) + return FALSE; + } + + if ((flags & TF_DISCONNECT) == TF_DISCONNECT) + closesocket (socket); + + return TRUE; } static struct @@ -1149,7 +1250,7 @@ static struct gpointer func; } extension_functions[] = { {WSAID_DISCONNECTEX, wapi_disconnectex}, - {WSAID_TRANSMITFILE, wapi_transmitfile}, + {WSAID_TRANSMITFILE, TransmitFile}, {{0}, NULL}, }; @@ -1492,3 +1593,5 @@ int WSASend (guint32 fd, WapiWSABuf *buffers, guint32 count, guint32 *sent, *sent = ret; return 0; } + +#endif /* ifndef DISABLE_SOCKETS */