std.socket is horrible.
Daniel Gibson
metalcaedes at gmail.com
Sun Aug 22 13:13:45 PDT 2010
Hi,
I've been experimenting with passing a socket (descriptor) from one
process to another (on Linux, should be the same on most POSIX systems).
This may be done with ancillary messages (on local AF_UNIX sockets),
which needs sendmsg() and recvmsg() and related structs and
macros/functions, that are currently not available in std.c.*
That is not such a big deal though, I just implemented it in C and
linked it, really painless (if you're interested in the code:
http://pastebin.com/8h1GaAQ7 ).
However, it is not painless at all to create a std.socket.Socket
(compatible) object with an existing socket_t (like the int returned by
recv_fd).
It could be really easy: The Socket class only needs a socket_t and an
AddressFamily object - but they're private and all constructors create
the socket_t themselves - there is no public (or at least protected)
constructor to set it.
And that's where the pain starts: To make it work I derived a class from
std.socket.Socket - and, because its socket_t (sock) and AddressFamily
(_family) are private, I had to copy the whole implementation, just to
add this friggin' constructor.
To add insult to injury, this still doesn't work: apart from minor stuff
that's defined as private on module-level (like private const int
_SOCKET_ERROR and _lasterr()) the most important methods of Address -
the class that wraps struct sockaddr - which are name() (returning a
pointer to the sockaddr) and nameLen() (returning its length) are
protected - WTF?!
This makes this whole class Address useless outside of std.socket. And
it forced me to write a wrapper-class, that provides public getters for
the sockaddr and its length.. not trivial, if the wrapper-class (even
though it's derived from Address) can't access said protected methods..
I had to check (e.g. via "is(addr : InternetAddress)") what specific
kind of Address that is and use the getters (in that case port() and
addr()) of the derived class to build a *new* sockaddr (or sockaddr_in
in that case).. This of course breaks if any new classes derived from
Address appear - the wrapper would have to be updated or it will be
pretty useless (returning null for name()).
And then of course I had to adjust all those methods in Socket
expect/use an Address (bind(), remoteAddress(), sendTo() etc) to wrap
the given Address in my Wrapper-Class and to use my public getters.. -
All this mess just because someone had to protect his class members too
much...
While I'm at it: Support for local sockets (AF_UNIX) could be better -
it'd be nice if struct sockaddr_un was defined somewhere and if there
was a specific class derived from Address for that (like InternetAddress
for internet-addresses). I wrote code for that, feel free to use it:
http://pastebin.com/CLgphG6Q
To make local sockets really painless the function "int socketpair(int
domain, int type, int protocol, int sv[2])" (like defined in
sys/socket.h) or something like that would be nice.
Maybe some static function returning those two sockets as actual
std.socket.Socket objects would be helpful - or again one needs a Socket
constructor that accepts a socket_t...
I've done this with D1/phobos1, but at least the stuff in std.socket
seems the same in phobos2 (I've checked the trunk of the phobos project
at dsource).
Cheers,
- Daniel
PS: If you wanna see or even use the whole mess (all that
aforementioned D code I wrote including the Socket class):
http://pastebin.com/Ldgq8DtV
PPS: Despite my rage about the sockets situation (and more rants may
follow, for example about some things in std.stream) I really enjoy
using D, thanks :-)
More information about the Digitalmars-d
mailing list