*/
#include <config.h>
+
+#ifndef DISABLE_SOCKETS
+
#include <glib.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <sys/poll.h>
+#ifdef HAVE_SYS_UIO_H
+# include <sys/uio.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
#ifdef HAVE_SYS_FILIO_H
#include <sys/filio.h> /* defines FIONBIO and FIONREAD */
#endif
#include <mono/io-layer/socket-private.h>
#include <mono/io-layer/handles-private.h>
#include <mono/io-layer/socket-wrappers.h>
+#include <mono/utils/mono-poll.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <arpa/inet.h>
+#ifdef HAVE_SYS_SENDFILE_H
+#include <sys/sendfile.h>
+#endif
-#undef DEBUG
+#if 0
+#define DEBUG(...) g_message(__VA_ARGS__)
+#else
+#define DEBUG(...)
+#endif
static guint32 startup_count=0;
+static guint32 in_cleanup = 0;
static void socket_close (gpointer handle, gpointer data);
int ret;
struct _WapiHandle_socket *socket_handle = (struct _WapiHandle_socket *)data;
-#ifdef DEBUG
- g_message ("%s: closing socket handle %p", __func__, handle);
-#endif
+ DEBUG ("%s: closing socket handle %p", __func__, handle);
- if (startup_count == 0) {
+ if (startup_count == 0 && !in_cleanup) {
WSASetLastError (WSANOTINITIALISED);
return;
}
if (ret == -1) {
gint errnum = errno;
-#ifdef DEBUG
- g_message ("%s: close error: %s", __func__, strerror (errno));
-#endif
+ DEBUG ("%s: close error: %s", __func__, strerror (errno));
errnum = errno_to_WSA (errnum, __func__);
- WSASetLastError (errnum);
+ if (!in_cleanup)
+ WSASetLastError (errnum);
}
- socket_handle->saved_error = 0;
+ if (!in_cleanup)
+ socket_handle->saved_error = 0;
}
int WSAStartup(guint32 requested, WapiWSAData *data)
data->wVersion = requested < data->wHighVersion? requested:
data->wHighVersion;
-#ifdef DEBUG
- g_message ("%s: high version 0x%x", __func__, data->wHighVersion);
-#endif
+ DEBUG ("%s: high version 0x%x", __func__, data->wHighVersion);
strncpy (data->szDescription, "WAPI", WSADESCRIPTION_LEN);
strncpy (data->szSystemStatus, "groovy", WSASYS_STATUS_LEN);
int WSACleanup(void)
{
-#ifdef DEBUG
- g_message ("%s: cleaning up", __func__);
-#endif
+ DEBUG ("%s: cleaning up", __func__);
if (--startup_count) {
/* Do nothing */
return(0);
}
+ in_cleanup = 1;
_wapi_handle_foreach (WAPI_HANDLE_SOCKET, cleanup_close, NULL);
+ in_cleanup = 0;
return(0);
}
if (new_fd == -1) {
gint errnum = errno;
-#ifdef DEBUG
- g_message ("%s: accept error: %s", __func__, strerror(errno));
-#endif
+ DEBUG ("%s: accept error: %s", __func__, strerror(errno));
errnum = errno_to_WSA (errnum, __func__);
WSASetLastError (errnum);
}
if (new_fd >= _wapi_fd_reserve) {
-#ifdef DEBUG
- g_message ("%s: File descriptor is too big", __func__);
-#endif
+ DEBUG ("%s: File descriptor is too big", __func__);
WSASetLastError (WSASYSCALLFAILURE);
return(INVALID_SOCKET);
}
-#ifdef DEBUG
- g_message ("%s: returning newly accepted socket handle %p with",
+ DEBUG ("%s: returning newly accepted socket handle %p with",
__func__, new_handle);
-#endif
return(new_fd);
}
ret = bind (fd, my_addr, addrlen);
if (ret == -1) {
gint errnum = errno;
-#ifdef DEBUG
- g_message ("%s: bind error: %s", __func__, strerror(errno));
-#endif
+ DEBUG ("%s: bind error: %s", __func__, strerror(errno));
errnum = errno_to_WSA (errnum, __func__);
WSASetLastError (errnum);
}
if (connect (fd, serv_addr, addrlen) == -1) {
- struct pollfd fds;
+ mono_pollfd fds;
int so_error;
socklen_t len;
errnum = errno;
if (errno != EINTR) {
-#ifdef DEBUG
- g_message ("%s: connect error: %s", __func__,
+ DEBUG ("%s: connect error: %s", __func__,
strerror (errnum));
-#endif
errnum = errno_to_WSA (errnum, __func__);
if (errnum == WSAEINPROGRESS)
WAPI_HANDLE_SOCKET,
(gpointer *)&socket_handle);
if (ok == FALSE) {
- g_warning ("%s: error looking up socket handle %p", __func__, handle);
+ /* ECONNRESET means the socket was closed by another thread */
+ /* Async close on mac raises ECONNABORTED. */
+ if (errnum != WSAECONNRESET && errnum != WSAENETDOWN)
+ g_warning ("%s: error looking up socket handle %p (error %d)", __func__, handle, errnum);
} else {
socket_handle->saved_error = errnum;
}
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__);
-#ifdef DEBUG
- g_message ("%s: connect poll error: %s",
+ DEBUG ("%s: connect poll error: %s",
__func__, strerror (errno));
-#endif
WSASetLastError (errnum);
return(SOCKET_ERROR);
&len) == -1) {
errnum = errno_to_WSA (errno, __func__);
-#ifdef DEBUG
- g_message ("%s: connect getsockopt error: %s",
+ DEBUG ("%s: connect getsockopt error: %s",
__func__, strerror (errno));
-#endif
WSASetLastError (errnum);
return(SOCKET_ERROR);
socket_handle->saved_error = errnum;
}
-#ifdef DEBUG
- g_message ("%s: connect getsockopt returned error: %s",
+ DEBUG ("%s: connect getsockopt returned error: %s",
__func__, strerror (so_error));
-#endif
WSASetLastError (errnum);
return(SOCKET_ERROR);
ret = getpeername (fd, name, namelen);
if (ret == -1) {
gint errnum = errno;
-#ifdef DEBUG
- g_message ("%s: getpeername error: %s", __func__,
+ DEBUG ("%s: getpeername error: %s", __func__,
strerror (errno));
-#endif
errnum = errno_to_WSA (errnum, __func__);
WSASetLastError (errnum);
ret = getsockname (fd, name, namelen);
if (ret == -1) {
gint errnum = errno;
-#ifdef DEBUG
- g_message ("%s: getsockname error: %s", __func__,
+ DEBUG ("%s: getsockname error: %s", __func__,
strerror (errno));
-#endif
errnum = errno_to_WSA (errnum, __func__);
WSASetLastError (errnum);
ret = getsockopt (fd, level, optname, tmp_val, optlen);
if (ret == -1) {
gint errnum = errno;
-#ifdef DEBUG
- g_message ("%s: getsockopt error: %s", __func__,
+ DEBUG ("%s: getsockopt error: %s", __func__,
strerror (errno));
-#endif
errnum = errno_to_WSA (errnum, __func__);
WSASetLastError (errnum);
ret = listen (fd, backlog);
if (ret == -1) {
gint errnum = errno;
-#ifdef DEBUG
- g_message ("%s: listen error: %s", __func__, strerror (errno));
-#endif
+ DEBUG ("%s: listen error: %s", __func__, strerror (errno));
errnum = errno_to_WSA (errnum, __func__);
WSASetLastError (errnum);
if (ret == -1) {
gint errnum = errno;
-#ifdef DEBUG
- g_message ("%s: recv error: %s", __func__, strerror(errno));
-#endif
+ DEBUG ("%s: recv error: %s", __func__, strerror(errno));
+
+ errnum = errno_to_WSA (errnum, __func__);
+ WSASetLastError (errnum);
+
+ return(SOCKET_ERROR);
+ }
+ return(ret);
+}
+
+static int
+_wapi_recvmsg(guint32 fd, struct msghdr *msg, int recv_flags)
+{
+ gpointer handle = GUINT_TO_POINTER (fd);
+ struct _WapiHandle_socket *socket_handle;
+ gboolean ok;
+ int ret;
+
+ if (startup_count == 0) {
+ WSASetLastError (WSANOTINITIALISED);
+ return(SOCKET_ERROR);
+ }
+
+ if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
+ WSASetLastError (WSAENOTSOCK);
+ return(SOCKET_ERROR);
+ }
+
+ do {
+ ret = recvmsg (fd, msg, recv_flags);
+ } while (ret == -1 && errno == EINTR &&
+ !_wapi_thread_cur_apc_pending ());
+
+ if (ret == 0) {
+ /* see _wapi_recvfrom */
+ ok = _wapi_lookup_handle (handle, WAPI_HANDLE_SOCKET,
+ (gpointer *)&socket_handle);
+ if (ok == FALSE || socket_handle->still_readable != 1) {
+ ret = -1;
+ errno = EINTR;
+ }
+ }
+
+ if (ret == -1) {
+ gint errnum = errno;
+ DEBUG ("%s: recvmsg error: %s", __func__, strerror(errno));
errnum = errno_to_WSA (errnum, __func__);
WSASetLastError (errnum);
if (ret == -1) {
gint errnum = errno;
-#ifdef DEBUG
- g_message ("%s: send error: %s", __func__, strerror (errno));
-#endif
+ DEBUG ("%s: send error: %s", __func__, strerror (errno));
+#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);
if (ret == -1) {
gint errnum = errno;
-#ifdef DEBUG
- g_message ("%s: send error: %s", __func__, strerror (errno));
-#endif
+ DEBUG ("%s: send error: %s", __func__, strerror (errno));
+
+ errnum = errno_to_WSA (errnum, __func__);
+ WSASetLastError (errnum);
+
+ return(SOCKET_ERROR);
+ }
+ return(ret);
+}
+
+static int
+_wapi_sendmsg(guint32 fd, const struct msghdr *msg, int send_flags)
+{
+ gpointer handle = GUINT_TO_POINTER (fd);
+ int ret;
+
+ if (startup_count == 0) {
+ WSASetLastError (WSANOTINITIALISED);
+ return(SOCKET_ERROR);
+ }
+
+ if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
+ WSASetLastError (WSAENOTSOCK);
+ return(SOCKET_ERROR);
+ }
+
+ do {
+ ret = sendmsg (fd, msg, send_flags);
+ } while (ret == -1 && errno == EINTR &&
+ !_wapi_thread_cur_apc_pending ());
+
+ if (ret == -1) {
+ gint errnum = errno;
+ DEBUG ("%s: sendmsg error: %s", __func__, strerror (errno));
errnum = errno_to_WSA (errnum, __func__);
WSASetLastError (errnum);
ret = setsockopt (fd, level, optname, tmp_val, optlen);
if (ret == -1) {
gint errnum = errno;
-#ifdef DEBUG
- g_message ("%s: setsockopt error: %s", __func__,
+ DEBUG ("%s: setsockopt error: %s", __func__,
strerror (errno));
-#endif
errnum = errno_to_WSA (errnum, __func__);
WSASetLastError (errnum);
/* BSD's and MacOS X multicast sockets also need SO_REUSEPORT when SO_REUSEADDR is requested. */
if (level == SOL_SOCKET && optname == SO_REUSEADDR) {
int type;
- int type_len = sizeof (type);
+ socklen_t type_len = sizeof (type);
if (!getsockopt (fd, level, SO_TYPE, &type, &type_len)) {
if (type == SOCK_DGRAM)
ret = shutdown (fd, how);
if (ret == -1) {
gint errnum = errno;
-#ifdef DEBUG
- g_message ("%s: shutdown error: %s", __func__,
+ DEBUG ("%s: shutdown error: %s", __func__,
strerror (errno));
-#endif
errnum = errno_to_WSA (errnum, __func__);
WSASetLastError (errnum);
if (fd == -1 && domain == AF_INET && type == SOCK_RAW &&
protocol == 0) {
/* Retry with protocol == 4 (see bug #54565) */
+ // https://bugzilla.novell.com/show_bug.cgi?id=MONO54565
socket_handle.protocol = 4;
fd = socket (AF_INET, SOCK_RAW, 4);
}
if (fd == -1) {
gint errnum = errno;
-#ifdef DEBUG
- g_message ("%s: socket error: %s", __func__, strerror (errno));
-#endif
+ DEBUG ("%s: socket error: %s", __func__, strerror (errno));
errnum = errno_to_WSA (errnum, __func__);
WSASetLastError (errnum);
}
if (fd >= _wapi_fd_reserve) {
-#ifdef DEBUG
- g_message ("%s: File descriptor is too big (%d >= %d)",
+ DEBUG ("%s: File descriptor is too big (%d >= %d)",
__func__, fd, _wapi_fd_reserve);
-#endif
WSASetLastError (WSASYSCALLFAILURE);
close (fd);
/* .net seems to set this by default for SOCK_STREAM, not for
* SOCK_DGRAM (see bug #36322)
+ * https://bugzilla.novell.com/show_bug.cgi?id=MONO36322
*
* It seems winsock has a rather different idea of what
* SO_REUSEADDR means. If it's set, then a new socket can be
* behaves as though any other system would when SO_REUSEADDR
* is true, so we don't need to do anything else here. See
* bug 53992.
+ * https://bugzilla.novell.com/show_bug.cgi?id=MONO53992
*/
{
int ret, true = 1;
if (ret == -1) {
int errnum = errno;
-#ifdef DEBUG
- g_message ("%s: Error setting SO_REUSEADDR", __func__);
-#endif
+ DEBUG ("%s: Error setting SO_REUSEADDR", __func__);
errnum = errno_to_WSA (errnum, __func__);
WSASetLastError (errnum);
return(INVALID_SOCKET);
}
-#ifdef DEBUG
- g_message ("%s: returning socket handle %p", __func__, handle);
-#endif
+ DEBUG ("%s: returning socket handle %p", __func__, handle);
return(fd);
}
he = gethostbyname (hostname);
if (he == NULL) {
-#ifdef DEBUG
- g_message ("%s: gethostbyname error: %s", __func__,
+ DEBUG ("%s: gethostbyname error: %s", __func__,
strerror (h_errno));
-#endif
switch(h_errno) {
case HOST_NOT_FOUND:
if (newsock == -1) {
gint errnum = errno;
-#ifdef DEBUG
- g_message ("%s: socket error: %s", __func__, strerror (errno));
-#endif
+ DEBUG ("%s: socket error: %s", __func__, strerror (errno));
errnum = errno_to_WSA (errnum, __func__);
WSASetLastError (errnum);
if (ret == -1) {
gint errnum = errno;
-#ifdef DEBUG
- g_message ("%s: dup2 error: %s", __func__, strerror (errno));
-#endif
+ DEBUG ("%s: dup2 error: %s", __func__, strerror (errno));
errnum = errno_to_WSA (errnum, __func__);
WSASetLastError (errnum);
static gboolean wapi_disconnectex (guint32 fd, WapiOverlapped *overlapped,
guint32 flags, guint32 reserved)
{
-#ifdef DEBUG
- g_message ("%s: called on socket %d!", __func__, fd);
-#endif
+ DEBUG ("%s: called on socket %d!", __func__, fd);
if (reserved != 0) {
WSASetLastError (WSAEINVAL);
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
gpointer func;
} extension_functions[] = {
{WSAID_DISCONNECTEX, wapi_disconnectex},
- {WSAID_TRANSMITFILE, wapi_transmitfile},
+ {WSAID_TRANSMITFILE, TransmitFile},
{{0}, NULL},
};
return(SOCKET_ERROR);
}
+ if (command == SIO_KEEPALIVE_VALS) {
+ uint32_t onoff;
+ uint32_t keepalivetime;
+ uint32_t keepaliveinterval;
+
+ if (i_len < (3 * sizeof (uint32_t))) {
+ WSASetLastError (WSAEINVAL);
+ return SOCKET_ERROR;
+ }
+ memcpy (&onoff, input, sizeof (uint32_t));
+ memcpy (&keepalivetime, input + sizeof (uint32_t), sizeof (uint32_t));
+ memcpy (&keepaliveinterval, input + 2 * sizeof (uint32_t), sizeof (uint32_t));
+ ret = setsockopt (fd, SOL_SOCKET, SO_KEEPALIVE, &onoff, sizeof (uint32_t));
+ if (ret < 0) {
+ gint errnum = errno;
+ errnum = errno_to_WSA (errnum, __func__);
+ WSASetLastError (errnum);
+ return SOCKET_ERROR;
+ }
+ if (onoff != 0) {
+#if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL)
+ /* Values are in ms, but we need s */
+ uint32_t rem;
+
+ /* keepalivetime and keepaliveinterval are > 0 (checked in managed code) */
+ rem = keepalivetime % 1000;
+ keepalivetime /= 1000;
+ if (keepalivetime == 0 || rem >= 500)
+ keepalivetime++;
+ ret = setsockopt (fd, IPPROTO_TCP, TCP_KEEPIDLE, &keepalivetime, sizeof (uint32_t));
+ if (ret == 0) {
+ rem = keepaliveinterval % 1000;
+ keepaliveinterval /= 1000;
+ if (keepaliveinterval == 0 || rem >= 500)
+ keepaliveinterval++;
+ ret = setsockopt (fd, IPPROTO_TCP, TCP_KEEPINTVL, &keepaliveinterval, sizeof (uint32_t));
+ }
+ if (ret != 0) {
+ gint errnum = errno;
+ errnum = errno_to_WSA (errnum, __func__);
+ WSASetLastError (errnum);
+ return SOCKET_ERROR;
+ }
+ return 0;
+#endif
+ }
+ return 0;
+ }
+
if (i_len > 0) {
buffer = g_memdup (input, i_len);
}
ret = ioctl (fd, command, buffer);
if (ret == -1) {
gint errnum = errno;
-#ifdef DEBUG
- g_message("%s: WSAIoctl error: %s", __func__,
+ DEBUG("%s: WSAIoctl error: %s", __func__,
strerror (errno));
-#endif
errnum = errno_to_WSA (errnum, __func__);
WSASetLastError (errnum);
return(0);
}
+#ifndef PLATFORM_PORT_PROVIDES_IOCTLSOCKET
int ioctlsocket(guint32 fd, gint32 command, gpointer arg)
{
gpointer handle = GUINT_TO_POINTER (fd);
}
break;
#endif /* O_NONBLOCK */
- case FIONREAD:
+ /* Unused in Mono */
case SIOCATMARK:
ret = ioctl (fd, command, arg);
break;
+
+ case FIONREAD:
+ {
+#if defined (PLATFORM_MACOSX)
+
+ // ioctl (fd, FIONREAD, XXX) returns the size of
+ // the UDP header as well on
+ // Darwin.
+ //
+ // Use getsockopt SO_NREAD instead to get the
+ // right values for TCP and UDP.
+ //
+ // ai_canonname can be null in some cases on darwin, where the runtime assumes it will
+ // be the value of the ip buffer.
+
+ socklen_t optlen = sizeof (int);
+ ret = getsockopt (fd, SOL_SOCKET, SO_NREAD, arg, &optlen);
+#else
+ ret = ioctl (fd, command, arg);
+#endif
+ break;
+ }
default:
WSASetLastError (WSAEINVAL);
return(SOCKET_ERROR);
if (ret == -1) {
gint errnum = errno;
-#ifdef DEBUG
- g_message ("%s: ioctl error: %s", __func__, strerror (errno));
-#endif
+ DEBUG ("%s: ioctl error: %s", __func__, strerror (errno));
errnum = errno_to_WSA (errnum, __func__);
WSASetLastError (errnum);
if (ret == -1) {
gint errnum = errno;
-#ifdef DEBUG
- g_message ("%s: select error: %s", __func__, strerror (errno));
-#endif
+ DEBUG ("%s: select error: %s", __func__, strerror (errno));
errnum = errno_to_WSA (errnum, __func__);
WSASetLastError (errnum);
FD_SET (fd, set);
}
+#endif
+
+static void
+wsabuf_to_msghdr (WapiWSABuf *buffers, guint32 count, struct msghdr *hdr)
+{
+ guint32 i;
+
+ memset (hdr, 0, sizeof (struct msghdr));
+ hdr->msg_iovlen = count;
+ hdr->msg_iov = g_new0 (struct iovec, count);
+ for (i = 0; i < count; i++) {
+ hdr->msg_iov [i].iov_base = buffers [i].buf;
+ hdr->msg_iov [i].iov_len = buffers [i].len;
+ }
+}
+
+static void
+msghdr_iov_free (struct msghdr *hdr)
+{
+ g_free (hdr->msg_iov);
+}
int WSARecv (guint32 fd, WapiWSABuf *buffers, guint32 count, guint32 *received,
guint32 *flags, WapiOverlapped *overlapped,
WapiOverlappedCB *complete)
{
- int ret, i, buflen = 0, offset = 0, copylen;
- gint8 *recvbuf;
+ int ret;
+ struct msghdr hdr;
g_assert (overlapped == NULL);
g_assert (complete == NULL);
-
- for(i = 0; i < count; i++) {
- buflen += buffers[i].len;
- }
- recvbuf = g_new0 (gint8, buflen);
- ret = _wapi_recvfrom (fd, recvbuf, buflen, *flags, NULL, 0);
+ wsabuf_to_msghdr (buffers, count, &hdr);
+ ret = _wapi_recvmsg (fd, &hdr, *flags);
+ msghdr_iov_free (&hdr);
+
if(ret == SOCKET_ERROR) {
- g_free (recvbuf);
return(ret);
}
- for(i = 0; i < count; i++) {
- copylen = buffers[i].len > (buflen - offset)? (buflen - offset):buffers[i].len;
- memcpy (buffers[i].buf, recvbuf + offset, copylen);
-
- if (copylen != buffers[i].len) {
- break;
- }
- offset += copylen;
- }
-
*received = ret;
+ *flags = hdr.msg_flags;
+
return(0);
}
guint32 flags, WapiOverlapped *overlapped,
WapiOverlappedCB *complete)
{
- int ret, i, buflen = 0, offset = 0, copylen;
- gint8 *sendbuf;
+ int ret;
+ struct msghdr hdr;
g_assert (overlapped == NULL);
g_assert (complete == NULL);
- if (count == 1)
- ret = _wapi_sendto (fd, buffers [0].buf, buffers [0].len, flags, NULL, 0);
- else {
- for(i = 0; i < count; i++) {
- buflen += buffers[i].len;
- }
-
- sendbuf = g_new0 (gint8, buflen);
- for(i = 0; i < count; i++) {
- copylen = buffers[i].len;
- memcpy (sendbuf + offset, buffers[i].buf, copylen);
- offset += copylen;
- }
-
- ret = _wapi_sendto (fd, sendbuf, buflen, flags, NULL, 0);
- g_free (sendbuf);
-
- }
+ wsabuf_to_msghdr (buffers, count, &hdr);
+ ret = _wapi_sendmsg (fd, &hdr, flags);
+ msghdr_iov_free (&hdr);
if(ret == SOCKET_ERROR)
return ret;
*sent = ret;
return 0;
}
+
+#endif /* ifndef DISABLE_SOCKETS */