| plan 9 kernel history: overview | file list | diff list |
1999/0907/port/devsdp.c (diff list | history)
| port/devsdp.c on 1999/0824 | ||
| 1999/0824 | #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/netif.h" #include "../port/error.h" #include <libcrypt.h> | |
| 1999/0907 | /* * sdp - secure datagram protocol */ | |
| 1999/0902 | typedef struct Sdp Sdp; typedef struct Conv Conv; | |
| 1999/0907 | typedef struct OneWay OneWay; typedef struct ConnectPkt ConnectPkt; | |
| 1999/0824 | enum { Qtopdir= 1, /* top level directory */ Qsdpdir, /* sdp directory */ Qclone, Qstats, Qlog, | |
| 1999/0901 | Qconvdir, /* directory per conversation */ | |
| 1999/0824 | Qctl, | |
| 1999/0902 | Qdata, /* unreliable packet channel */ Qcontrol, /* reliable control channel */ | |
| 1999/0824 | Qstatus, MaxQ, | |
| 1999/0907 | Maxconv= 256, // power of 2 Nfs= 4, // number of file systems | |
| 1999/0906 | Maxretries= 4, | |
| 1999/0907 | KeyLength= 32, | |
| 1999/0824 | }; #define TYPE(x) ((x).path & 0xff) | |
| 1999/0901 | #define CONV(x) (((x).path >> 8)&(Maxconv-1)) | |
| 1999/0824 | #define QID(x, y) (((x)<<8) | (y)) | |
| 1999/0907 | struct OneWay | |
| 1999/0901 | { ulong seqwrap; // number of wraps of the sequence number ulong seq; | |
| 1999/0907 | ulong window; | |
| 1999/0901 | ||
| 1999/0907 | Rendez controlready; | |
| 1999/0902 | Block *controlpkt; // control channel | |
| 1999/0907 | ulong controlseq; | |
| 1999/0901 | ||
| 1999/0902 | void *cipherstate; // state cipher | |
| 1999/0907 | int cipherivlen; // initial vector length int cipherblklen; // block length int (*cipher)(OneWay*, uchar *buf, int len); | |
| 1999/0902 | void *authstate; // auth state int authlen; // auth data length in bytes | |
| 1999/0907 | int (*auth)(OneWay*, uchar *buf, int len); | |
| 1999/0902 | void *compstate; | |
| 1999/0907 | int (*comp)(OneWay*, uchar *dst, uchar *src, int n); | |
| 1999/0901 | }; | |
| 1999/0907 | // conv states | |
| 1999/0902 | enum { | |
| 1999/0906 | CInit, | |
| 1999/0902 | COpening, COpen, CClosing, | |
| 1999/0906 | CClosed, | |
| 1999/0902 | }; | |
| 1999/0901 | struct Conv { QLock; | |
| 1999/0824 | int id; | |
| 1999/0906 | int ref; // number of times the conv is opened | |
| 1999/0824 | Sdp *sdp; | |
| 1999/0901 | ||
| 1999/0902 | int state; | |
| 1999/0906 | int dataopen; | |
| 1999/0901 | ||
| 1999/0906 | ulong timeout; int retries; // the following pair uniquely define conversation on this port ulong dialid; ulong acceptid; | |
| 1999/0907 | Proc *readproc; QLock readlk; | |
| 1999/0902 | Chan *chan; // packet channel | |
| 1999/0907 | char owner[NAMELEN]; /* protections */ | |
| 1999/0901 | int perm; | |
| 1999/0907 | uchar masterkey[KeyLength]; | |
| 1999/0906 | int drop; | |
| 1999/0907 | OneWay in; OneWay out; | |
| 1999/0824 | }; struct Sdp { QLock; Log; | |
| 1999/0906 | Rendez vous; /* used by sdpackproc */ | |
| 1999/0901 | int nconv; | |
| 1999/0902 | Conv *conv[Maxconv]; | |
| 1999/0906 | int ackproc; | |
| 1999/0824 | }; | |
| 1999/0906 | enum { TConnect, TControl, TControlAck, TData, TThwackC, TThwackU, }; enum { ConOpen, ConOpenAck, ConOpenNack, ConClose, ConCloseAck, }; | |
| 1999/0907 | struct ConnectPkt | |
| 1999/0906 | { uchar type; // always zero = connection packet uchar op; uchar pad[2]; uchar dialid[4]; uchar acceptid[4]; }; | |
| 1999/0907 | ||
| 1999/0824 | static Dirtab sdpdirtab[]={ "stats", {Qstats}, 0, 0444, "log", {Qlog}, 0, 0666, | |
| 1999/0901 | "clone", {Qclone}, 0, 0666, | |
| 1999/0824 | }; | |
| 1999/0901 | static Dirtab convdirtab[]={ | |
| 1999/0824 | "ctl", {Qctl}, 0, 0666, "data", {Qdata}, 0, 0666, | |
| 1999/0902 | "control", {Qcontrol}, 0, 0666, | |
| 1999/0824 | "status", {Qstatus}, 0, 0444, }; static int m2p[] = { [OREAD] 4, [OWRITE] 2, [ORDWR] 6 }; enum { Logcompress= (1<<0), Logauth= (1<<1), Loghmac= (1<<2), }; static Logflag logflags[] = { { "compress", Logcompress, }, { "auth", Logauth, }, { "hmac", Loghmac, }, { nil, 0, }, }; static Dirtab *dirtab[MaxQ]; static Sdp sdptab[Nfs]; static int sdpgen(Chan *c, Dirtab*, int, int s, Dir *dp); | |
| 1999/0901 | static Conv *sdpclone(Sdp *sdp); | |
| 1999/0906 | static void convsetstate(Conv *c, int state); static void sdpackproc(void *a); | |
| 1999/0907 | static void onewaycleanup(OneWay *ow); static int readready(void *a); static int controlread(); static Block *conviput(Conv *c, Block *b, int control); static void conviput2(Conv *c, Block *b); static Block *readcontrol(Conv *c, int n); static Block *readdata(Conv *c, int n); static void convoput(Conv *c, int type, Block *b); static void convoput2(Conv *c, int op, ulong dialid, ulong acceptid); | |
| 1999/0824 | ||
| 1999/0907 | ||
| 1999/0824 | static void sdpinit(void) { int i; Dirtab *dt; // setup dirtab with non directory entries for(i=0; i<nelem(sdpdirtab); i++) { dt = sdpdirtab + i; dirtab[TYPE(dt->qid)] = dt; } | |
| 1999/0901 | for(i=0; i<nelem(convdirtab); i++) { dt = convdirtab + i; | |
| 1999/0824 | dirtab[TYPE(dt->qid)] = dt; } | |
| 1999/0906 | ||
| 1999/0824 | } static Chan* sdpattach(char* spec) { Chan *c; int dev; | |
| 1999/0906 | char buf[100]; Sdp *sdp; int start; | |
| 1999/0824 | dev = atoi(spec); if(dev<0 || dev >= Nfs) error("bad specification"); | |
| 1999/0901 | c = devattach('T', spec); | |
| 1999/0824 | c->qid = (Qid){QID(0, Qtopdir)|CHDIR, 0}; c->dev = dev; | |
| 1999/0906 | sdp = sdptab + dev; qlock(sdp); start = sdp->ackproc == 0; sdp->ackproc = 1; qunlock(sdp); if(start) { snprint(buf, sizeof(buf), "sdpackproc%d", dev); kproc(buf, sdpackproc, sdp); } | |
| 1999/0824 | return c; } static int sdpwalk(Chan *c, char *name) { if(strcmp(name, "..") == 0){ switch(TYPE(c->qid)){ case Qtopdir: case Qsdpdir: c->qid = (Qid){CHDIR|Qtopdir, 0}; break; | |
| 1999/0901 | case Qconvdir: | |
| 1999/0824 | c->qid = (Qid){CHDIR|Qsdpdir, 0}; break; default: panic("sdpwalk %lux", c->qid.path); } return 1; } return devwalk(c, name, 0, 0, sdpgen); } static void sdpstat(Chan* c, char* db) { devstat(c, db, nil, 0, sdpgen); } static Chan* | |
| 1999/0901 | sdpopen(Chan* ch, int omode) | |
| 1999/0824 | { int perm; Sdp *sdp; | |
| 1999/0901 | Conv *c; | |
| 1999/0824 | omode &= 3; perm = m2p[omode]; USED(perm); | |
| 1999/0901 | sdp = sdptab + ch->dev; | |
| 1999/0824 | ||
| 1999/0901 | switch(TYPE(ch->qid)) { | |
| 1999/0824 | default: break; case Qtopdir: case Qsdpdir: | |
| 1999/0901 | case Qconvdir: | |
| 1999/0824 | case Qstats: if(omode != OREAD) error(Eperm); break; case Qlog: logopen(sdp); break; | |
| 1999/0901 | case Qclone: c = sdpclone(sdp); if(c == nil) error(Enodev); ch->qid.path = QID(c->id, Qctl); break; | |
| 1999/0902 | case Qdata: case Qctl: case Qstatus: case Qcontrol: c = sdp->conv[CONV(ch->qid)]; qlock(c); if(waserror()) { qunlock(c); nexterror(); } if((perm & (c->perm>>6)) != perm) | |
| 1999/0907 | if(strcmp(up->user, c->owner) != 0 || (perm & c->perm) != perm) | |
| 1999/0902 | error(Eperm); c->ref++; | |
| 1999/0907 | if(TYPE(ch->qid) == Qdata) c->dataopen++; | |
| 1999/0902 | qunlock(c); poperror(); break; | |
| 1999/0824 | } | |
| 1999/0901 | ch->mode = openmode(omode); ch->flag |= COPEN; ch->offset = 0; return ch; | |
| 1999/0824 | } static void | |
| 1999/0902 | sdpclose(Chan* ch) | |
| 1999/0824 | { | |
| 1999/0902 | Sdp *sdp = sdptab + ch->dev; | |
| 1999/0907 | Conv *c; | |
| 1999/0824 | ||
| 1999/0902 | switch(TYPE(ch->qid)) { | |
| 1999/0824 | case Qlog: | |
| 1999/0902 | if(ch->flag & COPEN) | |
| 1999/0824 | logclose(sdp); break; | |
| 1999/0907 | case Qdata: case Qctl: case Qstatus: case Qcontrol: if(!(ch->flag & COPEN)) break; c = sdp->conv[CONV(ch->qid)]; qlock(c); if(waserror()) { qunlock(c); nexterror(); } c->ref--; if(TYPE(ch->qid) == Qdata) { c->dataopen--; if(c->dataopen == 0) wakeup(&c->in.controlready); } if(c->ref == 0) { switch(c->state) { default: convsetstate(c, CClosed); break; case COpen: convsetstate(c, CClosing); break; case CClosing: break; } } qunlock(c); poperror(); break; | |
| 1999/0824 | } } static long | |
| 1999/0901 | sdpread(Chan *ch, void *a, long n, vlong off) | |
| 1999/0824 | { char buf[256]; | |
| 1999/0901 | Sdp *sdp = sdptab + ch->dev; | |
| 1999/0902 | char *s; | |
| 1999/0901 | Conv *c; | |
| 1999/0907 | Block *b; | |
| 1999/0824 | USED(off); | |
| 1999/0901 | switch(TYPE(ch->qid)) { | |
| 1999/0824 | default: error(Eperm); case Qtopdir: case Qsdpdir: | |
| 1999/0901 | case Qconvdir: return devdirread(ch, a, n, 0, 0, sdpgen); | |
| 1999/0824 | case Qlog: return logread(sdp, a, off, n); case Qstatus: | |
| 1999/0901 | c = sdp->conv[CONV(ch->qid)]; | |
| 1999/0902 | qlock(c); switch(c->state) { default: panic("unknown state"); case CClosed: s = "closed"; break; case COpening: s = "opening"; break; case COpen: s = "open"; break; case CClosing: s = "closing"; break; | |
| 1999/0824 | } | |
| 1999/0902 | n = readstr(off, a, n, s); qunlock(c); | |
| 1999/0824 | return n; | |
| 1999/0901 | case Qctl: sprint(buf, "%lud", CONV(ch->qid)); return readstr(off, a, n, buf); | |
| 1999/0907 | case Qcontrol: b = readcontrol(sdp->conv[CONV(ch->qid)], n); if(b == nil) return 0; if(BLEN(b) < n) n = BLEN(b); memmove(a, b->rp, n); freeb(b); return n; case Qdata: b = readdata(sdp->conv[CONV(ch->qid)], n); if(b == nil) return 0; if(BLEN(b) < n) n = BLEN(b); memmove(a, b->rp, n); freeb(b); return n; | |
| 1999/0824 | } } | |
| 1999/0907 | static Block* sdpbread(Chan* ch, long n, ulong offset) { Sdp *sdp = sdptab + ch->dev; if(TYPE(ch->qid) != Qdata) return devbread(ch, n, offset); return readdata(sdp->conv[CONV(ch->qid)], n); } | |
| 1999/0824 | static long | |
| 1999/0901 | sdpwrite(Chan *ch, void *a, long n, vlong off) | |
| 1999/0824 | { | |
| 1999/0901 | Sdp *sdp = sdptab + ch->dev; | |
| 1999/0824 | Cmdbuf *cb; char *arg0; char *p; | |
| 1999/0906 | Conv *c; | |
| 1999/0824 | USED(off); | |
| 1999/0901 | switch(TYPE(ch->qid)) { | |
| 1999/0824 | default: error(Eperm); case Qctl: | |
| 1999/0906 | c = sdp->conv[CONV(ch->qid)]; print("Qctl write : conv->id = %d\n", c->id); | |
| 1999/0824 | cb = parsecmd(a, n); | |
| 1999/0906 | qlock(c); | |
| 1999/0824 | if(waserror()) { | |
| 1999/0906 | qunlock(c); | |
| 1999/0824 | free(cb); nexterror(); } if(cb->nf == 0) error("short write"); arg0 = cb->f[0]; | |
| 1999/0901 | print("cmd = %s\n", arg0); | |
| 1999/0906 | if(strcmp(arg0, "chan") == 0) { if(cb->nf != 2) error("usage: chan file"); if(c->chan != nil) error("chan already set"); c->chan = namec(cb->f[1], Aopen, ORDWR, 0); } else if(strcmp(arg0, "accept") == 0) { if(cb->nf != 2) error("usage: accect id"); c->dialid = atoi(cb->f[1]); convsetstate(c, COpen); } else if(strcmp(arg0, "dial") == 0) { if(cb->nf != 1) error("usage: dial"); convsetstate(c, COpening); } else if(strcmp(arg0, "drop") == 0) { if(cb->nf != 2) error("usage: drop permil"); c->drop = atoi(cb->f[1]); | |
| 1999/0824 | } else error("unknown control request"); poperror(); | |
| 1999/0906 | qunlock(c); | |
| 1999/0824 | free(cb); return n; case Qlog: cb = parsecmd(a, n); p = logctl(sdp, cb->nf, cb->f, logflags); free(cb); if(p != nil) error(p); return n; } } static int sdpgen(Chan *c, Dirtab*, int, int s, Dir *dp) { Sdp *sdp = sdptab + c->dev; int type = TYPE(c->qid); char buf[32]; Dirtab *dt; Qid qid; switch(type) { default: // non directory entries end up here if(c->qid.path & CHDIR) panic("sdpgen: unexpected directory"); if(s != 0) return -1; dt = dirtab[TYPE(c->qid)]; if(dt == nil) panic("sdpgen: unknown type: %d", TYPE(c->qid)); devdir(c, c->qid, dt->name, dt->length, eve, dt->perm, dp); return 1; case Qtopdir: if(s != 0) return -1; devdir(c, (Qid){QID(0,Qsdpdir)|CHDIR,0}, "sdp", 0, eve, 0555, dp); return 1; case Qsdpdir: if(s<nelem(sdpdirtab)) { dt = sdpdirtab+s; devdir(c, dt->qid, dt->name, dt->length, eve, dt->perm, dp); return 1; } s -= nelem(sdpdirtab); | |
| 1999/0901 | if(s >= sdp->nconv) | |
| 1999/0824 | return -1; | |
| 1999/0901 | qid = (Qid){QID(s,Qconvdir)|CHDIR, 0}; | |
| 1999/0824 | snprint(buf, sizeof(buf), "%d", s); devdir(c, qid, buf, 0, eve, 0555, dp); return 1; | |
| 1999/0901 | case Qconvdir: if(s>=nelem(convdirtab)) | |
| 1999/0824 | return -1; | |
| 1999/0901 | dt = convdirtab+s; qid = (Qid){QID(CONV(c->qid),TYPE(dt->qid)),0}; | |
| 1999/0824 | devdir(c, qid, dt->name, dt->length, eve, dt->perm, dp); return 1; } | |
| 1999/0901 | } static Conv* sdpclone(Sdp *sdp) { Conv *c, **pp, **ep; c = nil; ep = sdp->conv + nelem(sdp->conv); | |
| 1999/0902 | qlock(sdp); if(waserror()) { qunlock(sdp); nexterror(); } | |
| 1999/0901 | for(pp = sdp->conv; pp < ep; pp++) { c = *pp; if(c == nil){ c = malloc(sizeof(Conv)); if(c == nil) error(Enomem); qlock(c); c->sdp = sdp; c->id = pp - sdp->conv; *pp = c; sdp->nconv++; break; } if(canqlock(c)){ | |
| 1999/0902 | if(c->state == CClosed) | |
| 1999/0901 | break; qunlock(c); } } | |
| 1999/0902 | poperror(); qunlock(sdp); | |
| 1999/0901 | ||
| 1999/0902 | if(pp >= ep) | |
| 1999/0901 | return nil; | |
| 1999/0902 | c->ref++; | |
| 1999/0906 | c->state = CInit; | |
| 1999/0902 | ||
| 1999/0907 | strncpy(c->owner, up->user, sizeof(c->owner)); | |
| 1999/0901 | c->perm = 0660; qunlock(c); | |
| 1999/0902 | ||
| 1999/0901 | return c; | |
| 1999/0824 | } | |
| 1999/0906 | // assume c is locked static int convretry(Conv *c) { c->retries++; if(c->retries > Maxretries) { print("convretry: giving up\n"); convsetstate(c, CClosed); return 0; } c->timeout = TK2SEC(m->ticks) + (1<<c->retries); return 1; } | |
| 1999/0902 | static void | |
| 1999/0906 | convtimer(Conv *c, ulong sec) | |
| 1999/0902 | { | |
| 1999/0906 | if(c->timeout == 0 || c->timeout > sec) return; | |
| 1999/0902 | qlock(c); | |
| 1999/0906 | if(waserror()) { | |
| 1999/0902 | qunlock(c); | |
| 1999/0906 | nexterror(); | |
| 1999/0902 | } | |
| 1999/0906 | switch(c->state) { case COpening: print("COpening timeout\n"); if(convretry(c)) | |
| 1999/0907 | convoput2(c, ConOpen, c->dialid, 0); | |
| 1999/0906 | break; case COpen: // check for control packet break; case CClosing: print("CClosing timeout\n"); if(convretry(c)) | |
| 1999/0907 | convoput2(c, ConClose, c->dialid, c->acceptid); | |
| 1999/0906 | break; } qunlock(c); } | |
| 1999/0902 | ||
| 1999/0906 | static void sdpackproc(void *a) { Sdp *sdp = a; ulong sec; int i; Conv *c; for(;;) { tsleep(&sdp->vous, return0, 0, 1000); sec = TK2SEC(m->ticks); qlock(sdp); for(i=0; i<sdp->nconv; i++) { c = sdp->conv[i]; if(!waserror()) { convtimer(c, sec); poperror(); } } qunlock(sdp); | |
| 1999/0902 | } } | |
| 1999/0824 | Dev sdpdevtab = { 'T', "sdp", devreset, sdpinit, sdpattach, devclone, sdpwalk, sdpstat, sdpopen, devcreate, sdpclose, sdpread, devbread, sdpwrite, devbwrite, devremove, devwstat, }; | |
| 1999/0906 | // assume hold lock on c static void convsetstate(Conv *c, int state) { | |
| 1999/0907 | print("convsetstate %d -> %d\n", c->state, state); | |
| 1999/0906 | switch(state) { default: panic("setstate: bad state: %d", state); case COpening: if(c->state != CInit) error("convsetstate: illegal transition"); c->dialid = (rand()<<16) + rand(); c->timeout = TK2SEC(m->ticks) + 2; c->retries = 0; | |
| 1999/0907 | convoput2(c, ConOpen, c->dialid, 0); | |
| 1999/0906 | break; case COpen: switch(c->state) { default: error("convsetstate: illegal transition"); case CInit: c->acceptid = (rand()<<16) + rand(); | |
| 1999/0907 | convoput2(c, ConOpenAck, c->dialid, c->acceptid); | |
| 1999/0906 | break; case COpening: break; } // setup initial key and auth method break; case CClosing: | |
| 1999/0907 | convoput2(c, ConClose, c->dialid, c->acceptid); | |
| 1999/0906 | c->timeout = TK2SEC(m->ticks) + 2; c->retries = 0; break; case CClosed: | |
| 1999/0907 | if(c->readproc) postnote(c->readproc, 1, "interrupt", 0); if(c->ref) break; if(c->chan) { cclose(c->chan); c->chan = nil; } strcpy(c->owner, "network"); c->perm = 0660; c->dialid = 0; c->acceptid = 0; c->timeout = 0; c->retries = 0; c->drop = 0; memset(c->masterkey, 0, sizeof(c->masterkey)); onewaycleanup(&c->in); onewaycleanup(&c->out); | |
| 1999/0906 | break; } c->state = state; } static void | |
| 1999/0907 | onewaycleanup(OneWay *ow) | |
| 1999/0906 | { | |
| 1999/0907 | if(ow->controlpkt) freeb(ow->controlpkt); if(ow->authstate) free(ow->authstate); if(ow->cipherstate) free(ow->cipherstate); if(ow->compstate) free(ow->compstate); memset(ow, 0, sizeof(OneWay)); } | |
| 1999/0906 | ||
| 1999/0907 | static Block * convreadblock(Conv *c, int n) { Block *b; qlock(&c->readlk); if(waserror()) { c->readproc = nil; qunlock(&c->readlk); nexterror(); } qlock(c); if(c->state == CClosed) { qunlock(c); poperror(); qunlock(&c->readlk); return 0; } c->readproc = up; qunlock(c); b = devtab[c->chan->type]->bread(c->chan, n, 0); c->readproc = nil; poperror(); qunlock(&c->readlk); return b; } // assume we hold lock for c static Block * conviput(Conv *c, Block *b, int control) { int type; ulong seq, cseq; if(BLEN(b) < 4) { freeb(b); return nil; } type = b->rp[0]; if(type == TConnect) { conviput2(c, b); return nil; } seq = (b->rp[1]<<16) + (b->rp[2]<<8) + b->rp[3]; b->rp += 4; USED(seq); // auth // decrypt // ok the packet is good switch(type) { case TControl: if(BLEN(b) <= 4) break; cseq = nhgetl(b->rp); if(cseq == c->in.controlseq) { // duplicate control packet // send ack b->wp = b->rp + 4; convoput(c, TControlAck, b); return nil; } if(cseq != c->in.controlseq+1) break; c->in.controlseq = cseq; b->rp += 4; if(control) return b; c->in.controlpkt = b; wakeup(&c->in.controlready); return nil; case TControlAck: if(BLEN(b) != 4) break; cseq = nhgetl(b->rp); if(cseq != c->out.controlseq) break; freeb(b); freeb(c->out.controlpkt); c->out.controlpkt = 0; wakeup(&c->out.controlready); return nil; case TData: if(control) break; return b; } print("droping packet %d n=%ld\n", type, BLEN(b)); freeb(b); return nil; } // assume hold conv lock static void conviput2(Conv *c, Block *b) { ConnectPkt *con; ulong dialid; ulong acceptid; if(BLEN(b) != sizeof(ConnectPkt)) { freeb(b); return; } con = (ConnectPkt*)b->rp; dialid = nhgetl(con->dialid); acceptid = nhgetl(con->acceptid); print("conviput2: %d %uld %uld\n", con->op, dialid, acceptid); switch(con->op) { case ConOpen: if(c->state != COpen || dialid != c->dialid || acceptid != c->acceptid) convoput2(c, ConOpenNack, dialid, acceptid); else convoput2(c, ConOpenAck, dialid, acceptid); break; case ConOpenAck: if(c->state != COpening || dialid != c->dialid) break; c->acceptid = acceptid; convsetstate(c, COpen); break; case ConOpenNack: if(c->state != COpening || dialid != c->dialid) break; convsetstate(c, CClosed); break; case ConClose: if(dialid != c->dialid || acceptid != c->acceptid) break; convsetstate(c, CClosed); break; case ConCloseAck: if(c->state != CClosing || dialid != c->dialid || acceptid != c->acceptid) break; convsetstate(c, CClosed); break; } } // assume hold conv lock static void convoput(Conv *c, int type, Block *b) { // try and compress /* Make space to fit sdp header */ b = padblock(b, 4 + c->out.cipherivlen); b->rp[0] = type; c->out.seq++; if(c->out.seq == (1<<24)) { c->out.seq = 0; c->out.seqwrap++; } b->rp[1] = c->out.seq>>16; b->rp[2] = c->out.seq>>8; b->rp[3] = c->out.seq; // encrypt // auth // simulated errors if(c->drop && c->drop > nrand(c->drop)) return; devtab[c->chan->type]->bwrite(c->chan, b, 0); } // assume hold conv lock static void convoput2(Conv *c, int op, ulong dialid, ulong acceptid) { ConnectPkt con; | |
| 1999/0906 | if(c->chan == nil) { print("chan = nil\n"); error("no channel attached"); } memset(&con, 0, sizeof(con)); con.type = TConnect; con.op = op; hnputl(con.dialid, dialid); hnputl(con.acceptid, acceptid); // simulated errors if(c->drop && c->drop > nrand(c->drop)) return; devtab[c->chan->type]->write(c->chan, &con, sizeof(con), 0); | |
| 1999/0907 | } static int readready(void *a) { Conv *c = a; return (c->state == CClosed) || c->in.controlpkt != nil || c->dataopen == 0; } static Block * readcontrol(Conv *c, int n) { Block *b; for(;;) { qlock(c); if(c->state == CClosed || c->state == CInit) { qunlock(c); return nil; } if(c->in.controlpkt != nil) { b = c->in.controlpkt; c->in.controlpkt = nil; qunlock(c); return b; } qunlock(c); // hack - this is to avoid gating onto the // read which will in general result in excessive // context switches. // The assumed behavior is that the client will read // from the control channel until the session is authenticated // at which point it will open the data channel and // start reading on that. After the data channel is opened, // read on the channel are required for packets to // be delivered to the control channel if(c->dataopen) { sleep(&c->in.controlready, readready, c); } else { b = convreadblock(c, n); if(b == nil) return nil; qlock(c); if(waserror()) { qunlock(c); return nil; } b = conviput(c, b, 1); poperror(); qunlock(c); if(b != nil) return b; } } } static Block * readdata(Conv *c, int n) { Block *b; for(;;) { b = convreadblock(c, n); if(b == nil) return nil; qlock(c); if(waserror()) { qunlock(c); return nil; } b = conviput(c, b, 0); poperror(); qunlock(c); if(b != nil) return b; } | |
| 1999/0906 | } | |