From: Fredrik Tolf Date: Fri, 17 Oct 2008 23:11:09 +0000 (+0200) Subject: Merge branch 'master' into socket X-Git-Tag: 1.3~11^2 X-Git-Url: http://dolda2000.com/gitweb/?p=doldaconnect.git;a=commitdiff_plain;h=51da262d8d796aa8a31ee1513783735a40130931;hp=3c7f2d14ba774a61baea64c9180b8d70cbe3e020 Merge branch 'master' into socket Conflicts: daemon/net.c --- diff --git a/daemon/auth-unix.c b/daemon/auth-unix.c index 00266e1..7cf9c8e 100644 --- a/daemon/auth-unix.c +++ b/daemon/auth-unix.c @@ -59,16 +59,18 @@ static int unixauth(struct authhandle *auth, struct socket *sk, char *passdata) { struct passwd *pwd; struct unixdata *data; + uid_t uid; + gid_t gid; data = auth->mechdata; if((pwd = getpwnam(data->username)) == NULL) return(AUTH_ERR); - if(sk->ucred.uid == -1) { + if(getucred(sk, &uid, &gid)) { errno = EOPNOTSUPP; /* Bleh */ return(AUTH_ERR); } - if(pwd->pw_uid == sk->ucred.uid) { - flog(LOG_INFO, "successful authentication as %s with Unix credentials (uid=%i, gid=%i)", data->username, sk->ucred.uid, sk->ucred.gid); + if(pwd->pw_uid == uid) { + flog(LOG_INFO, "successful authentication as %s with Unix credentials (uid=%i, gid=%i)", data->username, uid, gid); return(AUTH_SUCCESS); } auth->text = swcsdup(L"Unix credentials do not match supplied user name"); @@ -77,7 +79,7 @@ static int unixauth(struct authhandle *auth, struct socket *sk, char *passdata) static int available(struct socket *sk) { - return((sk->family == PF_UNIX) && (sk->ucred.uid != -1)); + return(sockfamily(sk) == PF_UNIX); } static struct authmech mechdesc = { diff --git a/daemon/fnet-adc.c b/daemon/fnet-adc.c index a15575d..0112710 100644 --- a/daemon/fnet-adc.c +++ b/daemon/fnet-adc.c @@ -81,7 +81,8 @@ struct adchub { static wchar_t *eoc, *ns, *fmt; /* I've never understood why both of these are necessary, but... */ static wchar_t *privid, *cid; -struct socket *udpsock, *tcpsock; +struct socket *udpsock; +struct lport *tcpsock; static wchar_t **parseadc(wchar_t *cmdline) { @@ -240,13 +241,13 @@ static void sendinf(struct fnetnode *fn) sendadc(sk, 1, L"VEDolda ", ns, icsmbstowcs(VERSION, "us-ascii", NULL), NULL); sendadc(sk, 1, L"NI", ns, fn->mynick, NULL); sendadc(sk, 1, L"SS", ns, fmt, L"mi", (intmax_t)sharesize, L"SF", ns, fmt, L"i", sharedfiles, NULL); - if(sk->family == AF_INET) + if(sockfamily(sk) == AF_INET) sendadc(sk, 1, L"I40.0.0.0", NULL); - else if(sk->family == AF_INET6) + else if(sockfamily(sk) == AF_INET6) sendadc(sk, 1, L"I6::", NULL); sendadc(sk, 1, L"SL", ns, fmt, L"i", confgetint("transfer", "slot"), NULL); if(tcpsock != NULL) { - if((sk->family == AF_INET) && !sockgetremotename(udpsock, (struct sockaddr **)&a4, &alen)) { + if((sockfamily(sk) == AF_INET) && !sockgetremotename(udpsock, (struct sockaddr **)&a4, &alen)) { sendadc(sk, 1, L"U4", ns, fmt, L"i", ntohs(a4->sin_port), NULL); free(a4); } @@ -359,7 +360,7 @@ static void dispatch(struct qcmd *qcmd, struct fnetnode *fn) flog(LOG_DEBUG, "unknown adc command: %ls", qcmd->args[0]); } -static void peeraccept(struct socket *sk, struct socket *newsk, void *uudata) +static void peeraccept(struct lport *lp, struct socket *newsk, void *uudata) { } @@ -463,7 +464,7 @@ static void hubkill(struct fnetnode *fn) struct adchub *hub; hub = fn->data; - hub->sk->close = 1; + closesock(hub->sk); } static int hubsetnick(struct fnetnode *fn, wchar_t *newnick) @@ -565,7 +566,7 @@ static int updateudpport(struct configvar *var, void *uudata) static int updatetcpport(struct configvar *var, void *uudata) { struct sockaddr_in addr; - struct socket *newsock; + struct lport *newsock; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; @@ -573,7 +574,7 @@ static int updatetcpport(struct configvar *var, void *uudata) if((newsock = netcslisten(SOCK_STREAM, (struct sockaddr *)&addr, sizeof(addr), peeraccept, NULL)) == NULL) flog(LOG_INFO, "could not listen to a remote address, going into passive mode"); if(tcpsock != NULL) - putsock(tcpsock); + closelport(tcpsock); tcpsock = newsock; return(0); } diff --git a/daemon/fnet-dc.c b/daemon/fnet-dc.c index 5123c80..828e6d0 100644 --- a/daemon/fnet-dc.c +++ b/daemon/fnet-dc.c @@ -141,7 +141,7 @@ struct dcpeer static struct fnet dcnet; static struct transferiface dctransfer; static struct socket *udpsock = NULL; -static struct socket *tcpsock = NULL; +static struct lport *tcpsock = NULL; static struct dcpeer *peers = NULL; int numdcpeers = 0; static struct dcexppeer *expected = NULL; @@ -1145,7 +1145,7 @@ static void cmd_search(struct socket *sk, struct fnetnode *fn, char *cmd, char * goto out; prefix = sprintf2("$SR %s ", hub->nativenick); infix = sprintf2(" %i/%i\005", slotsleft(), confgetint("transfer", "slots")); - postfix = sprintf2(" (%s)\005%s|", formataddress(hub->sk->remote, hub->sk->remotelen), args + 4); + postfix = sprintf2(" (%s)\005%s|", formatsockpeer(hub->sk), args + 4); dsk = sk; getsock(dsk); } else { @@ -1158,8 +1158,8 @@ static void cmd_search(struct socket *sk, struct fnetnode *fn, char *cmd, char * addr.sin_port = htons(atoi(p2)); prefix = sprintf2("$SR %s ", hub->nativenick); infix = sprintf2(" %i/%i\005", slotsleft(), confgetint("transfer", "slots")); - postfix = sprintf2(" (%s)|", formataddress(hub->sk->remote, hub->sk->remotelen)); - netdgramconn(dsk = netdupsock(udpsock), (struct sockaddr *)&addr, sizeof(addr)); + postfix = sprintf2(" (%s)|", formatsockpeer(hub->sk)); + dsk = netdgramconn(udpsock, (struct sockaddr *)&addr, sizeof(addr)); } minsize = maxsize = -1; @@ -1351,7 +1351,7 @@ static void sendctm(struct socket *sk, char *nick) if(tcpsock == NULL) return; - if(sockgetremotename2(tcpsock, sk, &addr, &addrlen) < 0) + if(lstgetremotename2(tcpsock, sk, &addr, &addrlen) < 0) return; if(addr->sa_family == AF_INET) qstrf(sk, "$ConnectToMe %s %s|", nick, formataddress(addr, addrlen)); @@ -2295,7 +2295,6 @@ static void cmd_adcsnd(struct socket *sk, struct dcpeer *peer, char *cmd, char * { sockpushdata(sk, peer->inbuf, peer->inbufdata); peer->inbufdata = 0; - transread(sk, peer); } } else { /* We certainly didn't request this...*/ @@ -2328,7 +2327,6 @@ static void cmd_sending(struct socket *sk, struct dcpeer *peer, char *cmd, char { sockpushdata(sk, peer->inbuf, peer->inbufdata); peer->inbufdata = 0; - transread(sk, peer); } } @@ -2694,7 +2692,7 @@ static void dctransgotdata(struct transfer *transfer, struct dcpeer *peer) if((peer->state == PEER_TRNS) || (peer->state == PEER_SYNC)) { - if(sockqueuesize(peer->sk) < 65536) + if(sockqueueleft(peer->sk) > 0) { if((buf = transfergetdata(transfer, &bufsize)) != NULL) { @@ -2765,18 +2763,14 @@ static void dctransendofdata(struct transfer *transfer, struct dcpeer *peer) dctransgotdata(transfer, peer); } -static void dcwantdata(struct transfer *transfer, struct dcpeer *peer) -{ - if(transferdatasize(transfer) < 65536) - peer->sk->ignread = 0; -} - static void transread(struct socket *sk, struct dcpeer *peer) { void *buf; size_t bufsize; struct transfer *transfer; + if(transferdatasize(peer->transfer) < 0) + return; if((buf = sockgetinbuf(sk, &bufsize)) == NULL) return; if(peer->transfer == NULL) @@ -2794,8 +2788,12 @@ static void transread(struct socket *sk, struct dcpeer *peer) transferendofdata(transfer); return; } - if(transferdatasize(peer->transfer) > 65535) - sk->ignread = 1; +} + +static void dcwantdata(struct transfer *transfer, struct dcpeer *peer) +{ + if(transferdatasize(transfer) > 0) + transread(peer->sk, peer); } static void transerr(struct socket *sk, int err, struct dcpeer *peer) @@ -2829,6 +2827,7 @@ static void udpread(struct socket *sk, void *data) size_t buflen, hashlen; char *nick, *filename, *hubname; struct sockaddr_in hubaddr; + struct sockaddr *addrbuf; off_t size; int slots; struct fnetnode *fn, *myfn; @@ -2948,13 +2947,15 @@ static void udpread(struct socket *sk, void *data) { for(fn = fnetnodes; fn != NULL; fn = fn->next) { - if((fn->fnet == &dcnet) && ((hub = fn->data) != NULL)) + if((fn->fnet == &dcnet) && ((hub = fn->data) != NULL) && !sockpeeraddr(hub->sk, &addrbuf, NULL)) { - if((hub->sk != NULL) && addreq(hub->sk->remote, (struct sockaddr *)&hubaddr)) + if((hub->sk != NULL) && addreq(addrbuf, (struct sockaddr *)&hubaddr)) { myfn = fn; + free(addrbuf); break; } + free(addrbuf); } } } @@ -2993,6 +2994,8 @@ static void hubread(struct socket *sk, struct fnetnode *fn) char *p, *p2; hub = (struct dchub *)fn->data; + if(hub->queue.size > 1000) + return; if((newbuf = sockgetinbuf(sk, &datalen)) == NULL) return; if(hub->inbufdata > 500000) /* Discard possible malicious data */ @@ -3016,8 +3019,6 @@ static void hubread(struct socket *sk, struct fnetnode *fn) p = p2; } memmove(hub->inbuf, p, hub->inbufdata -= p - hub->inbuf); - if(hub->queue.size > 1000) - sk->ignread = 1; } static void huberr(struct socket *sk, int err, struct fnetnode *fn) @@ -3205,7 +3206,7 @@ static void hubkill(struct fnetnode *fn) struct dchub *hub; hub = (struct dchub *)fn->data; - hub->sk->close = 1; + closesock(hub->sk); } static struct transferiface dctransfer = @@ -3234,6 +3235,10 @@ static void peerread(struct socket *sk, struct dcpeer *peer) size_t datalen, cnlen; struct command *cmd; + if(peer->state == PEER_CMD) { + if((peer->queue.size > 50) || (peer->inbufdata > 65536)) + return; + } if((newbuf = sockgetinbuf(sk, &datalen)) == NULL) return; sizebuf2(peer->inbuf, peer->inbufdata + datalen, 1); @@ -3259,16 +3264,11 @@ static void peerread(struct socket *sk, struct dcpeer *peer) { peer->state = PEER_STOP; break; - } else { - if(peer->queue.size > 50) - sk->ignread = 1; } } } else if(peer->state == PEER_TTHL) { handletthl(peer); } - if(peer->inbufdata > 500000) - sk->ignread = 1; } static void peererror(struct socket *sk, int err, struct dcpeer *peer) @@ -3302,7 +3302,7 @@ static void peerconnect(struct socket *sk, int err, struct fnetnode *fn) sendpeerlock(peer); } -static void peeraccept(struct socket *sk, struct socket *newsk, void *data) +static void peeraccept(struct lport *lp, struct socket *newsk, void *data) { struct dcpeer *peer; @@ -3772,7 +3772,7 @@ static int run(void) quota--; } if(hub->queue.size < 1000) - hub->sk->ignread = 0; + hubread(hub->sk, fn); if(quota < 1) break; } @@ -3791,7 +3791,7 @@ static int run(void) quota--; } if((peer->queue.size < 50) && (peer->inbufdata < 500000)) - peer->sk->ignread = 0; + peerread(peer->sk, peer); if(quota < 1) break; } @@ -3834,7 +3834,7 @@ static int updateudpport(struct configvar *var, void *uudata) static int updatetcpport(struct configvar *var, void *uudata) { struct sockaddr_in addr; - struct socket *newsock; + struct lport *newsock; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; @@ -3842,7 +3842,7 @@ static int updatetcpport(struct configvar *var, void *uudata) if((newsock = netcslisten(SOCK_STREAM, (struct sockaddr *)&addr, sizeof(addr), peeraccept, NULL)) == NULL) flog(LOG_INFO, "could not listen to a remote address, going into passive mode"); if(tcpsock != NULL) - putsock(tcpsock); + closelport(tcpsock); tcpsock = newsock; return(0); } @@ -3857,7 +3857,7 @@ static int init(int hup) if(udpsock != NULL) putsock(udpsock); if(tcpsock != NULL) - putsock(tcpsock); + closelport(tcpsock); addr.sin_family = AF_INET; memset(&addr.sin_addr, 0, sizeof(addr.sin_addr)); addr.sin_port = htons(confgetint("dc", "udpport")); diff --git a/daemon/net.c b/daemon/net.c index d0cd9c8..240855a 100644 --- a/daemon/net.c +++ b/daemon/net.c @@ -91,7 +91,43 @@ static struct configvar myvars[] = {CONF_VAR_END} }; -static struct socket *sockets = NULL; +#define UFD_SOCK 0 +#define UFD_PIPE 1 +#define UFD_LISTEN 2 + +struct scons { + struct scons *n, *p; + struct socket *s; +}; + +struct ufd { + struct ufd *next, *prev; + int fd; + int type; + int ignread; + struct socket *sk; + union { + struct { + int family; + int type; + struct sockaddr *remote; + socklen_t remotelen; + struct { + uid_t uid; + gid_t gid; + } ucred; + } s; + struct { + struct lport *lp; + int family; + } l; + } d; +}; + +static int getlocalname(int fd, struct sockaddr **namebuf, socklen_t *lenbuf); + +static struct ufd *ufds = NULL; +static struct scons *rbatch, *wbatch, *cbatch; int numsocks = 0; /* XXX: Get autoconf for all this... */ @@ -171,93 +207,145 @@ int getpublicaddr(int af, struct sockaddr **addr, socklen_t *lenbuf) return(1); } -static struct socket *newsock(int type) +static struct socket *newsock1(int dgram) { struct socket *new; - new = smalloc(sizeof(*new)); - memset(new, 0, sizeof(*new)); - new->refcount = 2; - new->fd = -1; - new->isrealsocket = 1; - new->family = -1; - new->tos = 0; - new->type = type; + new = memset(smalloc(sizeof(*new)), 0, sizeof(*new)); + new->refcount = 1; new->state = -1; - new->ignread = 0; - new->close = 0; - new->remote = NULL; - new->remotelen = 0; - new->ucred.uid = -1; - new->ucred.gid = -1; - switch(type) - { - case SOCK_STREAM: - new->outbuf.s.buf = NULL; - new->outbuf.s.bufsize = 0; - new->outbuf.s.datasize = 0; - new->inbuf.s.buf = NULL; - new->inbuf.s.bufsize = 0; - new->inbuf.s.datasize = 0; - break; - case SOCK_DGRAM: - new->outbuf.d.f = new->outbuf.d.l = NULL; - new->inbuf.d.f = new->inbuf.d.l = NULL; - break; - } - new->conncb = NULL; - new->errcb = NULL; - new->readcb = NULL; - new->writecb = NULL; - new->acceptcb = NULL; - new->next = sockets; - new->prev = NULL; - if(sockets != NULL) - sockets->prev = new; - sockets = new; + new->dgram = dgram; + new->maxbuf = 65536; numsocks++; return(new); } +static struct socket *sockpair(int dgram) +{ + struct socket *s1, *s2; + + s1 = newsock1(dgram); + s2 = newsock1(dgram); + s1->back = s2; + s2->back = s1; + putsock(s2); + return(s1); +} + +static void sksetstate(struct socket *sk, int state) +{ + sk->state = state; + sk->back->state = state; +} + +static void closeufd(struct ufd *ufd) +{ + if(ufd->fd != -1) + close(ufd->fd); + ufd->fd = -1; +} + +static void freeufd(struct ufd *ufd) +{ + if(ufd->next != NULL) + ufd->next->prev = ufd->prev; + if(ufd->prev != NULL) + ufd->prev->next = ufd->next; + if(ufd == ufds) + ufds = ufd->next; + closeufd(ufd); + if(ufd->sk != NULL) + putsock(ufd->sk); + if(ufd->type == UFD_SOCK) { + if(ufd->d.s.remote != NULL) + free(ufd->d.s.remote); + } + free(ufd); +} + +static struct ufd *mkufd(int fd, int type, struct socket *sk) +{ + struct ufd *ufd; + + ufd = memset(smalloc(sizeof(*ufd)), 0, sizeof(*ufd)); + ufd->fd = fd; + ufd->type = type; + if(sk != NULL) { + getsock(ufd->sk = sk); + sk->ufd = ufd; + } + if(type == UFD_SOCK) { + ufd->d.s.ucred.uid = -1; + ufd->d.s.ucred.gid = -1; + } + ufd->next = ufds; + if(ufds) + ufds->prev = ufd; + ufds = ufd; + return(ufd); +} + +static struct ufd *dupufd(struct ufd *ufd) +{ + struct ufd *nufd; + struct socket *nsk; + + if(ufd->sk != NULL) + nsk = sockpair(ufd->sk->dgram); + else + nsk = NULL; + nufd = mkufd(ufd->fd, ufd->type, nsk); + if(nsk != NULL) + putsock(nsk); + if((nufd->fd = dup(ufd->fd)) < 0) + { + flog(LOG_WARNING, "could not dup() fd: %s", strerror(errno)); + freeufd(nufd); + return(NULL); + } + sksetstate(nsk, SOCK_EST); + if(ufd->type == UFD_SOCK) { + nufd->d.s.family = ufd->d.s.family; + nufd->d.s.type = ufd->d.s.type; + nufd->d.s.ucred.uid = ufd->d.s.ucred.uid; + nufd->d.s.ucred.gid = ufd->d.s.ucred.gid; + if(ufd->d.s.remote != NULL) + nufd->d.s.remote = memcpy(smalloc(ufd->d.s.remotelen), ufd->d.s.remote, nufd->d.s.remotelen = ufd->d.s.remotelen); + } else if(ufd->type == UFD_LISTEN) { + nufd->d.l.family = ufd->d.l.family; + } + return(nufd); +} + static struct socket *mksock(int domain, int type) { int fd; - struct socket *new; + struct socket *sk; + struct ufd *ufd; if((fd = socket(domain, type, 0)) < 0) { flog(LOG_CRIT, "could not create socket: %s", strerror(errno)); return(NULL); } - new = newsock(type); - new->fd = fd; - new->family = domain; + sk = sockpair(type == SOCK_DGRAM); + ufd = mkufd(fd, UFD_SOCK, sk); + ufd->d.s.family = domain; + ufd->d.s.type = type; fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); - return(new); + return(sk); } struct socket *wrapsock(int fd) { - struct socket *new; + struct socket *sk; + struct ufd *ufd; - new = newsock(SOCK_STREAM); - new->fd = fd; - new->state = SOCK_EST; - new->isrealsocket = 0; + sk = sockpair(0); + ufd = mkufd(fd, UFD_PIPE, sk->back); + sksetstate(sk, SOCK_EST); fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); - return(new); -} - -static void unlinksock(struct socket *sk) -{ - if(sk->prev != NULL) - sk->prev->next = sk->next; - if(sk->next != NULL) - sk->next->prev = sk->prev; - if(sk == sockets) - sockets = sk->next; - putsock(sk); - numsocks--; + return(sk); } void getsock(struct socket *sk) @@ -265,59 +353,99 @@ void getsock(struct socket *sk) sk->refcount++; } -void putsock(struct socket *sk) +static void freesock(struct socket *sk) { struct dgrambuf *buf; - if(--(sk->refcount) == 0) - { - switch(sk->type) - { - case SOCK_STREAM: - if(sk->outbuf.s.buf != NULL) - free(sk->outbuf.s.buf); - if(sk->inbuf.s.buf != NULL) - free(sk->inbuf.s.buf); - break; - case SOCK_DGRAM: - while((buf = sk->outbuf.d.f) != NULL) - { - sk->outbuf.d.f = buf->next; - free(buf->data); - free(buf->addr); - free(buf); - } - while((buf = sk->inbuf.d.f) != NULL) - { - sk->inbuf.d.f = buf->next; - free(buf->data); - free(buf->addr); - free(buf); - } - break; + if(sk->dgram) { + while((buf = sk->buf.d.f) != NULL) { + sk->buf.d.f = buf->next; + freedgbuf(buf); } - closesock(sk); - if(sk->remote != NULL) - free(sk->remote); - free(sk); + } else { + if(sk->buf.s.buf != NULL) + free(sk->buf.s.buf); } + free(sk); + numsocks--; +} + +void putsock(struct socket *sk) +{ + struct socket *back; + + if(--(sk->refcount) < 0) { + flog(LOG_CRIT, "BUG: socket refcount < 0"); + abort(); + } + if((sk->refcount == 0) && (sk->back->refcount == 0)) { + back = sk->back; + freesock(sk); + freesock(back); + } +} + +static void linksock(struct scons **list, struct socket *sk) +{ + struct scons *sc; + + for(sc = *list; sc != NULL; sc = sc->n) { + if(sc->s == sk) + return; + } + sc = smalloc(sizeof(*sc)); + getsock(sc->s = sk); + sc->n = *list; + sc->p = NULL; + if(*list) + (*list)->p = sc; + *list = sc; } void sockpushdata(struct socket *sk, void *buf, size_t size) { - switch(sk->type) - { - case SOCK_STREAM: - sizebuf(&sk->inbuf.s.buf, &sk->inbuf.s.bufsize, sk->inbuf.s.datasize + size, 1, 1); - memmove(sk->inbuf.s.buf + size, sk->inbuf.s.buf, sk->inbuf.s.datasize); - memcpy(sk->inbuf.s.buf, buf, size); - sk->inbuf.s.datasize += size; - break; - case SOCK_DGRAM: + if(size == 0) + return; + if(sk->dgram) { /* XXX */ - break; + } else { + sizebuf(&sk->buf.s.buf, &sk->buf.s.bufsize, sk->buf.s.datasize + size, 1, 1); + memmove(sk->buf.s.buf + size, sk->buf.s.buf, sk->buf.s.datasize); + memcpy(sk->buf.s.buf, buf, size); + sk->buf.s.datasize += size; + linksock(&rbatch, sk); } - return; +} + +/* Read as the preterite of `read' */ +void sockread(struct socket *sk) +{ + if((sockgetdatalen(sk) == 0) && (sk->eos == 1)) + linksock(&rbatch, sk); + linksock(&wbatch, sk->back); +} + +void freedgbuf(struct dgrambuf *dg) +{ + if(dg->data != NULL) + free(dg->data); + if(dg->addr != NULL) + free(dg->addr); + free(dg); +} + +struct dgrambuf *sockgetdgbuf(struct socket *sk) +{ + struct dgrambuf *dbuf; + + if((dbuf = sk->buf.d.f) == NULL) + return(NULL); + sk->buf.d.f = dbuf->next; + if(dbuf->next == NULL) + sk->buf.d.l = NULL; + dbuf->next = NULL; + sockread(sk); + return(dbuf); } void *sockgetinbuf(struct socket *sk, size_t *size) @@ -325,35 +453,90 @@ void *sockgetinbuf(struct socket *sk, size_t *size) void *buf; struct dgrambuf *dbuf; - switch(sk->type) - { - case SOCK_STREAM: - if((sk->inbuf.s.buf == NULL) || (sk->inbuf.s.datasize == 0)) - { - *size = 0; - return(NULL); - } - buf = sk->inbuf.s.buf; - *size = sk->inbuf.s.datasize; - sk->inbuf.s.buf = NULL; - sk->inbuf.s.bufsize = sk->inbuf.s.datasize = 0; - return(buf); - case SOCK_DGRAM: - if((dbuf = sk->inbuf.d.f) == NULL) - return(NULL); - sk->inbuf.d.f = dbuf->next; - if(dbuf->next == NULL) - sk->inbuf.d.l = NULL; + if(sk->dgram) { + dbuf = sockgetdgbuf(sk); buf = dbuf->data; *size = dbuf->size; free(dbuf->addr); free(dbuf); - return(buf); + } else { + if((sk->buf.s.buf == NULL) || (sk->buf.s.datasize == 0)) + { + *size = 0; + return(NULL); + } + buf = sk->buf.s.buf; + *size = sk->buf.s.datasize; + sk->buf.s.buf = NULL; + sk->buf.s.bufsize = sk->buf.s.datasize = 0; + sockread(sk); } - return(NULL); + return(buf); } -static void recvcmsg(struct socket *sk, struct msghdr *msg) +void sockqueue(struct socket *sk, void *data, size_t size) +{ + struct dgrambuf *new; + struct sockaddr *remote; + socklen_t remotelen; + + if(size == 0) + return; + if(sk->state == SOCK_STL) + return; + if(sk->dgram) { + if(sockpeeraddr(sk, &remote, &remotelen)) + return; + new = smalloc(sizeof(*new)); + new->next = NULL; + memcpy(new->data = smalloc(size), data, new->size = size); + new->addr = remote; + new->addrlen = remotelen; + if(sk->back->buf.d.l == NULL) + { + sk->back->buf.d.l = sk->back->buf.d.f = new; + } else { + sk->back->buf.d.l->next = new; + sk->back->buf.d.l = new; + } + } else { + sizebuf(&(sk->back->buf.s.buf), &(sk->back->buf.s.bufsize), sk->back->buf.s.datasize + size, 1, 1); + memcpy(sk->back->buf.s.buf + sk->back->buf.s.datasize, data, size); + sk->back->buf.s.datasize += size; + } + linksock(&rbatch, sk->back); +} + +void sockqueuedg(struct socket *sk, struct dgrambuf *dg) +{ + if(sk->state == SOCK_STL) { + freedgbuf(dg); + return; + } + if(!sk->dgram) { + flog(LOG_ERR, "BUG: sockqueuedg called on non-dgram socket"); + freedgbuf(dg); + return; + } + dg->next = NULL; + if(sk->back->buf.d.l == NULL) + { + sk->back->buf.d.l = sk->back->buf.d.f = dg; + } else { + sk->back->buf.d.l->next = dg; + sk->back->buf.d.l = dg; + } + linksock(&rbatch, sk->back); +} + +void sockerror(struct socket *sk, int en) +{ + sksetstate(sk, SOCK_STL); + if(sk->back->errcb != NULL) + sk->back->errcb(sk->back, en, sk->back->data); +} + +static void recvcmsg(struct ufd *ufd, struct msghdr *msg) { struct cmsghdr *cmsg; @@ -363,95 +546,64 @@ static void recvcmsg(struct socket *sk, struct msghdr *msg) if((cmsg->cmsg_level == SOL_SOCKET) && (cmsg->cmsg_type == SCM_CREDENTIALS)) { struct ucred *cred; - if(sk->ucred.uid == -1) + if(ufd->d.s.ucred.uid == -1) { cred = (struct ucred *)CMSG_DATA(cmsg); - sk->ucred.uid = cred->uid; - sk->ucred.gid = cred->gid; + ufd->d.s.ucred.uid = cred->uid; + ufd->d.s.ucred.gid = cred->gid; } } #endif } } -static void sockrecv(struct socket *sk) +static int ufddgram(struct ufd *ufd) +{ + int dgram; + + if(ufd->type == UFD_SOCK) { + dgram = ufd->d.s.type == SOCK_DGRAM; + } else if(ufd->type == UFD_PIPE) { + dgram = 0; + } else { + flog(LOG_ERR, "BUG: calling ufddgram on ufd of bad type %i", ufd->type); + return(-1); + } + if(ufd->sk == NULL) { + flog(LOG_ERR, "BUG: calling ufddgram on socketless ufd (type %i)", ufd->type); + return(-1); + } + if(dgram != ufd->sk->dgram) { + flog(LOG_ERR, "BUG: ufd/socket dgram value mismatch"); + return(-1); + } + return(dgram); +} + +static void sockrecv(struct ufd *ufd) { int ret, inq; + int dgram; struct dgrambuf *dbuf; struct msghdr msg; char cbuf[65536]; struct iovec bufvec; + void *buf; memset(&msg, 0, sizeof(msg)); msg.msg_iov = &bufvec; msg.msg_iovlen = 1; msg.msg_control = cbuf; msg.msg_controllen = sizeof(cbuf); - switch(sk->type) - { - case SOCK_STREAM: -#if defined(HAVE_LINUX_SOCKIOS_H) && defined(SIOCINQ) - /* SIOCINQ is Linux-specific AFAIK, but I really have no idea - * how to read the inqueue size on other OSs */ - if(sk->isrealsocket) { - if(ioctl(sk->fd, SIOCINQ, &inq)) - { - /* I don't really know what could go wrong here, so let's - * assume it's transient. */ - flog(LOG_WARNING, "SIOCINQ return %s on socket %i, falling back to 2048 bytes", strerror(errno), sk->fd); - inq = 2048; - } - } else { - /* There are perils when trying to use SIOCINQ on files >2GiB... */ - inq = 65536; - } -#else - inq = 2048; -#endif - if(inq > 65536) - inq = 65536; - sizebuf(&sk->inbuf.s.buf, &sk->inbuf.s.bufsize, sk->inbuf.s.datasize + inq, 1, 1); - if(sk->isrealsocket) - { - bufvec.iov_base = sk->inbuf.s.buf + sk->inbuf.s.datasize; - bufvec.iov_len = inq; - ret = recvmsg(sk->fd, &msg, 0); - } else { - ret = read(sk->fd, sk->inbuf.s.buf + sk->inbuf.s.datasize, inq); - msg.msg_controllen = 0; - msg.msg_flags = 0; - } - if(ret < 0) - { - if((errno == EINTR) || (errno == EAGAIN)) - return; - if(sk->errcb != NULL) - sk->errcb(sk, errno, sk->data); - closesock(sk); - return; - } - if(msg.msg_flags & MSG_CTRUNC) - flog(LOG_DEBUG, "ancillary data was truncated"); - else - recvcmsg(sk, &msg); - if(ret == 0) - { - if(sk->errcb != NULL) - sk->errcb(sk, 0, sk->data); - closesock(sk); - return; - } - sk->inbuf.s.datasize += ret; - if(sk->readcb != NULL) - sk->readcb(sk, sk->data); - break; - case SOCK_DGRAM: + if((dgram = ufddgram(ufd)) < 0) + return; + if(dgram) { #if defined(HAVE_LINUX_SOCKIOS_H) && defined(SIOCINQ) - if(ioctl(sk->fd, SIOCINQ, &inq)) + if(ioctl(ufd->fd, SIOCINQ, &inq)) { /* I don't really know what could go wrong here, so let's * assume it's transient. */ - flog(LOG_WARNING, "SIOCINQ return %s on socket %i", strerror(errno), sk->fd); + flog(LOG_WARNING, "SIOCINQ return %s on socket %i", strerror(errno), ufd->fd); return; } #else @@ -460,152 +612,138 @@ static void sockrecv(struct socket *sk) dbuf = smalloc(sizeof(*dbuf)); dbuf->data = smalloc(inq); dbuf->addr = smalloc(dbuf->addrlen = sizeof(struct sockaddr_storage)); - /* - ret = recvfrom(sk->fd, dbuf->data, inq, 0, dbuf->addr, &dbuf->addrlen); - */ msg.msg_name = dbuf->addr; msg.msg_namelen = dbuf->addrlen; bufvec.iov_base = dbuf->data; bufvec.iov_len = inq; - ret = recvmsg(sk->fd, &msg, 0); + ret = recvmsg(ufd->fd, &msg, 0); dbuf->addrlen = msg.msg_namelen; if(ret < 0) { - free(dbuf->addr); - free(dbuf->data); - free(dbuf); + freedgbuf(dbuf); if((errno == EINTR) || (errno == EAGAIN)) return; - if(sk->errcb != NULL) - sk->errcb(sk, errno, sk->data); - closesock(sk); + closeufd(ufd); + sockerror(ufd->sk, errno); return; } if(msg.msg_flags & MSG_CTRUNC) flog(LOG_DEBUG, "ancillary data was truncated"); else - recvcmsg(sk, &msg); + recvcmsg(ufd, &msg); /* On UDP/IPv[46], ret == 0 doesn't mean EOF (since UDP can't * have EOF), but rather an empty packet. I don't know if any * other potential DGRAM protocols might have an EOF * condition, so let's play safe. */ if(ret == 0) { - free(dbuf->addr); - free(dbuf->data); - free(dbuf); - if(!((sk->family == AF_INET) || (sk->family == AF_INET6))) + freedgbuf(dbuf); + if((ufd->type != UFD_SOCK) || !((ufd->d.s.family == AF_INET) || (ufd->d.s.family == AF_INET6))) { - if(sk->errcb != NULL) - sk->errcb(sk, 0, sk->data); - closesock(sk); + closesock(ufd->sk); + closeufd(ufd); } return; } dbuf->addr = srealloc(dbuf->addr, dbuf->addrlen); dbuf->data = srealloc(dbuf->data, dbuf->size = ret); dbuf->next = NULL; - if(sk->inbuf.d.l != NULL) - sk->inbuf.d.l->next = dbuf; + sockqueuedg(ufd->sk, dbuf); + } else { +#if defined(HAVE_LINUX_SOCKIOS_H) && defined(SIOCINQ) + /* SIOCINQ is Linux-specific AFAIK, but I really have no idea + * how to read the inqueue size on other OSs */ + if(ufd->type == UFD_SOCK) { + if(ioctl(ufd->fd, SIOCINQ, &inq)) + { + /* I don't really know what could go wrong here, so let's + * assume it's transient. */ + flog(LOG_WARNING, "SIOCINQ return %s on socket %i, falling back to 2048 bytes", strerror(errno), ufd->fd); + inq = 2048; + } + } else { + /* There are perils when trying to use SIOCINQ on files >2GiB... */ + inq = 65536; + } +#else + inq = 2048; +#endif + if(inq > 65536) + inq = 65536; + /* This part could be optimized by telling the kernel to read + * directly into ufd->sk->back->buf, but that would be uglier + * by not using the socket function interface. */ + buf = smalloc(inq); + if(ufd->type == UFD_SOCK) + { + bufvec.iov_base = buf; + bufvec.iov_len = inq; + ret = recvmsg(ufd->fd, &msg, 0); + } else { + ret = read(ufd->fd, buf, inq); + msg.msg_controllen = 0; + msg.msg_flags = 0; + } + if(ret < 0) + { + free(buf); + if((errno == EINTR) || (errno == EAGAIN)) + return; + closeufd(ufd); + sockerror(ufd->sk, errno); + return; + } + if(msg.msg_flags & MSG_CTRUNC) + flog(LOG_DEBUG, "ancillary data was truncated"); else - sk->inbuf.d.f = dbuf; - sk->inbuf.d.l = dbuf; - if(sk->readcb != NULL) - sk->readcb(sk, sk->data); - break; + recvcmsg(ufd, &msg); + if(ret == 0) + { + free(buf); + closeufd(ufd); + closesock(ufd->sk); + return; + } + sockqueue(ufd->sk, buf, ret); + free(buf); } } -static void sockflush(struct socket *sk) +static int sockflush(struct ufd *ufd) { int ret; struct dgrambuf *dbuf; + int dgram; - switch(sk->type) - { - case SOCK_STREAM: - if(sk->isrealsocket) - ret = send(sk->fd, sk->outbuf.s.buf, sk->outbuf.s.datasize, MSG_DONTWAIT | MSG_NOSIGNAL); + if((dgram = ufddgram(ufd)) < 0) { + errno = EBADFD; + return(-1); + } + if(dgram) { + dbuf = sockgetdgbuf(ufd->sk); + sendto(ufd->fd, dbuf->data, dbuf->size, MSG_DONTWAIT | MSG_NOSIGNAL, dbuf->addr, dbuf->addrlen); + freedgbuf(dbuf); + } else { + if(ufd->type == UFD_SOCK) + ret = send(ufd->fd, ufd->sk->buf.s.buf, ufd->sk->buf.s.datasize, MSG_DONTWAIT | MSG_NOSIGNAL); else - ret = write(sk->fd, sk->outbuf.s.buf, sk->outbuf.s.datasize); + ret = write(ufd->fd, ufd->sk->buf.s.buf, ufd->sk->buf.s.datasize); if(ret < 0) - { - if((errno != EINTR) && (errno != EAGAIN)) - { - if(sk->errcb != NULL) - sk->errcb(sk, errno, sk->data); - closesock(sk); - } - break; - } - if(ret > 0) - { - memmove(sk->outbuf.s.buf, ((char *)sk->outbuf.s.buf) + ret, sk->outbuf.s.datasize -= ret); - if(sk->writecb != NULL) - sk->writecb(sk, sk->data); + return(-1); + if(ret > 0) { + memmove(ufd->sk->buf.s.buf, ((char *)ufd->sk->buf.s.buf) + ret, ufd->sk->buf.s.datasize -= ret); + sockread(ufd->sk); } - break; - case SOCK_DGRAM: - dbuf = sk->outbuf.d.f; - if((sk->outbuf.d.f = dbuf->next) == NULL) - sk->outbuf.d.l = NULL; - sendto(sk->fd, dbuf->data, dbuf->size, MSG_DONTWAIT | MSG_NOSIGNAL, dbuf->addr, dbuf->addrlen); - free(dbuf->data); - free(dbuf->addr); - free(dbuf); - if(sk->writecb != NULL) - sk->writecb(sk, sk->data); - break; } + return(0); } void closesock(struct socket *sk) { - struct sockaddr_un *un; - - if((sk->family == AF_UNIX) && !sockgetlocalname(sk, (struct sockaddr **)(void *)&un, NULL) && (un->sun_family == PF_UNIX)) - { - if((sk->state == SOCK_LST) && strchr(un->sun_path, '/')) - { - if(unlink(un->sun_path)) - flog(LOG_WARNING, "could not unlink Unix socket %s: %s", un->sun_path, strerror(errno)); - } - } - sk->state = SOCK_STL; - close(sk->fd); - sk->fd = -1; - sk->close = 0; -} - -void sockqueue(struct socket *sk, void *data, size_t size) -{ - struct dgrambuf *new; - - if(sk->state == SOCK_STL) - return; - switch(sk->type) - { - case SOCK_STREAM: - sizebuf(&(sk->outbuf.s.buf), &(sk->outbuf.s.bufsize), sk->outbuf.s.datasize + size, 1, 1); - memcpy(sk->outbuf.s.buf + sk->outbuf.s.datasize, data, size); - sk->outbuf.s.datasize += size; - break; - case SOCK_DGRAM: - if(sk->remote == NULL) - return; - new = smalloc(sizeof(*new)); - new->next = NULL; - memcpy(new->data = smalloc(size), data, new->size = size); - memcpy(new->addr = smalloc(sk->remotelen), sk->remote, new->addrlen = sk->remotelen); - if(sk->outbuf.d.l == NULL) - { - sk->outbuf.d.l = sk->outbuf.d.f = new; - } else { - sk->outbuf.d.l->next = new; - sk->outbuf.d.l = new; - } - break; - } + sksetstate(sk, SOCK_STL); + if(sk->back->eos == 0) + sk->back->eos = 1; + linksock(&rbatch, sk->back); } size_t sockgetdatalen(struct socket *sk) @@ -613,49 +751,36 @@ size_t sockgetdatalen(struct socket *sk) struct dgrambuf *b; size_t ret; - switch(sk->type) - { - case SOCK_STREAM: - ret = sk->inbuf.s.datasize; - break; - case SOCK_DGRAM: + if(sk->dgram) { ret = 0; - for(b = sk->inbuf.d.f; b != NULL; b = b->next) + for(b = sk->buf.d.f; b != NULL; b = b->next) ret += b->size; - break; + } else { + ret = sk->buf.s.datasize; } return(ret); } -size_t sockqueuesize(struct socket *sk) +/* size_t sockqueuesize(struct socket *sk) */ +/* { */ +/* return(sockgetdatalen(sk->back)); */ +/* } */ + +ssize_t sockqueueleft(struct socket *sk) { - struct dgrambuf *b; - size_t ret; - - switch(sk->type) - { - case SOCK_STREAM: - ret = sk->outbuf.s.datasize; - break; - case SOCK_DGRAM: - ret = 0; - for(b = sk->outbuf.d.f; b != NULL; b = b->next) - ret += b->size; - break; - } - return(ret); + return(sk->back->maxbuf - sockgetdatalen(sk->back)); } /* * Seriously, I don't know if it's naughty or not to remove * pre-existing Unix sockets. */ -static int rebindunix(struct socket *sk, struct sockaddr *name, socklen_t namelen) +static int rebindunix(struct ufd *ufd, struct sockaddr *name, socklen_t namelen) { struct sockaddr_un *un; struct stat sb; - if((sk->family != AF_UNIX) || (name->sa_family != PF_UNIX)) + if((ufd->d.l.family != AF_UNIX) || (name->sa_family != PF_UNIX)) return(-1); un = (struct sockaddr_un *)name; if(stat(un->sun_path, &sb)) @@ -664,11 +789,24 @@ static int rebindunix(struct socket *sk, struct sockaddr *name, socklen_t namele return(-1); if(unlink(un->sun_path)) return(-1); - if(bind(sk->fd, name, namelen) < 0) + if(bind(ufd->fd, name, namelen) < 0) return(-1); return(0); } +void closelport(struct lport *lp) +{ + struct ufd *ufd; + struct sockaddr_un *un; + + ufd = lp->ufd; + if((ufd->d.l.family == AF_UNIX) && !getlocalname(ufd->fd, (struct sockaddr **)(void *)&un, NULL) && (un->sun_family == PF_UNIX) && strchr(un->sun_path, '/')) { + if(unlink(un->sun_path)) + flog(LOG_WARNING, "could not unlink Unix socket %s: %s", un->sun_path, strerror(errno)); + } + freeufd(lp->ufd); +} + /* * The difference between netcslisten() and netcslistenlocal() is that * netcslistenlocal() always listens on the local host, instead of @@ -677,9 +815,11 @@ static int rebindunix(struct socket *sk, struct sockaddr *name, socklen_t namele * netcslisten() instead. */ -struct socket *netcslistenlocal(int type, struct sockaddr *name, socklen_t namelen, void (*func)(struct socket *, struct socket *, void *), void *data) +struct lport *netcslistenlocal(int type, struct sockaddr *name, socklen_t namelen, void (*func)(struct lport *, struct socket *, void *), void *data) { - struct socket *sk; + struct lport *lp; + struct ufd *ufd; + int fd; int intbuf; /* I don't know if this is actually correct (it probably isn't), @@ -688,30 +828,32 @@ struct socket *netcslistenlocal(int type, struct sockaddr *name, socklen_t namel * smoother implementation. If it breaks something on your * platform, please tell me so. */ - if((sk = mksock(name->sa_family, type)) == NULL) + if((fd = socket(name->sa_family, type, 0)) < 0) return(NULL); - sk->state = SOCK_LST; - if(confgetint("net", "reuseaddr")) - { + if(confgetint("net", "reuseaddr")) { intbuf = 1; - setsockopt(sk->fd, SOL_SOCKET, SO_REUSEADDR, &intbuf, sizeof(intbuf)); + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &intbuf, sizeof(intbuf)); } - if((bind(sk->fd, name, namelen) < 0) && ((errno != EADDRINUSE) || (rebindunix(sk, name, namelen) < 0))) - { - putsock(sk); + ufd = mkufd(fd, UFD_LISTEN, NULL); + ufd->d.l.family = name->sa_family; + lp = memset(smalloc(sizeof(*lp)), 0, sizeof(*lp)); + lp->ufd = ufd; + ufd->d.l.lp = lp; + if((bind(fd, name, namelen) < 0) && ((errno != EADDRINUSE) || (rebindunix(ufd, name, namelen) < 0))) { + freeufd(ufd); return(NULL); } - if(listen(sk->fd, 16) < 0) + if(listen(fd, 16) < 0) { - putsock(sk); + freeufd(ufd); return(NULL); } - sk->acceptcb = func; - sk->data = data; - return(sk); + lp->acceptcb = func; + lp->data = data; + return(lp); } -struct socket *netcslisten(int type, struct sockaddr *name, socklen_t namelen, void (*func)(struct socket *, struct socket *, void *), void *data) +struct lport *netcslisten(int type, struct sockaddr *name, socklen_t namelen, void (*func)(struct lport *, struct socket *, void *), void *data) { if(confgetint("net", "mode") == 1) { @@ -724,14 +866,14 @@ struct socket *netcslisten(int type, struct sockaddr *name, socklen_t namelen, v return(NULL); } -struct socket *netcstcplisten(int port, int local, void (*func)(struct socket *, struct socket *, void *), void *data) +struct lport *netcstcplisten(int port, int local, void (*func)(struct lport *, struct socket *, void *), void *data) { struct sockaddr_in addr; #ifdef HAVE_IPV6 struct sockaddr_in6 addr6; #endif - struct socket *(*csfunc)(int, struct sockaddr *, socklen_t, void (*)(struct socket *, struct socket *, void *), void *); - struct socket *ret; + struct lport *(*csfunc)(int, struct sockaddr *, socklen_t, void (*)(struct lport *, struct socket *, void *), void *); + struct lport *ret; if(local) csfunc = netcslistenlocal; @@ -763,42 +905,27 @@ struct socket *netcsdgram(struct sockaddr *name, socklen_t namelen) { if((sk = mksock(name->sa_family, SOCK_DGRAM)) == NULL) return(NULL); - if(bind(sk->fd, name, namelen) < 0) + if(bind(sk->ufd->fd, name, namelen) < 0) { putsock(sk); return(NULL); } - sk->state = SOCK_EST; - return(sk); + sksetstate(sk, SOCK_EST); + return(sk->back); } errno = EOPNOTSUPP; return(NULL); } -struct socket *netdupsock(struct socket *sk) +struct socket *netdgramconn(struct socket *sk, struct sockaddr *addr, socklen_t addrlen) { - struct socket *newsk; + struct ufd *nufd; - newsk = newsock(sk->type); - if((newsk->fd = dup(sk->fd)) < 0) - { - flog(LOG_WARNING, "could not dup() socket: %s", strerror(errno)); - putsock(newsk); - return(NULL); - } - newsk->state = sk->state; - newsk->ignread = sk->ignread; - if(sk->remote != NULL) - memcpy(newsk->remote = smalloc(sk->remotelen), sk->remote, newsk->remotelen = sk->remotelen); - return(newsk); -} - -void netdgramconn(struct socket *sk, struct sockaddr *addr, socklen_t addrlen) -{ - if(sk->remote != NULL) - free(sk->remote); - memcpy(sk->remote = smalloc(addrlen), addr, sk->remotelen = addrlen); - sk->ignread = 1; + nufd = dupufd(sk->back->ufd); + getsock(sk = nufd->sk->back); + memcpy(nufd->d.s.remote = smalloc(addrlen), addr, nufd->d.s.remotelen = addrlen); + nufd->ignread = 1; + return(sk); } struct socket *netcsconn(struct sockaddr *addr, socklen_t addrlen, void (*func)(struct socket *, int, void *), void *data) @@ -811,19 +938,19 @@ struct socket *netcsconn(struct sockaddr *addr, socklen_t addrlen, void (*func)( { if((sk = mksock(addr->sa_family, SOCK_STREAM)) == NULL) return(NULL); - memcpy(sk->remote = smalloc(addrlen), addr, sk->remotelen = addrlen); - if(!connect(sk->fd, addr, addrlen)) + memcpy(sk->ufd->d.s.remote = smalloc(addrlen), addr, sk->ufd->d.s.remotelen = addrlen); + sk->back->conncb = func; + sk->back->data = data; + if(!connect(sk->ufd->fd, addr, addrlen)) { - sk->state = SOCK_EST; - func(sk, 0, data); - return(sk); + sksetstate(sk, SOCK_EST); + linksock(&cbatch, sk->back); + return(sk->back); } if(errno == EINPROGRESS) { - sk->state = SOCK_SYN; - sk->conncb = func; - sk->data = data; - return(sk); + sksetstate(sk, SOCK_SYN); + return(sk->back); } putsock(sk); return(NULL); @@ -832,57 +959,114 @@ struct socket *netcsconn(struct sockaddr *addr, socklen_t addrlen, void (*func)( return(NULL); } -static void acceptunix(struct socket *sk) +static void acceptunix(struct ufd *ufd) { int buf; buf = 1; #if UNIX_AUTH_STYLE == 1 - if(setsockopt(sk->fd, SOL_SOCKET, SO_PASSCRED, &buf, sizeof(buf)) < 0) - flog(LOG_WARNING, "could not enable SO_PASSCRED on Unix socket %i: %s", sk->fd, strerror(errno)); + if(setsockopt(ufd->fd, SOL_SOCKET, SO_PASSCRED, &buf, sizeof(buf)) < 0) + flog(LOG_WARNING, "could not enable SO_PASSCRED on Unix socket %i: %s", ufd->fd, strerror(errno)); #elif UNIX_AUTH_STYLE == 2 - if(getpeereid(sk->fd, &sk->ucred.uid, &sk->ucred.gid) < 0) + if(getpeereid(ufd->fd, &ufd->d.s.ucred.uid, &ufd->d.s.ucred.gid) < 0) { - flog(LOG_WARNING, "could not get peer creds on Unix socket %i: %s", sk->fd, strerror(errno)); - sk->ucred.uid = -1; - sk->ucred.gid = -1; + flog(LOG_WARNING, "could not get peer creds on Unix socket %i: %s", ufd->fd, strerror(errno)); + ufd->d.s.ucred.uid = -1; + ufd->d.s.ucred.gid = -1; } #endif } +static void runbatches(void) +{ + struct scons *sc, *nsc; + + for(sc = cbatch, cbatch = NULL; sc; sc = nsc) { + nsc = sc->n; + if(sc->s->conncb != NULL) + sc->s->conncb(sc->s, 0, sc->s->data); + putsock(sc->s); + free(sc); + } + for(sc = rbatch, rbatch = NULL; sc; sc = nsc) { + nsc = sc->n; + if(sc->s->readcb != NULL) + sc->s->readcb(sc->s, sc->s->data); + if((sockgetdatalen(sc->s) == 0) && (sc->s->eos == 1)) { + if(sc->s->errcb != NULL) + sc->s->errcb(sc->s, 0, sc->s->data); + sc->s->eos = 2; + } + putsock(sc->s); + free(sc); + } + for(sc = wbatch, wbatch = NULL; sc; sc = nsc) { + nsc = sc->n; + if(sc->s->writecb != NULL) + sc->s->writecb(sc->s, sc->s->data); + putsock(sc->s); + free(sc); + } +} + +static void cleansocks(void) +{ + struct ufd *ufd, *next; + + for(ufd = ufds; ufd != NULL; ufd = next) { + next = ufd->next; + if(ufd->sk && ((ufd->fd < 0) || (sockgetdatalen(ufd->sk) == 0))) { + if(ufd->sk->eos == 1) { + ufd->sk->eos = 2; + closeufd(ufd); + closesock(ufd->sk); + } + if((ufd->sk->refcount == 1) && (ufd->sk->back->refcount == 0)) { + freeufd(ufd); + continue; + } + } + } +} + int pollsocks(int timeout) { - int ret, fd; + int ret; socklen_t retlen; int newfd, maxfd; fd_set rfds, wfds, efds; - struct socket *sk, *next, *newsk; + struct ufd *ufd, *nufd; + struct socket *nsk; struct sockaddr_storage ss; socklen_t sslen; struct timeval tv; + cleansocks(); FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); - for(maxfd = 0, sk = sockets; sk != NULL; sk = sk->next) - { - if((sk->state == SOCK_STL) || (sk->fd < 0)) + for(maxfd = 0, ufd = ufds; ufd != NULL; ufd = ufd->next) { + if(ufd->fd < 0) continue; - if(!sk->ignread) - FD_SET(sk->fd, &rfds); - if((sk->state == SOCK_SYN) || (sockqueuesize(sk) > 0)) - FD_SET(sk->fd, &wfds); - FD_SET(sk->fd, &efds); - if(sk->fd > maxfd) - maxfd = sk->fd; + if(!ufd->ignread && ((ufd->sk == NULL) || (sockqueueleft(ufd->sk) > 0))) + FD_SET(ufd->fd, &rfds); + if(ufd->sk != NULL) { + if(sockgetdatalen(ufd->sk) > 0) + FD_SET(ufd->fd, &wfds); + else if(ufd->sk->state == SOCK_SYN) + FD_SET(ufd->fd, &wfds); + } + FD_SET(ufd->fd, &efds); + if(ufd->fd > maxfd) + maxfd = ufd->fd; } + if(rbatch || wbatch || cbatch) + timeout = 0; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; ret = select(maxfd + 1, &rfds, &wfds, &efds, (timeout < 0)?NULL:&tv); - if(ret < 0) - { - if(errno != EINTR) - { + if(ret < 0) { + if(errno != EINTR) { flog(LOG_CRIT, "pollsocks: select errored out: %s", strerror(errno)); /* To avoid CPU hogging in case it's bad, which it * probably is. */ @@ -890,106 +1074,101 @@ int pollsocks(int timeout) } return(1); } - for(sk = sockets; sk != NULL; sk = next) - { - next = sk->next; - fd = sk->fd; - switch(sk->state) - { - case SOCK_LST: - if(FD_ISSET(fd, &rfds)) - { + for(ufd = ufds; ufd != NULL; ufd = ufd->next) { + if(ufd->sk < 0) + continue; + if(ufd->type == UFD_LISTEN) { + if(FD_ISSET(ufd->fd, &rfds)) { sslen = sizeof(ss); - if((newfd = accept(fd, (struct sockaddr *)&ss, &sslen)) < 0) - { - if(sk->errcb != NULL) - sk->errcb(sk, errno, sk->data); + if((newfd = accept(ufd->fd, (struct sockaddr *)&ss, &sslen)) < 0) { + if(ufd->d.l.lp->errcb != NULL) + ufd->d.l.lp->errcb(ufd->d.l.lp, errno, ufd->d.l.lp->data); } - newsk = newsock(sk->type); - newsk->fd = newfd; - newsk->family = sk->family; - newsk->state = SOCK_EST; - memcpy(newsk->remote = smalloc(sslen), &ss, sslen); - newsk->remotelen = sslen; + nsk = sockpair(0); + nufd = mkufd(newfd, UFD_SOCK, nsk); + nufd->d.s.family = ufd->d.l.family; + sksetstate(nsk, SOCK_EST); + memcpy(nufd->d.s.remote = smalloc(sslen), &ss, sslen); + nufd->d.s.remotelen = sslen; if(ss.ss_family == PF_UNIX) - acceptunix(newsk); - if(sk->acceptcb != NULL) - sk->acceptcb(sk, newsk, sk->data); - putsock(newsk); + acceptunix(nufd); + if(ufd->d.l.lp->acceptcb != NULL) + ufd->d.l.lp->acceptcb(ufd->d.l.lp, nsk->back, ufd->d.l.lp->data); + putsock(nsk); } - if(FD_ISSET(fd, &efds)) - { + if(FD_ISSET(ufd->fd, &efds)) { retlen = sizeof(ret); - getsockopt(fd, SOL_SOCKET, SO_ERROR, &ret, &retlen); - if(sk->errcb != NULL) - sk->errcb(sk, ret, sk->data); + getsockopt(ufd->fd, SOL_SOCKET, SO_ERROR, &ret, &retlen); + if(ufd->d.l.lp->errcb != NULL) + ufd->d.l.lp->errcb(ufd->d.l.lp, ret, ufd->d.l.lp->data); continue; } - break; - case SOCK_SYN: - if(FD_ISSET(fd, &efds)) - { - retlen = sizeof(ret); - getsockopt(fd, SOL_SOCKET, SO_ERROR, &ret, &retlen); - if(sk->conncb != NULL) - sk->conncb(sk, ret, sk->data); - closesock(sk); - continue; - } - if(FD_ISSET(fd, &rfds) || FD_ISSET(fd, &wfds)) - { - sk->state = SOCK_EST; - if(sk->conncb != NULL) - sk->conncb(sk, 0, sk->data); - } - break; - case SOCK_EST: - if(FD_ISSET(fd, &efds)) - { - retlen = sizeof(ret); - getsockopt(fd, SOL_SOCKET, SO_ERROR, &ret, &retlen); - if(sk->errcb != NULL) - sk->errcb(sk, ret, sk->data); - closesock(sk); - continue; - } - if(FD_ISSET(fd, &rfds)) - sockrecv(sk); - if(FD_ISSET(fd, &wfds)) - { - if(sockqueuesize(sk) > 0) - sockflush(sk); + } else { + if(ufd->sk->state == SOCK_SYN) { + if(FD_ISSET(ufd->fd, &efds)) { + retlen = sizeof(ret); + getsockopt(ufd->fd, SOL_SOCKET, SO_ERROR, &ret, &retlen); + if(ufd->sk->back->conncb != NULL) + ufd->sk->back->conncb(ufd->sk->back, ret, ufd->sk->back->data); + closeufd(ufd); + continue; + } + if(FD_ISSET(ufd->fd, &rfds) || FD_ISSET(ufd->fd, &wfds)) { + sksetstate(ufd->sk, SOCK_EST); + linksock(&cbatch, ufd->sk->back); + } + } else if(ufd->sk->state == SOCK_EST) { + if(FD_ISSET(ufd->fd, &efds)) { + retlen = sizeof(ret); + getsockopt(ufd->fd, SOL_SOCKET, SO_ERROR, &ret, &retlen); + sockerror(ufd->sk, ret); + closeufd(ufd); + continue; + } + if(FD_ISSET(ufd->fd, &rfds)) + sockrecv(ufd); + if(ufd->fd == -1) + continue; + if(FD_ISSET(ufd->fd, &wfds)) { + if(sockflush(ufd)) { + sockerror(ufd->sk, errno); + closeufd(ufd); + continue; + } + } } - break; - } - } - for(sk = sockets; sk != NULL; sk = next) - { - next = sk->next; - if(sk->refcount == 1 && (sockqueuesize(sk) == 0)) - { - unlinksock(sk); - continue; - } - if(sk->close && (sockqueuesize(sk) == 0)) - closesock(sk); - if(sk->state == SOCK_STL) - { - unlinksock(sk); - continue; } } + runbatches(); + cleansocks(); return(1); } +static struct ufd *getskufd(struct socket *sk) +{ + while(1) { + if(sk->back->ufd != NULL) + return(sk->back->ufd); + if((sk = sk->back->pnext) == NULL) + break; + } + return(NULL); +} + int socksettos(struct socket *sk, int tos) { int buf; + struct ufd *ufd; int dscp2tos; - if(sk->family == AF_UNIX) + ufd = getskufd(sk); + if(ufd->type != UFD_SOCK) { + errno = EOPNOTSUPP; + return(-1); + } + if(ufd->d.s.family == AF_UNIX) return(0); /* Unix sockets are always perfect. :) */ - if(sk->family == AF_INET) + if(ufd->d.s.family == AF_INET) { dscp2tos = confgetint("net", "dscp-tos"); switch(tos) @@ -1025,14 +1204,14 @@ int socksettos(struct socket *sk, int tos) flog(LOG_WARNING, "attempted to set unknown TOS value %i to IPv4 sock", tos); return(-1); } - if(setsockopt(sk->fd, IPPROTO_IP, IP_TOS, &buf, sizeof(buf)) < 0) + if(setsockopt(ufd->fd, IPPROTO_IP, IP_TOS, &buf, sizeof(buf)) < 0) { flog(LOG_WARNING, "could not set sock TOS to %i: %s", tos, strerror(errno)); return(-1); } return(0); } - if(sk->family == AF_INET6) + if(ufd->d.s.family == AF_INET6) { switch(tos) { @@ -1066,7 +1245,7 @@ int socksettos(struct socket *sk, int tos) */ return(0); } - flog(LOG_WARNING, "could not set TOS on sock of family %i", sk->family); + flog(LOG_WARNING, "could not set TOS on sock of family %i", ufd->d.s.family); return(1); } @@ -1167,16 +1346,16 @@ int netresolve(char *addr, void (*callback)(struct sockaddr *addr, int addrlen, return(0); } -int sockgetlocalname(struct socket *sk, struct sockaddr **namebuf, socklen_t *lenbuf) +static int getlocalname(int fd, struct sockaddr **namebuf, socklen_t *lenbuf) { socklen_t len; struct sockaddr_storage name; *namebuf = NULL; - if((sk->state == SOCK_STL) || (sk->fd < 0)) + if(fd < 0) return(-1); len = sizeof(name); - if(getsockname(sk->fd, (struct sockaddr *)&name, &len) < 0) + if(getsockname(fd, (struct sockaddr *)&name, &len) < 0) { flog(LOG_ERR, "BUG: alive socket with dead fd in sockgetlocalname (%s)", strerror(errno)); return(-1); @@ -1187,6 +1366,26 @@ int sockgetlocalname(struct socket *sk, struct sockaddr **namebuf, socklen_t *le return(0); } +int lstgetlocalname(struct lport *lp, struct sockaddr **namebuf, socklen_t *lenbuf) +{ + struct ufd *ufd; + + ufd = lp->ufd; + return(getlocalname(ufd->fd, namebuf, lenbuf)); +} + +int sockgetlocalname(struct socket *sk, struct sockaddr **namebuf, socklen_t *lenbuf) +{ + struct ufd *ufd; + + ufd = getskufd(sk); + if(ufd->type != UFD_SOCK) { + errno = EOPNOTSUPP; + return(-1); + } + return(getlocalname(ufd->fd, namebuf, lenbuf)); +} + static void sethostaddr(struct sockaddr *dst, struct sockaddr *src) { if(dst->sa_family != src->sa_family) @@ -1226,22 +1425,15 @@ static int makepublic(struct sockaddr *addr) return(0); } -int sockgetremotename(struct socket *sk, struct sockaddr **namebuf, socklen_t *lenbuf) +static int getremotename(int fd, struct sockaddr **namebuf, socklen_t *lenbuf) { socklen_t len; struct sockaddr *name; - - switch(confgetint("net", "mode")) - { + + switch(confgetint("net", "mode")) { case 0: *namebuf = NULL; - if((sk->state == SOCK_STL) || (sk->fd < 0)) - { - errno = EBADF; - return(-1); - } - if(!sockgetlocalname(sk, &name, &len)) - { + if(!getlocalname(fd, &name, &len)) { *namebuf = name; *lenbuf = len; makepublic(name); @@ -1259,19 +1451,50 @@ int sockgetremotename(struct socket *sk, struct sockaddr **namebuf, socklen_t *l } } +int sockgetremotename(struct socket *sk, struct sockaddr **namebuf, socklen_t *lenbuf) +{ + struct ufd *ufd; + + ufd = getskufd(sk); + if(ufd->type != UFD_SOCK) { + errno = EOPNOTSUPP; + return(-1); + } + if(ufd->fd < 0) { + errno = EBADF; + return(-1); + } + return(getremotename(ufd->fd, namebuf, lenbuf)); +} + +int lstgetremotename(struct lport *lp, struct sockaddr **namebuf, socklen_t *lenbuf) +{ + struct ufd *ufd; + + ufd = lp->ufd; + return(getremotename(ufd->fd, namebuf, lenbuf)); +} + int sockgetremotename2(struct socket *sk, struct socket *sk2, struct sockaddr **namebuf, socklen_t *lenbuf) { struct sockaddr *name1, *name2; socklen_t len1, len2; + struct ufd *ufd1, *ufd2; - if(sk->family != sk2->family) + ufd1 = getskufd(sk); + ufd2 = getskufd(sk2); + if((ufd1->type != UFD_SOCK) || (ufd2->type != UFD_SOCK)) { + errno = EOPNOTSUPP; + return(-1); + } + if(ufd1->d.s.family != ufd2->d.s.family) { - flog(LOG_ERR, "using sockgetremotename2 with sockets of differing family: %i %i", sk->family, sk2->family); + flog(LOG_ERR, "using sockgetremotename2 with sockets of differing family: %i %i", ufd1->d.s.family, ufd2->d.s.family); return(-1); } - if(sockgetremotename(sk, &name1, &len1)) + if(getremotename(ufd1->fd, &name1, &len1)) return(-1); - if(sockgetremotename(sk2, &name2, &len2)) { + if(getremotename(ufd2->fd, &name2, &len2)) { free(name1); return(-1); } @@ -1282,6 +1505,104 @@ int sockgetremotename2(struct socket *sk, struct socket *sk2, struct sockaddr ** return(0); } +int lstgetremotename2(struct lport *lp, struct socket *sk2, struct sockaddr **namebuf, socklen_t *lenbuf) +{ + struct sockaddr *name1, *name2; + socklen_t len1, len2; + struct ufd *ufd1, *ufd2; + + ufd1 = lp->ufd; + ufd2 = getskufd(sk2); + if(ufd2->type != UFD_SOCK) { + errno = EOPNOTSUPP; + return(-1); + } + if(ufd1->d.l.family != ufd2->d.s.family) + { + flog(LOG_ERR, "using lstgetremotename2 with sockets of differing family: %i %i", ufd1->d.l.family, ufd2->d.s.family); + return(-1); + } + if(getremotename(ufd1->fd, &name1, &len1)) + return(-1); + if(getremotename(ufd2->fd, &name2, &len2)) { + free(name1); + return(-1); + } + sethostaddr(name1, name2); + free(name2); + *namebuf = name1; + *lenbuf = len1; + return(0); +} + +int getucred(struct socket *sk, uid_t *uid, gid_t *gid) +{ + struct ufd *ufd; + + ufd = getskufd(sk); + if(ufd->type != UFD_SOCK) { + errno = EOPNOTSUPP; + return(-1); + } + if(ufd->d.s.family != AF_UNIX) { + errno = EOPNOTSUPP; + return(-1); + } + *uid = ufd->d.s.ucred.uid; + *gid = ufd->d.s.ucred.gid; + return(0); +} + +/* void sockblock(struct socket *sk, int block) */ +/* { */ +/* struct ufd *ufd; */ + +/* ufd = getskufd(sk); */ +/* ufd->ignread = block; */ +/* } */ + +int sockfamily(struct socket *sk) +{ + struct ufd *ufd; + + ufd = getskufd(sk); + if(ufd->type != UFD_SOCK) { + errno = EOPNOTSUPP; + return(-1); + } + return(ufd->d.s.family); +} + +int sockpeeraddr(struct socket *sk, struct sockaddr **namebuf, socklen_t *lenbuf) +{ + struct ufd *ufd; + + ufd = getskufd(sk); + if(ufd->type != UFD_SOCK) { + errno = EOPNOTSUPP; + return(-1); + } + if(ufd->d.s.remote == NULL) + return(-1); + *namebuf = memcpy(smalloc(ufd->d.s.remotelen), ufd->d.s.remote, ufd->d.s.remotelen); + if(lenbuf != NULL) + *lenbuf = ufd->d.s.remotelen; + return(0); +} + +char *formatsockpeer(struct socket *sk) +{ + struct sockaddr *name; + socklen_t nlen; + char *ret; + + if(sockpeeraddr(sk, &name, &nlen)) + return(NULL); + ret = formataddress(name, nlen); + free(name); + return(ret); +} + int addreq(struct sockaddr *x, struct sockaddr *y) { struct sockaddr_un *u1, *u2; @@ -1422,8 +1743,10 @@ static int init(int hup) static void terminate(void) { - while(sockets != NULL) - unlinksock(sockets); + /* + while(ufds != NULL) + freeufd(ufds); + */ } static struct module me = diff --git a/daemon/net.h b/daemon/net.h index 2e7e2d9..24e7ca5 100644 --- a/daemon/net.h +++ b/daemon/net.h @@ -22,10 +22,9 @@ #include #include -#define SOCK_LST 0 /* Listening */ -#define SOCK_SYN 1 /* Connecting */ -#define SOCK_EST 2 /* Established */ -#define SOCK_STL 3 /* Stale, dead */ +#define SOCK_SYN 0 /* Connecting */ +#define SOCK_EST 1 /* Established */ +#define SOCK_STL 2 /* Stale, dead */ #define SOCK_TOS_MINDELAY 4 #define SOCK_TOS_MAXTP 3 #define SOCK_TOS_MAXREL 2 @@ -42,37 +41,12 @@ struct dgrambuf struct socket { - struct socket *next, *prev; int refcount; - int fd; - int isrealsocket; /* Bleh... */ - int family; - int tos; - int type; int state; - int ignread; - int events; - int close; - struct sockaddr *remote; - socklen_t remotelen; - struct - { - uid_t uid; - gid_t gid; - } ucred; - union - { - struct - { - struct dgrambuf *f, *l; - } d; - struct - { - void *buf; - size_t bufsize; - size_t datasize; - } s; - } outbuf; + int dgram; + int eos; + size_t maxbuf; + struct socket *back, *pnext; union { struct @@ -85,39 +59,54 @@ struct socket size_t bufsize; size_t datasize; } s; - } inbuf; + } buf; void (*conncb)(struct socket *sk, int err, void *data); void (*errcb)(struct socket *sk, int err, void *data); void (*readcb)(struct socket *sk, void *data); void (*writecb)(struct socket *sk, void *data); - void (*acceptcb)(struct socket *sk, struct socket *newsk, void *data); + struct ufd *ufd; + void *data; +}; + +struct lport { + struct ufd *ufd; + void (*acceptcb)(struct lport *lp, struct socket *newsk, void *data); + void (*errcb)(struct lport *lp, int err, void *data); void *data; }; void putsock(struct socket *sk); void getsock(struct socket *sk); -struct socket *netcslisten(int type, struct sockaddr *name, socklen_t namelen, void (*func)(struct socket *, struct socket *, void *), void *data); -struct socket *netcslistenlocal(int type, struct sockaddr *name, socklen_t namelen, void (*func)(struct socket *, struct socket *, void *), void *data); -struct socket *netcstcplisten(int port, int local, void (*func)(struct socket *, struct socket *, void *), void *data); +struct lport *netcslisten(int type, struct sockaddr *name, socklen_t namelen, void (*func)(struct lport *, struct socket *, void *), void *data); +struct lport *netcslistenlocal(int type, struct sockaddr *name, socklen_t namelen, void (*func)(struct lport *, struct socket *, void *), void *data); +struct lport *netcstcplisten(int port, int local, void (*func)(struct lport *, struct socket *, void *), void *data); struct socket *netcsconn(struct sockaddr *addr, socklen_t addrlen, void (*func)(struct socket *, int, void *), void *data); int pollsocks(int timeout); +void freedgbuf(struct dgrambuf *dg); void sockqueue(struct socket *sk, void *data, size_t size); -size_t sockqueuesize(struct socket *sk); +void sockerror(struct socket *sk, int en); +/* size_t sockqueuesize(struct socket *sk); */ +ssize_t sockqueueleft(struct socket *sk); int netresolve(char *addr, void (*callback)(struct sockaddr *addr, int addrlen, void *data), void *data); struct socket *netcsdgram(struct sockaddr *name, socklen_t namelen); -struct socket *netdupsock(struct socket *sk); -void netdgramconn(struct socket *sk, struct sockaddr *addr, socklen_t addrlen); -int sockgetlocalname(struct socket *sk, struct sockaddr **namebuf, socklen_t *lenbuf); +struct socket *netdgramconn(struct socket *sk, struct sockaddr *addr, socklen_t addrlen); int sockgetremotename(struct socket *sk, struct sockaddr **namebuf, socklen_t *lenbuf); int sockgetremotename2(struct socket *sk, struct socket *sk2, struct sockaddr **namebuf, socklen_t *lenbuf); +int lstgetremotename(struct lport *lp, struct sockaddr **namebuf, socklen_t *lenbuf); +int lstgetremotename2(struct lport *lp, struct socket *sk, struct sockaddr **namebuf, socklen_t *lenbuf); void closesock(struct socket *sk); +void closelport(struct lport *lp); void *sockgetinbuf(struct socket *sk, size_t *size); struct socket *wrapsock(int fd); size_t sockgetdatalen(struct socket *sk); -int getpublicaddr(int af, struct sockaddr **addr, socklen_t *lenbuf); int socksettos(struct socket *sk, int tos); int addreq(struct sockaddr *x, struct sockaddr *y); char *formataddress(struct sockaddr *arg, socklen_t arglen); +char *formatsockpeer(struct socket *sk); void sockpushdata(struct socket *sk, void *buf, size_t size); +/* void sockblock(struct socket *sk, int block); */ +int sockpeeraddr(struct socket *sk, struct sockaddr **namebuf, socklen_t *lenbuf); +int getucred(struct socket *sk, uid_t *uid, gid_t *gid); +int sockfamily(struct socket *sk); #endif diff --git a/daemon/transfer.c b/daemon/transfer.c index 29ad45d..1e674e6 100644 --- a/daemon/transfer.c +++ b/daemon/transfer.c @@ -234,9 +234,7 @@ static void transexpire(int cancelled, struct transfer *transfer) static void transferread(struct socket *sk, struct transfer *transfer) { - if(sockgetdatalen(sk) >= 65536) - sk->ignread = 1; - if((transfer->iface != NULL) && (transfer->iface->gotdata != NULL)) + if((sockgetdatalen(sk) > 0) && (transfer->iface != NULL) && (transfer->iface->gotdata != NULL)) transfer->iface->gotdata(transfer, transfer->ifacedata); } @@ -276,9 +274,9 @@ void transferendofdata(struct transfer *transfer) } } -size_t transferdatasize(struct transfer *transfer) +ssize_t transferdatasize(struct transfer *transfer) { - return(sockqueuesize(transfer->localend)); + return(sockqueueleft(transfer->localend)); } void *transfergetdata(struct transfer *transfer, size_t *size) @@ -287,7 +285,6 @@ void *transfergetdata(struct transfer *transfer, size_t *size) if(transfer->localend == NULL) return(NULL); - transfer->localend->ignread = 0; time(&transfer->activity); if((buf = sockgetinbuf(transfer->localend, size)) == NULL) return(NULL); @@ -311,7 +308,6 @@ void transferprepul(struct transfer *transfer, off_t size, off_t start, off_t en transfersetsize(transfer, size); transfer->curpos = start; transfer->endpos = end; - lesk->ignread = 1; transfersetlocalend(transfer, lesk); } @@ -326,7 +322,7 @@ void transferstartul(struct transfer *transfer, struct socket *sk) transfersetstate(transfer, TRNS_MAIN); socksettos(sk, confgetint("transfer", "ultos")); if(transfer->localend != NULL) - transfer->localend->ignread = 0; + transferread(transfer->localend, transfer); } void transfersetlocalend(struct transfer *transfer, struct socket *sk) @@ -716,7 +712,7 @@ int forkfilter(struct transfer *transfer) * the fd, and thus it closes it. Until I can find out whyever the * kernel gives a POLLIN on the fd (if I can at all...), I'll just * set ignread on insock for now. */ - insock->ignread = 1; +/* sockblock(insock, 1); */ transfer->filter = pid; transfersetlocalend(transfer, insock); getsock(transfer->filterout = outsock); diff --git a/daemon/transfer.h b/daemon/transfer.h index b4ffa69..4678254 100644 --- a/daemon/transfer.h +++ b/daemon/transfer.h @@ -113,7 +113,7 @@ void transfersetlocalend(struct transfer *transfer, struct socket *sk); void *transfergetdata(struct transfer *transfer, size_t *size); int forkfilter(struct transfer *transfer); void transferputdata(struct transfer *transfer, void *buf, size_t size); -size_t transferdatasize(struct transfer *transfer); +ssize_t transferdatasize(struct transfer *transfer); void transferendofdata(struct transfer *transfer); void transferprepul(struct transfer *transfer, off_t size, off_t start, off_t end, struct socket *lesk); void transferstartul(struct transfer *transfer, struct socket *sk); diff --git a/daemon/ui.c b/daemon/ui.c index fdedc50..3f65ea1 100644 --- a/daemon/ui.c +++ b/daemon/ui.c @@ -171,8 +171,8 @@ static void notifappend(struct notif *notif, ...); struct uiuser *users = NULL; struct uidata *actives = NULL; -struct socket *tcpsocket = NULL; -struct socket *unixsocket = NULL; +struct lport *tcpsocket = NULL; +struct lport *unixsocket = NULL; static time_t starttime; static wchar_t *quoteword(wchar_t *word) @@ -340,33 +340,35 @@ static void cmd_connect(struct socket *sk, struct uidata *data, int argc, wchar_ { int valid; struct in6_addr mv4lo; + struct sockaddr *remote; if(confgetint("ui", "onlylocal")) { - switch(sk->remote->sa_family) - { - case AF_INET: - valid = ((struct sockaddr_in *)sk->remote)->sin_addr.s_addr == INADDR_LOOPBACK; - break; - case AF_INET6: - inet_pton(AF_INET6, "::ffff:127.0.0.1", &mv4lo); - valid = 0; - if(!memcmp(&((struct sockaddr_in6 *)sk->remote)->sin6_addr, &in6addr_loopback, sizeof(in6addr_loopback))) - valid = 1; - if(!memcmp(&((struct sockaddr_in6 *)sk->remote)->sin6_addr, &mv4lo, sizeof(in6addr_loopback))) + valid = 0; + if(!sockpeeraddr(sk, &remote, NULL)) { + switch(remote->sa_family) + { + case AF_INET: + valid = ((struct sockaddr_in *)remote)->sin_addr.s_addr == INADDR_LOOPBACK; + break; + case AF_INET6: + inet_pton(AF_INET6, "::ffff:127.0.0.1", &mv4lo); + valid = 0; + if(!memcmp(&((struct sockaddr_in6 *)remote)->sin6_addr, &in6addr_loopback, sizeof(in6addr_loopback))) + valid = 1; + if(!memcmp(&((struct sockaddr_in6 *)remote)->sin6_addr, &mv4lo, sizeof(in6addr_loopback))) + valid = 1; + break; + case AF_UNIX: valid = 1; - break; - case AF_UNIX: - valid = 1; - break; - default: - valid = 0; - break; + break; + } + free(remote); } if(!valid) { sq(sk, 0, L"502", L"Only localhost connections allowed to this host", NULL); - sk->close = 1; + closesock(sk); data->close = 1; return; } @@ -463,20 +465,20 @@ static void cmd_login(struct socket *sk, struct uidata *data, int argc, wchar_t if(data->uid == -1) { sq(sk, 0, L"506", L"Authentication error", NULL); - flog(LOG_INFO, "user %ls authenticated successfully from %s, but no account existed", data->username, formataddress(sk->remote, sk->remotelen)); + flog(LOG_INFO, "user %ls authenticated successfully from %s, but no account existed", data->username, formatsockpeer(sk)); logout(data); } else if((data->userinfo == NULL) || (data->userinfo->perms & PERM_DISALLOW)) { sq(sk, 0, L"506", L"Authentication error", NULL); - flog(LOG_INFO, "user %ls authenticated successfully from %s, but was not authorized", data->username, formataddress(sk->remote, sk->remotelen)); + flog(LOG_INFO, "user %ls authenticated successfully from %s, but was not authorized", data->username, formatsockpeer(sk)); logout(data); } else { sq(sk, 0, L"200", L"Welcome", NULL); - flog(LOG_INFO, "%ls (UID %i) logged in from %s", data->username, data->uid, formataddress(sk->remote, sk->remotelen)); + flog(LOG_INFO, "%ls (UID %i) logged in from %s", data->username, data->uid, formatsockpeer(sk)); } break; case AUTH_DENIED: sq(sk, 0, L"506", L"Authentication error", L"%ls", (data->auth->text == NULL)?L"":(data->auth->text), NULL); - flog(LOG_INFO, "authentication failed for %ls from %s", data->username, formataddress(sk->remote, sk->remotelen)); + flog(LOG_INFO, "authentication failed for %ls from %s", data->username, formatsockpeer(sk)); logout(data); break; case AUTH_PASS: @@ -537,20 +539,20 @@ static void cmd_pass(struct socket *sk, struct uidata *data, int argc, wchar_t * if(data->uid == -1) { sq(sk, 0, L"506", L"Authentication error", NULL); - flog(LOG_INFO, "user %ls authenticated successfully from %s, but no account existed", data->username, formataddress(sk->remote, sk->remotelen)); + flog(LOG_INFO, "user %ls authenticated successfully from %s, but no account existed", data->username, formatsockpeer(sk)); logout(data); } else if((data->userinfo == NULL) || (data->userinfo->perms & PERM_DISALLOW)) { sq(sk, 0, L"506", L"Authentication error", NULL); - flog(LOG_INFO, "user %ls authenticated successfully from %s, but was not authorized", data->username, formataddress(sk->remote, sk->remotelen)); + flog(LOG_INFO, "user %ls authenticated successfully from %s, but was not authorized", data->username, formatsockpeer(sk)); logout(data); } else { sq(sk, 0, L"200", L"Welcome", NULL); - flog(LOG_INFO, "%ls (UID %i) logged in from %s", data->username, data->uid, formataddress(sk->remote, sk->remotelen)); + flog(LOG_INFO, "%ls (UID %i) logged in from %s", data->username, data->uid, formatsockpeer(sk)); } break; case AUTH_DENIED: sq(sk, 0, L"506", L"Authentication error", L"%ls", (data->auth->text == NULL)?L"":(data->auth->text), NULL); - flog(LOG_INFO, "authentication failed for %ls from %s", data->username, formataddress(sk->remote, sk->remotelen)); + flog(LOG_INFO, "authentication failed for %ls from %s", data->username, formatsockpeer(sk)); logout(data); break; case AUTH_PASS: @@ -1822,7 +1824,7 @@ static void uierror(struct socket *sk, int err, struct uidata *data) freeuidata(data); } -static void uiaccept(struct socket *sk, struct socket *newsk, void *data) +static void uiaccept(struct lport *lp, struct socket *newsk, void *data) { struct uidata *uidata; @@ -2236,7 +2238,7 @@ static struct sockaddr_un *makeunixname(void) static int tcpportupdate(struct configvar *var, void *uudata) { - struct socket *newsock; + struct lport *newsock; newsock = NULL; if((var->val.num != -1) && ((newsock = netcstcplisten(var->val.num, 1, uiaccept, NULL)) == NULL)) @@ -2246,7 +2248,7 @@ static int tcpportupdate(struct configvar *var, void *uudata) } if(tcpsocket != NULL) { - putsock(tcpsocket); + closelport(tcpsocket); tcpsocket = NULL; } tcpsocket = newsock; @@ -2255,7 +2257,7 @@ static int tcpportupdate(struct configvar *var, void *uudata) static int unixsockupdate(struct configvar *var, void *uudata) { - struct socket *newsock; + struct lport *newsock; struct sockaddr_un *un; mode_t ou; @@ -2270,7 +2272,7 @@ static int unixsockupdate(struct configvar *var, void *uudata) umask(ou); if(unixsocket != NULL) { - putsock(unixsocket); + closelport(unixsocket); unixsocket = NULL; } unixsocket = newsock; @@ -2428,9 +2430,9 @@ static void terminate(void) while(users != NULL) freeuser(users); if(tcpsocket != NULL) - putsock(tcpsocket); + closelport(tcpsocket); if(unixsocket != NULL) - putsock(unixsocket); + closelport(unixsocket); } static struct configvar myvars[] =