Subject: Re: Strange behavious of getpeername(2) on pipe
To: Martin J. Laubach <mjl@emsi.priv.at>
From: Frank van der Linden <fvdl@wasabisystems.com>
List: tech-kern
Date: 03/27/2001 15:47:47
On Tue, Mar 27, 2001 at 03:22:05PM +0200, Martin J. Laubach wrote:
> 	if(getpeername(fd) != 0 && errno == ENOTCONN)
> 		{
> 		... fastcgi, input comes via socket and special protocol ...
> 		}
> 	else
> 		{
> 		... normal cgi, input comes via pipe ...
> 		}
> 
>   Unfortunately, this works on all tested unixoid systems (Solaris 7,
> AIX, SINIS, FreeBSD, even OpenBSD!) but not on NetBSD.
> 
>   Therefore: ist our behaviour correct, and if so, what work-arounds
> are possible?

Our pipe call is based on the old BSD implementation, using a pair
of sockets. getpeername() should fail, but because of the implementation,
it succeeds as a side effect.

This doesn't happen anymore on the other BSDs (nor on any other modern
Unix I know), because they adopted a VM-based pipe implementation. Which
is a lot faster, and we should adopt it too. It's a localized, clean
change (basically a seperate source file), so if someone wants to look
at integrating it, be my guest.

Anyway, to determine if something is not a remote socket (i.e.
a plain filedescriptor or an AF_LOCAL socket), you might
want to do something like:

int
is_remote_socket(int fd)
{
	struct sockaddr_storage ss;
	socklen_t slen;

	slen = sizeof ss;
	if (getsockname(fd, &ss, &slen) == -1 || ss.ss_len == 0 ||
	    ss.ss_family == AF_LOCAL)
		return 0;

	return 1;
}

I'm not sure if this is exactly what you're looking for, but
in combination with getpeername() and the connected state of
a socket you can get the data you want in this case. I assume
that for CGI stuff you're not listening to AF_LOCAL (AF_UNIX)
sockets.

- Frank

-- 
Frank van der Linden                           fvdl@wasabisystems.com
======================================================================
Quality NetBSD CDs, Support & Service.   http://www.wasabisystems.com/