📄 devsdp.c
字号:
sdpclone(Sdp *sdp){ Conv *c, **pp, **ep; c = nil; ep = sdp->conv + nelem(sdp->conv); qlock(sdp); if(waserror()) { qunlock(sdp); nexterror(); } for(pp = sdp->conv; pp < ep; pp++) { c = *pp; if(c == nil){ c = malloc(sizeof(Conv)); if(c == nil) error(Enomem); memset(c, 0, sizeof(Conv)); qlock(c); c->sdp = sdp; c->id = pp - sdp->conv; *pp = c; sdp->nconv++; break; } if(c->ref == 0 && canqlock(c)){ if(c->ref == 0) break; qunlock(c); } } poperror(); qunlock(sdp); if(pp >= ep) return nil; assert(c->state == CFree); // set ref to 2 - 1 ref for open - 1 ref for channel state c->ref = 2; c->state = CInit; c->in.window = ~0; strncpy(c->owner, up->user, sizeof(c->owner)); c->perm = 0660; qunlock(c); return c;}// assume c is lockedstatic voidconvretryinit(Conv *c){ c->retries = 0; // +2 to avoid rounding effects. c->timeout = TK2SEC(m->ticks) + 2;}// assume c is lockedstatic intconvretry(Conv *c, int reset){ c->retries++; if(c->retries > MaxRetries) { if(reset) convoconnect(c, ConReset, c->dialid, c->acceptid); convsetstate(c, CClosed); return 0; } c->timeout = TK2SEC(m->ticks) + (c->retries+1); return 1;}// assumes c is lockedstatic voidconvtimer(Conv *c, ulong sec){ Block *b; if(c->timeout > sec) return; switch(c->state) { case CInit: break; case CDial: if(convretry(c, 1)) convoconnect(c, ConOpenRequest, c->dialid, 0); break; case CAccept: if(convretry(c, 1)) convoconnect(c, ConOpenAck, c->dialid, c->acceptid); break; case COpen: b = c->out.controlpkt; if(b != nil) { if(convretry(c, 1)) convoput(c, TControl, ControlMesg, copyblock(b, blocklen(b))); break; } c->timeout = c->lastrecv + KeepAlive; if(c->timeout > sec) break; // keepalive - randomly spaced between KeepAlive and 2*KeepAlive if(c->timeout + KeepAlive > sec && nrand(c->lastrecv + 2*KeepAlive - sec) > 0) break; // can not use writecontrol b = allocb(4); c->out.controlseq++; hnputl(b->wp, c->out.controlseq); b->wp += 4; c->out.controlpkt = b; convretryinit(c); if(!waserror()) { convoput(c, TControl, ControlMesg, copyblock(b, blocklen(b))); poperror(); } break; case CLocalClose: if(convretry(c, 0)) convoconnect(c, ConClose, c->dialid, c->acceptid); break; case CRemoteClose: case CClosed: break; }}static voidsdpackproc(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(c->ref == 0) continue; qunlock(sdp); qlock(c); if(c->ref > 0 && !waserror()) { convtimer(c, sec); poperror(); } qunlock(c); qlock(sdp); } qunlock(sdp); }}Dev sdpdevtab = { 'E', "sdp", devreset, sdpinit, sdpattach, devclone, sdpwalk, sdpstat, sdpopen, devcreate, sdpclose, sdpread, devbread, sdpwrite, devbwrite, devremove, devwstat,};// assume hold lock on cstatic voidconvsetstate(Conv *c, int state){if(1)print("convsetstate %d: %s -> %s\n", c->id, convstatename[c->state], convstatename[state]); switch(state) { default: panic("setstate: bad state: %d", state); case CDial: assert(c->state == CInit); c->dialid = (rand()<<16) + rand(); convretryinit(c); convoconnect(c, ConOpenRequest, c->dialid, 0); break; case CAccept: assert(c->state == CInit); c->acceptid = (rand()<<16) + rand(); convretryinit(c); convoconnect(c, ConOpenAck, c->dialid, c->acceptid); break; case COpen: assert(c->state == CDial || c->state == CAccept); c->lastrecv = TK2SEC(m->ticks); if(c->state == CDial) { convretryinit(c); convoconnect(c, ConOpenAckAck, c->dialid, c->acceptid); hnputl(c->in.secret, c->acceptid); hnputl(c->in.secret+4, c->dialid); hnputl(c->out.secret, c->dialid); hnputl(c->out.secret+4, c->acceptid); } else { hnputl(c->in.secret, c->dialid); hnputl(c->in.secret+4, c->acceptid); hnputl(c->out.secret, c->acceptid); hnputl(c->out.secret+4, c->dialid); } setalg(c, "hmac_md5_96", authalg, &c->auth); break; case CLocalClose: assert(c->state == CAccept || c->state == COpen); convretryinit(c); convoconnect(c, ConClose, c->dialid, c->acceptid); break; case CRemoteClose: wakeup(&c->in.controlready); wakeup(&c->out.controlready); break; case CClosed: wakeup(&c->in.controlready); wakeup(&c->out.controlready); if(c->readproc) postnote(c->readproc, 1, "interrupt", 0); if(c->state != CClosed) convderef(c); break; } c->state = state;}//assumes c is lockedstatic voidconvderef(Conv *c){ c->ref--; if(c->ref > 0) { return; } assert(c->ref == 0); assert(c->dataopen == 0); assert(c->controlopen == 0);if(0)print("convderef: %d: ref == 0!\n", c->id); c->state = CFree; if(c->chan) { cclose(c->chan); c->chan = nil; } if(c->channame) { free(c->channame); c->channame = nil; } c->cipher = nil; c->auth = nil; c->comp = nil; strcpy(c->owner, "network"); c->perm = 0660; c->dialid = 0; c->acceptid = 0; c->timeout = 0; c->retries = 0; c->drop = 0; onewaycleanup(&c->in); onewaycleanup(&c->out); memset(&c->lstats, 0, sizeof(Stats)); memset(&c->rstats, 0, sizeof(Stats));}static voidonewaycleanup(OneWay *ow){ 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));}// assumes conv is lockedstatic voidconvopenchan(Conv *c, char *path){ if(c->state != CInit || c->chan != nil) error("already connected"); c->chan = namec(path, Aopen, ORDWR, 0); c->channame = smalloc(strlen(path)+1); strcpy(c->channame, path); if(waserror()) { cclose(c->chan); c->chan = nil; free(c->channame); c->channame = nil; nexterror(); } kproc("convreader", convreader, c); assert(c->reader == 0 && c->ref > 0); // after kproc in case it fails c->reader = 1; c->ref++; poperror();}static voidconvstats(Conv *c, int local, char *buf, int n){ Stats *stats; char *p, *ep; int i; if(local) { stats = &c->lstats; } else { if(!waserror()) { writecontrol(c, 0, 0, 1); poperror(); } stats = &c->rstats; } qlock(c); p = buf; ep = buf + n; p += snprint(p, ep-p, "outPackets: %lud\n", stats->outPackets); p += snprint(p, ep-p, "outDataPackets: %lud\n", stats->outDataPackets); p += snprint(p, ep-p, "outDataBytes: %lud\n", stats->outDataBytes); p += snprint(p, ep-p, "outCompDataBytes: %lud\n", stats->outCompDataBytes); for(i=0; i<NCompStats; i++) { if(stats->outCompStats[i] == 0) continue; p += snprint(p, ep-p, "outCompStats[%d]: %lud\n", i, stats->outCompStats[i]); } p += snprint(p, ep-p, "inPackets: %lud\n", stats->inPackets); p += snprint(p, ep-p, "inDataPackets: %lud\n", stats->inDataPackets); p += snprint(p, ep-p, "inDataBytes: %lud\n", stats->inDataBytes); p += snprint(p, ep-p, "inCompDataBytes: %lud\n", stats->inCompDataBytes); p += snprint(p, ep-p, "inMissing: %lud\n", stats->inMissing); p += snprint(p, ep-p, "inDup: %lud\n", stats->inDup); p += snprint(p, ep-p, "inReorder: %lud\n", stats->inReorder); p += snprint(p, ep-p, "inBadComp: %lud\n", stats->inBadComp); p += snprint(p, ep-p, "inBadAuth: %lud\n", stats->inBadAuth); p += snprint(p, ep-p, "inBadSeq: %lud\n", stats->inBadSeq); p += snprint(p, ep-p, "inBadOther: %lud\n", stats->inBadOther); USED(p); qunlock(c);}// c is lockedstatic voidconvack(Conv *c){ Block *b; AckPkt *ack; Stats *s; int i; b = allocb(sizeof(AckPkt)); ack = (AckPkt*)b->wp; b->wp += sizeof(AckPkt); s = &c->lstats; hnputl(ack->cseq, c->in.controlseq); hnputl(ack->outPackets, s->outPackets); hnputl(ack->outDataPackets, s->outDataPackets); hnputl(ack->outDataBytes, s->outDataBytes); hnputl(ack->outCompDataBytes, s->outCompDataBytes); for(i=0; i<NCompStats; i++) hnputl(ack->outCompStats+i*4, s->outCompStats[i]); hnputl(ack->inPackets, s->inPackets); hnputl(ack->inDataPackets, s->inDataPackets); hnputl(ack->inDataBytes, s->inDataBytes); hnputl(ack->inCompDataBytes, s->inCompDataBytes); hnputl(ack->inMissing, s->inMissing); hnputl(ack->inDup, s->inDup); hnputl(ack->inReorder, s->inReorder); hnputl(ack->inBadComp, s->inBadComp); hnputl(ack->inBadAuth, s->inBadAuth); hnputl(ack->inBadSeq, s->inBadSeq); hnputl(ack->inBadOther, s->inBadOther); convoput(c, TControl, ControlAck, b);}// assume we hold lock for cstatic Block *conviput(Conv *c, Block *b, int control){ int type, subtype; ulong seq, seqwrap; long seqdiff; int pad; c->lstats.inPackets++; if(BLEN(b) < 4) { c->lstats.inBadOther++; freeb(b); return nil; } type = b->rp[0] >> 4; subtype = b->rp[0] & 0xf; b->rp += 1; if(type == TConnect) { conviconnect(c, subtype, b); return nil; } switch(c->state) { case CInit: case CDial: c->lstats.inBadOther++; convoconnect(c, ConReset, c->dialid, c->acceptid); convsetstate(c, CClosed); break; case CAccept: case CRemoteClose: case CLocalClose: c->lstats.inBadOther++; freeb(b); return nil; } seq = (b->rp[0]<<16) + (b->rp[1]<<8) + b->rp[2]; b->rp += 3; seqwrap = c->in.seqwrap; seqdiff = seq - c->in.seq; if(seqdiff < -(SeqMax*3/4)) { seqwrap++; seqdiff += SeqMax; } else if(seqdiff > SeqMax*3/4) { seqwrap--; seqdiff -= SeqMax; } if(seqdiff <= 0) { if(seqdiff <= -SeqWindow) {print("old sequence number: %ld (%ld %ld)\n", seq, c->in.seqwrap, seqdiff); c->lstats.inBadSeq++; freeb(b); return nil; } if(c->in.window & (1<<-seqdiff)) {print("dup sequence number: %ld (%ld %ld)\n", seq, c->in.seqwrap, seqdiff); c->lstats.inDup++; freeb(b); return nil; } c->lstats.inReorder++; } // ok the sequence number looks okif(0) print("coniput seq=%ulx\n", seq); if(c->in.auth != 0) { if(!(*c->in.auth)(&c->in, b->rp-4, BLEN(b)+4)) {print("bad auth %ld\n", BLEN(b)+4); c->lstats.inBadAuth++; freeb(b); return nil; } b->wp -= c->in.authlen; } if(c->in.cipher != 0) { if(!(*c->in.cipher)(&c->in, b->rp, BLEN(b))) {print("bad cipher\n"); c->lstats.inBadOther++; freeb(b); return nil; } b->rp += c->in.cipherivlen; if(c->in.cipherblklen > 1) { pad = b->wp[-1]; if(pad > BLEN(b)) {print("pad too big\n"); c->lstats.inBadOther++; freeb(b); return nil; } b->wp -= pad; } } // ok the packet is good if(seqdiff > 0) { while(seqdiff > 0 && c->in.window != 0) { if((c->in.window & (1<<(SeqWindow-1))) == 0) {//print("missing packet: %ld\n", seq - seqdiff); c->lstats.inMissing++; } c->in.window <<= 1; seqdiff--; } if(seqdiff > 0) {//print("missing packets: %ld-%ld\n", seq - SeqWindow - seqdiff+1, seq-SeqWindow); c->lstats.inMissing += seqdiff; } c->in.seq = seq; c->in.seqwrap = seqwrap; c->in.window |= 1; } c->lastrecv = TK2SEC(m->ticks); switch(type) { case TControl: convicontrol(c, subtype, b); return nil; case TData: c->lstats.inDataPackets++; c->lstats.inDataBytes += BLEN(b); if(control) break; return b; case TCompData: c->lstats.inDataPackets++; c->lstats.inCompDataBytes += BLEN(b); b = convicomp(c, subtype, seq, b); if(b == nil) { c->lstats.inBadComp++; return nil; } c->lstats.inDataBytes += BLEN(b); if(control) break; return b; }print("droping packet %d n=%ld\n", type, BLEN(b)); c->lstats.inBadOther++; freeb(b); return nil;}// assume hold conv lockstatic voidconviconnect(Conv *c, int subtype, Block *b){ ulong dialid; ulong acceptid; if(BLEN(b) != 8) { freeb(b); return; } dialid = nhgetl(b->rp); acceptid = nhgetl(b->rp + 4); freeb(b);if(0)print("conviconnect: %s: %d %uld %uld\n", convstatename[c->state], subtype, dialid, acceptid); if(subtype == ConReset) { convsetstate(c, CClosed); return; } switch(c->state) { default: panic("unknown state: %d", c->state); case CInit: break; case CDial: if(dialid != c->dialid) goto Reset; break; case CAccept: case COpen: case CLocalClose: case CRemoteClose: if(dialid != c->dialid || subtype != ConOpenRequest && acceptid != c->acceptid) goto Reset; break; case CClosed: goto Reset; } switch(subtype) { case ConOpenRequest: switch(c->state) { case CInit: c->dialid = dialid; convsetstate(c, CAccept); return; case CAccept: case COpen: // duplicate ConOpenRequest that we ignore return; } break; case ConOpenAck: switch(c->state) { case CDial: c->acceptid = acceptid; convsetstate(c, COpen); return; case COpen: // duplicate that we have to ack convoconnect(c, ConOpenAckAck, acceptid, dialid); return; } break; case ConOpenAckAck: switch(c->state) { case CAccept: convsetstate(c, COpen); return; case COpen: case CLocalClose: case CRemoteClose: // duplicate that we ignore return; } break; case ConClose: switch(c->state) { case COpen: convoconnect(c, ConCloseAck, dialid, acceptid); convsetstate(c, CRemoteClose); return; case CRemoteClose: // duplicate ConClose convoconnect(c, ConCloseAck, dialid, acceptid); return; } break; case ConCloseAck: switch(c->state) { case CLocalClose: convsetstate(c, CClosed); return; } break; }Reset: // invalid connection message - reset to senderif(0)print("invalid conviconnect - sending reset\n"); convoconnect(c, ConReset, dialid, acceptid); convsetstate(c, CClosed);}static voidconvicontrol(Conv *c, int subtype, Block *b){ ulong cseq; AckPkt *ack; int i; if(BLEN(b) < 4) return; cseq = nhgetl(b->rp); switch(subtype){ case ControlMesg: if(cseq == c->in.controlseq) {print("duplicate control packet: %ulx\n", cseq); // duplicate control packet freeb(b); if(c->in.controlpkt == nil) convack(c); return; } if(cseq != c->in.controlseq+1) return; c->in.controlseq = cseq; b->rp += 4; if(BLEN(b) == 0) { // just a ping freeb(b); convack(c); } else { c->in.controlpkt = b;if(0) print("recv %ld size=%ld\n", cseq, BLEN(b)); wakeup(&c->in.controlready); } return; case ControlAck: if(cseq != c->out.controlseq) return; if(BLEN(b) < sizeof(AckPkt)) return; ack = (AckPkt*)(b->rp); c->rstats.outPackets = nhgetl(ack->outPackets); c->rstats.outDataPackets = nhgetl(ack->outDataPackets); c->rstats.outDataBytes = nhgetl(ack->outDataBytes); c->rstats.outCompDataBytes = nhgetl(ack->outCompDataBytes); for(i=0; i<NCompStats; i++) c->rstats.outCompStats[i] = nhgetl(ack->outCompStats + 4*i); c->rstats.inPackets = nhgetl(ack->inPackets); c->rstats.inDataPackets = nhgetl(ack->inDataPackets); c->rstats.inDataBytes = nhgetl(ack->inDataBytes); c->rstats.inCompDataBytes = nhgetl(ack->inCompDataBytes); c->rstats.inMissing = nhgetl(ack->inMissing); c->rstats.inDup = nhgetl(ack->inDup); c->rstats.inReorder = nhgetl(ack->inReorder); c->rstats.inBadComp = nhgetl(ack->inBadComp); c->rstats.inBadAuth = nhgetl(ack->inBadAuth); c->rstats.inBadSeq = nhgetl(ack->inBadSeq); c->rstats.inBadOther = nhgetl(ack->inBadOther); freeb(b); freeb(c->out.controlpkt); c->out.controlpkt = nil; c->timeout = c->lastrecv + KeepAlive; wakeup(&c->out.controlready); return; }}static Block*convicomp(Conv *c, int subtype, ulong seq, Block *b){ if(c->in.comp == nil) { freeb(b); return nil; } if(!(*c->in.comp)(c, subtype, seq, &b)) return nil; return b;}// c is lockedstatic voidconvwriteblock(Conv *c, Block *b){ // simulated errors if(c->drop && nrand(c->drop) == 0) return; if(waserror()) { convsetstate(c, CClosed); nexterror(); } devtab[c->chan->type]->bwrite(c->chan, b, 0); poperror();}// assume hold conv lockstatic voidconvoput(Conv *c, int type, int subtype, Block *b){ int pad; c->lstats.outPackets++; /* Make room for sdp trailer */ if(c->out.cipherblklen > 1) pad = c->out.cipherblklen - (BLEN(b) + c->out.cipherivlen) % c->out.cipherblklen; else pad = 0; b = padblock(b, -(pad+c->out.authlen)); if(pad) { memset(b->wp, 0, pad-1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -