server.c 11 KB

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