#include "u.h"#include "lib.h"#include "dat.h"#include "fns.h"#include "error.h"#include "ip.h" #include "devip.h" void csclose(Chan*);long csread(Chan*, void*, long, vlong);long cswrite(Chan*, void*, long, vlong); void osipinit(void); enum{ Qtopdir = 1, /* top level directory */ Qtopbase, Qcs = Qtopbase, Qprotodir, /* directory for a protocol */ Qprotobase, Qclone = Qprotobase, Qconvdir, /* directory for a conversation */ Qconvbase, Qctl = Qconvbase, Qdata, Qstatus, Qremote, Qlocal, Qlisten, MAXPROTO = 4};#define TYPE(x) ((int)((x).path & 0xf))#define CONV(x) ((int)(((x).path >> 4)&0xfff))#define PROTO(x) ((int)(((x).path >> 16)&0xff))#define QID(p, c, y) (((p)<<16) | ((c)<<4) | (y))#define ipzero(x) memset(x, 0, IPaddrlen) typedef struct Proto Proto;typedef struct Conv Conv;struct Conv{ int x; Ref r; int sfd; int perm; char owner[KNAMELEN]; char* state; uchar laddr[IPaddrlen]; ushort lport; uchar raddr[IPaddrlen]; ushort rport; int restricted; char cerr[KNAMELEN]; Proto* p;}; struct Proto{ Lock l; int x; int stype; char name[KNAMELEN]; int nc; int maxconv; Conv** conv; Qid qid;}; static int np;static Proto proto[MAXPROTO]; static Conv* protoclone(Proto*, char*, int);static void setladdr(Conv*); static char network[] = "network"; static intip3gen(Chan *c, int i, Dir *dp){ Qid q; Conv *cv; char *p; cv = proto[PROTO(c->qid)].conv[CONV(c->qid)]; mkqid(&q, QID(PROTO(c->qid), CONV(c->qid), i), 0, QTFILE); switch(i) { default: return -1; case Qctl: devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp); return 1; case Qdata: devdir(c, q, "data", 0, cv->owner, cv->perm, dp); return 1; case Qlisten: devdir(c, q, "listen", 0, cv->owner, cv->perm, dp); return 1; case Qlocal: p = "local"; break; case Qremote: p = "remote"; break; case Qstatus: p = "status"; break; } devdir(c, q, p, 0, cv->owner, 0444, dp); return 1;} static intip2gen(Chan *c, int i, Dir *dp){ Qid q; switch(i) { case Qclone: mkqid(&q, QID(PROTO(c->qid), 0, Qclone), 0, QTFILE); devdir(c, q, "clone", 0, network, 0666, dp); return 1; } return -1;} static intip1gen(Chan *c, int i, Dir *dp){ Qid q; char *p; int prot; int len = 0; prot = 0666; mkqid(&q, QID(0, 0, i), 0, QTFILE); switch(i) { default: return -1; case Qcs: p = "cs"; prot = 0664; break; } devdir(c, q, p, len, network, prot, dp); return 1;} static intipgen(Chan *c, char *nname, Dirtab *d, int nd, int s, Dir *dp){ Qid q; Conv *cv; switch(TYPE(c->qid)) { case Qtopdir: if(s == DEVDOTDOT){ mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR); snprint(up->genbuf, sizeof up->genbuf, "#I%lud", c->dev); devdir(c, q, up->genbuf, 0, network, 0555, dp); return 1; } if(s < np) { mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR); devdir(c, q, proto[s].name, 0, network, 0555, dp); return 1; } s -= np; return ip1gen(c, s+Qtopbase, dp); case Qcs: return ip1gen(c, TYPE(c->qid), dp); case Qprotodir: if(s == DEVDOTDOT){ mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR); snprint(up->genbuf, sizeof up->genbuf, "#I%lud", c->dev); devdir(c, q, up->genbuf, 0, network, 0555, dp); return 1; } if(s < proto[PROTO(c->qid)].nc) { cv = proto[PROTO(c->qid)].conv[s]; snprint(up->genbuf, sizeof up->genbuf, "%d", s); mkqid(&q, QID(PROTO(c->qid), s, Qconvdir), 0, QTDIR); devdir(c, q, up->genbuf, 0, cv->owner, 0555, dp); return 1; } s -= proto[PROTO(c->qid)].nc; return ip2gen(c, s+Qprotobase, dp); case Qclone: return ip2gen(c, TYPE(c->qid), dp); case Qconvdir: if(s == DEVDOTDOT){ s = PROTO(c->qid); mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR); devdir(c, q, proto[s].name, 0, network, 0555, dp); return 1; } return ip3gen(c, s+Qconvbase, dp); case Qctl: case Qdata: case Qlisten: case Qlocal: case Qremote: case Qstatus: return ip3gen(c, TYPE(c->qid), dp); } return -1;} static voidnewproto(char *name, int type, int maxconv){ int l; Proto *p; if(np >= MAXPROTO) { print("no %s: increase MAXPROTO", name); return; } p = &proto[np]; strcpy(p->name, name); p->stype = type; p->qid.path = QID(np, 0, Qprotodir); p->qid.type = QTDIR; p->x = np++; p->maxconv = maxconv; l = sizeof(Conv*)*(p->maxconv+1); p->conv = mallocz(l, 1); if(p->conv == 0) panic("no memory");} voidipinit(void){ osipinit(); newproto("udp", S_UDP, 10); newproto("tcp", S_TCP, 30); fmtinstall('I', eipfmt); fmtinstall('E', eipfmt); } Chan *ipattach(char *spec){ Chan *c; c = devattach('I', spec); c->qid.path = QID(0, 0, Qtopdir); c->qid.type = QTDIR; c->qid.vers = 0; return c;} static Walkqid*ipwalk(Chan *c, Chan *nc, char **name, int nname){ return devwalk(c, nc, name, nname, 0, 0, ipgen);} intipstat(Chan *c, uchar *dp, int n){ return devstat(c, dp, n, 0, 0, ipgen);} Chan *ipopen(Chan *c, int omode){ Proto *p; uchar raddr[IPaddrlen]; ushort rport; int perm, sfd; Conv *cv, *lcv; omode &= 3; perm = 0; switch(omode) { case OREAD: perm = 4; break; case OWRITE: perm = 2; break; case ORDWR: perm = 6; break; } switch(TYPE(c->qid)) { default: break; case Qtopdir: case Qprotodir: case Qconvdir: case Qstatus: case Qremote: case Qlocal: if(omode != OREAD) error(Eperm); break; case Qclone: p = &proto[PROTO(c->qid)]; cv = protoclone(p, up->user, -1); if(cv == 0) error(Enodev); c->qid.path = QID(p->x, cv->x, Qctl); c->qid.vers = 0; break; case Qdata: case Qctl: p = &proto[PROTO(c->qid)]; lock(&p->l); cv = p->conv[CONV(c->qid)]; lock(&cv->r.lk); if((perm & (cv->perm>>6)) != perm) { if(strcmp(up->user, cv->owner) != 0 || (perm & cv->perm) != perm) { unlock(&cv->r.lk); unlock(&p->l); error(Eperm); } } cv->r.ref++; if(cv->r.ref == 1) { memmove(cv->owner, up->user, KNAMELEN); cv->perm = 0660; } unlock(&cv->r.lk); unlock(&p->l); break; case Qlisten: p = &proto[PROTO(c->qid)]; lcv = p->conv[CONV(c->qid)]; sfd = so_accept(lcv->sfd, raddr, &rport); cv = protoclone(p, up->user, sfd); if(cv == 0) { close(sfd); error(Enodev); } ipmove(cv->raddr, raddr); cv->rport = rport; setladdr(cv); cv->state = "Established"; c->qid.path = QID(p->x, cv->x, Qctl); break; } c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c;} voidipclose(Chan *c){ Conv *cc; switch(TYPE(c->qid)) { case Qcs: csclose(c); break; case Qdata: case Qctl: if((c->flag & COPEN) == 0) break; cc = proto[PROTO(c->qid)].conv[CONV(c->qid)]; if(decref(&cc->r) != 0) break; strcpy(cc->owner, network); cc->perm = 0666; cc->state = "Closed"; ipzero(cc->laddr); ipzero(cc->raddr); cc->lport = 0; cc->rport = 0; close(cc->sfd); break; }} longipread(Chan *ch, void *a, long n, vlong offset){ int r; Conv *c; Proto *x; uchar ip[IPaddrlen]; char buf[128], *p; /*print("ipread %s %lux\n", chanpath(ch), (long)ch->qid.path);*/ p = a; switch(TYPE(ch->qid)) { default: error(Eperm); case Qcs: return csread(ch, a, n, offset); case Qprotodir: case Qtopdir: case Qconvdir: return devdirread(ch, a, n, 0, 0, ipgen); case Qctl: sprint(buf, "%d", CONV(ch->qid)); return readstr(offset, p, n, buf); case Qremote: c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)]; ipmove(ip, c->raddr); sprint(buf, "%I!%d\n", ip, c->rport); return readstr(offset, p, n, buf); case Qlocal: c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)]; ipmove(ip, c->laddr); sprint(buf, "%I!%d\n", ip, c->lport); return readstr(offset, p, n, buf); case Qstatus: x = &proto[PROTO(ch->qid)]; c = x->conv[CONV(ch->qid)]; sprint(buf, "%s/%d %d %s \n", c->p->name, c->x, c->r.ref, c->state); return readstr(offset, p, n, buf); case Qdata: c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)]; r = so_recv(c->sfd, a, n, 0); if(r < 0){ oserrstr(); nexterror(); } return r; }} static voidsetladdr(Conv *c){ so_getsockname(c->sfd, c->laddr, &c->lport);} static voidsetlport(Conv *c){ if(c->restricted == 0 && c->lport == 0) return; if(c->sfd == -1) c->sfd = so_socket(c->p->stype, c->laddr); so_bind(c->sfd, c->restricted, c->lport, c->laddr);} static voidsetladdrport(Conv *c, char *str){ char *p; uchar addr[IPaddrlen]; p = strchr(str, '!'); if(p == 0) { p = str; ipzero(c->laddr); } else { *p++ = 0; parseip(addr, str); ipmove(c->laddr, addr); } if(*p == '*') c->lport = 0; else c->lport = atoi(p); setlport(c);} static char*setraddrport(Conv *c, char *str){ char *p; uchar addr[IPaddrlen]; p = strchr(str, '!'); if(p == 0) return "malformed address"; *p++ = 0; parseip(addr, str); ipmove(c->raddr, addr); c->rport = atoi(p); p = strchr(p, '!'); if(p) { if(strcmp(p, "!r") == 0) c->restricted = 1; } return 0;Lines 1–500 of 870. Load more
#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" #include "ip.h" #include "devip.h" void csclose(Chan*); long csread(Chan*, void*, long, vlong); long cswrite(Chan*, void*, long, vlong); void osipinit(void); enum { Qtopdir = 1, /* top level directory */ Qtopbase, Qcs = Qtopbase, Qprotodir, /* directory for a protocol */ Qprotobase, Qclone = Qprotobase, Qconvdir, /* directory for a conversation */ Qconvbase, Qctl = Qconvbase, Qdata, Qstatus, Qremote, Qlocal, Qlisten, MAXPROTO = 4 }; #define TYPE(x) ((int)((x).path & 0xf)) #define CONV(x) ((int)(((x).path >> 4)&0xfff)) #define PROTO(x) ((int)(((x).path >> 16)&0xff)) #define QID(p, c, y) (((p)<<16) | ((c)<<4) | (y)) #define ipzero(x) memset(x, 0, IPaddrlen) typedef struct Proto Proto; typedef struct Conv Conv; struct Conv { int x; Ref r; int sfd; int perm; char owner[KNAMELEN]; char* state; uchar laddr[IPaddrlen]; ushort lport; uchar raddr[IPaddrlen]; ushort rport; int restricted; char cerr[KNAMELEN]; Proto* p; }; struct Proto { Lock l; int x; int stype; char name[KNAMELEN]; int nc; int maxconv; Conv** conv; Qid qid; }; static int np; static Proto proto[MAXPROTO]; static Conv* protoclone(Proto*, char*, int); static void setladdr(Conv*); static char network[] = "network"; static int ip3gen(Chan *c, int i, Dir *dp) { Qid q; Conv *cv; char *p; cv = proto[PROTO(c->qid)].conv[CONV(c->qid)]; mkqid(&q, QID(PROTO(c->qid), CONV(c->qid), i), 0, QTFILE); switch(i) { default: return -1; case Qctl: devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp); return 1; case Qdata: devdir(c, q, "data", 0, cv->owner, cv->perm, dp); return 1; case Qlisten: devdir(c, q, "listen", 0, cv->owner, cv->perm, dp); return 1; case Qlocal: p = "local"; break; case Qremote: p = "remote"; break; case Qstatus: p = "status"; break; } devdir(c, q, p, 0, cv->owner, 0444, dp); return 1; } static int ip2gen(Chan *c, int i, Dir *dp) { Qid q; switch(i) { case Qclone: mkqid(&q, QID(PROTO(c->qid), 0, Qclone), 0, QTFILE); devdir(c, q, "clone", 0, network, 0666, dp); return 1; } return -1; } static int ip1gen(Chan *c, int i, Dir *dp) { Qid q; char *p; int prot; int len = 0; prot = 0666; mkqid(&q, QID(0, 0, i), 0, QTFILE); switch(i) { default: return -1; case Qcs: p = "cs"; prot = 0664; break; } devdir(c, q, p, len, network, prot, dp); return 1; } static int ipgen(Chan *c, char *nname, Dirtab *d, int nd, int s, Dir *dp) { Qid q; Conv *cv; switch(TYPE(c->qid)) { case Qtopdir: if(s == DEVDOTDOT){ mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR); snprint(up->genbuf, sizeof up->genbuf, "#I%lud", c->dev); devdir(c, q, up->genbuf, 0, network, 0555, dp); return 1; } if(s < np) { mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR); devdir(c, q, proto[s].name, 0, network, 0555, dp); return 1; } s -= np; return ip1gen(c, s+Qtopbase, dp); case Qcs: return ip1gen(c, TYPE(c->qid), dp); case Qprotodir: if(s == DEVDOTDOT){ mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR); snprint(up->genbuf, sizeof up->genbuf, "#I%lud", c->dev); devdir(c, q, up->genbuf, 0, network, 0555, dp); return 1; } if(s < proto[PROTO(c->qid)].nc) { cv = proto[PROTO(c->qid)].conv[s]; snprint(up->genbuf, sizeof up->genbuf, "%d", s); mkqid(&q, QID(PROTO(c->qid), s, Qconvdir), 0, QTDIR); devdir(c, q, up->genbuf, 0, cv->owner, 0555, dp); return 1; } s -= proto[PROTO(c->qid)].nc; return ip2gen(c, s+Qprotobase, dp); case Qclone: return ip2gen(c, TYPE(c->qid), dp); case Qconvdir: if(s == DEVDOTDOT){ s = PROTO(c->qid); mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR); devdir(c, q, proto[s].name, 0, network, 0555, dp); return 1; } return ip3gen(c, s+Qconvbase, dp); case Qctl: case Qdata: case Qlisten: case Qlocal: case Qremote: case Qstatus: return ip3gen(c, TYPE(c->qid), dp); } return -1; } static void newproto(char *name, int type, int maxconv) { int l; Proto *p; if(np >= MAXPROTO) { print("no %s: increase MAXPROTO", name); return; } p = &proto[np]; strcpy(p->name, name); p->stype = type; p->qid.path = QID(np, 0, Qprotodir); p->qid.type = QTDIR; p->x = np++; p->maxconv = maxconv; l = sizeof(Conv*)*(p->maxconv+1); p->conv = mallocz(l, 1); if(p->conv == 0) panic("no memory"); } void ipinit(void) { osipinit(); newproto("udp", S_UDP, 10); newproto("tcp", S_TCP, 30); fmtinstall('I', eipfmt); fmtinstall('E', eipfmt); } Chan * ipattach(char *spec) { Chan *c; c = devattach('I', spec); c->qid.path = QID(0, 0, Qtopdir); c->qid.type = QTDIR; c->qid.vers = 0; return c; } static Walkqid* ipwalk(Chan *c, Chan *nc, char **name, int nname) { return devwalk(c, nc, name, nname, 0, 0, ipgen); } int ipstat(Chan *c, uchar *dp, int n) { return devstat(c, dp, n, 0, 0, ipgen); } Chan * ipopen(Chan *c, int omode) { Proto *p; uchar raddr[IPaddrlen]; ushort rport; int perm, sfd; Conv *cv, *lcv; omode &= 3; perm = 0; switch(omode) { case OREAD: perm = 4; break; case OWRITE: perm = 2; break; case ORDWR: perm = 6; break; } switch(TYPE(c->qid)) { default: break; case Qtopdir: case Qprotodir: case Qconvdir: case Qstatus: case Qremote: case Qlocal: if(omode != OREAD) error(Eperm); break; case Qclone: p = &proto[PROTO(c->qid)]; cv = protoclone(p, up->user, -1); if(cv == 0) error(Enodev); c->qid.path = QID(p->x, cv->x, Qctl); c->qid.vers = 0; break; case Qdata: case Qctl: p = &proto[PROTO(c->qid)]; lock(&p->l); cv = p->conv[CONV(c->qid)]; lock(&cv->r.lk); if((perm & (cv->perm>>6)) != perm) { if(strcmp(up->user, cv->owner) != 0 || (perm & cv->perm) != perm) { unlock(&cv->r.lk); unlock(&p->l); error(Eperm); } } cv->r.ref++; if(cv->r.ref == 1) { memmove(cv->owner, up->user, KNAMELEN); cv->perm = 0660; } unlock(&cv->r.lk); unlock(&p->l); break; case Qlisten: p = &proto[PROTO(c->qid)]; lcv = p->conv[CONV(c->qid)]; sfd = so_accept(lcv->sfd, raddr, &rport); cv = protoclone(p, up->user, sfd); if(cv == 0) { close(sfd); error(Enodev); } ipmove(cv->raddr, raddr); cv->rport = rport; setladdr(cv); cv->state = "Established"; c->qid.path = QID(p->x, cv->x, Qctl); break; } c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c; } void ipclose(Chan *c) { Conv *cc; switch(TYPE(c->qid)) { case Qcs: csclose(c); break; case Qdata: case Qctl: if((c->flag & COPEN) == 0) break; cc = proto[PROTO(c->qid)].conv[CONV(c->qid)]; if(decref(&cc->r) != 0) break; strcpy(cc->owner, network); cc->perm = 0666; cc->state = "Closed"; ipzero(cc->laddr); ipzero(cc->raddr); cc->lport = 0; cc->rport = 0; close(cc->sfd); break; } } long ipread(Chan *ch, void *a, long n, vlong offset) { int r; Conv *c; Proto *x; uchar ip[IPaddrlen]; char buf[128], *p; /*print("ipread %s %lux\n", chanpath(ch), (long)ch->qid.path);*/ p = a; switch(TYPE(ch->qid)) { default: error(Eperm); case Qcs: return csread(ch, a, n, offset); case Qprotodir: case Qtopdir: case Qconvdir: return devdirread(ch, a, n, 0, 0, ipgen); case Qctl: sprint(buf, "%d", CONV(ch->qid)); return readstr(offset, p, n, buf); case Qremote: c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)]; ipmove(ip, c->raddr); sprint(buf, "%I!%d\n", ip, c->rport); return readstr(offset, p, n, buf); case Qlocal: c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)]; ipmove(ip, c->laddr); sprint(buf, "%I!%d\n", ip, c->lport); return readstr(offset, p, n, buf); case Qstatus: x = &proto[PROTO(ch->qid)]; c = x->conv[CONV(ch->qid)]; sprint(buf, "%s/%d %d %s \n", c->p->name, c->x, c->r.ref, c->state); return readstr(offset, p, n, buf); case Qdata: c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)]; r = so_recv(c->sfd, a, n, 0); if(r < 0){ oserrstr(); nexterror(); } return r; } } static void setladdr(Conv *c) { so_getsockname(c->sfd, c->laddr, &c->lport); } static void setlport(Conv *c) { if(c->restricted == 0 && c->lport == 0) return; if(c->sfd == -1) c->sfd = so_socket(c->p->stype, c->laddr); so_bind(c->sfd, c->restricted, c->lport, c->laddr); } static void setladdrport(Conv *c, char *str) { char *p; uchar addr[IPaddrlen]; p = strchr(str, '!'); if(p == 0) { p = str; ipzero(c->laddr); } else { *p++ = 0; parseip(addr, str); ipmove(c->laddr, addr); } if(*p == '*') c->lport = 0; else c->lport = atoi(p); setlport(c); } static char* setraddrport(Conv *c, char *str) { char *p; uchar addr[IPaddrlen]; p = strchr(str, '!'); if(p == 0) return "malformed address"; *p++ = 0; parseip(addr, str); ipmove(c->raddr, addr); c->rport = atoi(p); p = strchr(p, '!'); if(p) { if(strcmp(p, "!r") == 0) c->restricted = 1; } return 0;