19a747e4fSDavid du Colombier #include "all.h"
29a747e4fSDavid du Colombier #include <ndb.h>
39a747e4fSDavid du Colombier
49a747e4fSDavid du Colombier static int alarmflag;
59a747e4fSDavid du Colombier
69a747e4fSDavid du Colombier static int Iconv(Fmt*);
79a747e4fSDavid du Colombier static void openudp(int);
89a747e4fSDavid du Colombier static void cachereply(Rpccall*, void*, int);
99a747e4fSDavid du Colombier static int replycache(int, Rpccall*, long (*)(int, void*, long));
109a747e4fSDavid du Colombier static void udpserver(int, Progmap*);
119a747e4fSDavid du Colombier static void tcpserver(int, Progmap*);
12f27a9a5aSDavid du Colombier static void getendpoints(Udphdr*, char*);
139a747e4fSDavid du Colombier static long readtcp(int, void*, long);
149a747e4fSDavid du Colombier static long writetcp(int, void*, long);
159a747e4fSDavid du Colombier static int servemsg(int, long (*)(int, void*, long), long (*)(int, void*, long),
169a747e4fSDavid du Colombier int, Progmap*);
179a747e4fSDavid du Colombier void (*rpcalarm)(void);
189a747e4fSDavid du Colombier int rpcdebug;
199a747e4fSDavid du Colombier int rejectall;
209a747e4fSDavid du Colombier int p9debug;
219a747e4fSDavid du Colombier
229a747e4fSDavid du Colombier int nocache;
239a747e4fSDavid du Colombier
249a747e4fSDavid du Colombier uchar buf[9000];
259a747e4fSDavid du Colombier uchar rbuf[9000];
269a747e4fSDavid du Colombier uchar resultbuf[9000];
279a747e4fSDavid du Colombier
28363b328dSDavid du Colombier static int tcp;
29363b328dSDavid du Colombier
30363b328dSDavid du Colombier char *commonopts = "[-9CDrtv]"; /* for usage() messages */
31363b328dSDavid du Colombier
32363b328dSDavid du Colombier /*
33363b328dSDavid du Colombier * this recognises common, nominally rcp-related options.
34363b328dSDavid du Colombier * they may not take arguments.
35363b328dSDavid du Colombier */
36363b328dSDavid du Colombier int
argopt(int c)37363b328dSDavid du Colombier argopt(int c)
38363b328dSDavid du Colombier {
39363b328dSDavid du Colombier switch(c){
40363b328dSDavid du Colombier case '9':
41363b328dSDavid du Colombier ++p9debug;
42363b328dSDavid du Colombier return 0;
43363b328dSDavid du Colombier case 'C':
44363b328dSDavid du Colombier ++nocache;
45363b328dSDavid du Colombier return 0;
46363b328dSDavid du Colombier case 'D':
47363b328dSDavid du Colombier ++rpcdebug;
48363b328dSDavid du Colombier return 0;
49363b328dSDavid du Colombier case 'r':
50363b328dSDavid du Colombier ++rejectall;
51363b328dSDavid du Colombier return 0;
52363b328dSDavid du Colombier case 't':
53363b328dSDavid du Colombier tcp = 1;
54363b328dSDavid du Colombier return 0;
55363b328dSDavid du Colombier case 'v':
56363b328dSDavid du Colombier ++chatty;
57363b328dSDavid du Colombier return 0;
58363b328dSDavid du Colombier default:
59363b328dSDavid du Colombier return -1;
60363b328dSDavid du Colombier }
61363b328dSDavid du Colombier }
62363b328dSDavid du Colombier
63363b328dSDavid du Colombier /*
64363b328dSDavid du Colombier * all option parsing is now done in (*pg->init)(), which can call back
65363b328dSDavid du Colombier * here to argopt for common options.
66363b328dSDavid du Colombier */
679a747e4fSDavid du Colombier void
server(int argc,char ** argv,int myport,Progmap * progmap)689a747e4fSDavid du Colombier server(int argc, char **argv, int myport, Progmap *progmap)
699a747e4fSDavid du Colombier {
709a747e4fSDavid du Colombier Progmap *pg;
719a747e4fSDavid du Colombier
729a747e4fSDavid du Colombier fmtinstall('I', Iconv);
739a747e4fSDavid du Colombier fmtinstall('F', fcallfmt);
749a747e4fSDavid du Colombier fmtinstall('D', dirfmt);
759a747e4fSDavid du Colombier
769a747e4fSDavid du Colombier switch(rfork(RFNOWAIT|RFENVG|RFNAMEG|RFNOTEG|RFFDG|RFPROC)){
779a747e4fSDavid du Colombier case -1:
789a747e4fSDavid du Colombier panic("fork");
799a747e4fSDavid du Colombier default:
809a747e4fSDavid du Colombier _exits(0);
819a747e4fSDavid du Colombier case 0:
829a747e4fSDavid du Colombier break;
839a747e4fSDavid du Colombier }
846ab4d0ffSDavid du Colombier
856ab4d0ffSDavid du Colombier switch(rfork(RFMEM|RFPROC)){
866ab4d0ffSDavid du Colombier case 0:
876ab4d0ffSDavid du Colombier for(;;){
886ab4d0ffSDavid du Colombier sleep(30*1000);
896ab4d0ffSDavid du Colombier alarmflag = 1;
906ab4d0ffSDavid du Colombier }
916ab4d0ffSDavid du Colombier case -1:
926ab4d0ffSDavid du Colombier sysfatal("rfork: %r");
936ab4d0ffSDavid du Colombier }
946ab4d0ffSDavid du Colombier
959a747e4fSDavid du Colombier for(pg=progmap; pg->init; pg++)
96363b328dSDavid du Colombier (*pg->init)(argc, argv);
979a747e4fSDavid du Colombier if(tcp)
989a747e4fSDavid du Colombier tcpserver(myport, progmap);
999a747e4fSDavid du Colombier else
1009a747e4fSDavid du Colombier udpserver(myport, progmap);
1019a747e4fSDavid du Colombier }
1029a747e4fSDavid du Colombier
1039a747e4fSDavid du Colombier static void
udpserver(int myport,Progmap * progmap)1049a747e4fSDavid du Colombier udpserver(int myport, Progmap *progmap)
1059a747e4fSDavid du Colombier {
1069a747e4fSDavid du Colombier char service[128];
1079a747e4fSDavid du Colombier char data[128];
1089a747e4fSDavid du Colombier char devdir[40];
1099a747e4fSDavid du Colombier int ctlfd, datafd;
1109a747e4fSDavid du Colombier
1119a747e4fSDavid du Colombier snprint(service, sizeof service, "udp!*!%d", myport);
1129a747e4fSDavid du Colombier ctlfd = announce(service, devdir);
1139a747e4fSDavid du Colombier if(ctlfd < 0)
1149a747e4fSDavid du Colombier panic("can't announce %s: %r\n", service);
1159a747e4fSDavid du Colombier if(fprint(ctlfd, "headers") < 0)
1169a747e4fSDavid du Colombier panic("can't set header mode: %r\n");
1179a747e4fSDavid du Colombier
1189a747e4fSDavid du Colombier snprint(data, sizeof data, "%s/data", devdir);
1199a747e4fSDavid du Colombier datafd = open(data, ORDWR);
1209a747e4fSDavid du Colombier if(datafd < 0)
1219a747e4fSDavid du Colombier panic("can't open udp data: %r\n");
1229a747e4fSDavid du Colombier close(ctlfd);
1239a747e4fSDavid du Colombier
1249a747e4fSDavid du Colombier chatsrv(0);
1259a747e4fSDavid du Colombier clog("%s: listening to port %d\n", argv0, myport);
126f27a9a5aSDavid du Colombier while (servemsg(datafd, read, write, myport, progmap) >= 0)
127f27a9a5aSDavid du Colombier continue;
1289a747e4fSDavid du Colombier exits(0);
1299a747e4fSDavid du Colombier }
1309a747e4fSDavid du Colombier
1319a747e4fSDavid du Colombier static void
tcpserver(int myport,Progmap * progmap)1329a747e4fSDavid du Colombier tcpserver(int myport, Progmap *progmap)
1339a747e4fSDavid du Colombier {
1349a747e4fSDavid du Colombier char adir[40];
1359a747e4fSDavid du Colombier char ldir[40];
1369a747e4fSDavid du Colombier char ds[40];
1379a747e4fSDavid du Colombier int actl, lctl, data;
1389a747e4fSDavid du Colombier
1399a747e4fSDavid du Colombier snprint(ds, sizeof ds, "tcp!*!%d", myport);
1409a747e4fSDavid du Colombier chatsrv(0);
1419a747e4fSDavid du Colombier actl = -1;
1429a747e4fSDavid du Colombier for(;;){
1439a747e4fSDavid du Colombier if(actl < 0){
1449a747e4fSDavid du Colombier actl = announce(ds, adir);
1459a747e4fSDavid du Colombier if(actl < 0){
146883a8c51SDavid du Colombier clog("%s: listening to tcp port %d\n",
147883a8c51SDavid du Colombier argv0, myport);
1489a747e4fSDavid du Colombier clog("announcing: %r");
1499a747e4fSDavid du Colombier break;
1509a747e4fSDavid du Colombier }
1519a747e4fSDavid du Colombier }
1529a747e4fSDavid du Colombier lctl = listen(adir, ldir);
1539a747e4fSDavid du Colombier if(lctl < 0){
1549a747e4fSDavid du Colombier close(actl);
1559a747e4fSDavid du Colombier actl = -1;
1569a747e4fSDavid du Colombier continue;
1579a747e4fSDavid du Colombier }
1589a747e4fSDavid du Colombier switch(fork()){
1599a747e4fSDavid du Colombier case -1:
1609a747e4fSDavid du Colombier clog("%s!%d: %r\n", argv0, myport);
1619a747e4fSDavid du Colombier /* fall through */
1629a747e4fSDavid du Colombier default:
1639a747e4fSDavid du Colombier close(lctl);
1649a747e4fSDavid du Colombier continue;
1659a747e4fSDavid du Colombier case 0:
1669a747e4fSDavid du Colombier close(actl);
1679a747e4fSDavid du Colombier data = accept(lctl, ldir);
1689a747e4fSDavid du Colombier close(lctl);
1699a747e4fSDavid du Colombier if(data < 0)
1709a747e4fSDavid du Colombier exits(0);
1719a747e4fSDavid du Colombier
172883a8c51SDavid du Colombier /* pretend it's udp; fill in Udphdr */
173f27a9a5aSDavid du Colombier getendpoints((Udphdr*)buf, ldir);
1749a747e4fSDavid du Colombier
175883a8c51SDavid du Colombier while (servemsg(data, readtcp, writetcp, myport,
176883a8c51SDavid du Colombier progmap) >= 0)
177883a8c51SDavid du Colombier continue;
1789a747e4fSDavid du Colombier close(data);
1799a747e4fSDavid du Colombier exits(0);
1809a747e4fSDavid du Colombier }
1819a747e4fSDavid du Colombier }
1829a747e4fSDavid du Colombier exits(0);
1839a747e4fSDavid du Colombier }
1849a747e4fSDavid du Colombier
1859a747e4fSDavid du Colombier static int
servemsg(int fd,long (* readmsg)(int,void *,long),long (* writemsg)(int,void *,long),int myport,Progmap * progmap)1869a747e4fSDavid du Colombier servemsg(int fd, long (*readmsg)(int, void*, long), long (*writemsg)(int, void*, long),
1879a747e4fSDavid du Colombier int myport, Progmap * progmap)
1889a747e4fSDavid du Colombier {
1899a747e4fSDavid du Colombier int i, n, nreply;
1909a747e4fSDavid du Colombier Rpccall rcall, rreply;
1919a747e4fSDavid du Colombier int vlo, vhi;
1929a747e4fSDavid du Colombier Progmap *pg;
1939a747e4fSDavid du Colombier Procmap *pp;
1949a747e4fSDavid du Colombier char errbuf[ERRMAX];
1959a747e4fSDavid du Colombier
1969a747e4fSDavid du Colombier if(alarmflag){
1979a747e4fSDavid du Colombier alarmflag = 0;
1989a747e4fSDavid du Colombier if(rpcalarm)
1999a747e4fSDavid du Colombier (*rpcalarm)();
2009a747e4fSDavid du Colombier }
2019a747e4fSDavid du Colombier n = (*readmsg)(fd, buf, sizeof buf);
2029a747e4fSDavid du Colombier if(n < 0){
2039a747e4fSDavid du Colombier errstr(errbuf, sizeof errbuf);
2049a747e4fSDavid du Colombier if(strcmp(errbuf, "interrupted") == 0)
2059a747e4fSDavid du Colombier return 0;
2069a747e4fSDavid du Colombier clog("port %d: error: %s\n", myport, errbuf);
2079a747e4fSDavid du Colombier return -1;
2089a747e4fSDavid du Colombier }
2099a747e4fSDavid du Colombier if(n == 0){
2109a747e4fSDavid du Colombier clog("port %d: EOF\n", myport);
2119a747e4fSDavid du Colombier return -1;
2129a747e4fSDavid du Colombier }
2139a747e4fSDavid du Colombier if(rpcdebug == 1)
2149a747e4fSDavid du Colombier fprint(2, "%s: rpc from %d.%d.%d.%d/%d\n",
2159a747e4fSDavid du Colombier argv0, buf[12], buf[13], buf[14], buf[15],
2169a747e4fSDavid du Colombier (buf[32]<<8)|buf[33]);
2179a747e4fSDavid du Colombier i = rpcM2S(buf, &rcall, n);
2189a747e4fSDavid du Colombier if(i != 0){
2199a747e4fSDavid du Colombier clog("udp port %d: message format error %d\n",
2209a747e4fSDavid du Colombier myport, i);
2219a747e4fSDavid du Colombier return 0;
2229a747e4fSDavid du Colombier }
2239a747e4fSDavid du Colombier if(rpcdebug > 1)
2249a747e4fSDavid du Colombier rpcprint(2, &rcall);
2259a747e4fSDavid du Colombier if(rcall.mtype != CALL)
2269a747e4fSDavid du Colombier return 0;
2279a747e4fSDavid du Colombier if(replycache(fd, &rcall, writemsg))
2289a747e4fSDavid du Colombier return 0;
2299a747e4fSDavid du Colombier nreply = 0;
2309a747e4fSDavid du Colombier rreply.host = rcall.host;
2319a747e4fSDavid du Colombier rreply.port = rcall.port;
2329a747e4fSDavid du Colombier rreply.lhost = rcall.lhost;
2339a747e4fSDavid du Colombier rreply.lport = rcall.lport;
2349a747e4fSDavid du Colombier rreply.xid = rcall.xid;
2359a747e4fSDavid du Colombier rreply.mtype = REPLY;
2369a747e4fSDavid du Colombier if(rcall.rpcvers != 2){
2379a747e4fSDavid du Colombier rreply.stat = MSG_DENIED;
2389a747e4fSDavid du Colombier rreply.rstat = RPC_MISMATCH;
2399a747e4fSDavid du Colombier rreply.rlow = 2;
2409a747e4fSDavid du Colombier rreply.rhigh = 2;
2419a747e4fSDavid du Colombier goto send_reply;
2429a747e4fSDavid du Colombier }
2439a747e4fSDavid du Colombier if(rejectall){
2449a747e4fSDavid du Colombier rreply.stat = MSG_DENIED;
2459a747e4fSDavid du Colombier rreply.rstat = AUTH_ERROR;
2469a747e4fSDavid du Colombier rreply.authstat = AUTH_TOOWEAK;
2479a747e4fSDavid du Colombier goto send_reply;
2489a747e4fSDavid du Colombier }
2499a747e4fSDavid du Colombier i = n - (((uchar *)rcall.args) - buf);
2509a747e4fSDavid du Colombier if(rpcdebug > 1)
2519a747e4fSDavid du Colombier fprint(2, "arg size = %d\n", i);
2529a747e4fSDavid du Colombier rreply.stat = MSG_ACCEPTED;
2539a747e4fSDavid du Colombier rreply.averf.flavor = 0;
2549a747e4fSDavid du Colombier rreply.averf.count = 0;
2559a747e4fSDavid du Colombier rreply.results = resultbuf;
2569a747e4fSDavid du Colombier vlo = 0x7fffffff;
2579a747e4fSDavid du Colombier vhi = -1;
2589a747e4fSDavid du Colombier for(pg=progmap; pg->pmap; pg++){
2599a747e4fSDavid du Colombier if(pg->progno != rcall.prog)
2609a747e4fSDavid du Colombier continue;
2619a747e4fSDavid du Colombier if(pg->vers == rcall.vers)
2629a747e4fSDavid du Colombier break;
2639a747e4fSDavid du Colombier if(pg->vers < vlo)
2649a747e4fSDavid du Colombier vlo = pg->vers;
2659a747e4fSDavid du Colombier if(pg->vers > vhi)
2669a747e4fSDavid du Colombier vhi = pg->vers;
2679a747e4fSDavid du Colombier }
2689a747e4fSDavid du Colombier if(pg->pmap == 0){
2699a747e4fSDavid du Colombier if(vhi < 0)
2709a747e4fSDavid du Colombier rreply.astat = PROG_UNAVAIL;
2719a747e4fSDavid du Colombier else{
2729a747e4fSDavid du Colombier rreply.astat = PROG_MISMATCH;
2739a747e4fSDavid du Colombier rreply.plow = vlo;
2749a747e4fSDavid du Colombier rreply.phigh = vhi;
2759a747e4fSDavid du Colombier }
2769a747e4fSDavid du Colombier goto send_reply;
2779a747e4fSDavid du Colombier }
2789a747e4fSDavid du Colombier for(pp = pg->pmap; pp->procp; pp++)
2799a747e4fSDavid du Colombier if(rcall.proc == pp->procno){
2809a747e4fSDavid du Colombier if(rpcdebug > 1)
2819a747e4fSDavid du Colombier fprint(2, "process %d\n", pp->procno);
2829a747e4fSDavid du Colombier rreply.astat = SUCCESS;
2839a747e4fSDavid du Colombier nreply = (*pp->procp)(i, &rcall, &rreply);
2849a747e4fSDavid du Colombier goto send_reply;
2859a747e4fSDavid du Colombier }
2869a747e4fSDavid du Colombier rreply.astat = PROC_UNAVAIL;
2879a747e4fSDavid du Colombier send_reply:
2889a747e4fSDavid du Colombier if(nreply >= 0){
2899a747e4fSDavid du Colombier i = rpcS2M(&rreply, nreply, rbuf);
2909a747e4fSDavid du Colombier if(rpcdebug > 1)
2919a747e4fSDavid du Colombier rpcprint(2, &rreply);
2929a747e4fSDavid du Colombier (*writemsg)(fd, rbuf, i);
2939a747e4fSDavid du Colombier cachereply(&rreply, rbuf, i);
2949a747e4fSDavid du Colombier }
2959a747e4fSDavid du Colombier return 0;
2969a747e4fSDavid du Colombier }
2979a747e4fSDavid du Colombier
2989a747e4fSDavid du Colombier static void
getendpoint(char * dir,char * file,uchar * addr,uchar * port)2999a747e4fSDavid du Colombier getendpoint(char *dir, char *file, uchar *addr, uchar *port)
3009a747e4fSDavid du Colombier {
3019a747e4fSDavid du Colombier int fd, n;
3029a747e4fSDavid du Colombier char buf[128];
3039a747e4fSDavid du Colombier char *sys, *serv;
3049a747e4fSDavid du Colombier
3059a747e4fSDavid du Colombier sys = serv = 0;
3069a747e4fSDavid du Colombier
3079a747e4fSDavid du Colombier snprint(buf, sizeof buf, "%s/%s", dir, file);
3089a747e4fSDavid du Colombier fd = open(buf, OREAD);
3099a747e4fSDavid du Colombier if(fd >= 0){
3109a747e4fSDavid du Colombier n = read(fd, buf, sizeof(buf)-1);
3119a747e4fSDavid du Colombier if(n>0){
3129a747e4fSDavid du Colombier buf[n-1] = 0;
3139a747e4fSDavid du Colombier serv = strchr(buf, '!');
3149a747e4fSDavid du Colombier if(serv){
3159a747e4fSDavid du Colombier *serv++ = 0;
3169a747e4fSDavid du Colombier serv = strdup(serv);
3179a747e4fSDavid du Colombier }
3189a747e4fSDavid du Colombier sys = strdup(buf);
3199a747e4fSDavid du Colombier }
3209a747e4fSDavid du Colombier close(fd);
3219a747e4fSDavid du Colombier }
3229a747e4fSDavid du Colombier if(serv == 0)
3239a747e4fSDavid du Colombier serv = strdup("unknown");
3249a747e4fSDavid du Colombier if(sys == 0)
3259a747e4fSDavid du Colombier sys = strdup("unknown");
3269a747e4fSDavid du Colombier parseip(addr, sys);
3279a747e4fSDavid du Colombier n = atoi(serv);
3289a747e4fSDavid du Colombier hnputs(port, n);
3299a747e4fSDavid du Colombier }
3309a747e4fSDavid du Colombier
331*ea58ad6fSDavid du Colombier /* set Udphdr values from protocol dir local & remote files */
3329a747e4fSDavid du Colombier static void
getendpoints(Udphdr * ep,char * dir)333f27a9a5aSDavid du Colombier getendpoints(Udphdr *ep, char *dir)
3349a747e4fSDavid du Colombier {
3359a747e4fSDavid du Colombier getendpoint(dir, "local", ep->laddr, ep->lport);
3369a747e4fSDavid du Colombier getendpoint(dir, "remote", ep->raddr, ep->rport);
3379a747e4fSDavid du Colombier }
3389a747e4fSDavid du Colombier
3399a747e4fSDavid du Colombier static long
readtcp(int fd,void * vbuf,long blen)3409a747e4fSDavid du Colombier readtcp(int fd, void *vbuf, long blen)
3419a747e4fSDavid du Colombier {
3429a747e4fSDavid du Colombier uchar mk[4];
3439a747e4fSDavid du Colombier int n, m, sofar;
3449a747e4fSDavid du Colombier ulong done;
3459a747e4fSDavid du Colombier char *buf;
3469a747e4fSDavid du Colombier
3479a747e4fSDavid du Colombier buf = vbuf;
348f27a9a5aSDavid du Colombier buf += Udphdrsize;
349f27a9a5aSDavid du Colombier blen -= Udphdrsize;
3509a747e4fSDavid du Colombier
3519a747e4fSDavid du Colombier done = 0;
3529a747e4fSDavid du Colombier for(sofar = 0; !done; sofar += n){
3539a747e4fSDavid du Colombier m = readn(fd, mk, 4);
3549a747e4fSDavid du Colombier if(m < 4)
3559a747e4fSDavid du Colombier return 0;
3569a747e4fSDavid du Colombier done = (mk[0]<<24)|(mk[1]<<16)|(mk[2]<<8)|mk[3];
3579a747e4fSDavid du Colombier m = done & 0x7fffffff;
3589a747e4fSDavid du Colombier done &= 0x80000000;
3599a747e4fSDavid du Colombier if(m > blen-sofar)
3609a747e4fSDavid du Colombier return -1;
3619a747e4fSDavid du Colombier n = readn(fd, buf+sofar, m);
3629a747e4fSDavid du Colombier if(m != n)
3639a747e4fSDavid du Colombier return 0;
3649a747e4fSDavid du Colombier }
365f27a9a5aSDavid du Colombier return sofar + Udphdrsize;
3669a747e4fSDavid du Colombier }
3679a747e4fSDavid du Colombier
3689a747e4fSDavid du Colombier static long
writetcp(int fd,void * vbuf,long len)3699a747e4fSDavid du Colombier writetcp(int fd, void *vbuf, long len)
3709a747e4fSDavid du Colombier {
3719a747e4fSDavid du Colombier char *buf;
3729a747e4fSDavid du Colombier
3739a747e4fSDavid du Colombier buf = vbuf;
374f27a9a5aSDavid du Colombier buf += Udphdrsize;
375f27a9a5aSDavid du Colombier len -= Udphdrsize;
3769a747e4fSDavid du Colombier
3779a747e4fSDavid du Colombier buf -= 4;
3789a747e4fSDavid du Colombier buf[0] = 0x80 | (len>>24);
3799a747e4fSDavid du Colombier buf[1] = len>>16;
3809a747e4fSDavid du Colombier buf[2] = len>>8;
3819a747e4fSDavid du Colombier buf[3] = len;
3829a747e4fSDavid du Colombier len += 4;
3839a747e4fSDavid du Colombier return write(fd, buf, len);
3849a747e4fSDavid du Colombier }
3859a747e4fSDavid du Colombier /*
3869a747e4fSDavid du Colombier *long
3879a747e4fSDavid du Colombier *niwrite(int fd, void *buf, long count)
3889a747e4fSDavid du Colombier *{
3899a747e4fSDavid du Colombier * char errbuf[ERRLEN];
3909a747e4fSDavid du Colombier * long n;
3919a747e4fSDavid du Colombier *
3929a747e4fSDavid du Colombier * for(;;){
3939a747e4fSDavid du Colombier * n = write(fd, buf, count);
3949a747e4fSDavid du Colombier * if(n < 0){
3959a747e4fSDavid du Colombier * errstr(errbuf);
3969a747e4fSDavid du Colombier * if(strcmp(errbuf, "interrupted") == 0)
3979a747e4fSDavid du Colombier * continue;
3989a747e4fSDavid du Colombier * clog("niwrite error: %s\n", errbuf);
3999a747e4fSDavid du Colombier * werrstr(errbuf);
4009a747e4fSDavid du Colombier * }
4019a747e4fSDavid du Colombier * break;
4029a747e4fSDavid du Colombier * }
4039a747e4fSDavid du Colombier * return n;
4049a747e4fSDavid du Colombier *}
4059a747e4fSDavid du Colombier */
4069a747e4fSDavid du Colombier long
niwrite(int fd,void * buf,long n)4079a747e4fSDavid du Colombier niwrite(int fd, void *buf, long n)
4089a747e4fSDavid du Colombier {
4096ab4d0ffSDavid du Colombier // int savalarm;
4109a747e4fSDavid du Colombier
4116ab4d0ffSDavid du Colombier // savalarm = alarm(0);
4129a747e4fSDavid du Colombier n = write(fd, buf, n);
4136ab4d0ffSDavid du Colombier // if(savalarm > 0)
4146ab4d0ffSDavid du Colombier // alarm(savalarm);
4159a747e4fSDavid du Colombier return n;
4169a747e4fSDavid du Colombier }
4179a747e4fSDavid du Colombier
4189a747e4fSDavid du Colombier typedef struct Namecache Namecache;
4199a747e4fSDavid du Colombier struct Namecache {
4209a747e4fSDavid du Colombier char dom[256];
4219a747e4fSDavid du Colombier ulong ipaddr;
4229a747e4fSDavid du Colombier Namecache *next;
4239a747e4fSDavid du Colombier };
4249a747e4fSDavid du Colombier
4259a747e4fSDavid du Colombier Namecache *dnscache;
4269a747e4fSDavid du Colombier
4279a747e4fSDavid du Colombier static Namecache*
domlookupl(void * name,int len)4289a747e4fSDavid du Colombier domlookupl(void *name, int len)
4299a747e4fSDavid du Colombier {
4309a747e4fSDavid du Colombier Namecache *n, **ln;
4319a747e4fSDavid du Colombier
4329a747e4fSDavid du Colombier if(len >= sizeof(n->dom))
4339a747e4fSDavid du Colombier return nil;
4349a747e4fSDavid du Colombier
4359a747e4fSDavid du Colombier for(ln=&dnscache, n=*ln; n; ln=&(*ln)->next, n=*ln) {
4369a747e4fSDavid du Colombier if(strncmp(n->dom, name, len) == 0 && n->dom[len] == 0) {
4379a747e4fSDavid du Colombier *ln = n->next;
4389a747e4fSDavid du Colombier n->next = dnscache;
4399a747e4fSDavid du Colombier dnscache = n;
4409a747e4fSDavid du Colombier return n;
4419a747e4fSDavid du Colombier }
4429a747e4fSDavid du Colombier }
4439a747e4fSDavid du Colombier return nil;
4449a747e4fSDavid du Colombier }
4459a747e4fSDavid du Colombier
4469a747e4fSDavid du Colombier static Namecache*
domlookup(void * name)4479a747e4fSDavid du Colombier domlookup(void *name)
4489a747e4fSDavid du Colombier {
4499a747e4fSDavid du Colombier return domlookupl(name, strlen(name));
4509a747e4fSDavid du Colombier }
4519a747e4fSDavid du Colombier
4529a747e4fSDavid du Colombier static Namecache*
iplookup(ulong ip)4539a747e4fSDavid du Colombier iplookup(ulong ip)
4549a747e4fSDavid du Colombier {
4559a747e4fSDavid du Colombier Namecache *n, **ln;
4569a747e4fSDavid du Colombier
4579a747e4fSDavid du Colombier for(ln=&dnscache, n=*ln; n; ln=&(*ln)->next, n=*ln) {
4589a747e4fSDavid du Colombier if(n->ipaddr == ip) {
4599a747e4fSDavid du Colombier *ln = n->next;
4609a747e4fSDavid du Colombier n->next = dnscache;
4619a747e4fSDavid du Colombier dnscache = n;
4629a747e4fSDavid du Colombier return n;
4639a747e4fSDavid du Colombier }
4649a747e4fSDavid du Colombier }
4659a747e4fSDavid du Colombier return nil;
4669a747e4fSDavid du Colombier }
4679a747e4fSDavid du Colombier
4689a747e4fSDavid du Colombier static Namecache*
addcacheentry(void * name,int len,ulong ip)4699a747e4fSDavid du Colombier addcacheentry(void *name, int len, ulong ip)
4709a747e4fSDavid du Colombier {
4719a747e4fSDavid du Colombier Namecache *n;
4729a747e4fSDavid du Colombier
4739a747e4fSDavid du Colombier if(len >= sizeof(n->dom))
4749a747e4fSDavid du Colombier return nil;
4759a747e4fSDavid du Colombier
4769a747e4fSDavid du Colombier n = malloc(sizeof(*n));
4779a747e4fSDavid du Colombier if(n == nil)
4789a747e4fSDavid du Colombier return nil;
4799a747e4fSDavid du Colombier strncpy(n->dom, name, len);
4809a747e4fSDavid du Colombier n->dom[len] = 0;
4819a747e4fSDavid du Colombier n->ipaddr = ip;
4829a747e4fSDavid du Colombier n->next = dnscache;
4839a747e4fSDavid du Colombier dnscache = n;
4849a747e4fSDavid du Colombier return nil;
4859a747e4fSDavid du Colombier }
4869a747e4fSDavid du Colombier
4879a747e4fSDavid du Colombier int
getdnsdom(ulong ip,char * name,int len)4889a747e4fSDavid du Colombier getdnsdom(ulong ip, char *name, int len)
4899a747e4fSDavid du Colombier {
49057837e0bSDavid du Colombier char buf[128];
4919a747e4fSDavid du Colombier Namecache *nc;
49257837e0bSDavid du Colombier char *p;
4939a747e4fSDavid du Colombier
4949a747e4fSDavid du Colombier if(nc=iplookup(ip)) {
4959a747e4fSDavid du Colombier strncpy(name, nc->dom, len);
4969a747e4fSDavid du Colombier name[len-1] = 0;
4979a747e4fSDavid du Colombier return 0;
4989a747e4fSDavid du Colombier }
4999a747e4fSDavid du Colombier clog("getdnsdom: %I\n", ip);
5009a747e4fSDavid du Colombier snprint(buf, sizeof buf, "%I", ip);
50157837e0bSDavid du Colombier p = csgetvalue("/net", "ip", buf, "dom", nil);
50257837e0bSDavid du Colombier if(p == nil)
5039a747e4fSDavid du Colombier return -1;
50457837e0bSDavid du Colombier strncpy(name, p, len-1);
5059a747e4fSDavid du Colombier name[len] = 0;
50657837e0bSDavid du Colombier free(p);
5079a747e4fSDavid du Colombier addcacheentry(name, strlen(name), ip);
5089a747e4fSDavid du Colombier return 0;
5099a747e4fSDavid du Colombier }
5109a747e4fSDavid du Colombier
5119a747e4fSDavid du Colombier int
getdom(ulong ip,char * dom,int len)5129a747e4fSDavid du Colombier getdom(ulong ip, char *dom, int len)
5139a747e4fSDavid du Colombier {
5149a747e4fSDavid du Colombier int i;
5159a747e4fSDavid du Colombier static char *prefix[] = { "", "gate-", "fddi-", "u-", 0 };
5169a747e4fSDavid du Colombier char **pr;
5179a747e4fSDavid du Colombier
5189a747e4fSDavid du Colombier if(getdnsdom(ip, dom, len)<0)
5199a747e4fSDavid du Colombier return -1;
5209a747e4fSDavid du Colombier
5219a747e4fSDavid du Colombier for(pr=prefix; *pr; pr++){
5229a747e4fSDavid du Colombier i = strlen(*pr);
5239a747e4fSDavid du Colombier if(strncmp(dom, *pr, i) == 0) {
5249a747e4fSDavid du Colombier memmove(dom, dom+i, len-i);
5259a747e4fSDavid du Colombier break;
5269a747e4fSDavid du Colombier }
5279a747e4fSDavid du Colombier }
5289a747e4fSDavid du Colombier return 0;
5299a747e4fSDavid du Colombier }
5309a747e4fSDavid du Colombier
5319a747e4fSDavid du Colombier #define MAXCACHE 64
5329a747e4fSDavid du Colombier
5339a747e4fSDavid du Colombier static Rpccache *head, *tail;
5349a747e4fSDavid du Colombier static int ncache;
5359a747e4fSDavid du Colombier
5369a747e4fSDavid du Colombier static void
cachereply(Rpccall * rp,void * buf,int len)5379a747e4fSDavid du Colombier cachereply(Rpccall *rp, void *buf, int len)
5389a747e4fSDavid du Colombier {
5399a747e4fSDavid du Colombier Rpccache *cp;
5409a747e4fSDavid du Colombier
5419a747e4fSDavid du Colombier if(nocache)
5429a747e4fSDavid du Colombier return;
5439a747e4fSDavid du Colombier
5449a747e4fSDavid du Colombier if(ncache >= MAXCACHE){
5459a747e4fSDavid du Colombier if(rpcdebug)
5469a747e4fSDavid du Colombier fprint(2, "%s: drop %I/%ld, xid %uld, len %d\n",
5479a747e4fSDavid du Colombier argv0, tail->host,
5489a747e4fSDavid du Colombier tail->port, tail->xid, tail->n);
5499a747e4fSDavid du Colombier tail = tail->prev;
5509a747e4fSDavid du Colombier free(tail->next);
5519a747e4fSDavid du Colombier tail->next = 0;
5529a747e4fSDavid du Colombier --ncache;
5539a747e4fSDavid du Colombier }
5549a747e4fSDavid du Colombier cp = malloc(sizeof(Rpccache)+len-4);
5559a747e4fSDavid du Colombier if(cp == 0){
5569a747e4fSDavid du Colombier clog("cachereply: malloc %d failed\n", len);
5579a747e4fSDavid du Colombier return;
5589a747e4fSDavid du Colombier }
5599a747e4fSDavid du Colombier ++ncache;
5609a747e4fSDavid du Colombier cp->prev = 0;
5619a747e4fSDavid du Colombier cp->next = head;
5629a747e4fSDavid du Colombier if(head)
5639a747e4fSDavid du Colombier head->prev = cp;
5649a747e4fSDavid du Colombier else
5659a747e4fSDavid du Colombier tail = cp;
5669a747e4fSDavid du Colombier head = cp;
5679a747e4fSDavid du Colombier cp->host = rp->host;
5689a747e4fSDavid du Colombier cp->port = rp->port;
5699a747e4fSDavid du Colombier cp->xid = rp->xid;
5709a747e4fSDavid du Colombier cp->n = len;
5719a747e4fSDavid du Colombier memmove(cp->data, buf, len);
5729a747e4fSDavid du Colombier if(rpcdebug)
5739a747e4fSDavid du Colombier fprint(2, "%s: cache %I/%ld, xid %uld, len %d\n",
5749a747e4fSDavid du Colombier argv0, cp->host, cp->port, cp->xid, cp->n);
5759a747e4fSDavid du Colombier }
5769a747e4fSDavid du Colombier
5779a747e4fSDavid du Colombier static int
replycache(int fd,Rpccall * rp,long (* writemsg)(int,void *,long))5789a747e4fSDavid du Colombier replycache(int fd, Rpccall *rp, long (*writemsg)(int, void*, long))
5799a747e4fSDavid du Colombier {
5809a747e4fSDavid du Colombier Rpccache *cp;
5819a747e4fSDavid du Colombier
5829a747e4fSDavid du Colombier for(cp=head; cp; cp=cp->next)
5839a747e4fSDavid du Colombier if(cp->host == rp->host &&
5849a747e4fSDavid du Colombier cp->port == rp->port &&
5859a747e4fSDavid du Colombier cp->xid == rp->xid)
5869a747e4fSDavid du Colombier break;
5879a747e4fSDavid du Colombier if(cp == 0)
5889a747e4fSDavid du Colombier return 0;
5899a747e4fSDavid du Colombier if(cp->prev){ /* move to front */
5909a747e4fSDavid du Colombier cp->prev->next = cp->next;
5919a747e4fSDavid du Colombier if(cp->next)
5929a747e4fSDavid du Colombier cp->next->prev = cp->prev;
5939a747e4fSDavid du Colombier else
5949a747e4fSDavid du Colombier tail = cp->prev;
5959a747e4fSDavid du Colombier cp->prev = 0;
5969a747e4fSDavid du Colombier cp->next = head;
5979a747e4fSDavid du Colombier head->prev = cp;
5989a747e4fSDavid du Colombier head = cp;
5999a747e4fSDavid du Colombier }
6009a747e4fSDavid du Colombier (*writemsg)(fd, cp->data, cp->n);
6019a747e4fSDavid du Colombier if(rpcdebug)
6029a747e4fSDavid du Colombier fprint(2, "%s: reply %I/%ld, xid %uld, len %d\n",
6039a747e4fSDavid du Colombier argv0, cp->host, cp->port, cp->xid, cp->n);
6049a747e4fSDavid du Colombier return 1;
6059a747e4fSDavid du Colombier }
6069a747e4fSDavid du Colombier
6079a747e4fSDavid du Colombier static int
Iconv(Fmt * f)6089a747e4fSDavid du Colombier Iconv(Fmt *f)
6099a747e4fSDavid du Colombier {
6109a747e4fSDavid du Colombier char buf[16];
6119a747e4fSDavid du Colombier ulong h;
6129a747e4fSDavid du Colombier
6139a747e4fSDavid du Colombier h = va_arg(f->args, ulong);
6149a747e4fSDavid du Colombier snprint(buf, sizeof buf, "%ld.%ld.%ld.%ld",
6159a747e4fSDavid du Colombier (h>>24)&0xff, (h>>16)&0xff,
6169a747e4fSDavid du Colombier (h>>8)&0xff, h&0xff);
6179a747e4fSDavid du Colombier return fmtstrcpy(f, buf);
6189a747e4fSDavid du Colombier }
619