Setting up an AF_UNIX based launchd server
I have been able to setup a AF_INET launchd based server, but, as I understand it, an AF_UNIX based server offers better performance and there is no need to even think about allowing anything outside of the local machine to access the server. I have made an attempt to get something working, but it is not working yet. I am sure there are several problems with the test code, which can be found at: http://ericgorr.net/pq/AF_UNIX.zip (Developed on Mac OS X 10.6.8 using Xcode 4) On the client side, I try to connect to the server with the following code: #define kServerSocketPath "/var/tmp/net.ericgorr.testserver/Socket" int client_connect( void ) { int socketFD = socket( AF_UNIX, SOCK_STREAM, 0 ); assert( socketFD != -1 ); struct sockaddr_un addr; addr.sun_len = sizeof( addr ); addr.sun_family = AF_UNIX; strcpy( addr.sun_path, kServerSocketPath ); int result; int err; result = connect( socketFD, (struct sockaddr *)&socketFD, sizeof( socketFD ) ); err = MoreUNIXErrno( result ); CFShow( CFStringCreateWithFormat( NULL, NULL, CFSTR( "client_connect: %d" ), err ) ); assert( err == 0 ); return socketFD; } However, the connect call sets errno to 2, which I believes means that it cannot find kServerSocketPath. On the server side, I have the following plist: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>EnableTransactions</key> <true/> <key>Label</key> <string>net.ericgorr.testserver</string> <key>Program</key> <string>/usr/local/libexec/testserver</string> <key>ProgramArguments</key> <array> <string>testserver</string> <string>launchd</string> </array> <key>Sockets</key> <dict> <key>net.ericgorr.testserver.sock</key> <dict> <key>SockFamily</key> <string>Unix</string> <key>SockPathName</key> <string>/var/tmp/net.ericgorr.testserver/Socket</string> <key>SockPathMode</key> <integer>438</integer> <key>SockType</key> <string>Stream</string> </dict> </dict> </dict> </plist> One question is how should /var/tmp/net.ericgorr.testserver/Socket be created? Another question is, after I can launch the server, the server will need to check in with launchd and I need to know what index should be passed to launch_data_array_get_index...? And, where is this documented? These questions seem like they should be straightforward... Thank you.
On 24 Jul 2011, at 23:15, mailist@ericgorr.net wrote:
One question is how should /var/tmp/net.ericgorr.testserver/Socket be created?
This is your fundamental problem. The launchd infrastructure will take care of creating the UNIX domain socket for you, but it won't create intermediate directories. So the socket has to live within a directory that already exists. The standard path is for your service would be "/var/run/net.ericgorr.testserver.socket" ("/var/run" not "/var/tmp", and ".socket" not "/socket").
Another question is, after I can launch the server, the server will need to check in with launchd and I need to know what index should be passed to launch_data_array_get_index...? And, where is this documented?
In the TCP/IP case, the array can contain multiple elements (typically one for IPv4 and one for IPv6) and you are expected to work with all elements. In the UNIX domain sockets case, the array will contain just one element. S+E -- Quinn "The Eskimo!" <http://www.apple.com/developer/> Apple Developer Relations, Developer Technical Support, Core OS/Hardware
On Mon, 25 Jul 2011 10:51:51 +0100, Quinn "The Eskimo!" wrote:
On 24 Jul 2011, at 23:15, mailist@ericgorr.net wrote:
One question is how should /var/tmp/net.ericgorr.testserver/Socket be created?
This is your fundamental problem. The launchd infrastructure will take care of creating the UNIX domain socket for you, but it won't create intermediate directories. So the socket has to live within a directory that already exists. The standard path is for your service would be "/var/run/net.ericgorr.testserver.socket" ("/var/run" not "/var/tmp", and ".socket" not "/socket").
Ok. So, using /var/run and .socket also takes care of the issue mentioned in the CFLocalServer sample code: // This routine is called to safely bind the UNIX domain socket // specified by sockFD to the path specificed by socketPath. To avoid // security problems, socketPath must point it to a sticky directory // (such as "/var/tmp"). This allows us to create the socket with // very specific permissions, without us having to worry about a malicious // process switching stuff out from underneath us. I got a little farther, but my client still won't connect. After rebuilding the server and loading it into launchd, I do see: srw-rw-rw- 1 root daemon 0 Jul 25 06:54 net.ericgorr.testserver.socket= in /var/run In common.h, I now have: #define kServerSocketPath "/var/run/net.ericgorr.testserver.socket" and the client_connect function in the client code remained: int client_connect( void ) { int socketFD = socket( AF_UNIX, SOCK_STREAM, 0 ); assert( socketFD != -1 ); struct sockaddr_un addr; addr.sun_len = sizeof( addr ); addr.sun_family = AF_UNIX; strcpy( addr.sun_path, kServerSocketPath ); int result; int err; result = connect( socketFD, (struct sockaddr *)&socketFD, sizeof( socketFD ) ); err = MoreUNIXErrno( result ); CFShow( CFStringCreateWithFormat( NULL, NULL, CFSTR( "client_connect: %d" ), err ) ); assert( err == 0 ); return socketFD; } However, errno is still set to 2. I have updated the sample project at: http://ericgorr.net/pq/AF_UNIX.zip Thank you.
On 25 Jul 2011, at 12:04, mailist@ericgorr.net wrote:
result = connect( socketFD, (struct sockaddr *)&socketFD, sizeof( socketFD ) );
There's a straightforward programming error in this line. The last two references to "socketFD" should be replaced by references to "addr". S+E -- Quinn "The Eskimo!" <http://www.apple.com/developer/> Apple Developer Relations, Developer Technical Support, Core OS/Hardware
participants (2)
-
mailist@ericgorr.net
-
Quinn "The Eskimo!"