server.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618
  1. #include "all.h"
  2. #include <ndb.h>
  3. static int alarmflag;
  4. static int Iconv(Fmt*);
  5. static void openudp(int);
  6. static void cachereply(Rpccall*, void*, int);
  7. static int replycache(int, Rpccall*, long (*)(int, void*, long));
  8. static void udpserver(int, Progmap*);
  9. static void tcpserver(int, Progmap*);
  10. static void getendpoints(Udphdr*, char*);
  11. static long readtcp(int, void*, long);
  12. static long writetcp(int, void*, long);
  13. static int servemsg(int, long (*)(int, void*, long), long (*)(int, void*, long),
  14. int, Progmap*);
  15. void (*rpcalarm)(void);
  16. int rpcdebug;
  17. int rejectall;
  18. int p9debug;
  19. int nocache;
  20. uchar buf[9000];
  21. uchar rbuf[9000];
  22. uchar resultbuf[9000];
  23. static int tcp;
  24. char *commonopts = "[-9CDrtv]"; /* for usage() messages */
  25. /*
  26. * this recognises common, nominally rcp-related options.
  27. * they may not take arguments.
  28. */
  29. int
  30. argopt(int c)
  31. {
  32. switch(c){
  33. case '9':
  34. ++p9debug;
  35. return 0;
  36. case 'C':
  37. ++nocache;
  38. return 0;
  39. case 'D':
  40. ++rpcdebug;
  41. return 0;
  42. case 'r':
  43. ++rejectall;
  44. return 0;
  45. case 't':
  46. tcp = 1;
  47. return 0;
  48. case 'v':
  49. ++chatty;
  50. return 0;
  51. default:
  52. return -1;
  53. }
  54. }
  55. /*
  56. * all option parsing is now done in (*pg->init)(), which can call back
  57. * here to argopt for common options.
  58. */
  59. void
  60. server(int argc, char **argv, int myport, Progmap *progmap)
  61. {
  62. Progmap *pg;
  63. fmtinstall('I', Iconv);
  64. fmtinstall('F', fcallfmt);
  65. fmtinstall('D', dirfmt);
  66. switch(rfork(RFNOWAIT|RFENVG|RFNAMEG|RFNOTEG|RFFDG|RFPROC)){
  67. case -1:
  68. panic("fork");
  69. default:
  70. _exits(0);
  71. case 0:
  72. break;
  73. }
  74. switch(rfork(RFMEM|RFPROC)){
  75. case 0:
  76. for(;;){
  77. sleep(30*1000);
  78. alarmflag = 1;
  79. }
  80. case -1:
  81. sysfatal("rfork: %r");
  82. }
  83. for(pg=progmap; pg->init; pg++)
  84. (*pg->init)(argc, argv);
  85. if(tcp)
  86. tcpserver(myport, progmap);
  87. else
  88. udpserver(myport, progmap);
  89. }
  90. static void
  91. udpserver(int myport, Progmap *progmap)
  92. {
  93. char service[128];
  94. char data[128];
  95. char devdir[40];
  96. int ctlfd, datafd;
  97. snprint(service, sizeof service, "udp!*!%d", myport);
  98. ctlfd = announce(service, devdir);
  99. if(ctlfd < 0)
  100. panic("can't announce %s: %r\n", service);
  101. if(fprint(ctlfd, "headers") < 0)
  102. panic("can't set header mode: %r\n");
  103. snprint(data, sizeof data, "%s/data", devdir);
  104. datafd = open(data, ORDWR);
  105. if(datafd < 0)
  106. panic("can't open udp data: %r\n");
  107. close(ctlfd);
  108. chatsrv(0);
  109. clog("%s: listening to port %d\n", argv0, myport);
  110. while (servemsg(datafd, read, write, myport, progmap) >= 0)
  111. continue;
  112. exits(0);
  113. }
  114. static void
  115. tcpserver(int myport, Progmap *progmap)
  116. {
  117. char adir[40];
  118. char ldir[40];
  119. char ds[40];
  120. int actl, lctl, data;
  121. snprint(ds, sizeof ds, "tcp!*!%d", myport);
  122. chatsrv(0);
  123. actl = -1;
  124. for(;;){
  125. if(actl < 0){
  126. actl = announce(ds, adir);
  127. if(actl < 0){
  128. clog("%s: listening to tcp port %d\n",
  129. 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. /* pretend it's udp; fill in Udphdr */
  154. getendpoints((Udphdr*)buf, ldir);
  155. while (servemsg(data, readtcp, writetcp, myport,
  156. progmap) >= 0)
  157. continue;
  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. /* set Udhphdr values from protocol dir local & remote files */
  306. static void
  307. getendpoints(Udphdr *ep, char *dir)
  308. {
  309. getendpoint(dir, "local", ep->laddr, ep->lport);
  310. getendpoint(dir, "remote", ep->raddr, ep->rport);
  311. }
  312. static long
  313. readtcp(int fd, void *vbuf, long blen)
  314. {
  315. uchar mk[4];
  316. int n, m, sofar;
  317. ulong done;
  318. char *buf;
  319. buf = vbuf;
  320. buf += Udphdrsize;
  321. blen -= Udphdrsize;
  322. done = 0;
  323. for(sofar = 0; !done; sofar += n){
  324. m = readn(fd, mk, 4);
  325. if(m < 4)
  326. return 0;
  327. done = (mk[0]<<24)|(mk[1]<<16)|(mk[2]<<8)|mk[3];
  328. m = done & 0x7fffffff;
  329. done &= 0x80000000;
  330. if(m > blen-sofar)
  331. return -1;
  332. n = readn(fd, buf+sofar, m);
  333. if(m != n)
  334. return 0;
  335. }
  336. return sofar + Udphdrsize;
  337. }
  338. static long
  339. writetcp(int fd, void *vbuf, long len)
  340. {
  341. char *buf;
  342. buf = vbuf;
  343. buf += Udphdrsize;
  344. len -= Udphdrsize;
  345. buf -= 4;
  346. buf[0] = 0x80 | (len>>24);
  347. buf[1] = len>>16;
  348. buf[2] = len>>8;
  349. buf[3] = len;
  350. len += 4;
  351. return write(fd, buf, len);
  352. }
  353. /*
  354. *long
  355. *niwrite(int fd, void *buf, long count)
  356. *{
  357. * char errbuf[ERRLEN];
  358. * long n;
  359. *
  360. * for(;;){
  361. * n = write(fd, buf, count);
  362. * if(n < 0){
  363. * errstr(errbuf);
  364. * if(strcmp(errbuf, "interrupted") == 0)
  365. * continue;
  366. * clog("niwrite error: %s\n", errbuf);
  367. * werrstr(errbuf);
  368. * }
  369. * break;
  370. * }
  371. * return n;
  372. *}
  373. */
  374. long
  375. niwrite(int fd, void *buf, long n)
  376. {
  377. // int savalarm;
  378. // savalarm = alarm(0);
  379. n = write(fd, buf, n);
  380. // if(savalarm > 0)
  381. // alarm(savalarm);
  382. return n;
  383. }
  384. typedef struct Namecache Namecache;
  385. struct Namecache {
  386. char dom[256];
  387. ulong ipaddr;
  388. Namecache *next;
  389. };
  390. Namecache *dnscache;
  391. static Namecache*
  392. domlookupl(void *name, int len)
  393. {
  394. Namecache *n, **ln;
  395. if(len >= sizeof(n->dom))
  396. return nil;
  397. for(ln=&dnscache, n=*ln; n; ln=&(*ln)->next, n=*ln) {
  398. if(strncmp(n->dom, name, len) == 0 && n->dom[len] == 0) {
  399. *ln = n->next;
  400. n->next = dnscache;
  401. dnscache = n;
  402. return n;
  403. }
  404. }
  405. return nil;
  406. }
  407. static Namecache*
  408. domlookup(void *name)
  409. {
  410. return domlookupl(name, strlen(name));
  411. }
  412. static Namecache*
  413. iplookup(ulong ip)
  414. {
  415. Namecache *n, **ln;
  416. for(ln=&dnscache, n=*ln; n; ln=&(*ln)->next, n=*ln) {
  417. if(n->ipaddr == ip) {
  418. *ln = n->next;
  419. n->next = dnscache;
  420. dnscache = n;
  421. return n;
  422. }
  423. }
  424. return nil;
  425. }
  426. static Namecache*
  427. addcacheentry(void *name, int len, ulong ip)
  428. {
  429. Namecache *n;
  430. if(len >= sizeof(n->dom))
  431. return nil;
  432. n = malloc(sizeof(*n));
  433. if(n == nil)
  434. return nil;
  435. strncpy(n->dom, name, len);
  436. n->dom[len] = 0;
  437. n->ipaddr = ip;
  438. n->next = dnscache;
  439. dnscache = n;
  440. return nil;
  441. }
  442. int
  443. getdnsdom(ulong ip, char *name, int len)
  444. {
  445. char buf[128];
  446. Namecache *nc;
  447. char *p;
  448. if(nc=iplookup(ip)) {
  449. strncpy(name, nc->dom, len);
  450. name[len-1] = 0;
  451. return 0;
  452. }
  453. clog("getdnsdom: %I\n", ip);
  454. snprint(buf, sizeof buf, "%I", ip);
  455. p = csgetvalue("/net", "ip", buf, "dom", nil);
  456. if(p == nil)
  457. return -1;
  458. strncpy(name, p, len-1);
  459. name[len] = 0;
  460. free(p);
  461. addcacheentry(name, strlen(name), ip);
  462. return 0;
  463. }
  464. int
  465. getdom(ulong ip, char *dom, int len)
  466. {
  467. int i;
  468. static char *prefix[] = { "", "gate-", "fddi-", "u-", 0 };
  469. char **pr;
  470. if(getdnsdom(ip, dom, len)<0)
  471. return -1;
  472. for(pr=prefix; *pr; pr++){
  473. i = strlen(*pr);
  474. if(strncmp(dom, *pr, i) == 0) {
  475. memmove(dom, dom+i, len-i);
  476. break;
  477. }
  478. }
  479. return 0;
  480. }
  481. #define MAXCACHE 64
  482. static Rpccache *head, *tail;
  483. static int ncache;
  484. static void
  485. cachereply(Rpccall *rp, void *buf, int len)
  486. {
  487. Rpccache *cp;
  488. if(nocache)
  489. return;
  490. if(ncache >= MAXCACHE){
  491. if(rpcdebug)
  492. fprint(2, "%s: drop %I/%ld, xid %uld, len %d\n",
  493. argv0, tail->host,
  494. tail->port, tail->xid, tail->n);
  495. tail = tail->prev;
  496. free(tail->next);
  497. tail->next = 0;
  498. --ncache;
  499. }
  500. cp = malloc(sizeof(Rpccache)+len-4);
  501. if(cp == 0){
  502. clog("cachereply: malloc %d failed\n", len);
  503. return;
  504. }
  505. ++ncache;
  506. cp->prev = 0;
  507. cp->next = head;
  508. if(head)
  509. head->prev = cp;
  510. else
  511. tail = cp;
  512. head = cp;
  513. cp->host = rp->host;
  514. cp->port = rp->port;
  515. cp->xid = rp->xid;
  516. cp->n = len;
  517. memmove(cp->data, buf, len);
  518. if(rpcdebug)
  519. fprint(2, "%s: cache %I/%ld, xid %uld, len %d\n",
  520. argv0, cp->host, cp->port, cp->xid, cp->n);
  521. }
  522. static int
  523. replycache(int fd, Rpccall *rp, long (*writemsg)(int, void*, long))
  524. {
  525. Rpccache *cp;
  526. for(cp=head; cp; cp=cp->next)
  527. if(cp->host == rp->host &&
  528. cp->port == rp->port &&
  529. cp->xid == rp->xid)
  530. break;
  531. if(cp == 0)
  532. return 0;
  533. if(cp->prev){ /* move to front */
  534. cp->prev->next = cp->next;
  535. if(cp->next)
  536. cp->next->prev = cp->prev;
  537. else
  538. tail = cp->prev;
  539. cp->prev = 0;
  540. cp->next = head;
  541. head->prev = cp;
  542. head = cp;
  543. }
  544. (*writemsg)(fd, cp->data, cp->n);
  545. if(rpcdebug)
  546. fprint(2, "%s: reply %I/%ld, xid %uld, len %d\n",
  547. argv0, cp->host, cp->port, cp->xid, cp->n);
  548. return 1;
  549. }
  550. static int
  551. Iconv(Fmt *f)
  552. {
  553. char buf[16];
  554. ulong h;
  555. h = va_arg(f->args, ulong);
  556. snprint(buf, sizeof buf, "%ld.%ld.%ld.%ld",
  557. (h>>24)&0xff, (h>>16)&0xff,
  558. (h>>8)&0xff, h&0xff);
  559. return fmtstrcpy(f, buf);
  560. }