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