server.c 11 KB

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