Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 31 Jan 2008 19:47:41 +0100
From:      "Heiko Wundram (Beenic)" <wundram@beenic.net>
To:        Dag-Erling =?utf-8?q?Sm=C3=B8rgrav?= <des@des.no>
Cc:        freebsd-hackers@freebsd.org
Subject:   Re: OT: getting the protocol family of a file descriptor
Message-ID:  <200801311947.42545.wundram@beenic.net>
In-Reply-To: <86myqmvt0z.fsf@ds4.des.no>
References:  <200801310923.16029.wundram@beenic.net> <200801311701.49792.wundram@beenic.net> <86myqmvt0z.fsf@ds4.des.no>

next in thread | previous in thread | raw e-mail | index | archive | help
Am Donnerstag, 31. Januar 2008 17:50:20 schrieb Dag-Erling Sm=C3=B8rgrav:
> "Heiko Wundram (Beenic)" <wundram@beenic.net> writes:
> > Currently, you're basically required to do a getsockname to a struct
> > sockaddr_storage and typecast that to the actual socket addres type
> > based on the ss_family member (to be able to pass it to one of the
> > *_ntop-functions, for example), but generally, I don't find this too
> > beautiful. But, maybe, that's just my (horribly broken) taste. ;-)
>
> Uh, I'm pretty sure there's a function in the getaddr* family that will
> give you a string representation of any struct sockaddr.  Actually, I'm
> absolutely sure of it: getnameinfo() with NI_NUMERICHOST|NI_NUMERICSERV
> will format the numerical address for you instead of looking it up in
> DNS.
>
> But what I really don't understand is this: you say you just want the
> address family so you'll know how to format the address.  If you have
> the address, you already know the family.  So what's the issue, really?

Okay, formatting the address was just an example (and probably a bad one at=
=20
that), and is actually a negligible (diagnostic) part in the backend servic=
e=20
which gets passed a file-descriptor over a Unix Domain socket from other=20
daemons (actually, filters) running on the same machine.

What is the case here is that the server I'm building is basically a servic=
e=20
which works over any kind of SOCK_STREAM, but has to adapt its behaviour=20
slightly depending on the type of the socket being passed in. At the moment=
,=20
there are two different kinds of connections being handled by front-end=20
plugins (which basically accept on a listening socket, set up a certain=20
initial state and pass it to the backend): AF_INET(6) and AF_BLUETOOTH. The=
=20
latter won't work with the getaddr*-functions or getnameinfo() to format th=
e=20
address, and also requires me to handle the connection slightly differently=
=20
in parts (because the information being served is adapted for RFCOMM [i.e.,=
=20
mobile] delivery).

The plugins which accept connections and pass them back aren't written by m=
e,=20
and as such, I wanted to do at least some error checking on the passed in=20
socket (i.e., is SOCK_STREAM, has a family I support, isn't a listening=20
socket, etc.), and what I currently do is similar to the following (that's=
=20
just pseudo-code, beware of anything I got wrong from my head now):

struct sockaddr_storage addr;
socklen_t addrlen =3D sizeof(addr);

getsockname(fd,reinterpret_cast<struct sockaddr*>(&addr),&addrlen);

switch( addr->ss_family ) {
case AF_INET:
	// ...
	break;
case AF_INET6:
	// Set up some stuff...
	getpeername(fd,reinterpret_cast<struct sockaddr*>(&addr),&addrlen);
	...inet_ntop(reinterpret_cast<struct sockaddr*>(&addr));
	break;
case AF_BLUETOOTH:
	// Set up some other stuff...
	getpeername(fd,reinterpret_cast<struct sockaddr*>(&addr),&addrlen);
	bt_ntoa(reinterpret_cast<struct sockaddr_rfcomm*>(&addr)->rfcomm_bdaddr);
	break;
default:
	// We don't know this, ignore.
}

I personally don't find this especially beautiful, and generally, as there =
is=20
a getsockopt(SO_TYPE), I'd have thought the above should look (somewhat)=20
similar to the following:

int opt;
socklen_t optlen =3D sizeof(opt);

getsockopt(fd,SOL_SOCKET,SO_DOMAIN,&opt,&optlen);

switch( opt ) {
case PF_INET:
	// ...
	break;
case PF_INET6:
	// Initialize inet connection.
	initInet6();
	break;
case PF_BLUETOOTH:
	// Initialize bluetooth.
	initBluetooth();
	break;
default:
	// Do something else.
}

where initBluetooth() is

struct sockaddr_rfcomm addr;
socklen_t addrlen =3D sizeof(addr);

getpeername(fd,reinterpret_cast<struct sockaddr*>(&addr),&addrlen);

bt_ntoa(...addr.rfcomm_bdaddr);

There's just one explicit type-cast in the latter (which makes it so much m=
ore=20
readable IMHO).

Anyway, as I said before, this is basically a style issue, and because a=20
socket is constructed with an explicit domain parameter I'd have thought th=
at=20
there is some way to query that constructor argument (and explicitly _only_=
=20
that constructor argument), but apparently, nobody else feels the way I do,=
=20
which I can accept, don't worry. ;-)

=2D-=20
Heiko Wundram
Product & Application Development



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200801311947.42545.wundram>