net: Use chan flag O_NONBLOCK for nonblocking
[akaros.git] / kern / src / net / devip.c
index 94b0818..48f67cd 100644 (file)
@@ -100,6 +100,12 @@ extern char *eve;
 static long ndbwrite(struct Fs *, char *unused_char_p_t, uint32_t, int);
 static void closeconv(struct conv *);
 
+static struct conv *chan2conv(struct chan *chan)
+{
+       /* That's a lot of pointers to get to the conv! */
+       return ipfs[chan->dev]->p[PROTO(chan->qid)]->conv[CONV(chan->qid)];
+}
+
 static inline int founddevdir(struct chan *c, struct qid q, char *n,
                                                          int64_t length, char *user, long perm,
                                                          struct dir *db)
@@ -123,7 +129,7 @@ static int ip3gen(struct chan *c, int i, struct dir *dp)
        struct conv *cv;
        char *p;
 
-       cv = ipfs[c->dev]->p[PROTO(c->qid)]->conv[CONV(c->qid)];
+       cv = chan2conv(c);
        if (cv->owner == NULL)
                kstrdup(&cv->owner, eve);
        mkqid(&q, QID(PROTO(c->qid), CONV(c->qid), i), 0, QTFILE);
@@ -311,7 +317,7 @@ static struct Fs *ipgetfs(int dev)
 
        qlock(&fslock);
        if (ipfs[dev] == NULL) {
-               f = kzmalloc(sizeof(struct Fs), KMALLOC_WAIT);
+               f = kzmalloc(sizeof(struct Fs), MEM_WAIT);
                rwinit(&f->rwlock);
                qlock_init(&f->iprouter.qlock);
                ip_init(f);
@@ -453,9 +459,6 @@ static struct chan *ipopen(struct chan *c, int omode)
                                error(ENODEV, ERROR_FIXME);
                                break;
                        }
-                       /* we only honor nonblock on a clone */
-                       if (c->flag & O_NONBLOCK)
-                               Fsconvnonblock(cv, TRUE);
                        mkqid(&c->qid, QID(p->x, cv->x, Qctl), 0, QTFILE);
                        break;
                case Qdata:
@@ -537,7 +540,7 @@ static struct chan *ipopen(struct chan *c, int omode)
                                /* we can peek at incall without grabbing the cv qlock.  if
                                 * anything is there, it'll remain there until we dequeue it.
                                 * no one else can, since we hold the listenq lock */
-                               if (cv->nonblock && !cv->incall)
+                               if ((c->flag & O_NONBLOCK) && !cv->incall)
                                        error(EAGAIN, "listen queue empty");
                                /* wait for a connect */
                                rendez_sleep(&cv->listenr, should_wake, cv);
@@ -550,10 +553,6 @@ static struct chan *ipopen(struct chan *c, int omode)
                                        cv->incall = nc->next;
                                        mkqid(&c->qid, QID(PROTO(c->qid), nc->x, Qctl), 0, QTFILE);
                                        kstrdup(&cv->owner, ATTACHER(c));
-                                       /* O_NONBLOCK/CNONBLOCK when opening listen means the *new*
-                                        * conv is already non-blocking, like accept4() in Linux */
-                                       if (c->flag & O_NONBLOCK)
-                                               Fsconvnonblock(nc, TRUE);
                                }
                                qunlock(&cv->qlock);
 
@@ -626,8 +625,9 @@ static char *ipchaninfo(struct chan *ch, char *ret, size_t ret_l)
                case Qdata:
                        proto = f->p[PROTO(ch->qid)];
                        conv = proto->conv[CONV(ch->qid)];
-                       snprintf(ret, ret_l, "Qdata, proto %s, conv idx %d", proto->name,
-                                        conv->x);
+                       snprintf(ret, ret_l, "Qdata, %s proto %s, conv idx %d",
+                                SLIST_EMPTY(&conv->data_taps) ? "untapped" : "tapped",
+                                proto->name, conv->x);
                        break;
                case Qarp:
                        ret = "Qarp";
@@ -638,8 +638,9 @@ static char *ipchaninfo(struct chan *ch, char *ret, size_t ret_l)
                case Qlisten:
                        proto = f->p[PROTO(ch->qid)];
                        conv = proto->conv[CONV(ch->qid)];
-                       snprintf(ret, ret_l, "Qlisten, proto %s, conv idx %d", proto->name,
-                                        conv->x);
+                       snprintf(ret, ret_l, "Qlisten, %s proto %s, conv idx %d",
+                                SLIST_EMPTY(&conv->listen_taps) ? "untapped" : "tapped",
+                                proto->name, conv->x);
                        break;
                case Qlog:
                        ret = "Qlog";
