6 static int Iconv(Fmt*);
7 static void cachereply(Rpccall*, void*, int);
8 static int replycache(int, Rpccall*, long (*)(int, void*, long));
9 static void udpserver(int, Progmap*);
10 static void tcpserver(int, Progmap*);
11 static void getendpoints(Udphdr*, char*);
12 static long readtcp(int, void*, long);
13 static long writetcp(int, void*, long);
14 static int servemsg(int, long (*)(int, void*, long), long (*)(int, void*, long),
16 void (*rpcalarm)(void);
25 uchar resultbuf[9000];
29 char *commonopts = "[-9CDrtv]"; /* for usage() messages */
32 * this recognises common, nominally rcp-related options.
33 * they may not take arguments.
63 * all option parsing is now done in (*pg->init)(), which can call back
64 * here to argopt for common options.
67 server(int argc, char **argv, int myport, Progmap *progmap)
71 fmtinstall('I', Iconv);
72 fmtinstall('F', fcallfmt);
73 fmtinstall('D', dirfmt);
75 switch(rfork(RFNOWAIT|RFENVG|RFNAMEG|RFNOTEG|RFFDG|RFPROC)){
84 switch(rfork(RFMEM|RFPROC)){
91 sysfatal("rfork: %r");
94 for(pg=progmap; pg->init; pg++)
95 (*pg->init)(argc, argv);
97 tcpserver(myport, progmap);
99 udpserver(myport, progmap);
103 udpserver(int myport, Progmap *progmap)
110 snprint(service, sizeof service, "udp!*!%d", myport);
111 ctlfd = announce(service, devdir);
113 panic("can't announce %s: %r\n", service);
114 if(fprint(ctlfd, "headers") < 0)
115 panic("can't set header mode: %r\n");
117 snprint(data, sizeof data, "%s/data", devdir);
118 datafd = open(data, ORDWR);
120 panic("can't open udp data: %r\n");
124 clog("%s: listening to port %d\n", argv0, myport);
125 while (servemsg(datafd, read, write, myport, progmap) >= 0)
131 tcpserver(int myport, Progmap *progmap)
136 int actl, lctl, data;
138 snprint(ds, sizeof ds, "tcp!*!%d", myport);
143 actl = announce(ds, adir);
145 clog("%s: listening to tcp port %d\n",
147 clog("announcing: %r");
151 lctl = listen(adir, ldir);
159 clog("%s!%d: %r\n", argv0, myport);
166 data = accept(lctl, ldir);
171 /* pretend it's udp; fill in Udphdr */
172 getendpoints((Udphdr*)buf, ldir);
174 while (servemsg(data, readtcp, writetcp, myport,
185 servemsg(int fd, long (*readmsg)(int, void*, long), long (*writemsg)(int, void*, long),
186 int myport, Progmap * progmap)
189 Rpccall rcall, rreply;
200 n = (*readmsg)(fd, buf, sizeof buf);
202 errstr(errbuf, sizeof errbuf);
203 if(strcmp(errbuf, "interrupted") == 0)
205 clog("port %d: error: %s\n", myport, errbuf);
209 clog("port %d: EOF\n", myport);
213 fprint(2, "%s: rpc from %d.%d.%d.%d/%d\n",
214 argv0, buf[12], buf[13], buf[14], buf[15],
215 (buf[32]<<8)|buf[33]);
216 i = rpcM2S(buf, &rcall, n);
218 clog("udp port %d: message format error %d\n",
224 if(rcall.mtype != CALL)
226 if(replycache(fd, &rcall, writemsg))
229 rreply.host = rcall.host;
230 rreply.port = rcall.port;
231 rreply.lhost = rcall.lhost;
232 rreply.lport = rcall.lport;
233 rreply.xid = rcall.xid;
234 rreply.mtype = REPLY;
235 if(rcall.rpcvers != 2){
236 rreply.stat = MSG_DENIED;
237 rreply.rstat = RPC_MISMATCH;
243 rreply.stat = MSG_DENIED;
244 rreply.rstat = AUTH_ERROR;
245 rreply.authstat = AUTH_TOOWEAK;
248 i = n - (((uchar *)rcall.args) - buf);
250 fprint(2, "arg size = %d\n", i);
251 rreply.stat = MSG_ACCEPTED;
252 rreply.averf.flavor = 0;
253 rreply.averf.count = 0;
254 rreply.results = resultbuf;
257 for(pg=progmap; pg->pmap; pg++){
258 if(pg->progno != rcall.prog)
260 if(pg->vers == rcall.vers)
269 rreply.astat = PROG_UNAVAIL;
271 rreply.astat = PROG_MISMATCH;
277 for(pp = pg->pmap; pp->procp; pp++)
278 if(rcall.proc == pp->procno){
280 fprint(2, "process %d\n", pp->procno);
281 rreply.astat = SUCCESS;
282 nreply = (*pp->procp)(i, &rcall, &rreply);
285 rreply.astat = PROC_UNAVAIL;
288 i = rpcS2M(&rreply, nreply, rbuf);
290 rpcprint(2, &rreply);
291 (*writemsg)(fd, rbuf, i);
292 cachereply(&rreply, rbuf, i);
298 getendpoint(char *dir, char *file, uchar *addr, uchar *port)
306 snprint(buf, sizeof buf, "%s/%s", dir, file);
307 fd = open(buf, OREAD);
309 n = read(fd, buf, sizeof(buf)-1);
312 serv = strchr(buf, '!');
322 serv = strdup("unknown");
324 sys = strdup("unknown");
330 /* set Udphdr values from protocol dir local & remote files */
332 getendpoints(Udphdr *ep, char *dir)
334 getendpoint(dir, "local", ep->laddr, ep->lport);
335 getendpoint(dir, "remote", ep->raddr, ep->rport);
339 readtcp(int fd, void *vbuf, long blen)
351 for(sofar = 0; !done; sofar += n){
352 m = readn(fd, mk, 4);
355 done = (mk[0]<<24)|(mk[1]<<16)|(mk[2]<<8)|mk[3];
356 m = done & 0x7fffffff;
360 n = readn(fd, buf+sofar, m);
364 return sofar + Udphdrsize;
368 writetcp(int fd, void *vbuf, long len)
377 buf[0] = 0x80 | (len>>24);
382 return write(fd, buf, len);
386 *niwrite(int fd, void *buf, long count)
388 * char errbuf[ERRLEN];
392 * n = write(fd, buf, count);
395 * if(strcmp(errbuf, "interrupted") == 0)
397 * clog("niwrite error: %s\n", errbuf);
406 niwrite(int fd, void *buf, long n)
410 // savalarm = alarm(0);
411 n = write(fd, buf, n);
417 typedef struct Namecache Namecache;
427 domlookupl(void *name, int len)
431 if(len >= sizeof(n->dom))
434 for(ln=&dnscache, n=*ln; n; ln=&(*ln)->next, n=*ln) {
435 if(strncmp(n->dom, name, len) == 0 && n->dom[len] == 0) {
450 for(ln=&dnscache, n=*ln; n; ln=&(*ln)->next, n=*ln) {
451 if(n->ipaddr == ip) {
462 addcacheentry(void *name, int len, ulong ip)
466 if(len >= sizeof(n->dom))
469 n = malloc(sizeof(*n));
472 strncpy(n->dom, name, len);
481 getdnsdom(ulong ip, char *name, int len)
487 if(nc=iplookup(ip)) {
488 strncpy(name, nc->dom, len);
492 clog("getdnsdom: %I\n", ip);
493 snprint(buf, sizeof buf, "%I", ip);
494 p = csgetvalue("/net", "ip", buf, "dom", nil);
497 strncpy(name, p, len-1);
500 addcacheentry(name, strlen(name), ip);
505 getdom(ulong ip, char *dom, int len)
508 static char *prefix[] = { "", "gate-", "fddi-", "u-", 0 };
511 if(getdnsdom(ip, dom, len)<0)
514 for(pr=prefix; *pr; pr++){
516 if(strncmp(dom, *pr, i) == 0) {
517 memmove(dom, dom+i, len-i);
526 static Rpccache *head, *tail;
530 cachereply(Rpccall *rp, void *buf, int len)
537 if(ncache >= MAXCACHE){
539 fprint(2, "%s: drop %I/%ld, xid %uld, len %d\n",
541 tail->port, tail->xid, tail->n);
547 cp = malloc(sizeof(Rpccache)+len-4);
549 clog("cachereply: malloc %d failed\n", len);
564 memmove(cp->data, buf, len);
566 fprint(2, "%s: cache %I/%ld, xid %uld, len %d\n",
567 argv0, cp->host, cp->port, cp->xid, cp->n);
571 replycache(int fd, Rpccall *rp, long (*writemsg)(int, void*, long))
575 for(cp=head; cp; cp=cp->next)
576 if(cp->host == rp->host &&
577 cp->port == rp->port &&
582 if(cp->prev){ /* move to front */
583 cp->prev->next = cp->next;
585 cp->next->prev = cp->prev;
593 (*writemsg)(fd, cp->data, cp->n);
595 fprint(2, "%s: reply %I/%ld, xid %uld, len %d\n",
596 argv0, cp->host, cp->port, cp->xid, cp->n);
606 h = va_arg(f->args, ulong);
607 snprint(buf, sizeof buf, "%ld.%ld.%ld.%ld",
608 (h>>24)&0xff, (h>>16)&0xff,
609 (h>>8)&0xff, h&0xff);
610 return fmtstrcpy(f, buf);