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