@@ -794,14 +795,15 @@ static long ipread(struct chan *ch, void *a, long n, int64_t off)
                        x = f->p[PROTO(ch->qid)];
                        c = x->conv[CONV(ch->qid)];
                        sofar = (*x->state) (c, buf, Statelen - 2);
-                       sofar += snprintf(buf + sofar, Statelen - 2 - sofar, "nonblock %s\n",
-                                         c->nonblock ? "on" : "off");
                        rv = readstr(offset, p, n, buf);
                        kfree(buf);
                        return rv;
                case Qdata:
                        c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
-                       return qread(c->rq, a, n);
+                       if (ch->flag & O_NONBLOCK)
+                               return qread_nonblock(c->rq, a, n);
+                       else
+                               return qread(c->rq, a, n);
                case Qerr:
                        c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
                        return qread(c->eq, a, n);
@@ -823,15 +825,14 @@ static long ipread(struct chan *ch, void *a, long n, int64_t off)
 static struct block *ipbread(struct chan *ch, long n, uint32_t offset)
 {
        struct conv *c;
-       struct Proto *x;
-       struct Fs *f;
 
        switch (TYPE(ch->qid)) {
                case Qdata:
-                       f = ipfs[ch->dev];
-                       x = f->p[PROTO(ch->qid)];
-                       c = x->conv[CONV(ch->qid)];
-                       return qbread(c->rq, n);
+                       c = chan2conv(ch);
+                       if (ch->flag & O_NONBLOCK)
+                               return qbread_nonblock(c->rq, n);
+                       else
+                               return qbread(c->rq, n);
                default:
                        return devbread(ch, n, offset);
        }
@@ -848,7 +849,7 @@ static void setladdr(struct conv *c)
 /*
  *  set a local port making sure the quad of raddr,rport,laddr,lport is unique
  */
-static char *setluniqueport(struct conv *c, int lport)
+static void setluniqueport(struct conv *c, int lport)
 {
        struct Proto *p;
        struct conv *xp;
@@ -869,12 +870,11 @@ static char *setluniqueport(struct conv *c, int lport)
                        && ipcmp(xp->raddr, c->raddr) == 0
                        && ipcmp(xp->laddr, c->laddr) == 0) {
                        qunlock(&p->qlock);
-                       return "address in use";
+                       error(EFAIL, "address in use");
                }
        }
        c->lport = lport;
        qunlock(&p->qlock);
-       return NULL;
 }
 
 /*
@@ -928,15 +928,12 @@ static void setlport(struct conv *c)
  *  set a local address and port from a string of the form
  *     [address!]port[!r]
  */
