server.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. #include "all.h"
  2. #include <ndb.h>
  3. #include <ip.h>
  4. static int alarmflag;
  5. static int Iconv(Fmt*);
  6. static void openudp(int);
  7. static void cachereply(Rpccall*, void*, int);
  8. static int replycache(int, Rpccall*, long (*)(int, void*, long));
  9. static void udpserver(int, Progmap*);
  10. static void tcpserver(int, Progmap*);
  11. static void getendpoints(OUdphdr*, char*);
  12. static long readtcp(int, void*, long);
  13. static long writetcp(int, void*, long);
  14. static int servemsg(int, long (*)(int, void*, long), long (*)(int, void*, long),
  15. int, Progmap*);
  16. void (*rpcalarm)(void);
  17. int rpcdebug;
  18. int rejectall;
  19. int p9debug;
  20. int nocache;
  21. uchar buf[9000];
  22. uchar rbuf[9000];
  23. uchar resultbuf[9000];
  24. void
  25. server(int argc, char **argv, int myport, Progmap *progmap)
  26. {
  27. int Argc=argc; char **Argv=argv;
  28. int tcp = 0;
  29. Progmap *pg;
  30. fmtinstall('I', Iconv);
  31. fmtinstall('F', fcallfmt);
  32. fmtinstall('D', dirfmt);
  33. switch(rfork(RFNOWAIT|RFENVG|RFNAMEG|RFNOTEG|RFFDG|RFPROC)){
  34. case -1:
  35. panic("fork");
  36. default:
  37. _exits(0);
  38. case 0:
  39. break;
  40. }
  41. ARGBEGIN{
  42. case '9':
  43. ++p9debug;
  44. break;
  45. case 'r':
  46. ++rejectall;
  47. break;
  48. case 'v':
  49. ++chatty;
  50. break;
  51. case 'D':
  52. ++rpcdebug;
  53. break;
  54. case 'C':
  55. ++nocache;
  56. break;
  57. case 't':
  58. tcp = 1;
  59. break;
  60. }ARGEND
  61. switch(rfork(RFMEM|RFPROC)){
  62. case 0:
  63. for(;;){
  64. sleep(30*1000);
  65. alarmflag = 1;
  66. }
  67. case -1:
  68. sysfatal("rfork: %r");
  69. }
  70. for(pg=progmap; pg->init; pg++)
  71. (*pg->init)(Argc, Argv);
  72. if(tcp)
  73. tcpserver(myport, progmap);
  74. else
  75. udpserver(myport, progmap);
  76. }
  77. static void
  78. udpserver(int myport, Progmap *progmap)
  79. {
  80. char service[128];
  81. char data[128];
  82. char devdir[40];
  83. int ctlfd, datafd;
  84. snprint(service, sizeof service, "udp!*!%d", myport);
  85. ctlfd = announce(service, devdir);
  86. if(ctlfd < 0)
  87. panic("can't announce %s: %r\n", service);
  88. if(fprint(ctlfd, "headers") < 0)
  89. panic("can't set header mode: %r\n");
  90. fprint(ctlfd, "oldheaders");
  91. snprint(data, sizeof data, "%s/data", devdir);
  92. datafd = open(data, ORDWR);
  93. if(datafd < 0)
  94. panic("can't open udp data: %r\n");
  95. close(ctlfd);
  96. chatsrv(0);
  97. clog("%s: listening to port %d\n", argv0, myport);
  98. for(;;){
  99. if(servemsg(datafd, read, write, myport, progmap) < 0)
  100. break;
  101. }
  102. exits(0);
  103. }
  104. static void
  105. tcpserver(int myport, Progmap *progmap)
  106. {
  107. char adir[40];
  108. char ldir[40];
  109. char ds[40];
  110. int actl, lctl, data;
  111. snprint(ds, sizeof ds, "tcp!*!%d", myport);
  112. chatsrv(0);
  113. actl = -1;
  114. for(;;){
  115. if(actl < 0){
  116. actl = announce(ds, adir);
  117. if(actl < 0){
  118. clog("%s: listening to tcp port %d\n", argv0, myport);
  119. clog("announcing: %r");
  120. break;
  121. }
  122. }
  123. lctl = listen(adir, ldir);
  124. if(lctl < 0){
  125. close(actl);
  126. actl = -1;
  127. continue;
  128. }
  129. switch(fork()){
  130. case -1:
  131. clog("%s!%d: %r\n", argv0, myport);
  132. /* fall through */
  133. default:
  134. close(lctl);
  135. continue;
  136. case 0:
  137. close(actl);
  138. data = accept(lctl, ldir);
  139. close(lctl);
  140. if(data < 0)
  141. exits(0);
  142. getendpoints((OUdphdr*)buf, ldir);
  143. for(;;){
  144. if(servemsg(data, readtcp, writetcp, myport, progmap) < 0)
  145. break;
  146. }
  147. close(data);
  148. exits(0);
  149. }
  150. }
  151. exits(0);
  152. }
  153. static int
  154. servemsg(int fd, long (*readmsg)(int, void*, long), long (*writemsg)(int, void*, long),
  155. int myport, Progmap * progmap)
  156. {
  157. int i, n, nreply;
  158. Rpccall rcall, rreply;
  159. int vlo, vhi;
  160. Progmap *pg;
  161. Procmap *pp;
  162. char errbuf[ERRMAX];
  163. if(alarmflag){
  164. alarmflag = 0;
  165. if(rpcalarm)
  166. (*rpcalarm)();
  167. }
  168. n = (*readmsg)(fd, buf, sizeof buf);
  169. if(n < 0){
  170. errstr(errbuf, sizeof errbuf);
  171. if(strcmp(errbuf, "interrupted") == 0)
  172. return 0;
  173. clog("port %d: error: %s\n", myport, errbuf);
  174. return -1;
  175. }
  176. if(n == 0){
  177. clog("port %d: EOF\n", myport);
  178. return -1;
  179. }
  180. if(rpcdebug == 1)
  181. fprint(2, "%s: rpc from %d.%d.%d.%d/%d\n",
  182. argv0, buf[12], buf[13], buf[14], buf[15],
  183. (buf[32]<<8)|buf[33]);
  184. i = rpcM2S(buf, &rcall, n);
  185. if(i != 0){
  186. clog("udp port %d: message format error %d\n",
  187. myport, i);
  188. return 0;
  189. }
  190. if(rpcdebug > 1)
  191. rpcprint(2, &rcall);
  192. if(rcall.mtype != CALL)
  193. return 0;
  194. if(replycache(fd, &rcall, writemsg))
  195. return 0;
  196. nreply = 0;
  197. rreply.host = rcall.host;
  198. rreply.port = rcall.port;
  199. rreply.lhost = rcall.lhost;
  200. rreply.lport = rcall.lport;
  201. rreply.xid = rcall.xid;
  202. rreply.mtype = REPLY;
  203. if(rcall.rpcvers != 2){
  204. rreply.stat = MSG_DENIED;
  205. rreply.rstat = RPC_MISMATCH;
  206. rreply.rlow = 2;
  207. rreply.rhigh = 2;
  208. goto send_reply;
  209. }
  210. if(rejectall){
  211. rreply.stat = MSG_DENIED;
  212. rreply.rstat = AUTH_ERROR;
  213. rreply.authstat = AUTH_TOOWEAK;
  214. goto send_reply;
  215. }
  216. i = n - (((uchar *)rcall.args) - buf);
  217. if(rpcdebug > 1)
  218. fprint(2, "arg size = %d\n", i);
  219. rreply.stat = MSG_ACCEPTED;
  220. rreply.averf.flavor = 0;
  221. rreply.averf.count = 0;
  222. rreply.results = resultbuf;
  223. vlo = 0x7fffffff;
  224. vhi = -1;
  225. for(pg=progmap; pg->pmap; pg++){
  226. if(pg->progno != rcall.prog)
  227. continue;
  228. if(pg->vers == rcall.vers)
  229. break;
  230. if(pg->vers < vlo)
  231. vlo = pg->vers;
  232. if(pg->vers > vhi)
  233. vhi = pg->vers;
  234. }
  235. if(pg->pmap == 0){
  236. if(vhi < 0)
  237. rreply.astat = PROG_UNAVAIL;
  238. else{
  239. rreply.astat = PROG_MISMATCH;
  240. rreply.plow = vlo;
  241. rreply.phigh = vhi;
  242. }
  243. goto send_reply;
  244. }
  245. for(pp = pg->pmap; pp->procp; pp++)
  246. if(rcall.proc == pp->procno){
  247. if(rpcdebug > 1)
  248. fprint(2, "process %d\n", pp->procno);
  249. rreply.astat = SUCCESS;
  250. nreply = (*pp->procp)(i, &rcall, &rreply);
  251. goto send_reply;
  252. }
  253. rreply.astat = PROC_UNAVAIL;
  254. send_reply:
  255. if(nreply >= 0){
  256. i = rpcS2M(&rreply, nreply, rbuf);
  257. if(rpcdebug > 1)
  258. rpcprint(2, &rreply);
  259. (*writemsg)(fd, rbuf, i);
  260. cachereply(&rreply, rbuf, i);
  261. }
  262. return 0;
  263. }
  264. static void
  265. getendpoint(char *dir, char *file, uchar *addr, uchar *port)
  266. {
  267. int fd, n;
  268. char buf[128];
  269. char *sys, *serv;
  270. sys = serv = 0;
  271. snprint(buf, sizeof buf, "%s/%s", dir, file);
  272. fd = open(buf, OREAD);
  273. if(fd >= 0){
  274. n = read(fd, buf, sizeof(buf)-1);
  275. if(n>0){
  276. buf[n-1] = 0;
  277. serv = strchr(buf, '!');
  278. if(serv){
  279. *serv++ = 0;
  280. serv = strdup(serv);
  281. }
  282. sys = strdup(buf);
  283. }
  284. close(fd);
  285. }
  286. if(serv == 0)
  287. serv = strdup("unknown");
  288. if(sys == 0)
  289. sys = strdup("unknown");
  290. parseip(addr, sys);
  291. n = atoi(serv);
  292. hnputs(port, n);
  293. }
  294. static void
  295. getendpoints(OUdphdr *ep, char *dir)
  296. {
  297. getendpoint(dir, "local", ep->laddr, ep->lport);
  298. getendpoint(dir, "remote", ep->raddr, ep->rport);
  299. }
  300. static long
  301. readtcp(int fd, void *vbuf, long blen)
  302. {
  303. uchar mk[4];
  304. int n, m, sofar;
  305. ulong done;
  306. char *buf;
  307. buf = vbuf;
  308. buf += OUdphdrsize;
  309. blen -= OUdphdrsize;
  310. done = 0;
  311. for(sofar = 0; !done; sofar += n){
  312. m = readn(fd, mk, 4);
  313. if(m < 4)
  314. return 0;
  315. done = (mk[0]<<24)|(mk[1]<<16)|(mk[2]<<8)|mk[3];
  316. m = done & 0x7fffffff;
  317. done &= 0x80000000;
  318. if(m > blen-sofar)
  319. return -1;
  320. n = readn(fd, buf+sofar, m);
  321. if(m != n)
  322. return 0;
  323. }
  324. return sofar + OUdphdrsize;
  325. }
  326. static long
  327. writetcp(int fd, void *vbuf, long len)
  328. {
  329. char *buf;
  330. buf = vbuf;
  331. buf += OUdphdrsize;
  332. len -= OUdphdrsize;
  333. buf -= 4;
  334. buf[0] = 0x80 | (len>>24);
  335. buf[1] = len>>16;
  336. buf[2] = len>>8;
  337. buf[3] = len;
  338. len += 4;
  339. return write(fd, buf, len);
  340. }
  341. /*
  342. *long
  343. *niwrite(int fd, void *buf, long count)
  344. *{
  345. * char errbuf[ERRLEN];
  346. * long n;
  347. *
  348. * for(;;){
  349. * n = write(fd, buf, count);
  350. * if(n < 0){
  351. * errstr(errbuf);
  352. * if(strcmp(errbuf, "interrupted") == 0)
  353. * continue;
  354. * clog("niwrite error: %s\n", errbuf);
  355. * werrstr(errbuf);
  356. * }
  357. * break;
  358. * }
  359. * return n;
  360. *}
  361. */
  362. long
  363. niwrite(int fd, void *buf, long n)
  364. {
  365. // int savalarm;
  366. // savalarm = alarm(0);
  367. n = write(fd, buf, n);
  368. // if(savalarm > 0)
  369. // alarm(savalarm);
  370. return n;
  371. }
  372. typedef struct Namecache Namecache;
  373. struct Namecache {
  374. char dom[256];
  375. ulong ipaddr;
  376. Namecache *next;
  377. };
  378. Namecache *dnscache;
  379. static Namecache*
  380. domlookupl(void *name, int len)
  381. {
  382. Namecache *n, **ln;
  383. if(len >= sizeof(n->dom))
  384. return nil;
  385. for(ln=&dnscache, n=*ln; n; ln=&(*ln)->next, n=*ln) {
  386. if(strncmp(n->dom, name, len) == 0 && n->dom[len] == 0) {
  387. *ln = n->next;
  388. n->next = dnscache;
  389. dnscache = n;
  390. return n;
  391. }
  392. }
  393. return nil;
  394. }
  395. static Namecache*
  396. domlookup(void *name)
  397. {
  398. return domlookupl(name, strlen(name));
  399. }
  400. static Namecache*
  401. iplookup(ulong ip)
  402. {
  403. Namecache *n, **ln;
  404. for(ln=&dnscache, n=*ln; n; ln=&(*ln)->next, n=*ln) {
  405. if(n->ipaddr == ip) {
  406. *ln = n->next;
  407. n->next = dnscache;
  408. dnscache = n;
  409. return n;
  410. }
  411. }
  412. return nil;
  413. }
  414. static Namecache*
  415. addcacheentry(void *name, int len, ulong ip)
  416. {
  417. Namecache *n;
  418. if(len >= sizeof(n->dom))
  419. return nil;
  420. n = malloc(sizeof(*n));
  421. if(n == nil)
  422. return nil;
  423. strncpy(n->dom, name, len);
  424. n->dom[len] = 0;
  425. n->ipaddr = ip;
  426. n->next = dnscache;
  427. dnscache = n;
  428. return nil;
  429. }
  430. int
  431. getdnsdom(ulong ip, char *name, int len)
  432. {
  433. char buf[128];
  434. Namecache *nc;
  435. char *p;
  436. if(nc=iplookup(ip)) {
  437. strncpy(name, nc->dom, len);
  438. name[len-1] = 0;
  439. return 0;
  440. }
  441. clog("getdnsdom: %I\n", ip);
  442. snprint(buf, sizeof buf, "%I", ip);
  443. p = csgetvalue("/net", "ip", buf, "dom", nil);
  444. if(p == nil)
  445. return -1;
  446. strncpy(name, p, len-1);
  447. name[len] = 0;
  448. free(p);
  449. addcacheentry(name, strlen(name), ip);
  450. return 0;
  451. }
  452. int
  453. getdom(ulong ip, char *dom, int len)
  454. {
  455. int i;
  456. static char *prefix[] = { "", "gate-", "fddi-", "u-", 0 };
  457. char **pr;
  458. if(getdnsdom(ip, dom, len)<0)
  459. return -1;
  460. for(pr=prefix; *pr; pr++){
  461. i = strlen(*pr);
  462. if(strncmp(dom, *pr, i) == 0) {
  463. memmove(dom, dom+i, len-i);
  464. break;
  465. }
  466. }
  467. return 0;
  468. }
  469. #define MAXCACHE 64
  470. static Rpccache *head, *tail;
  471. static int ncache;
  472. static void
  473. cachereply(Rpccall *rp, void *buf, int len)
  474. {
  475. Rpccache *cp;
  476. if(nocache)
  477. return;
  478. if(ncache >= MAXCACHE){
  479. if(rpcdebug)
  480. fprint(2, "%s: drop %I/%ld, xid %uld, len %d\n",
  481. argv0, tail->host,
  482. tail->port, tail->xid, tail->n);
  483. tail = tail->prev;
  484. free(tail->next);
  485. tail->next = 0;
  486. --ncache;
  487. }
  488. cp = malloc(sizeof(Rpccache)+len-4);
  489. if(cp == 0){
  490. clog("cachereply: malloc %d failed\n", len);
  491. return;
  492. }
  493. ++ncache;
  494. cp->prev = 0;
  495. cp->next = head;
  496. if(head)
  497. head->prev = cp;
  498. else
  499. tail = cp;
  500. head = cp;
  501. cp->host = rp->host;
  502. cp->port = rp->port;
  503. cp->xid = rp->xid;
  504. cp->n = len;
  505. memmove(cp->data, buf, len);
  506. if(rpcdebug)
  507. fprint(2, "%s: cache %I/%ld, xid %uld, len %d\n",
  508. argv0, cp->host, cp->port, cp->xid, cp->n);
  509. }
  510. static int
  511. replycache(int fd, Rpccall *rp, long (*writemsg)(int, void*, long))
  512. {
  513. Rpccache *cp;
  514. for(cp=head; cp; cp=cp->next)
  515. if(cp->host == rp->host &&
  516. cp->port == rp->port &&
  517. cp->xid == rp->xid)
  518. break;
  519. if(cp == 0)
  520. return 0;
  521. if(cp->prev){ /* move to front */
  522. cp->prev->next = cp->next;
  523. if(cp->next)
  524. cp->next->prev = cp->prev;
  525. else
  526. tail = cp->prev;
  527. cp->prev = 0;
  528. cp->next = head;
  529. head->prev = cp;
  530. head = cp;
  531. }
  532. (*writemsg)(fd, cp->data, cp->n);
  533. if(rpcdebug)
  534. fprint(2, "%s: reply %I/%ld, xid %uld, len %d\n",
  535. argv0, cp->host, cp->port, cp->xid, cp->n);
  536. return 1;
  537. }
  538. static int
  539. Iconv(Fmt *f)
  540. {
  541. char buf[16];
  542. ulong h;
  543. h = va_arg(f->args, ulong);
  544. snprint(buf, sizeof buf, "%ld.%ld.%ld.%ld",
  545. (h>>24)&0xff, (h>>16)&0xff,
  546. (h>>8)&0xff, h&0xff);
  547. return fmtstrcpy(f, buf);
  548. }