qio: Track the amount of bytes read
[akaros.git] / kern / src / net / devip.c
index 65c638a..410f94d 100644 (file)
@@ -157,7 +157,9 @@ static int ip3gen(struct chan *c, int i, struct dir *dp)
                        return founddevdir(c, q, "err", qlen(cv->eq),
                                                           cv->owner, perm, dp);
                case Qlisten:
-                       return founddevdir(c, q, "listen", 0, cv->owner, cv->perm, dp);
+                       perm = cv->perm;
+                       perm |= cv->incall ? DMREADABLE : 0;
+                       return founddevdir(c, q, "listen", 0, cv->owner, perm, dp);
                case Qlocal:
                        p = "local";
                        break;
@@ -616,7 +618,7 @@ static int ipwstat(struct chan *c, uint8_t * dp, int n)
                error(EPERM, ERROR_FIXME);
        if (!emptystr(d->uid))
                kstrdup(&cv->owner, d->uid);
-       if (d->mode != ~0UL)
+       if (d->mode != -1)
                cv->perm = d->mode & 0777;
        poperror();
        kfree(d);
@@ -640,9 +642,11 @@ 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, %s, proto %s, conv idx %d, rq len %d, wq len %d",
+                       snprintf(ret, ret_l,
+                                "Qdata, %s, proto %s, conv idx %d, rq len %d, wq len %d, total read %llu",
                                 SLIST_EMPTY(&conv->data_taps) ? "untapped" : "tapped",
-                                proto->name, conv->x, qlen(conv->rq), qlen(conv->wq));
+                                proto->name, conv->x, qlen(conv->rq), qlen(conv->wq),
+                                        q_bytes_read(conv->rq));
                        break;
                case Qarp:
                        ret = "Qarp";
@@ -653,9 +657,10 @@ 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, %s proto %s, conv idx %d",
+                       snprintf(ret, ret_l,
+                                "Qlisten, %s proto %s, conv idx %d, has %sincalls",
                                 SLIST_EMPTY(&conv->listen_taps) ? "untapped" : "tapped",
-                                proto->name, conv->x);
+                                proto->name, conv->x, conv->incall ? "" : "no ");
                        break;
                case Qlog:
                        ret = "Qlog";
@@ -1043,12 +1048,18 @@ void Fsstdconnect(struct conv *c, char *argv[], int argc)
                        break;
        }
 
+       /* TODO: why is an IPnoaddr (in v6 format, equivalent to v6Unspecified),
+        * a v4 format? */
        if ((memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
                 memcmp(c->laddr, v4prefix, IPv4off) == 0)
                || ipcmp(c->raddr, IPnoaddr) == 0)
                c->ipversion = V4;
        else
                c->ipversion = V6;
+       /* Linux has taught people to use zeros for local interfaces.  TODO: We
+        * might need this for v6 in the future. */
+       if (!ipcmp(c->raddr, IPv4_zeroes))
+               ipmove(c->raddr, IPv4_loopback);
 }
 
 /*
@@ -1328,6 +1339,22 @@ static void ttlctlmsg(struct conv *c, struct cmdbuf *cb)
                c->ttl = atoi(cb->f[1]);
 }
 
+/* Binds a conversation, as if the user wrote "bind *" into ctl. */
+static void autobind(struct conv *cv)
+{
+       ERRSTACK(1);
+       struct cmdbuf *cb;
+
+       cb = parsecmd("bind *", 7);
+       if (waserror()) {
+               kfree(cb);
+               nexterror();
+       }
+       bindctlmsg(cv->p, cv, cb);
+       poperror();
+       kfree(cb);
+}
+
 static long ipwrite(struct chan *ch, void *v, long n, int64_t off)
 {
        ERRSTACK(1);
@@ -1348,6 +1375,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)];
+                       /* connection-less protocols (UDP) can write without manually
+                        * binding. */
+                       if (c->lport == 0)
+                               autobind(c);
                        if (ch->flag & O_NONBLOCK)
                                qwrite_nonblock(c->wq, a, n);
                        else