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