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
argopt(int c)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
server(int argc,char ** argv,int myport,Progmap * progmap)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
udpserver(int myport,Progmap * progmap)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
tcpserver(int myport,Progmap * progmap)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
servemsg(int fd,long (* readmsg)(int,void *,long),long (* writemsg)(int,void *,long),int myport,Progmap * progmap)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
getendpoint(char * dir,char * file,uchar * addr,uchar * port)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
getendpoints(Udphdr * ep,char * dir)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
readtcp(int fd,void * vbuf,long blen)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
writetcp(int fd,void * vbuf,long len)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
niwrite(int fd,void * buf,long n)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*
domlookupl(void * name,int len)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*
domlookup(void * name)447 domlookup(void *name)
448 {
449 return domlookupl(name, strlen(name));
450 }
451
452 static Namecache*
iplookup(ulong ip)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*
addcacheentry(void * name,int len,ulong ip)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
getdnsdom(ulong ip,char * name,int len)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
getdom(ulong ip,char * dom,int len)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
cachereply(Rpccall * rp,void * buf,int len)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
replycache(int fd,Rpccall * rp,long (* writemsg)(int,void *,long))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
Iconv(Fmt * f)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