OT: getting the protocol family of a file descriptor

Heiko Wundram (Beenic) wundram at beenic.net
Thu Jan 31 10:47:19 PST 2008


Am Donnerstag, 31. Januar 2008 17:50:20 schrieb Dag-Erling Smørgrav:
> "Heiko Wundram (Beenic)" <wundram at 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 
that), and is actually a negligible (diagnostic) part in the backend service 
which gets passed a file-descriptor over a Unix Domain socket from other 
daemons (actually, filters) running on the same machine.

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

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

struct sockaddr_storage addr;
socklen_t addrlen = 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 
a getsockopt(SO_TYPE), I'd have thought the above should look (somewhat) 
similar to the following:

int opt;
socklen_t optlen = 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 = 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 more 
readable IMHO).

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

-- 
Heiko Wundram
Product & Application Development


More information about the freebsd-hackers mailing list