Abstract sockets (linux)

freeman via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Fri Jun 26 07:39:13 PDT 2015


On Thursday, 25 June 2015 at 15:56:06 UTC, freeman wrote:
> I am having trouble using abstract sockets on Linux.
>
> Here is sample python code that works, which works:
>     ptm_sockname = "\0/var/run/ptmd.socket"
>     sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
>     sock.connect(ptm_sockname)
>     sock.setblocking(1)
>     sock.sendall('get-status detail')
>
> Similar code in D, which does not work:
>     string socket_name = "\0/var/run/ptmd.socket";
>     auto address = new UnixAddress(socket_name);
>     auto sock = new Socket(AddressFamily.UNIX, 
> SocketType.STREAM);
>     scope(exit) sock.close();
>     sock.blocking = true;
>     sock.connect(address);
>     sock.send("get-status detail");
>
> This is the equivalent with socat, which works:
>     $ echo "get-status detail" | socat - 
> ABSTRACT-CLIENT:/var/run/ptmd.socket
>
> My test D program exits on connect:
> std.socket.SocketOSException at runtime/phobos/std/socket.d(2674): 
> Unable to connect socket: Connection refused
>
> Any pointers?

OK, I believe I've figured it out.  The strace output I posted 
was the clue I needed to see what was going on.  The length of 
abstract sockets are seemingly improperly calculated.

In socket.d, I modified the constructor for UnixAddress as such:
         this(in char[] path)
         {
             //len = 
cast(socklen_t)(sockaddr_un.init.sun_path.offsetof + path.length 
+ 1);
             len = 
cast(socklen_t)(sockaddr_un.init.sun_path.offsetof + path.length);
             writefln("inside UnixSocket, len is %s", len);
             sun = cast(sockaddr_un*) (new ubyte[len]).ptr;
             sun.sun_family = AF_UNIX;
             sun.sun_path.ptr[0..path.length] = (cast(byte[]) 
path)[];
             sun.sun_path.ptr[path.length] = 0;
         }

This also explains why Ali's client/server code works with 
itself, but it doesn't work with my test case.

This seems to be a bug in socket.d.  If the first character of 
the path is a null character, do not add 1 to the length.  I 
don't have much socket programming experience, but my test code 
does work now.

My full test.d code follows, which now works as expected.  I 
compiled it with ยป ldc2 test.d std2/socket.d std2/socketstream.d. 
  The only modifications to socketstream.d was the module name and 
std.socket import.

     import std.stdio;
     import std2.socket;
     import std.stream;
     import std2.socketstream;

     void main() {
         enum string socket_name = "\0/var/run/ptmd.socket";
         auto address = new UnixAddress(socket_name);
         writefln("path is --%s--", address.path);
         writefln("length of string is --%s--", 
socket_name.length);
         writefln("length of address is --%s--", address.nameLen);
         auto sock = new Socket(AddressFamily.UNIX, 
SocketType.STREAM);
         scope(exit) sock.close();
         sock.blocking = true;
         sock.connect(address);
         writeln("connected!");

         Stream streamer = new SocketStream(sock);
         scope(exit) streamer.close();
         streamer.writeLine("get-status detail");
         while(true) {
             auto line = streamer.readLine();
             if (line.length == 0 || line == "EOF") {
                 break;
             }
             writeln(line);
         }
     }

Is this worthy of a bug report?  Not a lot of people use abstract 
sockets, but this was certainly frustrating for my use case :)



More information about the Digitalmars-d-learn mailing list