X-Git-Url: http://dolda2000.com/gitweb/?a=blobdiff_plain;f=daemon%2Fnet.c;h=86bc5522f206c3784230c74e5b03bb4336a851d9;hb=5760093c6a76eee741d70f8b8d71e9e52bd655ee;hp=7a68dae5c5dca11856a4824edda73fa7fd78ca6c;hpb=363c7059ebeac9d54a372a26737e2235d849eae5;p=doldaconnect.git diff --git a/daemon/net.c b/daemon/net.c index 7a68dae..86bc552 100644 --- a/daemon/net.c +++ b/daemon/net.c @@ -66,8 +66,6 @@ static struct configvar myvars[] = * and net.visibleipv4 are unspecified the address of the hub * connection is used. */ {CONF_VAR_STRING, "publicif", {.str = L""}}, - /* Diffserv should be supported on IPv4, too, but I don't know the - * API to do that. */ /** The Diffserv value to use on IPv6 connections when the * minimize cost TOS value is used (see the TOS VALUES * section). */ @@ -84,6 +82,12 @@ static struct configvar myvars[] = * minimize delay TOS value is used (see the TOS VALUES * section). */ {CONF_VAR_INT, "diffserv-mindelay", {.num = 0}}, + /** If enabled, the IP TOS interface will be used to set Diffserv + * codepoints on IPv4 sockets, by shifting the DSCP value two bits + * to the left (remember, the DSCP field in the IPv4 header is + * defined as the 6 uppermost bits of the TOS field, the lower two + * being left for ECN). This may only work on Linux. */ + {CONF_VAR_BOOL, "dscp-tos", {.num = 0}}, {CONF_VAR_END} }; @@ -211,6 +215,7 @@ static struct socket *newsock1(int dgram) new->refcount = 1; new->state = -1; new->dgram = dgram; + new->maxbuf = 65536; numsocks++; return(new); } @@ -233,6 +238,15 @@ static void sksetstate(struct socket *sk, int state) sk->back->state = state; } +struct socket *netsockpipe(void) +{ + struct socket *sk; + + sk = sockpair(0); + sksetstate(sk, SOCK_EST); + return(sk); +} + static void closeufd(struct ufd *ufd) { if(ufd->fd != -1) @@ -348,10 +362,41 @@ void getsock(struct socket *sk) sk->refcount++; } +static void sockdebug(int level, struct socket *sk, char *format, ...) +{ + va_list args; + char *tb; + + if((sk->dbgnm == NULL) || (level > sk->dbglvl)) + return; + va_start(args, format); + tb = vsprintf2(format, args); + va_end(args); + fprintf(stderr, "%s: %s\n", sk->dbgnm, tb); + free(tb); +} + +void socksetdebug(struct socket *sk, int level, char *nm, ...) +{ + va_list args; + char *tb; + + va_start(args, nm); + tb = vsprintf2(nm, args); + va_end(args); + sk->dbgnm = sprintf2("%s (f)", tb); + sk->back->dbgnm = sprintf2("%s (b)", tb); + free(tb); + sk->dbglvl = level; + sk->back->dbglvl = level; + sockdebug(1, sk, "enabled debugging"); +} + static void freesock(struct socket *sk) { struct dgrambuf *buf; + sockdebug(1, sk, "freeing socket"); if(sk->dgram) { while((buf = sk->buf.d.f) != NULL) { sk->buf.d.f = buf->next; @@ -361,6 +406,8 @@ static void freesock(struct socket *sk) if(sk->buf.s.buf != NULL) free(sk->buf.s.buf); } + if(sk->dbgnm != NULL) + free(sk->dbgnm); free(sk); numsocks--; } @@ -380,6 +427,14 @@ void putsock(struct socket *sk) } } +void quitsock(struct socket *sk) +{ + sk->readcb = NULL; + sk->writecb = NULL; + sk->errcb = NULL; + putsock(sk); +} + static void linksock(struct scons **list, struct socket *sk) { struct scons *sc; @@ -458,6 +513,7 @@ void *sockgetinbuf(struct socket *sk, size_t *size) if((sk->buf.s.buf == NULL) || (sk->buf.s.datasize == 0)) { *size = 0; + sockdebug(2, sk, "read 0 bytes", *size); return(NULL); } buf = sk->buf.s.buf; @@ -466,6 +522,7 @@ void *sockgetinbuf(struct socket *sk, size_t *size) sk->buf.s.bufsize = sk->buf.s.datasize = 0; sockread(sk); } + sockdebug(2, sk, "read %zi bytes", *size); return(buf); } @@ -475,6 +532,7 @@ void sockqueue(struct socket *sk, void *data, size_t size) struct sockaddr *remote; socklen_t remotelen; + sockdebug(2, sk, "queued %zi bytes", size); if(size == 0) return; if(sk->state == SOCK_STL) @@ -735,6 +793,7 @@ static int sockflush(struct ufd *ufd) void closesock(struct socket *sk) { + sockdebug(1, sk, "closed"); sksetstate(sk, SOCK_STL); if(sk->back->eos == 0) sk->back->eos = 1; @@ -756,9 +815,26 @@ size_t sockgetdatalen(struct socket *sk) return(ret); } -size_t sockqueuesize(struct socket *sk) +/* size_t sockqueuesize(struct socket *sk) */ +/* { */ +/* return(sockgetdatalen(sk->back)); */ +/* } */ + +size_t socktqueuesize(struct socket *sk) { - return(sockgetdatalen(sk->back)); + size_t ret; + + ret = 0; + while(1) { + ret += sockgetdatalen(sk->back); + if((sk = sk->back->pnext) == NULL) + return(ret); + } +} + +ssize_t sockqueueleft(struct socket *sk) +{ + return(sk->back->maxbuf - sockgetdatalen(sk->back)); } /* @@ -931,6 +1007,8 @@ struct socket *netcsconn(struct sockaddr *addr, socklen_t addrlen, void (*func)( memcpy(sk->ufd->d.s.remote = smalloc(addrlen), addr, sk->ufd->d.s.remotelen = addrlen); sk->back->conncb = func; sk->back->data = data; + getsock(sk->back); + putsock(sk); if(!connect(sk->ufd->fd, addr, addrlen)) { sksetstate(sk, SOCK_EST); @@ -1002,10 +1080,18 @@ static void runbatches(void) static void cleansocks(void) { struct ufd *ufd, *next; + int dead; for(ufd = ufds; ufd != NULL; ufd = next) { next = ufd->next; - if(ufd->sk && ((ufd->fd < 0) || (sockgetdatalen(ufd->sk) == 0))) { + if(ufd->sk) { + dead = (ufd->fd < 0); + if(ufd->sk->state == SOCK_STL) + dead = 1; + if((ufd->sk->state == SOCK_EST) && (sockgetdatalen(ufd->sk) == 0)) + dead = 1; + if(!dead) + continue; if(ufd->sk->eos == 1) { ufd->sk->eos = 2; closeufd(ufd); @@ -1038,7 +1124,7 @@ int pollsocks(int timeout) for(maxfd = 0, ufd = ufds; ufd != NULL; ufd = ufd->next) { if(ufd->fd < 0) continue; - if(!ufd->ignread) + if(!ufd->ignread && ((ufd->sk == NULL) || (sockqueueleft(ufd->sk) > 0))) FD_SET(ufd->fd, &rfds); if(ufd->sk != NULL) { if(sockgetdatalen(ufd->sk) > 0) @@ -1149,6 +1235,7 @@ int socksettos(struct socket *sk, int tos) { int buf; struct ufd *ufd; + int dscp2tos; ufd = getskufd(sk); if(ufd->type != UFD_SOCK) { @@ -1159,22 +1246,35 @@ int socksettos(struct socket *sk, int tos) return(0); /* Unix sockets are always perfect. :) */ if(ufd->d.s.family == AF_INET) { + dscp2tos = confgetint("net", "dscp-tos"); switch(tos) { case 0: buf = 0; break; case SOCK_TOS_MINCOST: - buf = 0x02; + if(dscp2tos) + buf = confgetint("net", "diffserv-mincost") << 2; + else + buf = 0x02; break; case SOCK_TOS_MAXREL: - buf = 0x04; + if(dscp2tos) + buf = confgetint("net", "diffserv-maxrel") << 2; + else + buf = 0x04; break; case SOCK_TOS_MAXTP: - buf = 0x08; + if(dscp2tos) + buf = confgetint("net", "diffserv-maxtp") << 2; + else + buf = 0x08; break; case SOCK_TOS_MINDELAY: - buf = 0x10; + if(dscp2tos) + buf = confgetint("net", "diffserv-mindelay") << 2; + else + buf = 0x10; break; default: flog(LOG_WARNING, "attempted to set unknown TOS value %i to IPv4 sock", tos); @@ -1529,13 +1629,13 @@ int getucred(struct socket *sk, uid_t *uid, gid_t *gid) return(0); } -void sockblock(struct socket *sk, int block) -{ - struct ufd *ufd; +/* void sockblock(struct socket *sk, int block) */ +/* { */ +/* struct ufd *ufd; */ - ufd = getskufd(sk); - ufd->ignread = block; -} +/* ufd = getskufd(sk); */ +/* ufd->ignread = block; */ +/* } */ int sockfamily(struct socket *sk) {