myoung@ingr.UUCP (Mark Young) (10/26/88)
I have a question concerning a call to getpeername(2) in the Xwindow server source (version 11.2). I am cross-posting this message to the the X window group in hopes that someone out there will offer some insight. the bsd4.3 documentation for getpeername reads: getpeername(s,name,namelen) int s; struct sockaddr *name; int *namelen; 'Getpeername' returns the name of the peer connected to socket 's'. The 'namelen' paramter should be initialized to indicate the amount of space pointed to by 'name'. On return it contains the acutal size of the name returned (in bytes). The name is truncated if the buffer provided is too small. A test case on a bsd4.3 release demonstrates that a call to getpeername specifying the fd for a unix domain socket returns success, with a 'namelen' that seems somewhat random. the 'sa_family' field, as well as the 'sa_data' field of the sockaddr struct are all zeros, an indication that the struct was 'bzero'd. There are no special notes in the documentation for getpeername(2) that indicate wierd results with unix domain sockets. I did note, however, that the function getsockname(2) does indeed list as a bug: Names bound to sockets in the UNIX domain are inaccessible; 'getsockname' returns a zero length name. Can someone explain the behavior of the bsd4.3 system in terms of the documentation? This is really strange. /--------------------------------------------------------------------/ /--- this next section intended primarily for server implementors ---/ /--------------------------------------------------------------------/ Based upon the above documentation for getpeername, and in light of the documentation for getsockname, it seems like it would be nice to change the function ConvertAddr in the file access.c. There is no check in ConvertAddr to make sure that the length passed is not zero, which would indicate that the sockaddr structure and associated fields (sa_family) would be invalid. In fact, there is a hint in the code that someone considered this possibility. In the function InvalidHost, if the length returned from getpeername is 0, the call to ConvertAddr passes a null pointer as the length parameter just so that ConvertAddr can special case it. Why not fix ConvertAddr to just check for the length equal to zero? This way you could remove the special case check for null and fix all the other calls to ConvertAddr at the same time. how about: ConvertAddr (saddr, len, addr) register struct sockaddr *saddr; int *len; pointer *addr; { /* * if (len == 0) **** this is no longer needed *** * return (0); */ if (*len == 0) /* cause this fixes the REAL problem */ return(0); switch (saddr->sa_family) { case AF_UNSPEC: case AF_UNIX: return(0); ... default: break; } return(-1); } Forgive me if I'm missing something really obvious. The reason that this turned up is that our kernal folks wrote getpeername to act like the call the getsockname in that it returns a zero length. as far as I can tell using our 4.3 vax, given that it zeros out the sockaddr struct, it should be returning zero length too! don't have the foggiest idea why it returns such randomness in the length parameter. All reasonable consideration welcome, Flames >/dev/null 2>&1, ...myoung --- ingr!myoung!myoung@uunet.uu.net | mark allan young | where {uunet,ihnp4}!ingr!myoung!myoung | intergraph corp, cr1105 | do I | one madison industrial pk | put the "As me about our Intergraph | huntsville, al 35807 | usual CLIPPER-based Workstations." | (205) 772-6094 | disclaimer
chris@mimsy.UUCP (Chris Torek) (10/27/88)
In article <2743@ingr.UUCP> myoung@ingr.UUCP (Mark Young) writes: >A test case on a bsd4.3 release demonstrates that a call to getpeername >specifying the fd for a unix domain socket returns success, with a 'namelen' >that seems somewhat random. Getpeername() on Unix domain sockets is broken in 4.3BSD. The behaviour you describe occurs on unconnected Unix domain sockets. Getpeername() on connected Unix domain sockets crashes the machine. Fixed in 4.3-tahoe, or apply the following to your kernel: [old] case PRU_PEERADDR: if (unp->unp_conn && unp->unp_conn->unp_addr) { nam->m_len = unp->unp_conn->unp_addr->m_len; bcopy(mtod(unp->unp_conn->unp_addr, caddr_t), mtod(m, caddr_t), (unsigned)m->m_len); } break; [new] case PRU_PEERADDR: if (unp->unp_conn && unp->unp_conn->unp_addr) { nam->m_len = unp->unp_conn->unp_addr->m_len; bcopy(mtod(unp->unp_conn->unp_addr, caddr_t), mtod(nam, caddr_t), (unsigned)nam->m_len); } else nam->m_len = 0; >I did note, however, that the function getsockname(2) does indeed list as >a bug: > > Names bound to sockets in the UNIX domain are inaccessible; > 'getsockname' returns a zero length name. The manual entry is wrong on both counts (not surprising)---the 4.3BSD distribution kernel leaves the name length unmodified, due to another kernel bug. Right above the case PRU_PEERADDR, you will find case PRU_SOCKADDR: break; which should read case PRU_SOCKADDR: if (unp->unp_addr) { nam->m_len = unp->unp_addr->m_len; bcopy(mtod(unp->unp_addr, caddr_t), mtod(nam, caddr_t), (unsigned)nam->m_len); } else nam->m_len = 0; break; (exactly analagous to the case for PRU_PEERADDR). -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris