📄 devip.c
字号:
ipbread(Chan* ch, long n, ulong offset){ Conv *c; Proto *x; 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); default: return devbread(ch, n, offset); }}/* * set local address to be that of the ifc closest to remote address */static voidsetladdr(Conv* c){ findlocalip(c->p->f, c->laddr, c->raddr);}/* * set a local port making sure the quad of raddr,rport,laddr,lport is unique */char*setluniqueport(Conv* c, int lport){ Proto *p; Conv *xp; int x; p = c->p; qlock(p); for(x = 0; x < p->nc; x++){ xp = p->conv[x]; if(xp == nil) break; if(xp == c) continue; if((xp->state == Connected || xp->state == Announced) && xp->lport == lport && xp->rport == c->rport && ipcmp(xp->raddr, c->raddr) == 0 && ipcmp(xp->laddr, c->laddr) == 0){ qunlock(p); return "address in use"; } } c->lport = lport; qunlock(p); return nil;}/* * pick a local port and set it */voidsetlport(Conv* c){ Proto *p; ushort *pp; int x, found; p = c->p; if(c->restricted) pp = &p->nextrport; else pp = &p->nextport; qlock(p); for(;;(*pp)++){ /* * Fsproto initialises p->nextport to 0 and the restricted * ports (p->nextrport) to 600. * Restricted ports must lie between 600 and 1024. * For the initial condition or if the unrestricted port number * has wrapped round, select a random port between 5000 and 1<<15 * to start at. */ if(c->restricted){ if(*pp >= 1024) *pp = 600; } else while(*pp < 5000) *pp = nrand(1<<15); found = 0; for(x = 0; x < p->nc; x++){ if(p->conv[x] == nil) break; if(p->conv[x]->lport == *pp){ found = 1; break; } } if(!found) break; } c->lport = (*pp)++; qunlock(p);}/* * set a local address and port from a string of the form * [address!]port[!r] */char*setladdrport(Conv* c, char* str, int announcing){ char *p; char *rv; ushort lport; uchar addr[IPaddrlen]; rv = nil; /* * ignore restricted part if it exists. it's * meaningless on local ports. */ p = strchr(str, '!'); if(p != nil){ *p++ = 0; if(strcmp(p, "r") == 0) p = nil; } c->lport = 0; if(p == nil){ if(announcing) ipmove(c->laddr, IPnoaddr); else setladdr(c); p = str; } else { if(strcmp(str, "*") == 0) ipmove(c->laddr, IPnoaddr); else { parseip(addr, str); if(ipforme(c->p->f, addr)) ipmove(c->laddr, addr); else return "not a local IP address"; } } /* one process can get all connections */ if(announcing && strcmp(p, "*") == 0){ if(!iseve()) error(Eperm); return setluniqueport(c, 0); } lport = atoi(p); if(lport <= 0) setlport(c); else rv = setluniqueport(c, lport); return rv;}static char*setraddrport(Conv* c, char* str){ char *p; p = strchr(str, '!'); if(p == nil) return "malformed address"; *p++ = 0; parseip(c->raddr, str); c->rport = atoi(p); p = strchr(p, '!'); if(p){ if(strstr(p, "!r") != nil) c->restricted = 1; } return nil;}/* * called by protocol connect routine to set addresses */char*Fsstdconnect(Conv *c, char *argv[], int argc){ char *p; switch(argc) { default: return "bad args to connect"; case 2: p = setraddrport(c, argv[1]); if(p != nil) return p; setladdr(c); setlport(c); break; case 3: p = setraddrport(c, argv[1]); if(p != nil) return p; p = setladdrport(c, argv[2], 0); if(p != nil) return p; } 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; return nil;}/* * initiate connection and sleep till its set up */static intconnected(void* a){ return ((Conv*)a)->state == Connected;}static voidconnectctlmsg(Proto *x, Conv *c, Cmdbuf *cb){ char *p; if(c->state != 0) error(Econinuse); c->state = Connecting; c->cerr[0] = '\0'; if(x->connect == nil) error("connect not supported"); p = x->connect(c, cb->f, cb->nf); if(p != nil) error(p); qunlock(c); if(waserror()){ qlock(c); nexterror(); } sleep(&c->cr, connected, c); qlock(c); poperror(); if(c->cerr[0] != '\0') error(c->cerr);}/* * called by protocol announce routine to set addresses */char*Fsstdannounce(Conv* c, char* argv[], int argc){ memset(c->raddr, 0, sizeof(c->raddr)); c->rport = 0; switch(argc){ default: break; case 2: return setladdrport(c, argv[1], 1); } return "bad args to announce";}/* * initiate announcement and sleep till its set up */static intannounced(void* a){ return ((Conv*)a)->state == Announced;}static voidannouncectlmsg(Proto *x, Conv *c, Cmdbuf *cb){ char *p; if(c->state != 0) error(Econinuse); c->state = Announcing; c->cerr[0] = '\0'; if(x->announce == nil) error("announce not supported"); p = x->announce(c, cb->f, cb->nf); if(p != nil) error(p); qunlock(c); if(waserror()){ qlock(c); nexterror(); } sleep(&c->cr, announced, c); qlock(c); poperror(); if(c->cerr[0] != '\0') error(c->cerr);}/* * called by protocol bind routine to set addresses */char*Fsstdbind(Conv* c, char* argv[], int argc){ switch(argc){ default: break; case 2: return setladdrport(c, argv[1], 0); } return "bad args to bind";}static voidbindctlmsg(Proto *x, Conv *c, Cmdbuf *cb){ char *p; if(x->bind == nil) p = Fsstdbind(c, cb->f, cb->nf); else p = x->bind(c, cb->f, cb->nf); if(p != nil) error(p);}static voidtosctlmsg(Conv *c, Cmdbuf *cb){ if(cb->nf < 2) c->tos = 0; else c->tos = atoi(cb->f[1]);}static voidttlctlmsg(Conv *c, Cmdbuf *cb){ if(cb->nf < 2) c->ttl = MAXTTL; else c->ttl = atoi(cb->f[1]);}static longipwrite(Chan* ch, void *v, long n, vlong off){ Conv *c; Proto *x; char *p; Cmdbuf *cb; uchar ia[IPaddrlen], ma[IPaddrlen]; Fs *f; char *a; ulong offset = off; a = v; f = ipfs[ch->dev]; switch(TYPE(ch->qid)){ default: error(Eperm); case Qdata: x = f->p[PROTO(ch->qid)]; c = x->conv[CONV(ch->qid)]; if(c->wq == nil) error(Eperm); qwrite(c->wq, a, n); break; case Qarp: return arpwrite(f, a, n); case Qiproute: return routewrite(f, ch, a, n); case Qlog: netlogctl(f, a, n); return n; case Qndb: return ndbwrite(f, a, offset, n); break; case Qctl: x = f->p[PROTO(ch->qid)]; c = x->conv[CONV(ch->qid)]; cb = parsecmd(a, n); qlock(c); if(waserror()) { qunlock(c); free(cb); nexterror(); } if(cb->nf < 1) error("short control request"); if(strcmp(cb->f[0], "connect") == 0) connectctlmsg(x, c, cb); else if(strcmp(cb->f[0], "announce") == 0) announcectlmsg(x, c, cb); else if(strcmp(cb->f[0], "bind") == 0) bindctlmsg(x, c, cb); else if(strcmp(cb->f[0], "ttl") == 0) ttlctlmsg(c, cb); else if(strcmp(cb->f[0], "tos") == 0) tosctlmsg(c, cb); else if(strcmp(cb->f[0], "ignoreadvice") == 0) c->ignoreadvice = 1; else if(strcmp(cb->f[0], "addmulti") == 0){ if(cb->nf < 2) error("addmulti needs interface address"); if(cb->nf == 2){ if(!ipismulticast(c->raddr)) error("addmulti for a non multicast address"); parseip(ia, cb->f[1]); ipifcaddmulti(c, c->raddr, ia); } else { parseip(ma, cb->f[2]); if(!ipismulticast(ma)) error("addmulti for a non multicast address"); parseip(ia, cb->f[1]); ipifcaddmulti(c, ma, ia); } } else if(strcmp(cb->f[0], "remmulti") == 0){ if(cb->nf < 2) error("remmulti needs interface address"); if(!ipismulticast(c->raddr)) error("remmulti for a non multicast address"); parseip(ia, cb->f[1]); ipifcremmulti(c, c->raddr, ia); } else if(x->ctl != nil) { p = x->ctl(c, cb->f, cb->nf); if(p != nil) error(p); } else error("unknown control request"); qunlock(c); free(cb); poperror(); } return n;}static longipbwrite(Chan* ch, Block* bp, ulong offset){ Conv *c; Proto *x; 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)]; if(c->wq == nil) error(Eperm); if(bp->next) bp = concatblock(bp); n = BLEN(bp); qbwrite(c->wq, bp); return n; default: return devbwrite(ch, bp, offset); }}Dev ipdevtab = { 'I', "ip", ipreset, devinit, devshutdown, ipattach, ipwalk, ipstat, ipopen, ipcreate, ipclose, ipread, ipbread, ipwrite, ipbwrite, ipremove, ipwstat,};intFsproto(Fs *f, Proto *p){ if(f->np >= Maxproto) return -1; p->f = f; if(p->ipproto > 0){ if(f->t2p[p->ipproto] != nil) return -1; f->t2p[p->ipproto] = p; } p->qid.type = QTDIR; p->qid.path = QID(f->np, 0, Qprotodir); p->conv = malloc(sizeof(Conv*)*(p->nc+1)); if(p->conv == nil) panic("Fsproto"); p->x = f->np; p->nextport = 0; p->nextrport = 600; f->p[f->np++] = p; return 0;}/* * return true if this protocol is * built in */intFsbuiltinproto(Fs* f, uchar proto){ return f->t2p[proto] != nil;}/* * called with protocol locked */Conv*Fsprotoclone(Proto *p, char *user){ Conv *c, **pp, **ep;retry: c = nil; ep = &p->conv[p->nc]; for(pp = p->conv; pp < ep; pp++) { c = *pp; if(c == nil){ c = malloc(sizeof(Conv)); if(c == nil) error(Enomem); qlock(c); c->p = p; c->x = pp - p->conv; if(p->ptclsize != 0){ c->ptcl = malloc(p->ptclsize); if(c->ptcl == nil) { free(c); error(Enomem); } } *pp = c; p->ac++; c->eq = qopen(1024, Qmsg, 0, 0); (*p->create)(c); break; } if(canqlock(c)){ /* * make sure both processes and protocol * are done with this Conv */ if(c->inuse == 0 && (p->inuse == nil || (*p->inuse)(c) == 0)) break; qunlock(c); } } if(pp >= ep) { if(p->gc != nil && (*p->gc)(p)) goto retry; return nil; } c->inuse = 1; kstrdup(&c->owner, user); c->perm = 0660; c->state = Idle; ipmove(c->laddr, IPnoaddr); ipmove(c->raddr, IPnoaddr); c->r = nil; c->rgen = 0; c->lport = 0; c->rport = 0; c->restricted = 0; c->ttl = MAXTTL; qreopen(c->rq); qreopen(c->wq); qreopen(c->eq); qunlock(c); return c;}intFsconnected(Conv* c, char* msg){ if(msg != nil && *msg != '\0') strncpy(c->cerr, msg, ERRMAX-1); switch(c->state){ case Announcing: c->state = Announced; break; case Connecting: c->state = Connected; break; } wakeup(&c->cr); return 0;}Proto*Fsrcvpcol(Fs* f, uchar proto){ if(f->ipmux) return f->ipmux; else return f->t2p[proto];}Proto*Fsrcvpcolx(Fs *f, uchar proto){ return f->t2p[proto];}/* * called with protocol locked */Conv*Fsnewcall(Conv *c, uchar *raddr, ushort rport, uchar *laddr, ushort lport, uchar version){ Conv *nc; Conv **l; int i; qlock(c); i = 0; for(l = &c->incall; *l; l = &(*l)->next) i++; if(i >= Maxincall) { qunlock(c); return nil; } /* find a free conversation */ nc = Fsprotoclone(c->p, network); if(nc == nil) { qunlock(c); return nil; } ipmove(nc->raddr, raddr); nc->rport = rport; ipmove(nc->laddr, laddr); nc->lport = lport; nc->next = nil; *l = nc; nc->state = Connected; nc->ipversion = version; qunlock(c); wakeup(&c->listenr); return nc;}longndbwrite(Fs *f, char *a, ulong off, int n){ if(off > strlen(f->ndb)) error(Eio); if(off+n >= sizeof(f->ndb)) error(Eio); memmove(f->ndb+off, a, n); f->ndb[off+n] = 0; f->ndbvers++; f->ndbmtime = seconds(); return n;}ulongscalednconv(void){ if(cpuserver && conf.npage*BY2PG >= 128*MB) return Nchans*4; return Nchans;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -