digitalmars.D - std.socket is horrible.
- Daniel Gibson (63/63) Aug 22 2010 Hi,
- Pedro Rodrigues (4/4) Aug 22 2010 I've run into similar problems and also ended up having to re-implement ...
- cemiller (18/18) Aug 22 2010 Would the problems be resolved with the following changes?
- Daniel Gibson (25/49) Aug 22 2010 I stumbled upon this after sending my initial mail - yes, this should
- Pedro Rodrigues (3/21) Aug 23 2010 Yes, that would most certainly help a lot.
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 :-)
Aug 22 2010
I've run into similar problems and also ended up having to re-implement a great part of the sockets module. A fix for these issues would be much welcomed. Regards
Aug 22 2010
Would the problems be resolved with the following changes? Add a Socket class constructor: this(socket_t sock, AddressFamily af) { assert(sock != socket_t.init); this.sock = sock; this._family = af; } Socket.newFamilyObject(): This is currently private but can be made protected to allow overriding to return new address types. Address.name() and Address.nameLen(): Is there a function you need to call with these? I suppose they can be made public just in case they're needed elsewhere. As for things like _SOCKET_ERROR and _lasterr(), they're just simple shortcuts to the low-level sockets. If you're working with the low-level sockets, then you have access to what _SOCKET_ERROR and _lasterr() refer to; otherwise, you don't need them.
Aug 22 2010
cemiller schrieb:Would the problems be resolved with the following changes? Add a Socket class constructor: this(socket_t sock, AddressFamily af) { assert(sock != socket_t.init); this.sock = sock; this._family = af; }Yes, this constructor would be really helpful.Socket.newFamilyObject(): This is currently private but can be made protected to allow overriding to return new address types.I stumbled upon this after sending my initial mail - yes, this should definitely be protected instead of private.Address.name() and Address.nameLen(): Is there a function you need to call with these? I suppose they can be made public just in case they're needed elsewhere.The obvious case (I came across myself) is that one might want to derive Socket and override methods like bind. Another thing is that you could just use the relatively high-level/painless Address-classes (like InternetAddress) to get such an Object and still pass the contained sockaddr to low-level functions that need it. IMHO they should just be made public, I guess it won't do any harm ;)As for things like _SOCKET_ERROR and _lasterr(), they're just simple shortcuts to the low-level sockets. If you're working with the low-level sockets, then you have access to what _SOCKET_ERROR and _lasterr() refer to; otherwise, you don't need them.I know, that's why I called it "minor stuff" - it really doesn't have to be exposed outside of std.socket. It was mainly the fact that I couldn't set the socket_t of Socket and couldn't access Address.name() and Address.nameLen() outside of std.socket that annoyed me. Considering that (if I'm not mistaken) you're the original author of that Code: Please don't take my rant personally, I guess you just didn't consider this weird stuff I'm doing when you were writing it - after all the Socket class is meant to be a higher level abstraction of sockets so it seems natural not to expose the internal socket handle. Apart from these small issues (that can easily be fixed by the maintainer) the I find general interface of std.socket quite usable :-) Cheers, - Daniel
Aug 22 2010
Yes, that would most certainly help a lot. "cemiller" <chris dprogramming.com> wrote in message news:op.vhu594gqycwdcp christop...Would the problems be resolved with the following changes? Add a Socket class constructor: this(socket_t sock, AddressFamily af) { assert(sock != socket_t.init); this.sock = sock; this._family = af; } Socket.newFamilyObject(): This is currently private but can be made protected to allow overriding to return new address types. Address.name() and Address.nameLen(): Is there a function you need to call with these? I suppose they can be made public just in case they're needed elsewhere. As for things like _SOCKET_ERROR and _lasterr(), they're just simple shortcuts to the low-level sockets. If you're working with the low-level sockets, then you have access to what _SOCKET_ERROR and _lasterr() refer to; otherwise, you don't need them.
Aug 23 2010