Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_posix/sys/src/cmd/9nfs/server.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
}