ref: baf602582a840a0253900d41a2f1cce7156dd770
dir: /vchan.c/
/* * [MS-RDPBCGR] 3.1.5.2 Static Virtual Channels * http://msdn.microsoft.com/en-us/library/cc240926.aspx */ #include <u.h> #include <libc.h> #include <draw.h> #include "dat.h" #include "fns.h" enum { /* 2.2.1.3.4.1 Channel Definition Structure */ ChanInited = 0x80000000, ChanShowproto = 0x00200000, /* 2.2.6.1 Virtual Channel PDU */ ChanChunkLen = 1600, /* 2.2.6.1.1 Channel PDU Header */ CFfirst= 0x01, CFlast= 0x02, CFshowproto= 0x10, }; Vchan vctab[] = { { .mcsid = GLOBALCHAN + 1, /* iota */ .name = "CLIPRDR", .fn = clipvcfn, .flags = ChanInited | ChanShowproto, }, }; uint nvc = nelem(vctab); Vchan* lookupvc(int mcsid) { int i; for(i=0; i<nvc; i++) if(vctab[i].mcsid == mcsid) return &vctab[i]; return nil; } Vchan* namevc(char* name) { int i; for(i=0; i<nvc; i++) if(strcmp(vctab[i].name, name) == 0) return &vctab[i]; return nil; } void scanvcpdu(uchar *p, uchar* ep, int chanid) { int flags, len, rem; uchar *q, *eq; Vchan* vc; vc = lookupvc(chanid); if(vc == nil) return; len = GLONG(p+0); flags = GLONG(p+4); p += 8; if(len < 0 || len > 8*1024*1024){ werrstr("bad length in virtual channel PDU header"); fprint(2, "scanvcpdu: %r\n"); return; } if(flags&CFfirst){ vc->defragging = 1; vc->pos = 0; } if(!vc->defragging){ vc->fn(p, ep); return; } vc->buf = erealloc(vc->buf, len); vc->nb = len; q = vc->buf + vc->pos; eq = vc->buf + len; rem = ep-p; if(rem > eq-q) rem = eq-q; memcpy(q, p, rem); vc->pos += rem; if(flags&CFlast){ q = vc->buf; vc->fn(q, eq); free(vc->buf); vc->buf = nil; vc->nb = 0; vc->defragging = 0; } } int sendvc(char* cname, uchar* a, int n) { int sofar, chunk; int flags; int nb, len, ndata; uchar buf[40+ChanChunkLen]; uchar *p, *q; Vchan* vc; int chanid; vc = namevc(cname); if(vc == nil){ werrstr("%s: no such vchannel", cname); return -1; } chanid = vc->mcsid; if(chanid < 0) return -1; if(n < 0) return -1; p = a; nb = sizeof(buf); flags = CFfirst | CFshowproto; for(sofar=0; sofar<n; sofar += chunk){ chunk = n-sofar; if(chunk > ChanChunkLen) chunk = ChanChunkLen; else flags |= CFlast; ndata = chunk+8; q = prebuf(buf, nb, ndata, chanid, 0); if(q == nil) return -1; PLONG(q+0, n); PLONG(q+4, flags); memcpy(q+8, p+sofar, chunk); len = q-buf+ndata; writen(rd.fd, buf, len); flags &= ~CFfirst; } return n; }