Reputation: 27621
Objective-C makes it very easy to use network sockets with streams doing something like this:
// Setup comms with the server, assumed to be running on the local host
NSHost* host = [NSHost hostWithAddress:@"127.0.0.1"];
NSInputStream *iStream;
NSOutputStream *oStream;
[NSStream getStreamsToHost:host port:_PORT inputStream: &iStream outputStream: &oStream];
However, is it possible to create and or connect to a local domain socket this way, or does Objective-C provide other classes for this?
If I can still use NSStream and getStreamsToHost, how would I specify the file and what would I put for the port number?
My research on this, so far, shows many examples working with TCP/IP or UDP, but not local domain sockets.
Upvotes: 3
Views: 2195
Reputation: 4433
You can’t use -getStreamsToHost:port:inputStream:outputStream:
for a UNIX domain socket, no. You can, however, create your own NSInputStream
and NSOutputStream
instances; the easiest way is to take advantage of toll-free bridging between CF(Read|Write)Stream
and NS(Input|Output)Stream
; for instance:
struct sockaddr_un sun;
sun.sun_family = AF_UNIX;
strcpy (sun.sun_path, "/path/to/my/socket");
sun.sun_len = SUN_LEN(&sun);
// Server side (naive)
int server_sock = socket (SOCK_UNIX, SOCK_STREAM, 0);
int ret = bind (server_sock, (struct sockaddr *)&sun, sun.sun_len);
listen (server_sock, 1); // In practice you'd specify more than 1
s = accept (server_sock, NULL, NULL); // In practice you want to keep calling this
// Client side
int s = socket (SOCK_UNIX, SOCK_STREAM, 0);
int ret = connect (s, (struct sockaddr *)&sun, sun.sun_len);
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocket (kCFAllocatorDefault, s, &readStream, &writeStream);
Then to get an NSInputStream
and NSOutputStream
you can just do
NSInputStream *inputStream = (__bridge_transfer NSInputStream *)readStream;
NSOutputStream *outputStream = (__bridge_transfer NSOutputSteram *)outputStream;
Obviously in practice you may want to wrap all of the above in a function or method in your own code. Also, take care with sockaddr_un
; the sun_path
member was probably supposed to have 1024 characters, but in the headers it seems to only have 104 (this is a long-standing problem and apparently goes way back to BSD4.4; some systems have other character counts here too). This is nowhere near PATH_MAX
, so in practice you may wish to write something more like
struct sockaddr_un *new_unix_addr (const char *path) {
size_t len = strlen (path);
size_t bytes = sizeof (struct sockaddr_un) + len + 1
- sizeof (((struct sockaddr_un *)0)->sun_path);
struct sockaddr_un *pun = (struct sockaddr_un *)malloc (bytes);
pun->sun_family = AF_UNIX;
pun->sun_len = bytes;
memcpy (pun->sun_path, path, len + 1);
return pun;
}
remembering later to free()
it.
Upvotes: 2