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>
