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