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