-static char *setladdrport(struct conv *c, char *str, int announcing)
+static void setladdrport(struct conv *c, char *str, int announcing)
 {
        char *p;
-       char *rv;
        uint16_t lport;
        uint8_t addr[IPaddrlen];
 
-       rv = NULL;
-
        /*
         *  ignore restricted part if it exists.  it's
         *  meaningless on local ports.
@@ -963,7 +960,7 @@ static char *setladdrport(struct conv *c, char *str, int announcing)
                        if (ipforme(c->p->f, addr))
                                ipmove(c->laddr, addr);
                        else
-                               return "not a local IP address";
+                               error(EFAIL, "not a local IP address");
                }
        }
 
@@ -971,24 +968,23 @@ static char *setladdrport(struct conv *c, char *str, int announcing)
        if (announcing && strcmp(p, "*") == 0) {
                if (!iseve())
                        error(EPERM, ERROR_FIXME);
-               return setluniqueport(c, 0);
+               setluniqueport(c, 0);
        }
 
        lport = atoi(p);
        if (lport <= 0)
                setlport(c);
        else
-               rv = setluniqueport(c, lport);
-       return rv;
+               setluniqueport(c, lport);
 }
 
-static char *setraddrport(struct conv *c, char *str)
+static void setraddrport(struct conv *c, char *str)
 {
        char *p;
 
        p = strchr(str, '!');
        if (p == NULL)
-               return "malformed address";
+               error(EFAIL, "malformed address");
        *p++ = 0;
        parseip(c->raddr, str);
        c->rport = atoi(p);
@@ -997,33 +993,25 @@ static char *setraddrport(struct conv *c, char *str)
                if (strstr(p, "!r") != NULL)
                        c->restricted = 1;
        }
-       return NULL;
 }
 
 /*
  *  called by protocol connect routine to set addresses
  */
-char *Fsstdconnect(struct conv *c, char *argv[], int argc)
+void Fsstdconnect(struct conv *c, char *argv[], int argc)
 {
-       char *p;
-
        switch (argc) {
                default:
-                       return "bad args to connect";
+                       error(EINVAL, "bad args to %s", __func__);
                case 2:
-                       p = setraddrport(c, argv[1]);
-                       if (p != NULL)
-                               return p;
+                       setraddrport(c, argv[1]);
                        setladdr(c);
                        setlport(c);
                        break;
                case 3:
-                       p = setraddrport(c, argv[1]);
-                       if (p != NULL)
-                               return p;
-                       p = setladdrport(c, argv[2], 0);
-                       if (p != NULL)
-                               return p;
+                       setraddrport(c, argv[1]);
+                       setladdrport(c, argv[2], 0);
+                       break;
        }
 
        if ((memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
@@ -1032,8 +1020,6 @@ char *Fsstdconnect(struct conv *c, char *argv[], int argc)
                c->ipversion = V4;
        else
                c->ipversion = V6;
-
-       return NULL;
 }
 
 /*
@@ -1055,9 +1041,7 @@ static void connectctlmsg(struct Proto *x, struct conv *c, struct cmdbuf *cb)
        c->cerr[0] = '\0';
        if (x->connect == NULL)
                error(EFAIL, "connect not supported");
-       p = x->connect(c, cb->f, cb->nf);
-       if (p != NULL)
-               error(EFAIL, p);
+       x->connect(c, cb->f, cb->nf);
 
        qunlock(&c->qlock);
        if (waserror()) {
@@ -1075,15 +1059,16 @@ static void connectctlmsg(struct Proto *x, struct conv *c, struct cmdbuf *cb)
 /*
  *  called by protocol announce routine to set addresses
  */
-char *Fsstdannounce(struct conv *c, char *argv[], int argc)
+void Fsstdannounce(struct conv *c, char *argv[], int argc)
 {
        memset(c->raddr, 0, sizeof(c->raddr));
        c->rport = 0;
        switch (argc) {
                default:
-                       return "bad args to announce";
+                       error(EINVAL, "bad args to announce");
                case 2:
-                       return setladdrport(c, argv[1], 1);
+                       setladdrport(c, argv[1], 1);
+                       break;
        }
 }
 
@@ -1106,9 +1091,7 @@ static void announcectlmsg(struct Proto *x, struct conv *c, struct cmdbuf *cb)
        c->cerr[0] = '\0';
        if (x->announce == NULL)
                error(EFAIL, "announce not supported");
-       p = x->announce(c, cb->f, cb->nf);
-       if (p != NULL)
-               error(EFAIL, p);
+       x->announce(c, cb->f, cb->nf);
 
        qunlock(&c->qlock);
        if (waserror()) {
@@ -1126,48 +1109,48 @@ static void announcectlmsg(struct Proto *x, struct conv *c, struct cmdbuf *cb)
 /*
  *  called by protocol bind routine to set addresses
  */
-char *Fsstdbind(struct conv *c, char *argv[], int argc)
+void Fsstdbind(struct conv *c, char *argv[], int argc)
 {
        switch (argc) {
                default:
-                       return "bad args to bind";
+                       error(EINVAL, "bad args to bind");
                case 2:
-                       return setladdrport(c, argv[1], 0);
+                       setladdrport(c, argv[1], 0);
+                       break;
        }
 }
 
-void Fsconvnonblock(struct conv *cv, bool onoff)
-{
-       qnonblock(cv->wq, onoff);
-       qnonblock(cv->rq, onoff);
-       cv->nonblock = onoff;
-}
-
 static void bindctlmsg(struct Proto *x, struct conv *c, struct cmdbuf *cb)
 {
-       char *p;
-
        if (x->bind == NULL)
-               p = Fsstdbind(c, cb->f, cb->nf);
+               Fsstdbind(c, cb->f, cb->nf);
        else
-               p = x->bind(c, cb->f, cb->nf);
-       if (p != NULL)
-               error(EFAIL, p);
+               x->bind(c, cb->f, cb->nf);
 }
 
-static void nonblockctlmsg(struct conv *c, struct cmdbuf *cb)
+static void shutdownctlmsg(struct conv *cv, struct cmdbuf *cb)
 {
        if (cb->nf < 2)
                goto err;
-       if (!strcmp(cb->f[1], "on"))
-               Fsconvnonblock(c, TRUE);
-       else if (!strcmp(cb->f[1], "off"))
-               Fsconvnonblock(c, FALSE);
-       else
+       if (!strcmp(cb->f[1], "rd")) {
+               qhangup(cv->rq, "shutdown");
+               if (cv->p->shutdown)
+                       cv->p->shutdown(cv, SHUT_RD);
+       } else if (!strcmp(cb->f[1], "wr")) {
+               qhangup(cv->wq, "shutdown");
+               if (cv->p->shutdown)
+                       cv->p->shutdown(cv, SHUT_WR);
+       } else if (!strcmp(cb->f[1], "rdwr")) {
+               qhangup(cv->rq, "shutdown");
+               qhangup(cv->wq, "shutdown");
+               if (cv->p->shutdown)
+                       cv->p->shutdown(cv, SHUT_RDWR);
+       } else {
                goto err;
+       }
        return;
 err:
-       error(EINVAL, "nonblock [on|off]");
+       error(EINVAL, "shutdown [rx|tx|rxtx]");
 }
 
 static void tosctlmsg(struct conv *c, struct cmdbuf *cb)
@@ -1206,7 +1189,10 @@ static long ipwrite(struct chan *ch, void *v, long n, int64_t off)
                case Qdata:
                        x = f->p[PROTO(ch->qid)];
                        c = x->conv[CONV(ch->qid)];
-                       qwrite(c->wq, a, n);
+                       if (ch->flag & O_NONBLOCK)
+                               qwrite_nonblock(c->wq, a, n);
+                       else
+                               qwrite(c->wq, a, n);
                        break;
                case Qarp:
                        return arpwrite(f, a, n);
@@ -1236,8 +1222,8 @@ static long ipwrite(struct chan *ch, void *v, long n, int64_t off)
                                announcectlmsg(x, c, cb);
                        else if (strcmp(cb->f[0], "bind") == 0)
                                bindctlmsg(x, c, cb);
-                       else if (strcmp(cb->f[0], "nonblock") == 0)
-                               nonblockctlmsg(c, cb);
+                       else if (strcmp(cb->f[0], "shutdown") == 0)
+                               shutdownctlmsg(c, cb);
                        else if (strcmp(cb->f[0], "ttl") == 0)
                                ttlctlmsg(c, cb);
                        else if (strcmp(cb->f[0], "tos") == 0)
@@ -1267,9 +1253,7 @@ static long ipwrite(struct chan *ch, void *v, long n, int64_t off)
                                parseip(ia, cb->f[1]);
                                ipifcremmulti(c, c->raddr, ia);
                        } else if (x->ctl != NULL) {
-                               p = x->ctl(c, cb->f, cb->nf);
-                               if (p != NULL)
-                                       error(EFAIL, p);
+                               x->ctl(c, cb->f, cb->nf);
                        } else
                                error(EFAIL, "unknown control request");
                        qunlock(&c->qlock);
@@ -1282,19 +1266,18 @@ static long ipwrite(struct chan *ch, void *v, long n, int64_t off)
 static long ipbwrite(struct chan *ch, struct block *bp, uint32_t offset)
 {
        struct conv *c;
-       struct Proto *x;
-       struct Fs *f;
        int n;
 
        switch (TYPE(ch->qid)) {
                case Qdata:
-                       f = ipfs[ch->dev];
-                       x = f->p[PROTO(ch->qid)];
-                       c = x->conv[CONV(ch->qid)];
+                       c = chan2conv(ch);
                        if (bp->next)
                                bp = concatblock(bp);
                        n = BLEN(bp);
-                       qbwrite(c->wq, bp);
+                       if (ch->flag & O_NONBLOCK)
+                               qbwrite_nonblock(c->wq, bp);
+                       else
+                               qbwrite(c->wq, bp);
                        return n;
                default:
                        return devbwrite(ch, bp, offset);
@@ -1339,9 +1322,7 @@ static void ip_wake_cb(struct queue *q, void *data, int filter)
 
 int iptapfd(struct chan *chan, struct fd_tap *tap, int cmd)
 {
-       struct conv *conv;
-       struct Proto *x;
-       struct Fs *f;
+       struct conv *conv = chan2conv(chan);
        int ret;
 
        #define DEVIP_LEGAL_DATA_TAPS (FDTAP_FILT_READABLE | FDTAP_FILT_WRITABLE | \
@@ -1349,11 +1330,6 @@ int iptapfd(struct chan *chan, struct fd_tap *tap, int cmd)
                                       FDTAP_FILT_ERROR)
        #define DEVIP_LEGAL_LISTEN_TAPS (FDTAP_FILT_READABLE | FDTAP_FILT_HANGUP)
 
-       /* That's a lot of pointers to get to the conv! */
-       f = ipfs[chan->dev];
-       x = f->p[PROTO(chan->qid)];
-       conv = x->conv[CONV(chan->qid)];
-
        switch (TYPE(chan->qid)) {
                case Qdata:
                        if (tap->filter & ~DEVIP_LEGAL_DATA_TAPS) {
@@ -1551,7 +1527,6 @@ retry:
        c->restricted = 0;
        c->ttl = MAXTTL;
        c->tos = DFLTTOS;
-       c->nonblock = FALSE;
        qreopen(c->rq);
        qreopen(c->wq);
        qreopen(c->eq);