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