📄 devsdp.c
字号:
#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 <libsec.h>#include "../port/thwack.h"/* * sdp - secure datagram protocol */typedef struct Sdp Sdp;typedef struct Conv Conv;typedef struct OneWay OneWay;typedef struct Stats Stats;typedef struct AckPkt AckPkt;typedef struct Algorithm Algorithm;typedef struct CipherRc4 CipherRc4;enum{ Qtopdir= 1, /* top level directory */ Qsdpdir, /* sdp directory */ Qclone, Qlog, Qconvdir, /* directory per conversation */ Qctl, Qdata, /* unreliable packet channel */ Qcontrol, /* reliable control channel */ Qstatus, Qstats, Qrstats, MaxQ, Maxconv= 256, // power of 2 Nfs= 4, // number of file systems MaxRetries= 12, KeepAlive = 120, // keep alive in seconds SecretLength= 32, // a secret per direction SeqMax = (1<<24), SeqWindow = 32, NCompStats = 8,};#define TYPE(x) ((x).path & 0xff)#define CONV(x) (((x).path >> 8)&(Maxconv-1))#define QID(x, y) (((x)<<8) | (y))struct Stats{ ulong outPackets; ulong outDataPackets; ulong outDataBytes; ulong outCompDataBytes; ulong outCompBytes; ulong outCompStats[NCompStats]; ulong inPackets; ulong inDataPackets; ulong inDataBytes; ulong inCompDataBytes; ulong inMissing; ulong inDup; ulong inReorder; ulong inBadComp; ulong inBadAuth; ulong inBadSeq; ulong inBadOther;};struct OneWay{ Rendez statsready; ulong seqwrap; // number of wraps of the sequence number ulong seq; ulong window; uchar secret[SecretLength]; QLock controllk; Rendez controlready; Block *controlpkt; // control channel ulong controlseq; void *cipherstate; // state cipher int cipherivlen; // initial vector length int cipherblklen; // block length int (*cipher)(OneWay*, uchar *buf, int len); void *authstate; // auth state int authlen; // auth data length in bytes int (*auth)(OneWay*, uchar *buf, int len); void *compstate; int (*comp)(Conv*, int subtype, ulong seq, Block **);};// conv statesenum { CFree, CInit, CDial, CAccept, COpen, CLocalClose, CRemoteClose, CClosed,};struct Conv { QLock; Sdp *sdp; int id; int ref; // holds conv up int state; int dataopen; // ref count of opens on Qdata int controlopen; // ref count of opens on Qcontrol int reader; // reader proc has been started Stats lstats; Stats rstats; ulong lastrecv; // time last packet was received ulong timeout; int retries; // the following pair uniquely define conversation on this port ulong dialid; ulong acceptid; QLock readlk; // protects readproc Proc *readproc; Chan *chan; // packet channel char *channame; char owner[NAMELEN]; /* protections */ int perm; Algorithm *auth; Algorithm *cipher; Algorithm *comp; int drop; OneWay in; OneWay out;};struct Sdp { QLock; Log; Rendez vous; /* used by sdpackproc */ int nconv; Conv *conv[Maxconv]; int ackproc;};enum { TConnect, TControl, TData, TCompData,};enum { ControlMesg, ControlAck,};enum { ThwackU, ThwackC,};enum { ConOpenRequest, ConOpenAck, ConOpenAckAck, ConClose, ConCloseAck, ConReset,};struct AckPkt{ uchar cseq[4]; uchar outPackets[4]; uchar outDataPackets[4]; uchar outDataBytes[4]; uchar outCompDataBytes[4]; uchar outCompStats[4*NCompStats]; uchar inPackets[4]; uchar inDataPackets[4]; uchar inDataBytes[4]; uchar inCompDataBytes[4]; uchar inMissing[4]; uchar inDup[4]; uchar inReorder[4]; uchar inBadComp[4]; uchar inBadAuth[4]; uchar inBadSeq[4]; uchar inBadOther[4];};struct Algorithm{ char *name; int keylen; // in bytes void (*init)(Conv*);};enum { RC4forward = 10*1024*1024, // maximum skip forward RC4back = 100*1024, // maximum look back};struct CipherRc4{ ulong cseq; // current byte sequence number RC4state current; int ovalid; // old is valid ulong lgseq; // last good sequence ulong oseq; // old byte sequence number RC4state old;};static Dirtab sdpdirtab[]={ "log", {Qlog}, 0, 0666, "clone", {Qclone}, 0, 0666,};static Dirtab convdirtab[]={ "ctl", {Qctl}, 0, 0666, "data", {Qdata}, 0, 0666, "control", {Qcontrol}, 0, 0666, "status", {Qstatus}, 0, 0444, "stats", {Qstats}, 0, 0444, "rstats", {Qrstats}, 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 char *convstatename[] = { [CFree] "Free", [CInit] "Init", [CDial] "Dial", [CAccept] "Accept", [COpen] "Open", [CLocalClose] "LocalClose", [CRemoteClose] "RemoteClose", [CClosed] "Closed",};static int sdpgen(Chan *c, Dirtab*, int, int s, Dir *dp);static Conv *sdpclone(Sdp *sdp);static void sdpackproc(void *a);static void onewaycleanup(OneWay *ow);static int readready(void *a);static int controlread();static void convsetstate(Conv *c, int state);static Block *readcontrol(Conv *c, int n);static void writecontrol(Conv *c, void *p, int n, int wait);static Block *readdata(Conv *c, int n);static long writedata(Conv *c, Block *b);static void convderef(Conv *c);static Block *conviput(Conv *c, Block *b, int control);static void conviconnect(Conv *c, int op, Block *b);static void convicontrol(Conv *c, int op, Block *b);static Block *convicomp(Conv *c, int op, ulong, Block *b);static void convoput(Conv *c, int type, int subtype, Block *b);static void convoconnect(Conv *c, int op, ulong dialid, ulong acceptid);static void convopenchan(Conv *c, char *path);static void convstats(Conv *c, int local, char *buf, int n);static void convreader(void *a);static void setalg(Conv *c, char *name, Algorithm *tab, Algorithm **);static void setsecret(OneWay *cc, char *secret);static void nullcipherinit(Conv*c);static void descipherinit(Conv*c);static void rc4cipherinit(Conv*c);static void nullauthinit(Conv*c);static void shaauthinit(Conv*c);static void md5authinit(Conv*c);static void nullcompinit(Conv*c);static void thwackcompinit(Conv*c);static Algorithm cipheralg[] ={ "null", 0, nullcipherinit, "des_56_cbc", 7, descipherinit, "rc4_128", 16, rc4cipherinit, "rc4_256", 32, rc4cipherinit, nil, 0, nil,};static Algorithm authalg[] ={ "null", 0, nullauthinit, "hmac_sha1_96", 16, shaauthinit, "hmac_md5_96", 16, md5authinit, nil, 0, nil,};static Algorithm compalg[] ={ "null", 0, nullcompinit, "thwack", 0, thwackcompinit, nil, 0, nil,};static voidsdpinit(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; } for(i=0; i<nelem(convdirtab); i++) { dt = convdirtab + i; dirtab[TYPE(dt->qid)] = dt; }}static Chan*sdpattach(char* spec){ Chan *c; int dev; char buf[100]; Sdp *sdp; int start; dev = atoi(spec); if(dev<0 || dev >= Nfs) error("bad specification"); c = devattach('E', spec); c->qid = (Qid){QID(0, Qtopdir)|CHDIR, 0}; c->dev = dev; 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); } return c;}static intsdpwalk(Chan *c, char *name){ return devwalk(c, name, 0, 0, sdpgen);}static voidsdpstat(Chan* c, char* db){ devstat(c, db, nil, 0, sdpgen);}static Chan*sdpopen(Chan* ch, int omode){ int perm; Sdp *sdp; Conv *c; omode &= 3; perm = m2p[omode]; USED(perm); sdp = sdptab + ch->dev; switch(TYPE(ch->qid)) { default: break; case Qtopdir: case Qsdpdir: case Qconvdir: if(omode != OREAD) error(Eperm); break; case Qlog: logopen(sdp); break; case Qclone: c = sdpclone(sdp); if(c == nil) error(Enodev); ch->qid.path = QID(c->id, Qctl); break; case Qdata: case Qctl: case Qstatus: case Qcontrol: case Qstats: case Qrstats: c = sdp->conv[CONV(ch->qid)]; qlock(c); if(waserror()) { qunlock(c); nexterror(); } if((perm & (c->perm>>6)) != perm) if(strcmp(up->user, c->owner) != 0 || (perm & c->perm) != perm) error(Eperm); c->ref++; if(TYPE(ch->qid) == Qdata) { c->dataopen++; // kill reader if Qdata is opened for the first time if(c->dataopen == 1) if(c->readproc != nil) postnote(c->readproc, 1, "interrupt", 0); } else if(TYPE(ch->qid) == Qcontrol) { c->controlopen++; } qunlock(c); poperror(); break; } ch->mode = openmode(omode); ch->flag |= COPEN; ch->offset = 0; return ch;}static voidsdpclose(Chan* ch){ Sdp *sdp = sdptab + ch->dev; Conv *c; if(!(ch->flag & COPEN)) return; switch(TYPE(ch->qid)) { case Qlog: logclose(sdp); break; case Qctl: case Qstatus: case Qstats: case Qrstats: c = sdp->conv[CONV(ch->qid)]; qlock(c); convderef(c); qunlock(c); break; case Qdata: c = sdp->conv[CONV(ch->qid)]; qlock(c); c->dataopen--; convderef(c); if(c->dataopen == 0) if(c->reader == 0) if(c->chan != nil) if(!waserror()) { kproc("convreader", convreader, c); c->reader = 1; c->ref++; poperror(); } qunlock(c); break; case Qcontrol: c = sdp->conv[CONV(ch->qid)]; qlock(c); c->controlopen--; convderef(c); if(c->controlopen == 0 && c->ref != 0) { switch(c->state) { default: convsetstate(c, CClosed); break; case CAccept: case COpen: convsetstate(c, CLocalClose); break; } } qunlock(c); poperror(); break; }}static longsdpread(Chan *ch, void *a, long n, vlong off){ char buf[256]; char *s; Sdp *sdp = sdptab + ch->dev; Conv *c; Block *b; int rv; USED(off); switch(TYPE(ch->qid)) { default: error(Eperm); case Qtopdir: case Qsdpdir: case Qconvdir: return devdirread(ch, a, n, 0, 0, sdpgen); case Qlog: return logread(sdp, a, off, n); case Qstatus: c = sdp->conv[CONV(ch->qid)]; qlock(c); n = readstr(off, a, n, convstatename[c->state]); qunlock(c); return n; case Qctl: sprint(buf, "%lud", CONV(ch->qid)); return readstr(off, a, n, buf); 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; case Qstats: case Qrstats: c = sdp->conv[CONV(ch->qid)]; s = smalloc(1000); convstats(c, TYPE(ch->qid) == Qstats, s, 1000); rv = readstr(off, a, n, s); free(s); return rv; }}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);}static longsdpwrite(Chan *ch, void *a, long n, vlong off){ Sdp *sdp = sdptab + ch->dev; Cmdbuf *cb; char *arg0; char *p; Conv *c; Block *b; USED(off); switch(TYPE(ch->qid)) { default: error(Eperm); case Qctl: c = sdp->conv[CONV(ch->qid)]; cb = parsecmd(a, n); qlock(c); if(waserror()) { qunlock(c); free(cb); nexterror(); } if(cb->nf == 0) error("short write"); arg0 = cb->f[0]; if(strcmp(arg0, "accept") == 0) { if(cb->nf != 2) error("usage: accect file"); convopenchan(c, cb->f[1]); } else if(strcmp(arg0, "dial") == 0) { if(cb->nf != 2) error("usage: accect file"); convopenchan(c, cb->f[1]); convsetstate(c, CDial); } else if(strcmp(arg0, "drop") == 0) { if(cb->nf != 2) error("usage: drop permil"); c->drop = atoi(cb->f[1]); } else if(strcmp(arg0, "cipher") == 0) { if(cb->nf != 2) error("usage: cipher alg"); setalg(c, cb->f[1], cipheralg, &c->cipher); } else if(strcmp(arg0, "auth") == 0) { if(cb->nf != 2) error("usage: auth alg"); setalg(c, cb->f[1], authalg, &c->auth); } else if(strcmp(arg0, "comp") == 0) { if(cb->nf != 2) error("usage: comp alg"); setalg(c, cb->f[1], compalg, &c->comp); } else if(strcmp(arg0, "insecret") == 0) { if(cb->nf != 2) error("usage: insecret secret"); setsecret(&c->in, cb->f[1]); if(c->cipher) c->cipher->init(c); if(c->auth) c->auth->init(c); } else if(strcmp(arg0, "outsecret") == 0) { if(cb->nf != 2) error("usage: outsecret secret"); setsecret(&c->out, cb->f[1]); if(c->cipher) c->cipher->init(c); if(c->auth) c->auth->init(c); } else error("unknown control request"); poperror(); qunlock(c); 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; case Qcontrol: writecontrol(sdp->conv[CONV(ch->qid)], a, n, 0); return n; case Qdata: b = allocb(n); memmove(b->wp, a, n); b->wp += n; return writedata(sdp->conv[CONV(ch->qid)], b); }}longsdpbwrite(Chan *ch, Block *bp, ulong offset){ Sdp *sdp = sdptab + ch->dev; if(TYPE(ch->qid) != Qdata) return devbwrite(ch, bp, offset); return writedata(sdp->conv[CONV(ch->qid)], bp);}static intsdpgen(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; if(s == DEVDOTDOT){ switch(TYPE(c->qid)){ case Qtopdir: case Qsdpdir: snprint(buf, sizeof(buf), "#E%ld", c->dev); devdir(c, (Qid){CHDIR|Qtopdir, 0}, buf, 0, eve, 0555, dp); break; case Qconvdir: snprint(buf, sizeof(buf), "%d", s); devdir(c, (Qid){CHDIR|Qsdpdir, 0}, buf, 0, eve, 0555, dp); break; default: panic("sdpwalk %lux", c->qid.path); } return 1; } 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); if(s >= sdp->nconv) return -1; qid = (Qid){QID(s,Qconvdir)|CHDIR, 0}; snprint(buf, sizeof(buf), "%d", s); devdir(c, qid, buf, 0, eve, 0555, dp); return 1; case Qconvdir: if(s>=nelem(convdirtab)) return -1; dt = convdirtab+s; qid = (Qid){QID(CONV(c->qid),TYPE(dt->qid)),0}; devdir(c, qid, dt->name, dt->length, eve, dt->perm, dp); return 1; }}static Conv*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -