Thread overview
Abstract sockets (linux)
Jun 25, 2015
freeman
Jun 25, 2015
freeman
Jun 25, 2015
Daniel Kozak
Jun 25, 2015
freeman
Jun 25, 2015
Ali Çehreli
Jun 26, 2015
freeman
Jun 26, 2015
Kagamin
Jun 26, 2015
freeman
Jun 26, 2015
Ali Çehreli
June 25, 2015
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@runtime/phobos/std/socket.d(2674): Unable to connect socket: Connection refused

Any pointers?
June 25, 2015
On 6/25/15 11:56 AM, 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@runtime/phobos/std/socket.d(2674): Unable
> to connect socket: Connection refused
>
> Any pointers?

I believe there was a recently fixed bug regarding unix sockets. The upcoming 2.068 may help, have you tried the beta?

http://downloads.dlang.org/pre-releases/2.x/2.068.0/

-Steve
June 25, 2015
On Thursday, 25 June 2015 at 16:07:51 UTC, Steven Schveighoffer wrote:
> I believe there was a recently fixed bug regarding unix sockets. The upcoming 2.068 may help, have you tried the beta?
>
> http://downloads.dlang.org/pre-releases/2.x/2.068.0/
>
> -Steve

Unfortunately the problem persists (I was using ldc2 before):

$ ./test
std.socket.SocketOSException@std/socket.d(2808): Unable to connect socket: Connection refused
----------------
./test(_Dmain+0xce) [0x443b42]
./test(_D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ6runAllMFZ9__lambda1MFZv+0x1f) [0x44ad7b]
./test(void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).tryExec(scope void delegate())+0x2a) [0x44acd6]
./test(void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).runAll()+0x2b) [0x44ad37]
./test(void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).tryExec(scope void delegate())+0x2a) [0x44acd6]
./test(_d_run_main+0x1d2) [0x44ac56]
./test(main+0x12) [0x447e96]
/lib64/libc.so.6(__libc_start_main+0xfd) [0x7f1bff50cd5d]


June 25, 2015
On Thu, 25 Jun 2015 15:56:04 +0000
freeman via Digitalmars-d-learn <digitalmars-d-learn@puremagic.com> 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@runtime/phobos/std/socket.d(2674): Unable to connect socket: Connection refused
> 
> Any pointers?

instead of:
string socket_name = "\0/var/run/ptmd.socket";
try:
string socket_name = "/var/run/ptmd.socket";
works for me
June 25, 2015
On Thursday, 25 June 2015 at 18:50:29 UTC, Daniel Kozak wrote:
>> Any pointers?
>
> instead of:
> string socket_name = "\0/var/run/ptmd.socket";
> try:
> string socket_name = "/var/run/ptmd.socket";
> works for me

It is the null character that makes it an abstract socket (see man unix).  There is no file /var/run/ptmd.socket, as what follows the null character is just a name:
    $ ls -al /var/run/ptmd.socket
    ls: cannot access /var/run/ptmd.socket: No such file or directory

Here is what happens when I remove the null:
    std.socket.SocketOSException@runtime/phobos/std/socket.d(2674): Unable to connect socket: No such file or directory
June 25, 2015
On 06/25/2015 08:56 AM, 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@runtime/phobos/std/socket.d(2674): Unable
> to connect socket: Connection refused
>
> Any pointers?

I've found an old example of mine, which uses abstract sockets. Apparently, it was a concurrency experiment as well. Just translated from Turkish to English:

  http://ddili.org/ornek_kod/client_server.d

One difference I see is that mine doesn't set blocking. You can use it like this:

1) Start it as a server:

  ./deneme --role=server

2) Start as many clients as needed:

  ./deneme --role=client

Ali

P.S. And here is the original Turkish version:

  http://ddili.org/ornek_kod/istemci_sunucu.d

June 26, 2015
On Thursday, 25 June 2015 at 19:47:37 UTC, Ali Çehreli wrote:
>
> I've found an old example of mine, which uses abstract sockets. Apparently, it was a concurrency experiment as well. Just translated from Turkish to English:
>
>   http://ddili.org/ornek_kod/client_server.d
>
> One difference I see is that mine doesn't set blocking. You can use it like this:
>
> 1) Start it as a server:
>
>   ./deneme --role=server
>
> 2) Start as many clients as needed:
>
>   ./deneme --role=client
>
> Ali
>
> P.S. And here is the original Turkish version:
>
>   http://ddili.org/ornek_kod/istemci_sunucu.d

Thank you for the example code!  I verified that client and server communicated, and that a standard file-based unix socket was not created.  Then I simply changed the socketName to the socket I was interested in, and tried the client against it.  Still no luck unfortunately, same error as earlier.

I have noticed that successful connect calls appear to show the size as 23, whereas unsuccessful connect calls show 24.

This works (socat):
    connect(3, {sa_family=AF_FILE, path=@"/var/run/ptmd.socket"}, 23) = 0

This does not (from deneme, modified):
    connect(3, {sa_family=AF_FILE, path=@"/var/run/ptmd.socket"}, 24) = -1 ECONNREFUSED (Connection refused)
June 26, 2015
On Friday, 26 June 2015 at 13:36:49 UTC, freeman wrote:
> This works (socat):
>     connect(3, {sa_family=AF_FILE, path=@"/var/run/ptmd.socket"}, 23) = 0
>
> This does not (from deneme, modified):
>     connect(3, {sa_family=AF_FILE, path=@"/var/run/ptmd.socket"}, 24) = -1 ECONNREFUSED (Connection refused)

Looks like contrary to other sockets, name of an abstract socket is treated as byte array instead of a string, hence every byte counts.
June 26, 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@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 :)

June 26, 2015
On 06/26/2015 07:39 AM, freeman wrote:

> Is this worthy of a bug report?

If it's a bug, yes. :)

Ali