From 8981489becf128c41e2befa6c03e2385e5e396d9 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Thu, 7 Mar 2013 15:39:35 +0000 Subject: [PATCH] * include/sys/un.h (UNIX_PATH_MAX): Rename from UNIX_PATH_LEN to follow Linux. * fhandler_socket.cc: Change UNIX_PATH_LEN to UNIX_PATH_MAX throughout. (fhandler_socket::recv_internal): Don't return prematurely in case of successful return. For AF_LOCAL sockets, overwrite returned AF_INET name with AF_LOCAL name. --- winsup/cygwin/ChangeLog | 9 +++++++ winsup/cygwin/fhandler_socket.cc | 45 +++++++++++++++++++++++++------- winsup/cygwin/include/sys/un.h | 6 ++--- 3 files changed, 48 insertions(+), 12 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 11299dd2b..d509568e1 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,12 @@ +2013-03-07 Corinna Vinschen + + * include/sys/un.h (UNIX_PATH_MAX): Rename from UNIX_PATH_LEN to + follow Linux. + * fhandler_socket.cc: Change UNIX_PATH_LEN to UNIX_PATH_MAX throughout. + (fhandler_socket::recv_internal): Don't return prematurely in case of + successful return. For AF_LOCAL sockets, overwrite returned AF_INET + name with AF_LOCAL name. + 2013-03-07 Corinna Vinschen * fhandler_socket.cc (fhandler_socket::bind): Fix check for AF_LOCAL diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc index d52f75901..1ccc7f81d 100644 --- a/winsup/cygwin/fhandler_socket.cc +++ b/winsup/cygwin/fhandler_socket.cc @@ -905,7 +905,7 @@ fhandler_socket::bind (const struct sockaddr *name, int namelen) /* Check that name is within bounds. Don't check if the string is NUL-terminated, because there are projects out there which set namelen to a value which doesn't cover the trailing NUL. */ - if (len <= 1 || (len = strnlen (un_addr->sun_path, len)) > UNIX_PATH_LEN) + if (len <= 1 || (len = strnlen (un_addr->sun_path, len)) > UNIX_PATH_MAX) { set_errno (len <= 1 ? (len == 1 ? ENOENT : EINVAL) : ENAMETOOLONG); goto out; @@ -1253,7 +1253,7 @@ fhandler_socket::getsockname (struct sockaddr *name, int *namelen) sun.sun_family = AF_LOCAL; sun.sun_path[0] = '\0'; if (get_sun_path ()) - strncat (sun.sun_path, get_sun_path (), UNIX_PATH_LEN - 1); + strncat (sun.sun_path, get_sun_path (), UNIX_PATH_MAX - 1); memcpy (name, &sun, MIN (*namelen, (int) SUN_LEN (&sun) + 1)); *namelen = (int) SUN_LEN (&sun) + (get_sun_path () ? 1 : 0); res = 0; @@ -1327,7 +1327,7 @@ fhandler_socket::getpeername (struct sockaddr *name, int *namelen) sun.sun_family = AF_LOCAL; sun.sun_path[0] = '\0'; if (get_peer_sun_path ()) - strncat (sun.sun_path, get_peer_sun_path (), UNIX_PATH_LEN - 1); + strncat (sun.sun_path, get_peer_sun_path (), UNIX_PATH_MAX - 1); memcpy (name, &sun, MIN (*namelen, (int) SUN_LEN (&sun) + 1)); *namelen = (int) SUN_LEN (&sun) + (get_peer_sun_path () ? 1 : 0); } @@ -1387,6 +1387,7 @@ fhandler_socket::recv_internal (LPWSAMSG wsamsg, bool use_recvmsg) LPWSABUF &wsabuf = wsamsg->lpBuffers; ULONG &wsacnt = wsamsg->dwBufferCount; static NO_COPY LPFN_WSARECVMSG WSARecvMsg; + int orig_namelen = wsamsg->namelen; DWORD wait_flags = wsamsg->dwFlags; bool waitall = !!(wait_flags & MSG_WAITALL); @@ -1483,17 +1484,43 @@ fhandler_socket::recv_internal (LPWSAMSG wsamsg, bool use_recvmsg) /* According to SUSv3, errno isn't set in that case and no error condition is returned. */ if (WSAGetLastError () == WSAEMSGSIZE) - return ret + wret; - - if (!ret) + ret += wret; + else if (!ret) { /* ESHUTDOWN isn't defined for recv in SUSv3. Simply EOF is returned in this case. */ if (WSAGetLastError () == WSAESHUTDOWN) - return 0; + ret = 0; + else + { + set_winsock_errno (); + return SOCKET_ERROR; + } + } + } - set_winsock_errno (); - return SOCKET_ERROR; + if (get_addr_family () == AF_LOCAL && wsamsg->name != NULL + && orig_namelen >= (int) sizeof (sa_family_t)) + { + /* WSARecvFrom copied the sockaddr_in block to wsamsg->name. + We have to overwrite it with a sockaddr_un block. */ + sockaddr_un *un = (sockaddr_un *) wsamsg->name; + un->sun_family = AF_LOCAL; + int len = orig_namelen - offsetof (struct sockaddr_un, sun_path); + if (len > 0) + { + if (!get_peer_sun_path ()) + wsamsg->namelen = sizeof (sa_family_t); + else + { + memset (un->sun_path, 0, len); + strncpy (un->sun_path, get_peer_sun_path (), len); + if (un->sun_path[len - 1] == '\0') + len = strlen (un->sun_path) + 1; + if (len > UNIX_PATH_MAX) + len = UNIX_PATH_MAX; + wsamsg->namelen = offsetof (struct sockaddr_un, sun_path) + len; + } } } diff --git a/winsup/cygwin/include/sys/un.h b/winsup/cygwin/include/sys/un.h index 3d72ba277..a2f3dacb1 100644 --- a/winsup/cygwin/include/sys/un.h +++ b/winsup/cygwin/include/sys/un.h @@ -1,6 +1,6 @@ /* sys/un.h - Copyright 1999, 2000, 2001, 2005, 2009 Red Hat, Inc. + Copyright 1999, 2000, 2001, 2005, 2009, 2013 Red Hat, Inc. This file is part of Cygwin. @@ -15,11 +15,11 @@ details. */ #include /* POSIX requires only at least 100 bytes */ -#define UNIX_PATH_LEN 108 +#define UNIX_PATH_MAX 108 struct sockaddr_un { sa_family_t sun_family; /* address family AF_LOCAL/AF_UNIX */ - char sun_path[UNIX_PATH_LEN]; /* 108 bytes of socket address */ + char sun_path[UNIX_PATH_MAX]; /* 108 bytes of socket address */ }; /* Evaluates the actual length of `sockaddr_un' structure. */