19a747e4fSDavid du Colombier #include "all.h" 29a747e4fSDavid du Colombier #include <ndb.h> 39a747e4fSDavid du Colombier #include <ip.h> 49a747e4fSDavid du Colombier 59a747e4fSDavid du Colombier static int alarmflag; 69a747e4fSDavid du Colombier 79a747e4fSDavid du Colombier static int Iconv(Fmt*); 89a747e4fSDavid du Colombier static void openudp(int); 99a747e4fSDavid du Colombier static void cachereply(Rpccall*, void*, int); 109a747e4fSDavid du Colombier static int replycache(int, Rpccall*, long (*)(int, void*, long)); 119a747e4fSDavid du Colombier static void udpserver(int, Progmap*); 129a747e4fSDavid du Colombier static void tcpserver(int, Progmap*); 13*f27a9a5aSDavid du Colombier static void getendpoints(Udphdr*, char*); 149a747e4fSDavid du Colombier static long readtcp(int, void*, long); 159a747e4fSDavid du Colombier static long writetcp(int, void*, long); 169a747e4fSDavid du Colombier static int servemsg(int, long (*)(int, void*, long), long (*)(int, void*, long), 179a747e4fSDavid du Colombier int, Progmap*); 189a747e4fSDavid du Colombier void (*rpcalarm)(void); 199a747e4fSDavid du Colombier int rpcdebug; 209a747e4fSDavid du Colombier int rejectall; 219a747e4fSDavid du Colombier int p9debug; 229a747e4fSDavid du Colombier 239a747e4fSDavid du Colombier int nocache; 249a747e4fSDavid du Colombier 259a747e4fSDavid du Colombier uchar buf[9000]; 269a747e4fSDavid du Colombier uchar rbuf[9000]; 279a747e4fSDavid du Colombier uchar resultbuf[9000]; 289a747e4fSDavid du Colombier 29363b328dSDavid du Colombier static int tcp; 30363b328dSDavid du Colombier 31363b328dSDavid du Colombier char *commonopts = "[-9CDrtv]"; /* for usage() messages */ 32363b328dSDavid du Colombier 33363b328dSDavid du Colombier /* 34363b328dSDavid du Colombier * this recognises common, nominally rcp-related options. 35363b328dSDavid du Colombier * they may not take arguments. 36363b328dSDavid du Colombier */ 37363b328dSDavid du Colombier int 38363b328dSDavid du Colombier argopt(int c) 39363b328dSDavid du Colombier { 40363b328dSDavid du Colombier switch(c){ 41363b328dSDavid du Colombier case '9': 42363b328dSDavid du Colombier ++p9debug; 43363b328dSDavid du Colombier return 0; 44363b328dSDavid du Colombier case 'C': 45363b328dSDavid du Colombier ++nocache; 46363b328dSDavid du Colombier return 0; 47363b328dSDavid du Colombier case 'D': 48363b328dSDavid du Colombier ++rpcdebug; 49363b328dSDavid du Colombier return 0; 50363b328dSDavid du Colombier case 'r': 51363b328dSDavid du Colombier ++rejectall; 52363b328dSDavid du Colombier return 0; 53363b328dSDavid du Colombier case 't': 54363b328dSDavid du Colombier tcp = 1; 55363b328dSDavid du Colombier return 0; 56363b328dSDavid du Colombier case 'v': 57363b328dSDavid du Colombier ++chatty; 58363b328dSDavid du Colombier return 0; 59363b328dSDavid du Colombier default: 60363b328dSDavid du Colombier return -1; 61363b328dSDavid du Colombier } 62363b328dSDavid du Colombier } 63363b328dSDavid du Colombier 64363b328dSDavid du Colombier /* 65363b328dSDavid du Colombier * all option parsing is now done in (*pg->init)(), which can call back 66363b328dSDavid du Colombier * here to argopt for common options. 67363b328dSDavid du Colombier */ 689a747e4fSDavid du Colombier void 699a747e4fSDavid du Colombier server(int argc, char **argv, int myport, Progmap *progmap) 709a747e4fSDavid du Colombier { 719a747e4fSDavid du Colombier Progmap *pg; 729a747e4fSDavid du Colombier 739a747e4fSDavid du Colombier fmtinstall('I', Iconv); 749a747e4fSDavid du Colombier fmtinstall('F', fcallfmt); 759a747e4fSDavid du Colombier fmtinstall('D', dirfmt); 769a747e4fSDavid du Colombier 779a747e4fSDavid du Colombier switch(rfork(RFNOWAIT|RFENVG|RFNAMEG|RFNOTEG|RFFDG|RFPROC)){ 789a747e4fSDavid du Colombier case -1: 799a747e4fSDavid du Colombier panic("fork"); 809a747e4fSDavid du Colombier default: 819a747e4fSDavid du Colombier _exits(0); 829a747e4fSDavid du Colombier case 0: 839a747e4fSDavid du Colombier break; 849a747e4fSDavid du Colombier } 856ab4d0ffSDavid du Colombier 866ab4d0ffSDavid du Colombier switch(rfork(RFMEM|RFPROC)){ 876ab4d0ffSDavid du Colombier case 0: 886ab4d0ffSDavid du Colombier for(;;){ 896ab4d0ffSDavid du Colombier sleep(30*1000); 906ab4d0ffSDavid du Colombier alarmflag = 1; 916ab4d0ffSDavid du Colombier } 926ab4d0ffSDavid du Colombier case -1: 936ab4d0ffSDavid du Colombier sysfatal("rfork: %r"); 946ab4d0ffSDavid du Colombier } 956ab4d0ffSDavid du Colombier 969a747e4fSDavid du Colombier for(pg=progmap; pg->init; pg++) 97363b328dSDavid du Colombier (*pg->init)(argc, argv); 989a747e4fSDavid du Colombier if(tcp) 999a747e4fSDavid du Colombier tcpserver(myport, progmap); 1009a747e4fSDavid du Colombier else 1019a747e4fSDavid du Colombier udpserver(myport, progmap); 1029a747e4fSDavid du Colombier } 1039a747e4fSDavid du Colombier 1049a747e4fSDavid du Colombier static void 1059a747e4fSDavid du Colombier udpserver(int myport, Progmap *progmap) 1069a747e4fSDavid du Colombier { 1079a747e4fSDavid du Colombier char service[128]; 1089a747e4fSDavid du Colombier char data[128]; 1099a747e4fSDavid du Colombier char devdir[40]; 1109a747e4fSDavid du Colombier int ctlfd, datafd; 1119a747e4fSDavid du Colombier 1129a747e4fSDavid du Colombier snprint(service, sizeof service, "udp!*!%d", myport); 1139a747e4fSDavid du Colombier ctlfd = announce(service, devdir); 1149a747e4fSDavid du Colombier if(ctlfd < 0) 1159a747e4fSDavid du Colombier panic("can't announce %s: %r\n", service); 1169a747e4fSDavid du Colombier if(fprint(ctlfd, "headers") < 0) 1179a747e4fSDavid du Colombier panic("can't set header mode: %r\n"); 1189a747e4fSDavid du Colombier 1199a747e4fSDavid du Colombier snprint(data, sizeof data, "%s/data", devdir); 1209a747e4fSDavid du Colombier datafd = open(data, ORDWR); 1219a747e4fSDavid du Colombier if(datafd < 0) 1229a747e4fSDavid du Colombier panic("can't open udp data: %r\n"); 1239a747e4fSDavid du Colombier close(ctlfd); 1249a747e4fSDavid du Colombier 1259a747e4fSDavid du Colombier chatsrv(0); 1269a747e4fSDavid du Colombier clog("%s: listening to port %d\n", argv0, myport); 127*f27a9a5aSDavid du Colombier while (servemsg(datafd, read, write, myport, progmap) >= 0) 128*f27a9a5aSDavid du Colombier continue; 1299a747e4fSDavid du Colombier exits(0); 1309a747e4fSDavid du Colombier } 1319a747e4fSDavid du Colombier 1329a747e4fSDavid du Colombier static void 1339a747e4fSDavid du Colombier tcpserver(int myport, Progmap *progmap) 1349a747e4fSDavid du Colombier { 1359a747e4fSDavid du Colombier char adir[40]; 1369a747e4fSDavid du Colombier char ldir[40]; 1379a747e4fSDavid du Colombier char ds[40]; 1389a747e4fSDavid du Colombier int actl, lctl, data; 1399a747e4fSDavid du Colombier 1409a747e4fSDavid du Colombier snprint(ds, sizeof ds, "tcp!*!%d", myport); 1419a747e4fSDavid du Colombier chatsrv(0); 1429a747e4fSDavid du Colombier actl = -1; 1439a747e4fSDavid du Colombier for(;;){ 1449a747e4fSDavid du Colombier if(actl < 0){ 1459a747e4fSDavid du Colombier actl = announce(ds, adir); 1469a747e4fSDavid du Colombier if(actl < 0){ 1479a747e4fSDavid du Colombier clog("%s: listening to tcp port %d\n", 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 172*f27a9a5aSDavid du Colombier getendpoints((Udphdr*)buf, ldir); 1739a747e4fSDavid du Colombier 1749a747e4fSDavid du Colombier for(;;){ 1759a747e4fSDavid du Colombier if(servemsg(data, readtcp, writetcp, myport, progmap) < 0) 1769a747e4fSDavid du Colombier break; 1779a747e4fSDavid du Colombier } 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 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 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 3319a747e4fSDavid du Colombier static void 332*f27a9a5aSDavid du Colombier getendpoints(Udphdr *ep, char *dir) 3339a747e4fSDavid du Colombier { 3349a747e4fSDavid du Colombier getendpoint(dir, "local", ep->laddr, ep->lport); 3359a747e4fSDavid du Colombier getendpoint(dir, "remote", ep->raddr, ep->rport); 3369a747e4fSDavid du Colombier } 3379a747e4fSDavid du Colombier 3389a747e4fSDavid du Colombier static long 3399a747e4fSDavid du Colombier readtcp(int fd, void *vbuf, long blen) 3409a747e4fSDavid du Colombier { 3419a747e4fSDavid du Colombier uchar mk[4]; 3429a747e4fSDavid du Colombier int n, m, sofar; 3439a747e4fSDavid du Colombier ulong done; 3449a747e4fSDavid du Colombier char *buf; 3459a747e4fSDavid du Colombier 3469a747e4fSDavid du Colombier buf = vbuf; 347*f27a9a5aSDavid du Colombier buf += Udphdrsize; 348*f27a9a5aSDavid du Colombier blen -= Udphdrsize; 3499a747e4fSDavid du Colombier 3509a747e4fSDavid du Colombier done = 0; 3519a747e4fSDavid du Colombier for(sofar = 0; !done; sofar += n){ 3529a747e4fSDavid du Colombier m = readn(fd, mk, 4); 3539a747e4fSDavid du Colombier if(m < 4) 3549a747e4fSDavid du Colombier return 0; 3559a747e4fSDavid du Colombier done = (mk[0]<<24)|(mk[1]<<16)|(mk[2]<<8)|mk[3]; 3569a747e4fSDavid du Colombier m = done & 0x7fffffff; 3579a747e4fSDavid du Colombier done &= 0x80000000; 3589a747e4fSDavid du Colombier if(m > blen-sofar) 3599a747e4fSDavid du Colombier return -1; 3609a747e4fSDavid du Colombier n = readn(fd, buf+sofar, m); 3619a747e4fSDavid du Colombier if(m != n) 3629a747e4fSDavid du Colombier return 0; 3639a747e4fSDavid du Colombier } 364*f27a9a5aSDavid du Colombier return sofar + Udphdrsize; 3659a747e4fSDavid du Colombier } 3669a747e4fSDavid du Colombier 3679a747e4fSDavid du Colombier static long 3689a747e4fSDavid du Colombier writetcp(int fd, void *vbuf, long len) 3699a747e4fSDavid du Colombier { 3709a747e4fSDavid du Colombier char *buf; 3719a747e4fSDavid du Colombier 3729a747e4fSDavid du Colombier buf = vbuf; 373*f27a9a5aSDavid du Colombier buf += Udphdrsize; 374*f27a9a5aSDavid du Colombier len -= Udphdrsize; 3759a747e4fSDavid du Colombier 3769a747e4fSDavid du Colombier buf -= 4; 3779a747e4fSDavid du Colombier buf[0] = 0x80 | (len>>24); 3789a747e4fSDavid du Colombier buf[1] = len>>16; 3799a747e4fSDavid du Colombier buf[2] = len>>8; 3809a747e4fSDavid du Colombier buf[3] = len; 3819a747e4fSDavid du Colombier len += 4; 3829a747e4fSDavid du Colombier return write(fd, buf, len); 3839a747e4fSDavid du Colombier } 3849a747e4fSDavid du Colombier /* 3859a747e4fSDavid du Colombier *long 3869a747e4fSDavid du Colombier *niwrite(int fd, void *buf, long count) 3879a747e4fSDavid du Colombier *{ 3889a747e4fSDavid du Colombier * char errbuf[ERRLEN]; 3899a747e4fSDavid du Colombier * long n; 3909a747e4fSDavid du Colombier * 3919a747e4fSDavid du Colombier * for(;;){ 3929a747e4fSDavid du Colombier * n = write(fd, buf, count); 3939a747e4fSDavid du Colombier * if(n < 0){ 3949a747e4fSDavid du Colombier * errstr(errbuf); 3959a747e4fSDavid du Colombier * if(strcmp(errbuf, "interrupted") == 0) 3969a747e4fSDavid du Colombier * continue; 3979a747e4fSDavid du Colombier * clog("niwrite error: %s\n", errbuf); 3989a747e4fSDavid du Colombier * werrstr(errbuf); 3999a747e4fSDavid du Colombier * } 4009a747e4fSDavid du Colombier * break; 4019a747e4fSDavid du Colombier * } 4029a747e4fSDavid du Colombier * return n; 4039a747e4fSDavid du Colombier *} 4049a747e4fSDavid du Colombier */ 4059a747e4fSDavid du Colombier long 4069a747e4fSDavid du Colombier niwrite(int fd, void *buf, long n) 4079a747e4fSDavid du Colombier { 4086ab4d0ffSDavid du Colombier // int savalarm; 4099a747e4fSDavid du Colombier 4106ab4d0ffSDavid du Colombier // savalarm = alarm(0); 4119a747e4fSDavid du Colombier n = write(fd, buf, n); 4126ab4d0ffSDavid du Colombier // if(savalarm > 0) 4136ab4d0ffSDavid du Colombier // alarm(savalarm); 4149a747e4fSDavid du Colombier return n; 4159a747e4fSDavid du Colombier } 4169a747e4fSDavid du Colombier 4179a747e4fSDavid du Colombier typedef struct Namecache Namecache; 4189a747e4fSDavid du Colombier struct Namecache { 4199a747e4fSDavid du Colombier char dom[256]; 4209a747e4fSDavid du Colombier ulong ipaddr; 4219a747e4fSDavid du Colombier Namecache *next; 4229a747e4fSDavid du Colombier }; 4239a747e4fSDavid du Colombier 4249a747e4fSDavid du Colombier Namecache *dnscache; 4259a747e4fSDavid du Colombier 4269a747e4fSDavid du Colombier static Namecache* 4279a747e4fSDavid du Colombier domlookupl(void *name, int len) 4289a747e4fSDavid du Colombier { 4299a747e4fSDavid du Colombier Namecache *n, **ln; 4309a747e4fSDavid du Colombier 4319a747e4fSDavid du Colombier if(len >= sizeof(n->dom)) 4329a747e4fSDavid du Colombier return nil; 4339a747e4fSDavid du Colombier 4349a747e4fSDavid du Colombier for(ln=&dnscache, n=*ln; n; ln=&(*ln)->next, n=*ln) { 4359a747e4fSDavid du Colombier if(strncmp(n->dom, name, len) == 0 && n->dom[len] == 0) { 4369a747e4fSDavid du Colombier *ln = n->next; 4379a747e4fSDavid du Colombier n->next = dnscache; 4389a747e4fSDavid du Colombier dnscache = n; 4399a747e4fSDavid du Colombier return n; 4409a747e4fSDavid du Colombier } 4419a747e4fSDavid du Colombier } 4429a747e4fSDavid du Colombier return nil; 4439a747e4fSDavid du Colombier } 4449a747e4fSDavid du Colombier 4459a747e4fSDavid du Colombier static Namecache* 4469a747e4fSDavid du Colombier domlookup(void *name) 4479a747e4fSDavid du Colombier { 4489a747e4fSDavid du Colombier return domlookupl(name, strlen(name)); 4499a747e4fSDavid du Colombier } 4509a747e4fSDavid du Colombier 4519a747e4fSDavid du Colombier static Namecache* 4529a747e4fSDavid du Colombier iplookup(ulong ip) 4539a747e4fSDavid du Colombier { 4549a747e4fSDavid du Colombier Namecache *n, **ln; 4559a747e4fSDavid du Colombier 4569a747e4fSDavid du Colombier for(ln=&dnscache, n=*ln; n; ln=&(*ln)->next, n=*ln) { 4579a747e4fSDavid du Colombier if(n->ipaddr == ip) { 4589a747e4fSDavid du Colombier *ln = n->next; 4599a747e4fSDavid du Colombier n->next = dnscache; 4609a747e4fSDavid du Colombier dnscache = n; 4619a747e4fSDavid du Colombier return n; 4629a747e4fSDavid du Colombier } 4639a747e4fSDavid du Colombier } 4649a747e4fSDavid du Colombier return nil; 4659a747e4fSDavid du Colombier } 4669a747e4fSDavid du Colombier 4679a747e4fSDavid du Colombier static Namecache* 4689a747e4fSDavid du Colombier addcacheentry(void *name, int len, ulong ip) 4699a747e4fSDavid du Colombier { 4709a747e4fSDavid du Colombier Namecache *n; 4719a747e4fSDavid du Colombier 4729a747e4fSDavid du Colombier if(len >= sizeof(n->dom)) 4739a747e4fSDavid du Colombier return nil; 4749a747e4fSDavid du Colombier 4759a747e4fSDavid du Colombier n = malloc(sizeof(*n)); 4769a747e4fSDavid du Colombier if(n == nil) 4779a747e4fSDavid du Colombier return nil; 4789a747e4fSDavid du Colombier strncpy(n->dom, name, len); 4799a747e4fSDavid du Colombier n->dom[len] = 0; 4809a747e4fSDavid du Colombier n->ipaddr = ip; 4819a747e4fSDavid du Colombier n->next = dnscache; 4829a747e4fSDavid du Colombier dnscache = n; 4839a747e4fSDavid du Colombier return nil; 4849a747e4fSDavid du Colombier } 4859a747e4fSDavid du Colombier 4869a747e4fSDavid du Colombier int 4879a747e4fSDavid du Colombier getdnsdom(ulong ip, char *name, int len) 4889a747e4fSDavid du Colombier { 48957837e0bSDavid du Colombier char buf[128]; 4909a747e4fSDavid du Colombier Namecache *nc; 49157837e0bSDavid du Colombier char *p; 4929a747e4fSDavid du Colombier 4939a747e4fSDavid du Colombier if(nc=iplookup(ip)) { 4949a747e4fSDavid du Colombier strncpy(name, nc->dom, len); 4959a747e4fSDavid du Colombier name[len-1] = 0; 4969a747e4fSDavid du Colombier return 0; 4979a747e4fSDavid du Colombier } 4989a747e4fSDavid du Colombier clog("getdnsdom: %I\n", ip); 4999a747e4fSDavid du Colombier snprint(buf, sizeof buf, "%I", ip); 50057837e0bSDavid du Colombier p = csgetvalue("/net", "ip", buf, "dom", nil); 50157837e0bSDavid du Colombier if(p == nil) 5029a747e4fSDavid du Colombier return -1; 50357837e0bSDavid du Colombier strncpy(name, p, len-1); 5049a747e4fSDavid du Colombier name[len] = 0; 50557837e0bSDavid du Colombier free(p); 5069a747e4fSDavid du Colombier addcacheentry(name, strlen(name), ip); 5079a747e4fSDavid du Colombier return 0; 5089a747e4fSDavid du Colombier } 5099a747e4fSDavid du Colombier 5109a747e4fSDavid du Colombier int 5119a747e4fSDavid du Colombier getdom(ulong ip, char *dom, int len) 5129a747e4fSDavid du Colombier { 5139a747e4fSDavid du Colombier int i; 5149a747e4fSDavid du Colombier static char *prefix[] = { "", "gate-", "fddi-", "u-", 0 }; 5159a747e4fSDavid du Colombier char **pr; 5169a747e4fSDavid du Colombier 5179a747e4fSDavid du Colombier if(getdnsdom(ip, dom, len)<0) 5189a747e4fSDavid du Colombier return -1; 5199a747e4fSDavid du Colombier 5209a747e4fSDavid du Colombier for(pr=prefix; *pr; pr++){ 5219a747e4fSDavid du Colombier i = strlen(*pr); 5229a747e4fSDavid du Colombier if(strncmp(dom, *pr, i) == 0) { 5239a747e4fSDavid du Colombier memmove(dom, dom+i, len-i); 5249a747e4fSDavid du Colombier break; 5259a747e4fSDavid du Colombier } 5269a747e4fSDavid du Colombier } 5279a747e4fSDavid du Colombier return 0; 5289a747e4fSDavid du Colombier } 5299a747e4fSDavid du Colombier 5309a747e4fSDavid du Colombier #define MAXCACHE 64 5319a747e4fSDavid du Colombier 5329a747e4fSDavid du Colombier static Rpccache *head, *tail; 5339a747e4fSDavid du Colombier static int ncache; 5349a747e4fSDavid du Colombier 5359a747e4fSDavid du Colombier static void 5369a747e4fSDavid du Colombier cachereply(Rpccall *rp, void *buf, int len) 5379a747e4fSDavid du Colombier { 5389a747e4fSDavid du Colombier Rpccache *cp; 5399a747e4fSDavid du Colombier 5409a747e4fSDavid du Colombier if(nocache) 5419a747e4fSDavid du Colombier return; 5429a747e4fSDavid du Colombier 5439a747e4fSDavid du Colombier if(ncache >= MAXCACHE){ 5449a747e4fSDavid du Colombier if(rpcdebug) 5459a747e4fSDavid du Colombier fprint(2, "%s: drop %I/%ld, xid %uld, len %d\n", 5469a747e4fSDavid du Colombier argv0, tail->host, 5479a747e4fSDavid du Colombier tail->port, tail->xid, tail->n); 5489a747e4fSDavid du Colombier tail = tail->prev; 5499a747e4fSDavid du Colombier free(tail->next); 5509a747e4fSDavid du Colombier tail->next = 0; 5519a747e4fSDavid du Colombier --ncache; 5529a747e4fSDavid du Colombier } 5539a747e4fSDavid du Colombier cp = malloc(sizeof(Rpccache)+len-4); 5549a747e4fSDavid du Colombier if(cp == 0){ 5559a747e4fSDavid du Colombier clog("cachereply: malloc %d failed\n", len); 5569a747e4fSDavid du Colombier return; 5579a747e4fSDavid du Colombier } 5589a747e4fSDavid du Colombier ++ncache; 5599a747e4fSDavid du Colombier cp->prev = 0; 5609a747e4fSDavid du Colombier cp->next = head; 5619a747e4fSDavid du Colombier if(head) 5629a747e4fSDavid du Colombier head->prev = cp; 5639a747e4fSDavid du Colombier else 5649a747e4fSDavid du Colombier tail = cp; 5659a747e4fSDavid du Colombier head = cp; 5669a747e4fSDavid du Colombier cp->host = rp->host; 5679a747e4fSDavid du Colombier cp->port = rp->port; 5689a747e4fSDavid du Colombier cp->xid = rp->xid; 5699a747e4fSDavid du Colombier cp->n = len; 5709a747e4fSDavid du Colombier memmove(cp->data, buf, len); 5719a747e4fSDavid du Colombier if(rpcdebug) 5729a747e4fSDavid du Colombier fprint(2, "%s: cache %I/%ld, xid %uld, len %d\n", 5739a747e4fSDavid du Colombier argv0, cp->host, cp->port, cp->xid, cp->n); 5749a747e4fSDavid du Colombier } 5759a747e4fSDavid du Colombier 5769a747e4fSDavid du Colombier static int 5779a747e4fSDavid du Colombier replycache(int fd, Rpccall *rp, long (*writemsg)(int, void*, long)) 5789a747e4fSDavid du Colombier { 5799a747e4fSDavid du Colombier Rpccache *cp; 5809a747e4fSDavid du Colombier 5819a747e4fSDavid du Colombier for(cp=head; cp; cp=cp->next) 5829a747e4fSDavid du Colombier if(cp->host == rp->host && 5839a747e4fSDavid du Colombier cp->port == rp->port && 5849a747e4fSDavid du Colombier cp->xid == rp->xid) 5859a747e4fSDavid du Colombier break; 5869a747e4fSDavid du Colombier if(cp == 0) 5879a747e4fSDavid du Colombier return 0; 5889a747e4fSDavid du Colombier if(cp->prev){ /* move to front */ 5899a747e4fSDavid du Colombier cp->prev->next = cp->next; 5909a747e4fSDavid du Colombier if(cp->next) 5919a747e4fSDavid du Colombier cp->next->prev = cp->prev; 5929a747e4fSDavid du Colombier else 5939a747e4fSDavid du Colombier tail = cp->prev; 5949a747e4fSDavid du Colombier cp->prev = 0; 5959a747e4fSDavid du Colombier cp->next = head; 5969a747e4fSDavid du Colombier head->prev = cp; 5979a747e4fSDavid du Colombier head = cp; 5989a747e4fSDavid du Colombier } 5999a747e4fSDavid du Colombier (*writemsg)(fd, cp->data, cp->n); 6009a747e4fSDavid du Colombier if(rpcdebug) 6019a747e4fSDavid du Colombier fprint(2, "%s: reply %I/%ld, xid %uld, len %d\n", 6029a747e4fSDavid du Colombier argv0, cp->host, cp->port, cp->xid, cp->n); 6039a747e4fSDavid du Colombier return 1; 6049a747e4fSDavid du Colombier } 6059a747e4fSDavid du Colombier 6069a747e4fSDavid du Colombier static int 6079a747e4fSDavid du Colombier Iconv(Fmt *f) 6089a747e4fSDavid du Colombier { 6099a747e4fSDavid du Colombier char buf[16]; 6109a747e4fSDavid du Colombier ulong h; 6119a747e4fSDavid du Colombier 6129a747e4fSDavid du Colombier h = va_arg(f->args, ulong); 6139a747e4fSDavid du Colombier snprint(buf, sizeof buf, "%ld.%ld.%ld.%ld", 6149a747e4fSDavid du Colombier (h>>24)&0xff, (h>>16)&0xff, 6159a747e4fSDavid du Colombier (h>>8)&0xff, h&0xff); 6169a747e4fSDavid du Colombier return fmtstrcpy(f, buf); 6179a747e4fSDavid du Colombier } 618