diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 36bb97659..fb8c26310 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,23 @@ +2009-08-13 Corinna Vinschen + + * fhandler.h (class fhandler_socket): Add peer_sun_path member. + (fhandler_socket::set_peer_sun_path): New method. + (fhandler_socket::get_peer_sun_path): New method. + * fhandler_socket.cc (fhandler_socket::fhandler_socket): Initialize + peer_sun_path to NULL. + (fhandler_socket::~fhandler_socket): Free peer_sun_path if necessary. + (fhandler_socket::dup): Duplicate peer_sun_path. + (fhandler_socket::accept): Ditto. Return fake unbound peer content + and len in case of AF_LOCAL sockets. + (fhandler_socket::getsockname): Always use local sockaddr_storage to + store socket address and copy over to incoming address. Handle every + namelen correctly per POSIX. + (fhandler_socket::getpeername): Ditto. Add code path to return + correct value for AF_LOCAL sockets. + (fhandler_socket::set_peer_sun_path): New method. + * net.cc (socketpair): Set peer_sun_path to empty string, just like + sun_path. + 2009-08-13 Corinna Vinschen Dave Korn diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index f661fc01f..7733d8f50 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -462,6 +462,7 @@ class fhandler_socket: public fhandler_base private: char *sun_path; + char *peer_sun_path; struct status_flags { unsigned async_io : 1; /* async I/O */ @@ -533,6 +534,8 @@ class fhandler_socket: public fhandler_base int get_socket_type () {return type;} void set_sun_path (const char *path); char *get_sun_path () {return sun_path;} + void set_peer_sun_path (const char *path); + char *get_peer_sun_path () {return peer_sun_path;} int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2))); int __stdcall fstatvfs (struct statvfs *buf) __attribute__ ((regparm (2))); diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc index 71e4bde4d..80ea0aed1 100644 --- a/winsup/cygwin/fhandler_socket.cc +++ b/winsup/cygwin/fhandler_socket.cc @@ -152,6 +152,7 @@ fhandler_socket::fhandler_socket () : wsock_mtx (NULL), wsock_evt (NULL), sun_path (NULL), + peer_sun_path (NULL), status () { need_fork_fixup (true); @@ -161,6 +162,8 @@ fhandler_socket::~fhandler_socket () { if (sun_path) cfree (sun_path); + if (peer_sun_path) + cfree (peer_sun_path); } char * @@ -664,6 +667,7 @@ fhandler_socket::dup (fhandler_base *child) if (get_addr_family () == AF_LOCAL) { fhs->set_sun_path (get_sun_path ()); + fhs->set_peer_sun_path (get_peer_sun_path ()); if (get_socket_type () == SOCK_STREAM) { fhs->sec_pid = sec_pid; @@ -1043,7 +1047,7 @@ fhandler_socket::connect (const struct sockaddr *name, int namelen) } if (get_addr_family () == AF_LOCAL && (!res || in_progress)) - set_sun_path (name->sa_data); + set_peer_sun_path (name->sa_data); if (get_addr_family () == AF_LOCAL && get_socket_type () == SOCK_STREAM) { @@ -1141,6 +1145,7 @@ fhandler_socket::accept (struct sockaddr *peer, int *len) if (get_addr_family () == AF_LOCAL) { sock->set_sun_path (get_sun_path ()); + sock->set_peer_sun_path (get_peer_sun_path ()); if (get_socket_type () == SOCK_STREAM) { /* Don't forget to copy credentials from accepting @@ -1163,8 +1168,20 @@ fhandler_socket::accept (struct sockaddr *peer, int *len) res = res_fd; if (peer) { - *len = min (*len, llen); - memcpy (peer, &lpeer, *len); + if (get_addr_family () == AF_LOCAL) + { + /* FIXME: Right now we have no way to determine the + bound socket name of the peer's socket. For now + we just fake an unbound socket on the other side. */ + static struct sockaddr_un un = { AF_LOCAL, "" }; + *len = min (*len, 2); + memcpy (peer, &un, *len); + } + else + { + *len = min (*len, llen); + memcpy (peer, &lpeer, *len); + } } } else @@ -1186,28 +1203,29 @@ fhandler_socket::getsockname (struct sockaddr *name, int *namelen) if (get_addr_family () == AF_LOCAL) { - struct sockaddr_un *sun = (struct sockaddr_un *) name; - memset (sun, 0, *namelen); - sun->sun_family = AF_LOCAL; - - if (!get_sun_path ()) - sun->sun_path[0] = '\0'; - else - /* According to SUSv2 "If the actual length of the address is - greater than the length of the supplied sockaddr structure, the - stored address will be truncated." We play it save here so - that the path always has a trailing 0 even if it's truncated. */ - strncpy (sun->sun_path, get_sun_path (), - *namelen - sizeof *sun + sizeof sun->sun_path - 1); - - *namelen = sizeof *sun - sizeof sun->sun_path - + strlen (sun->sun_path) + 1; + struct sockaddr_un sun; + 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); + *namelen = min (*namelen, (int) SUN_LEN (&sun) + 1); + memcpy (name, &sun, *namelen); res = 0; } else { - res = ::getsockname (get_socket (), name, namelen); - if (res) + /* Always use a local big enough buffer and truncate later as necessary + per POSIX. WinSock unfortunaltey only returns WSAEFAULT if the buffer + is too small. */ + struct sockaddr_storage sock; + int len = sizeof sock; + res = ::getsockname (get_socket (), (struct sockaddr *) &sock, &len); + if (!res) + { + *namelen = min (*namelen, len); + memcpy (name, &sock, *namelen); + } + else { if (WSAGetLastError () == WSAEINVAL) { @@ -1219,11 +1237,11 @@ fhandler_socket::getsockname (struct sockaddr *name, int *namelen) { case AF_INET: res = 0; - *namelen = sizeof (struct sockaddr_in); + *namelen = min (*namelen, (int) sizeof (struct sockaddr_in)); break; case AF_INET6: res = 0; - *namelen = sizeof (struct sockaddr_in6); + *namelen = min (*namelen, (int) sizeof (struct sockaddr_in6)); break; default: WSASetLastError (WSAEOPNOTSUPP); @@ -1246,9 +1264,30 @@ fhandler_socket::getsockname (struct sockaddr *name, int *namelen) int fhandler_socket::getpeername (struct sockaddr *name, int *namelen) { - int res = ::getpeername (get_socket (), name, namelen); + /* Always use a local big enough buffer and truncate later as necessary + per POSIX. WinSock unfortunately only returns WSAEFAULT if the buffer + is too small. */ + struct sockaddr_storage sock; + int len = sizeof sock; + int res = ::getpeername (get_socket (), (struct sockaddr *) &sock, &len); if (res) set_winsock_errno (); + else if (get_addr_family () == AF_LOCAL) + { + struct sockaddr_un sun; + memset (&sun, 0, sizeof sun); + 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); + *namelen = min (*namelen, (int) SUN_LEN (&sun) + 1); + memcpy (name, &sun, *namelen); + } + else + { + *namelen = min (*namelen, len); + memcpy (name, &sock, *namelen); + } return res; } @@ -1915,6 +1954,12 @@ fhandler_socket::set_sun_path (const char *path) sun_path = path ? cstrdup (path) : NULL; } +void +fhandler_socket::set_peer_sun_path (const char *path) +{ + peer_sun_path = path ? cstrdup (path) : NULL; +} + int fhandler_socket::getpeereid (pid_t *pid, __uid32_t *euid, __gid32_t *egid) { diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc index efc06ad25..80f869a25 100644 --- a/winsup/cygwin/net.cc +++ b/winsup/cygwin/net.cc @@ -2867,6 +2867,7 @@ socketpair (int family, int type, int protocol, int *sb) if (sb0 >= 0 && fdsock (sb0, dev, insock)) { ((fhandler_socket *) sb0)->set_sun_path (""); + ((fhandler_socket *) sb0)->set_peer_sun_path (""); ((fhandler_socket *) sb0)->set_addr_family (family); ((fhandler_socket *) sb0)->set_socket_type (type); ((fhandler_socket *) sb0)->connect_state (connected); @@ -2878,6 +2879,7 @@ socketpair (int family, int type, int protocol, int *sb) if (sb1 >= 0 && fdsock (sb1, dev, outsock)) { ((fhandler_socket *) sb1)->set_sun_path (""); + ((fhandler_socket *) sb1)->set_peer_sun_path (""); ((fhandler_socket *) sb1)->set_addr_family (family); ((fhandler_socket *) sb1)->set_socket_type (type); ((fhandler_socket *) sb1)->connect_state (connected);