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 :)

Reply via email to