⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pptpd.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
	proc(argv, pfd[0], pfd[0], 2);	close(pfd[0]);	c->pppfd = pfd[1];	c->next = srv.hash[h];	srv.hash[h] = c;	qunlock(&srv.lk);	c->ref++;	thread(pppread, c);	c->ref++;	thread(gretimeout, c);	syslog(0, LOG, ": src=%I: call started: id=%d: remote ip=%I", srv.remote, id, c->remoteip);	return c;}voidcallclose(Call *c){	Call *oc;	int id;	uint h;	syslog(0, LOG, ": src=%I: call closed: id=%d: send=%d sendack=%d recv=%d recvack=%d dropped=%d missing=%d sendwait=%d sendtimeout=%d",		srv.remote, c->id, c->stat.send, c->stat.sendack, c->stat.recv, c->stat.recvack,		c->stat.dropped, c->stat.missing, c->stat.sendwait, c->stat.sendtimeout);	qlock(&srv.lk);	if(c->closed) {		qunlock(&srv.lk);		return;	}	c->closed = 1;	close(c->dhcpfd[0]);	close(c->dhcpfd[1]);	close(c->pppfd);	c->pppfd = -1;	h = c->id%Nhash;	id = c->id;	for(c=srv.hash[h],oc=0; c; oc=c,c=c->next)		if(c->id == id)			break;	if(oc == 0)		srv.hash[h] = c->next;	else		oc->next = c->next;	c->next = 0;	qunlock(&srv.lk);	callfree(c);}voidcallfree(Call *c){		int ref;		qlock(&srv.lk);	ref = --c->ref;	qunlock(&srv.lk);	if(ref > 0)		return;		/* already unhooked from hash list - see callclose */	assert(c->closed == 1);	assert(ref == 0);	assert(c->next == 0);SDB "call free\n" EDB		free(c);}Call*calllookup(int id){	uint h;	Call *c;	h = id%Nhash;	qlock(&srv.lk);	for(c=srv.hash[h]; c; c=c->next)		if(c->id == id)			break;	if(c != 0)		c->ref++;	qunlock(&srv.lk);	return c;}voidsrvinit(void){	char buf[100];	int fd, n;	sprint(buf, "%s/local", srv.tcpdir);	if((fd = open(buf, OREAD)) < 0)		myfatal("could not open %s: %r", buf);	if((n = read(fd, buf, sizeof(buf))) < 0)		myfatal("could not read %s: %r", buf);	buf[n] = 0;	parseip(srv.local, buf);	close(fd);	sprint(buf, "%s/remote", srv.tcpdir);	if((fd = open(buf, OREAD)) < 0)		myfatal("could not open %s: %r", buf);	if((n = read(fd, buf, sizeof(buf))) < 0)		myfatal("could not read %s: %r", buf);	buf[n] = 0;	parseip(srv.remote, buf);	close(fd);	if(srv.pppdir == 0)		srv.pppdir = "/net";	if(srv.pppexec == 0)		srv.pppexec = "/bin/ip/ppp";	if(myipaddr(srv.ipaddr, srv.pppdir) < 0)		myfatal("could not read local ip addr: %r");	if(srv.recvwindow == 0)		srv.recvwindow = Window;}voidgreinit(void){	char addr[100], *p;	int fd, cfd;	SDB "srv.tcpdir = %s\n", srv.tcpdir EDB	strcpy(addr, srv.tcpdir);	p = strrchr(addr, '/');	if(p == 0)		myfatal("bad tcp dir: %s", srv.tcpdir);	*p = 0;	p = strrchr(addr, '/');	if(p == 0)		myfatal("bad tcp dir: %s", srv.tcpdir);	sprint(p, "/gre!%I!34827", srv.remote);	SDB "addr = %s\n", addr EDB	fd = dial(addr, 0, 0, &cfd);	if(fd < 0)		myfatal("%I: dial %s failed: %r", srv.remote, addr);	srv.grefd = fd;	srv.grecfd = cfd;	thread(greread, 0);}voidgreread(void *){	uchar buf[Pktsize], *p;	int n, i;	int flag, prot, len, callid;	uchar src[IPaddrlen], dst[IPaddrlen];	uint rseq, ack;	Call *c;	static double t, last;	for(;;) {		n = read(srv.grefd, buf, sizeof(buf));		if(n < 0)			myfatal("%I: bad read on gre: %r", srv.remote);		if(n == sizeof(buf))			myfatal("%I: gre read: buf too small", srv.remote);		p = buf;		v4tov6(src, p);		v4tov6(dst, p+4);		flag = GSHORT(p+8);		prot = GSHORT(p+10);		p += 12; n -= 12;		if(ipcmp(src, srv.remote) != 0 || ipcmp(dst, srv.local) != 0)			myfatal("%I: gre read bad address src=%I dst=%I", srv.remote, src, dst);		if(prot != GRE_ppp)			myfatal("%I: gre read gave bad protocol", srv.remote);		if(flag & (GRE_chksum|GRE_routing)){			p += 4; n -= 4;		}		if(!(flag&GRE_key))			myfatal("%I: gre packet does not contain a key: f=%ux",				srv.remote, flag);		len = GSHORT(p);		callid = GSHORT(p+2);		p += 4; n -= 4;		c = calllookup(callid);		if(c == 0) {			SDB "%I: unknown callid: %d\n", srv.remote, callid EDB			continue;		}		qlock(&c->lk);		c->stat.recv++;		if(flag&GRE_seq) {			rseq = GLONG(p);			p += 4; n -= 4;		} else			rseq = c->rseq;		if(flag&GRE_ack){			ack = GLONG(p);			p += 4; n -= 4;		} else			ack = c->ack;		/* skip routing if present */		if(flag&GRE_routing) {			while((i=p[3]) != 0) {				n -= i;				p += i;			}		}		if(len > n)			myfatal("%I: bad len in gre packet", srv.remote);		if((int)(ack-c->ack) > 0) {			c->ack = ack;			esignal(&c->eack);		}		if(debug)			t = realtime();		if(len == 0) {			/* ack packet */			c->stat.recvack++;SDB "%I: %.3f (%.3f): gre %d: recv ack a=%ux n=%d flag=%ux\n", srv.remote, t, t-last,	c->id, ack, n, flag EDB		} else {SDB "%I: %.3f (%.3f): gre %d: recv s=%ux a=%ux len=%d\n", srv.remote, t, t-last,	c->id, rseq, ack, len EDB			/*			 * the following handles the case of a single pair of packets			 * received out of order			 */			n = rseq-c->rseq;			if(n > 0 && (drop == 0. || frand() > drop)) {				c->stat.missing += n-1;				/* current packet */				write(c->pppfd, p, len);			} else {				/* out of sequence - drop on the floor */				c->stat.dropped++;SDB "%I: %.3f: gre %d: recv out of order or dup packet: seq=%ux len=%d\n",srv.remote, realtime(), c->id, rseq, len EDB			}		}		if((int)(rseq-c->rseq) > 0)			c->rseq = rseq;		if(debug)			last=t;		/* open up client window */		if((int)(c->rseq-c->rack) > (c->recvwindow>>1))			greack(c);		qunlock(&c->lk);		callfree(c);	}}voidgreack(Call *c){	uchar buf[20];	c->stat.sendack++;SDB "%I: %.3f: gre %d: send ack %ux\n", srv.remote, realtime(), c->id, c->rseq EDB	v6tov4(buf+0, srv.local);		/* source */	v6tov4(buf+4, srv.remote);		/* source */	PSHORT(buf+8, GRE_key|GRE_ack|1);	PSHORT(buf+10, GRE_ppp);	PSHORT(buf+12, 0);	PSHORT(buf+14, c->id);	PLONG(buf+16, c->rseq);	write(srv.grefd, buf, sizeof(buf));	c->rack = c->rseq;}voidgretimeout(void *a){	Call *c;	c = a;	while(!c->closed) {		sleep(Tick);		qlock(&c->lk);		c->tick++;		qunlock(&c->lk);		esignal(&c->eack);	}	callfree(c);	exits(0);}voidpppread(void *a){	Call *c;	uchar buf[2000], *p;	int n;	ulong tick;	c = a;	for(;;) {		p = buf+24;		n = read(c->pppfd, p, sizeof(buf)-24);		if(n <= 0)			break;				qlock(&c->lk);		/* add gre header */		c->seq++;		tick = c->tick;		while(c->seq-c->ack>c->sendwindow && c->tick-tick<Sendtimeout && !c->closed) {			c->stat.sendwait++;SDB "window full seq = %d ack = %ux window = %ux\n", c->seq, c->ack, c->sendwindow EDB			qunlock(&c->lk);			ewait(&c->eack);			qlock(&c->lk);		}				if(c->tick-tick >= Sendtimeout) {			c->stat.sendtimeout++;SDB "send timeout = %d ack = %ux window = %ux\n", c->seq, c->ack, c->sendwindow EDB		}		v6tov4(buf+0, srv.local);		/* source */		v6tov4(buf+4, srv.remote);		/* source */		PSHORT(buf+8, GRE_key|GRE_seq|GRE_ack|1);		PSHORT(buf+10, GRE_ppp);		PSHORT(buf+12, n);		PSHORT(buf+14, c->id);		PLONG(buf+16, c->seq);		PLONG(buf+20, c->rseq);		c->stat.send++;		c->rack = c->rseq;SDB "%I: %.3f: gre %d: send s=%ux a=%ux len=%d\n", srv.remote, realtime(),	c->id,  c->seq, c->rseq, n EDB		if(drop == 0. || frand() > drop)			if(write(srv.grefd, buf, n+24)<n+24)				myfatal("pppread: write failed: %r");		qunlock(&c->lk);	}	SDB "pppread exit: %d\n", c->id);		callfree(c);	exits(0);}voidtimeoutthread(void*){	for(;;) {		sleep(30*1000);		qlock(&srv.lk);		if(realtime() - srv.rcvtime > 5*60)			myfatal("server timedout");		qunlock(&srv.lk);	}}/* use syslog() rather than fprint(2, ...) */voidmyfatal(char *fmt, ...){	char sbuf[512];	va_list arg;	uchar buf[16];	/* NT don't seem to like us just going away */	memset(buf, 0, sizeof(buf));	PSHORT(buf+0, sizeof(buf));	/* length */	PSHORT(buf+2, 1);		/* message type */	PLONG(buf+4, Magic);		/* magic */	PSHORT(buf+8, Tstop);		/* op */	buf[12] = 3;			/* local shutdown */	write(1, buf, sizeof(buf));	va_start(arg, fmt);	vseprint(sbuf, sbuf+sizeof(sbuf), fmt, arg);	va_end(arg);	SDB "%I: fatal: %s\n", srv.remote, sbuf EDB	syslog(0, LOG, ": src=%I: fatal: %s", srv.remote, sbuf);	close(0);	close(1);	close(srv.grefd);	close(srv.grecfd);	postnote(PNGROUP, getpid(), "die");	exits(sbuf);}intargatoi(char *p){	char *q;	int i;	if(p == 0)		usage();	i = strtol(p, &q, 0);	if(q == p)		usage();	return i;}voiddhcpclientwatch(void *a){	Call *c = a;	uchar buf[1];	for(;;) {		if(read(c->dhcpfd[0], buf, sizeof(buf)) <= 0)			break;	}	if(!c->closed)		myfatal("dhcpclient terminated");	callfree(c);	exits(0);}intipaddralloc(Call *c){	int pfd[2][2];	char *argv[4], *p;	Biobuf bio;	argv[0] = "/bin/ip/dhcpclient";	argv[1] = "-x";	argv[2] = srv.pppdir;	argv[3] = 0;	if(pipe(pfd[0])<0)		myfatal("ipaddralloc: pipe failed: %r");	if(pipe(pfd[1])<0)		myfatal("ipaddralloc: pipe failed: %r");	if(proc(argv, pfd[0][0], pfd[1][1], 2) < 0)		myfatal("ipaddralloc: proc failed: %r");	close(pfd[0][0]);	close(pfd[1][1]);	c->dhcpfd[0] = pfd[1][0];	c->dhcpfd[1] = pfd[0][1];	Binit(&bio, pfd[1][0], OREAD);	for(;;) {		p = Brdline(&bio, '\n');		if(p == 0)			break;		if(strncmp(p, "ip=", 3) == 0) {			p += 3;			parseip(c->remoteip, p);		} else if(strncmp(p, "end\n", 4) == 0)			break;	}	Bterm(&bio);	c->ref++;	thread(dhcpclientwatch, c);	return ipcmp(c->remoteip, IPnoaddr) != 0;}voidesignal(Event *e){		qlock(e);	if(e->wait == 0) {		e->ready = 1;		qunlock(e);		return;	}	assert(e->ready == 0);	e->wait = 0;	rendezvous(e, (void*)1);	qunlock(e);}voidewait(Event *e){	qlock(&e->waitlk);	qlock(e);	assert(e->wait == 0);	if(e->ready) {		e->ready = 0;	} else {			e->wait = 1;		qunlock(e);		rendezvous(e, (void*)2);		qlock(e);	}	qunlock(e);	qunlock(&e->waitlk);}ulongthread(void(*f)(void*), void *a){	int pid;	pid=rfork(RFNOWAIT|RFMEM|RFPROC);	if(pid < 0)		myfatal("rfork failed: %r");	if(pid != 0)		return pid;	(*f)(a);	return 0; // never reaches here}doublerealtime(void){	long times(long*);	return times(0) / 1000.0;}void *emallocz(int size){	void *p;	p = malloc(size);	if(p == 0)		myfatal("malloc failed: %r");	memset(p, 0, size);	return p;}static voidfdclose(void){	int fd, n, i;	Dir *d, *p;	if((fd = open("#d", OREAD)) < 0)		return;	n = dirreadall(fd, &d);	for(p = d; n > 0; n--, p++) {		i = atoi(p->name);		if(i > 2)			close(i);	}	free(d);}intproc(char **argv, int fd0, int fd1, int fd2){	int r, flag;	char *arg0, file[200];	arg0 = argv[0];	strcpy(file, arg0);	if(access(file, 1) < 0) {		if(strncmp(arg0, "/", 1)==0		|| strncmp(arg0, "#", 1)==0		|| strncmp(arg0, "./", 2)==0		|| strncmp(arg0, "../", 3)==0)			return 0;		sprint(file, "/bin/%s", arg0);		if(access(file, 1) < 0)			return 0;	}	flag = RFPROC|RFFDG|RFENVG|RFNOWAIT;	if((r = rfork(flag)) != 0) {		if(r < 0)			return 0;		return r;	}	if(fd0 != 0) {		if(fd1 == 0)			fd1 = dup(0, -1);		if(fd2 == 0)			fd2 = dup(0, -1);		close(0);		if(fd0 >= 0)			dup(fd0, 0);	}	if(fd1 != 1) {		if(fd2 == 1)			fd2 = dup(1, -1);		close(1);		if(fd1 >= 0)			dup(fd1, 1);	}	if(fd2 != 2) {		close(2);		if(fd2 >= 0)			dup(fd2, 2);	}	fdclose();	exec(file, argv);	myfatal("proc: exec failed: %r");	return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -