Automatically naming local datagrams AF_UNIX?

I am implementing a simple service using datagrams through local unix sockets (AF_UNIX address family, i.e. not UDP ). The server is tied to a public address, and it receives requests just fine. Unfortunately, when it comes to the answer, sendto fails if the client is not connected either. (common error Transport endpoint is not connected ).

Binding to some random name (file or abstract) is applied. But I would like to avoid this: who am I to ensure that the names I choose will not collide?

The documentation in unix socket stream mode tells us that the abstract name will be assigned to them in connect if they don't already have them. Is this feature available for datagram-oriented sockets?

+4
source share
4 answers

I assume you are using Linux; I do not know if this rule applies to SunOS or UNIX.

First answer: after socket () and before connecting () or first sendto () try adding this code:

 struct sockaddr_un me; me.sun_family = AF_UNIX; int result = bind(fd, (void*)&me, sizeof(short)); 

Now the explanation: the unix (7) man page says the following:

When a socket is connected, and it does not have a local address, a unique address in the abstract will create a namespace automatically.

Unfortunately, the manual page is.

Studying the source code for Linux , we see that unix_dgram_connect () calls unix_autobind () if SOCK_PASSCRED is set in the socket flags. Since I do not know what SOCK_PASSCRED is, and now it’s 1:00, I need to look for another solution.

Studying unix_bind , I notice that unix_bind calls unix_autobind if the size of the passed value is "sizeof (short)". So the solution is higher.

Good luck and good morning.

Rob

+4
source

The unix (7) man page I linked to had this information about UNIX sockets for the auto business:

If the bind (2) call indicates addrlen as sizeof (sa_family_t), or the socket parameter SO_PASSCRED was specified for a socket that was not explicitly bound to an address, then the socket is automatically bound to an abstract address.

This is why the Linux kernel checks that the address length is sizeof (short), because sa_family_t is short. Another unix (7) man page referenced by Rob's Great Answer says that client sockets always connect to auto-join, but since SOCK_DGRAM sockets are not available (even though you are connecting to them), I believe this only applies to SOCK_STREAM sockets.

Also note that when providing proper names for name names of names, the socket address in this namespace is specified by extra bytes in sun_path, which are covered by the specified length of the address structure.

 struct sockaddr_un me; const char name[] = "\0myabstractsocket"; me.sun_family = AF_UNIX; // size-1 because abstract socket names are not null terminated memcpy(me.sun_path, name, sizeof(name) - 1); int result = bind(fd, (void*)&me, sizeof(me.sun_family) + sizeof(name) - 1); 

sendto () should also limit the length of the address, and not pass sizeof (sockaddr_un).

+3
source

A bit of a late answer, but for those who find it using Google, like me. Rob Ad's answer helped me get a β€œreal” answer to this question: just use set ( SO_SOCKET level, see man 7 unix ) to set SO_PASSCRED to 1. No silly binding needed.

I used this in PHP, but it does not have SO_PASSCRED (stupid PHP). However, it still works if you define it yourself. On my computer, it has a value of 16, and I believe that it will work quite portable.

0
source

I'm not sure I fully understand your question, but here is the implementation of the echo server datagram that I just wrote. You can see that the server is responding to the client on the same IP / PORT from which it was sent.

Here is the code

First, the server (listener)

 from socket import * import time class Listener: def __init__(self, port): self.port = port self.buffer = 102400 def listen(self): sock = socket(AF_INET, SOCK_DGRAM) sock.bind(('', self.port)) while 1: data, addr = sock.recvfrom(self.buffer) print "Received: " + data print "sending to %s" % addr[0] print "sending data %s" % data time.sleep(0.25) #print addr # will tell you what IP address the request came from and port sock.sendto(data, (addr[0], addr[1])) print "sent" sock.close() if __name__ == "__main__": l = Listener(1975) l.listen() 

And now the Client (sender), which receives a response from the Listener

 from socket import * from time import sleep class Sender: def __init__(self, server): self.port = 1975 self.server = server self.buffer = 102400 def sendPacket(self, packet): sock = socket(AF_INET, SOCK_DGRAM) sock.settimeout(10.75) sock.sendto(packet, (self.server, int(self.port))) while 1: print "waiting for response" data, addr = sock.recvfrom(self.buffer) sock.close() return data if __name__ == "__main__": s = Sender("127.0.0.1") response = s.sendPacket("Hello, world!") print response 
-1
source

Source: https://habr.com/ru/post/1276878/


All Articles