From: Simon Tatham Date: Sun, 17 Nov 2013 14:04:29 +0000 (+0000) Subject: Add support in uxnet.c for Unix-domain listening sockets. X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=commitdiff_plain;h=74bd5355cfb92583e229355a0458827e4ce34561;p=PuTTY_svn.git Add support in uxnet.c for Unix-domain listening sockets. There are two new functions: one to construct a SockAddr wrapping a Unix socket pathname (which can also be used as the destination for new_connection), and one to establish a new listening Unix-domain socket. git-svn-id: http://svn.tartarus.org/sgt/putty@10072 cda61777-01e9-0310-a592-d414129be87e --- diff --git a/unix/uxnet.c b/unix/uxnet.c index f15795cf..0bd0f9f5 100644 --- a/unix/uxnet.c +++ b/unix/uxnet.c @@ -316,10 +316,7 @@ static int sk_nextaddr(SockAddr addr, SockAddrStep *step) void sk_getaddr(SockAddr addr, char *buf, int buflen) { - /* XXX not clear what we should return for Unix-domain sockets; let's - * hope the question never arises */ - assert(addr->superfamily != UNIX); - if (addr->superfamily == UNRESOLVED) { + if (addr->superfamily == UNRESOLVED || addr->superfamily == UNIX) { strncpy(buf, addr->hostname, buflen); buf[buflen-1] = '\0'; } else { @@ -1281,8 +1278,8 @@ static int net_select_result(int fd, int event) nonblock(t); actx.i = t; - if (s->localhost_only && - !sockaddr_is_loopback(&su.sa)) { + if ((!s->addr || s->addr->superfamily != UNIX) && + s->localhost_only && !sockaddr_is_loopback(&su.sa)) { close(t); /* someone let nonlocal through?! */ } else if (plug_accepting(s->plug, sk_tcp_accept, actx)) { close(t); /* denied or error */ @@ -1494,3 +1491,104 @@ SockAddr platform_get_x11_unix_address(const char *sockpath, int displaynum) ret->refcount = 1; return ret; } + +SockAddr unix_sock_addr(const char *path) +{ + SockAddr ret = snew(struct SockAddr_tag); + int n; + + memset(ret, 0, sizeof *ret); + ret->superfamily = UNIX; + n = snprintf(ret->hostname, sizeof ret->hostname, "%s", path); + + if (n < 0) + ret->error = "snprintf failed"; + else if (n >= sizeof ret->hostname) + ret->error = "socket pathname too long"; + +#ifndef NO_IPV6 + ret->ais = NULL; +#else + ret->addresses = NULL; + ret->naddresses = 0; +#endif + ret->refcount = 1; + return ret; +} + +Socket new_unix_listener(SockAddr listenaddr, Plug plug) +{ + int s; + union sockaddr_union u; + union sockaddr_union *addr; + int addrlen; + Actual_Socket ret; + int retcode; + + /* + * Create Socket structure. + */ + ret = snew(struct Socket_tag); + ret->fn = &tcp_fn_table; + ret->error = NULL; + ret->plug = plug; + bufchain_init(&ret->output_data); + ret->writable = 0; /* to start with */ + ret->sending_oob = 0; + ret->frozen = 0; + ret->localhost_only = TRUE; + ret->pending_error = 0; + ret->parent = ret->child = NULL; + ret->oobpending = FALSE; + ret->outgoingeof = EOF_NO; + ret->incomingeof = FALSE; + ret->listener = 1; + ret->addr = listenaddr; + + assert(listenaddr->superfamily == UNIX); + + /* + * Open socket. + */ + s = socket(AF_UNIX, SOCK_STREAM, 0); + if (s < 0) { + ret->error = strerror(errno); + return (Socket) ret; + } + + cloexec(s); + + ret->oobinline = 0; + + memset(&u, '\0', sizeof(u)); + u.su.sun_family = AF_UNIX; + strncpy(u.su.sun_path, listenaddr->hostname, sizeof(u.su.sun_path)-1); + addr = &u; + addrlen = sizeof(u.su); + + if (unlink(u.su.sun_path) < 0 && errno != ENOENT) { + close(s); + ret->error = strerror(errno); + return (Socket) ret; + } + + retcode = bind(s, &addr->sa, addrlen); + if (retcode < 0) { + close(s); + ret->error = strerror(errno); + return (Socket) ret; + } + + if (listen(s, SOMAXCONN) < 0) { + close(s); + ret->error = strerror(errno); + return (Socket) ret; + } + + ret->s = s; + + uxsel_tell(ret); + add234(sktree, ret); + + return (Socket) ret; +}