/* * Reconnecting Venti proxy * * Proxies requests to a remove Venti; if the connection to a remove server * fails, it keeps retrying the request till a connection can be reestablished * * Usage: * vtrc -a listenaddress -h hostventi [-v] * vtrc listens on listenaddress, proxying connections to hostventi * * based on Russ Cox's venti/ro.c */ #include #include #include #include #include #ifndef _UNISTD_H_ #pragma varargck type "F" VtFcall* #pragma varargck type "T" void #endif char *za = nil; VtConn *z =nil; int verbose; QLock vtconnlock; enum { STACK = 4096 }; /* called with the vtconnlock held */ void try_reconnect(void) { if (z != nil) vtfreeconn(z); z = vtdial(za); if (z != nil) vtconnect(z); } void usage(void) { fprint(2, "usage: vtrc [-v] [-a address] [-h address]\n"); exits("usage"); } void readthread(void *v) { char err[ERRMAX]; VtReq *r; uchar *buf; int n = -1; r = v; buf = vtmalloc(r->tx.count); qlock(&vtconnlock); for (;;) { n = -1; if (z != nil) n = vtread(z, r->tx.score, r->tx.blocktype, buf, r->tx.count); if (n < 0) try_reconnect(); else break; } qunlock(&vtconnlock); r->rx.data = packetforeign(buf, n, free, buf); vtrespond(r); } void writethread(void *v) { VtReq *r; int n = -1; r = v; packetsha1(r->tx.data, r->rx.score); qlock(&vtconnlock); for (;;) { n = -1; if (z != nil) n = vtwritepacket(z, r->rx.score, r->tx.blocktype, r->tx.data); if (n < 0) try_reconnect(); else break; } qunlock(&vtconnlock); vtrespond(r); } VtSrv *srv; void coreproc(void *v) { VtReq *r1; while((r1 = vtgetreq(srv)) != nil){ r1->rx.msgtype = r1->tx.msgtype+1; if(verbose) fprint(2, "<- %F\n", &r1->tx); switch(r1->tx.msgtype){ case VtTping: vtrespond(r1); break; case VtTgoodbye: vtrespond(r1); break; case VtTread: proccreate(readthread, r1, 16384); continue; case VtTwrite: proccreate(writethread, r1, 16384); continue; case VtTsync: vtrespond(r1); break; } if(verbose) fprint(2, "-> %F\n", &r1->rx); } } void threadmain(int argc, char **argv) { char *address, *ventiaddress; fmtinstall('F', vtfcallfmt); fmtinstall('V', vtscorefmt); address = "tcp!*!venti"; ventiaddress = nil; ARGBEGIN{ case 'v': verbose++; break; case 'a': address = EARGF(usage()); break; case 'h': ventiaddress = EARGF(usage()); break; default: usage(); }ARGEND if((z = vtdial(ventiaddress)) == nil) sysfatal("vtdial %s: %r", ventiaddress); if(vtconnect(z) < 0) sysfatal("vtconnect: %r"); za = ventiaddress; if (za == nil) sysfatal("no remote address"); srv = vtlisten(address); if(srv == nil) sysfatal("vtlisten %s: %r", address); print("vtrc: Ice Nine, Baby\n"); rfork(RFNOTEG); proccreate(coreproc, nil, 4096*16); exits(nil); }