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

📄 telco.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
	default:		return "file is a directory";	case Qctl:		d = &dev[DEV(f->qid)];		clen = strlen(cmsg);		if(cnt < clen || strncmp(thdr.data, cmsg, clen) != 0){			/*			 *  send control message to real control file			 */			if(seek(d->ctl, off, 0) < 0 || write(d->ctl, thdr.data, cnt) < 0){				errstr(errbuf, sizeof errbuf);				return errbuf;			}		} else {			/*			 *  connect			 */			cnt -= clen;			if(cnt >= sizeof(buf))				cnt = sizeof(buf) - 1;			if(cnt < 0)				return Ebadaddr;			strncpy(buf, &thdr.data[clen], cnt);			buf[cnt] = 0;			cp = dialout(d, buf);			if(cp)				return cp;		}		rhdr.count = cnt;		break;	case Qdata:		d = &dev[DEV(f->qid)];		if(write(d->data, thdr.data, cnt) < 0){			errstr(errbuf, sizeof errbuf);			return errbuf;		}		rhdr.count = cnt;		break;	}	return 0;}char *rclunk(Fid *f){	Dev *d;	if(f->open)		switch(TYPE(f->qid)){		case Qdata:		case Qctl:			d = &dev[DEV(f->qid)];			if(d->open == 1)				onhook(d);			d->open--;			break;		}	free(f->user);	f->busy = 0;	f->open = 0;	return 0;}char *rremove(Fid *f){	USED(f);	return Eperm;}char *rstat(Fid *f){	Dir d;	d.qid = f->qid;	rhdr.stat = statbuf;	rhdr.nstat = devstat(&d, statbuf, sizeof statbuf);	return 0;}char *rwstat(Fid *f){	Dev *d;	Dir dir;	if(TYPE(f->qid) < Qlvl3)		return Eperm;	convM2D(thdr.stat, thdr.nstat, &dir, rhdr.data);	/* rhdr.data is a known place to scribble */	d = &dev[DEV(f->qid)];	/*	 * To change mode, must be owner	 */	if(d->perm != dir.mode){		if(strcmp(f->user, d->user) != 0)		if(strcmp(f->user, user) != 0)			return Eperm;	}	/* all ok; do it */	d->perm = dir.mode & ~DMDIR;	return 0;}Fid *newfid(int fid){	Fid *f, *ff;	ff = 0;	for(f = fids; f; f = f->next)		if(f->fid == fid)			return f;		else if(!ff && !f->busy)			ff = f;	if(ff){		ff->fid = fid;		return ff;	}	f = emalloc(sizeof *f);	f->fid = fid;	f->next = fids;	fids = f;	return f;}/* *  read fs requests and dispatch them */voidio(void){	char *err;	int n;	for(;;){		/*		 * reading from a pipe or a network device		 * will give an error after a few eof reads		 * however, we cannot tell the difference		 * between a zero-length read and an interrupt		 * on the processes writing to us,		 * so we wait for the error		 */		n = read9pmsg(mfd[0], mdata, messagesize);		if(n == 0)			continue;		if(n < 0)			error("mount read");		if(convM2S(mdata, n, &thdr) != n)			error("convM2S error");		rhdr.data = (char*)mdata + IOHDRSZ;		if(!fcalls[thdr.type])			err = "bad fcall type";		else			err = (*fcalls[thdr.type])(newfid(thdr.fid));		if(err){			if(*err == 0)				continue;	/* assigned to a slave */			rhdr.type = Rerror;			rhdr.ename = err;		}else{			rhdr.type = thdr.type + 1;			rhdr.fid = thdr.fid;		}		rhdr.tag = thdr.tag;		n = convS2M(&rhdr, mdata, messagesize);		if(write(mfd[1], mdata, n) != n)			error("mount write");	}}intperm(Fid *f, Dev *d, int p){	if((p*Pother) & d->perm)		return 1;	if(strcmp(f->user, user)==0 && ((p*Pgroup) & d->perm))		return 1;	if(strcmp(f->user, d->user)==0 && ((p*Powner) & d->perm))		return 1;	return 0;}voiderror(char *s){	fprint(2, "%s: %s: %r\n", argv0, s);	syslog(0, LOGFILE, "%s: %r", s);	remove("/srv/telco");	postnote(PNGROUP, getpid(), "exit");	exits(s);}void *emalloc(ulong n){	void *p;	p = mallocz(n, 1);	if(!p)		error("out of memory");	return p;}void *erealloc(void *p, ulong n){	p = realloc(p, n);	if(!p)		error("out of memory");	return p;}/* *  send bytes to modem */intsend(Dev *d, char *x){	if(verbose)		syslog(0, LOGFILE, "->%s", x);	return write(d->data, x, strlen(x));}/* *  apply a string of commands to modem */intapply(Dev *d, char *s, char *substr, int secs){	char buf[128];	char *p;	int c, m;	p = buf;	m = Ok;	while(*s){		c = *p++ = *s++;		if(c == '\r' || *s == 0){			if(c != '\r')				*p++ = '\r';			*p = 0;			if(send(d, buf) < 0)				return Failure;			m = readmsg(d, secs, substr);			p = buf;		}	}	return m;}/* *  apply a command type */intapplyspecial(Dev *d, int index){	char *cmd;	cmd = d->t->commands[index];	if(cmd == 0 && d->baset)		cmd = d->baset->commands[index];	if(cmd == 0)		return Failure;	return apply(d, cmd, 0, 2);}/* *  get modem into command mode if it isn't already */intattention(Dev *d){	int i;	for(i = 0; i < 2; i++){		sleep(250);		if(send(d, "+") < 0)			continue;		sleep(250);		if(send(d, "+") < 0)			continue;		sleep(250);		if(send(d, "+") < 0)			continue;		sleep(250);		readmsg(d, 0, 0);		if(apply(d, "ATZH0", 0, 2) == Ok)			return Ok;	}	return Failure;}int portspeed[] = { 56000, 38400, 19200, 14400, 9600, 4800, 2400, 1200, 600, 300, 0 };/* *  get the modem's type and speed */char*modemtype(Dev *d, int limit,  int fax){	int *p;	Type *t, *bt;	char buf[28];	d->t = typetab;	d->baset = 0;	/* assume we're at a good speed, try getting attention a few times */	attention(d);	/* find a common port rate */	for(p = portspeed; *p; p++){		if(*p > limit)			continue;		setspeed(d, *p);		if(attention(d) == Ok)			break;	}	if(*p == 0)		return Eattn;	d->speed = *p;	if(verbose)		syslog(0, LOGFILE, "port speed %d", *p);	/*	 *  basic Hayes commands everyone implements (we hope)	 *	Q0 = report result codes	 * 	V1 = full word result codes	 *	E0 = don't echo commands	 *	M1 = speaker on until on-line	 *	S0=0 = autoanswer off	 */	if(apply(d, "ATQ0V1E0M1S0=0", 0, 2) != Ok)		return Eattn;	/* find modem type */	for(t = typetab; t->name; t++){		if(t->ident == 0 || t->response == 0)			continue;		if(apply(d, t->ident, t->response, 2) == Found)			break;		readmsg(d, 0, 0);	}	readmsg(d, 0, 0);	if(t->name){		d->t = t;		if(t->basetype){			for(bt = typetab; bt->name; bt++)				if(strcmp(bt->name, t->basetype) == 0)					break;			if(bt->name)				d->baset = bt;		}	}	if(verbose)		syslog(0, LOGFILE, "modem %s", d->t->name);	/* try setting fax modes */	d->fclass = 0;	if(fax){		/* set up fax parameters */		if(applyspecial(d, Cfclass2) != Failure)			d->fclass = 2;		/* setup a source id */		if(srcid){			sprint(buf, "AT+FLID=\"%s\"", srcid);			apply(d, buf, 0, 2);		}		/* allow both data and fax calls in */		apply(d, "AT+FAA=1", 0, 2);	} else		applyspecial(d, Cfclass0);	return 0;}/* *  a process to read input from a modem. */voidmonitor(Dev *d){	int n;	char *p;	char file[256];	int background;	background = 0;	d->ctl = d->data = -1;	for(;;){		lock(d);		sprint(file, "%sctl", d->path);		d->ctl = open(file, ORDWR);		if(d->ctl < 0)			error("opening ctl");		d->data = open(d->path, ORDWR);		if(d->data < 0)			error("opening data");		d->wp = d->rp = d->rbuf;		unlock(d);		if(!background){			background = 1;			switch(d->pid = rfork(RFPROC|RFMEM)){			case -1:				error("out of processes");			case 0:				break;			default:				return;			}		}		/* wait for ring or off hook */		while(d->open == 0){			d->rp = d->rbuf;			p = d->wp;			n = read(d->data, p, 1);			if(n < 1)				continue;			if(p < &d->rbuf[Nrbuf] - 2)				d->wp++;			if(*p == '\r' || *p == '\n'){				*(p+1) = 0;				if(verbose)					syslog(0, LOGFILE, "<:-%s", d->rp);				if(answer && strncmp(d->rp, "RING", 4) == 0){					receiver(d);					continue;				}				if(d->open == 0)					d->wp = d->rbuf;			}		}		/* shuttle bytes till on hook */		while(d->open){			if(d->wp >= d->rp)				n = &d->rbuf[Nrbuf] - d->wp;			else				n = d->rp - d->wp - 1;			if(n > 0)				n = read(d->data, d->wp, n);			else {				read(d->data, file, sizeof(file));				continue;			}			if(n < 0)				break;			lock(d);			if(d->wp + n >= &d->rbuf[Nrbuf])				d->wp = d->rbuf;			else				d->wp += n;			serve(d);			unlock(d);		}		close(d->ctl);		close(d->data);	}}/* *  get bytes input by monitor() (only routine that changes d->rp) */intgetinput(Dev *d, char *buf, int n){	char *p;	int i;	p = buf;	while(n > 0){		if(d->wp == d->rp)			break;		if(d->wp < d->rp)			i = &d->rbuf[Nrbuf] - d->rp;		else			i = d->wp - d->rp;		if(i > n)			i = n;		memmove(p, d->rp, i);		if(d->rp + i == &d->rbuf[Nrbuf])			d->rp = d->rbuf;		else			d->rp += i;		n -= i;		p += i;	}	return p - buf;}/* *  fulfill a read request (we assume d is locked) */voidserve(Dev *d){	Request *r;	int n;	Fcall rhdr;	uchar *mdata;	char *buf;	mdata = malloc(messagesize);	buf = malloc(messagesize-IOHDRSZ);	for(;;){		if(d->r == 0 || d->rp == d->wp)			break;		r = d->r;		if(r->count > sizeof(buf))			r->count = sizeof(buf);		n = getinput(d, buf, r->count);		if(n == 0)			break;		d->r = r->next;		rhdr.type = Rread;		rhdr.fid = r->fid->fid;		rhdr.tag = r->tag;		rhdr.data = buf;		rhdr.count = n;		n = convS2M(&rhdr, mdata, messagesize);		if(write(mfd[1], mdata, n) != n)			fprint(2, "telco: error writing\n");		free(r);	}	free(mdata);	free(buf);}/* *  dial a number */char*dialout(Dev *d, char *number){	int i, m, compress, rateadjust, speed, fax;	char *err;	char *field[5];	char dialstr[128];	compress = Ok;	rateadjust = Failure;	speed = maxspeed;	fax = Failure;	m = getfields(number, field, 5, 1, "!");	for(i = 1; i < m; i++){		if(field[i][0] >= '0' && field[i][0] <= '9')			speed = atoi(field[i]);		else if(strcmp(field[i], "nocompress") == 0)			compress = Failure;		else if(strcmp(field[i], "fax") == 0)			fax = Ok;	}	syslog(0, LOGFILE, "dialing %s speed=%d %s", number, speed, fax==Ok?"fax":"");		err = modemtype(d, speed, fax == Ok);	if(err)		return err;	/*	 *  extented Hayes commands, meaning depends on modem (VGA all over again)	 */	if(fax != Ok){		if(d->fclass != 0)			applyspecial(d, Cfclass0);		applyspecial(d, Cerrorcorrection);		if(compress == Ok)			compress = applyspecial(d, Ccompression);		if(compress != Ok)			rateadjust = applyspecial(d, Crateadjust);	}	applyspecial(d, Cflowctl);	/* dialout */	sprint(dialstr, "ATD%c%s\r", pulsed ? 'P' : 'T', number);	if(send(d, dialstr) < 0)		return Edial;	if(fax == Ok)		return 0;		/* fax sender worries about the rest */	switch(readmsg(d, 120, 0)){	case Success:		break;	default:		return d->msgbuf;	}	/* change line rate if not compressing */	if(rateadjust == Ok)		setspeed(d, getspeed(d->msgbuf, d->speed));	return 0;}/* *  start a receiving process */voidreceiver(Dev *d){	int fd;	char file[256];	char *argv[8];	int argc;	int pfd[2];	char *prog;	pipe(pfd);	switch(rfork(RFPROC|RFMEM|RFFDG|RFNAMEG)){	case -1:		return;	case 0:		fd = open("/srv/telco", ORDWR);		if(fd < 0){			syslog(0, LOGFILE, "can't open telco: %r");			exits(0);		}		if(mount(fd, -1, "/net", MAFTER, "") < 0){			syslog(0, LOGFILE, "can't mount: %r");			exits(0);		}		close(fd);		/* open connection through the file system interface */		sprint(file, "/net/telco/%ld/data", d - dev);		fd = open(file, ORDWR);		if(fd < 0){			syslog(0, LOGFILE, "can't open %s: %r", file);			exits(0);		}		/* let parent continue */		close(pfd[0]);		close(pfd[1]);		/* answer the phone and see what flavor call this is */		prog = "/bin/service/telcodata";		switch(apply(d, "ATA", "+FCON", 30)){		case Success:			break;		case Found:			prog = "/bin/service/telcofax";			break;		default:			syslog(0, LOGFILE, "bad ATA response");			exits(0);		}		/* fork a receiving process */		dup(fd, 0);		dup(fd, 1);		close(fd);		argc = 0;		argv[argc++] = strrchr(prog, '/')+1;		argv[argc++] = file;		argv[argc++] = dev->t->name;		argv[argc] = 0;		exec(prog, argv);		syslog(0, LOGFILE, "can't exec %s: %r\n", prog);		exits(0);	default:		/* wait till child gets the device open */		close(pfd[1]);		read(pfd[0], file, 1);		close(pfd[0]);		break;	}}/* *  hang up an connections in progress */voidonhook(Dev *d){	write(d->ctl, "d0", 2);	write(d->ctl, "r0", 2);	sleep(250);	write(d->ctl, "r1", 2);	write(d->ctl, "d1", 2);	modemtype(d, maxspeed, 1);}/* *  read till we see a message or we time out */intreadmsg(Dev *d, int secs, char *substr){	ulong start;	char *p;	int i, len;	Msg *pp;	int found = 0;	p = d->msgbuf;	len = sizeof(d->msgbuf) - 1;	for(start = time(0); time(0) <= start+secs;){		if(len && d->rp == d->wp){			sleep(100);			continue;		}		i = getinput(d, p, 1);		if(i == 0)			continue;		if(*p == '\n' || *p == '\r' || len == 0){			*p = 0;			if(verbose && p != d->msgbuf)				syslog(0, LOGFILE, "<-%s", d->msgbuf);			if(substr && strstr(d->msgbuf, substr))				found = 1;			for(pp = msgs; pp->text; pp++)				if(strncmp(pp->text, d->msgbuf, strlen(pp->text))==0)					return found ? Found : pp->type;			start = time(0);			p = d->msgbuf;			len = sizeof(d->msgbuf) - 1;			continue;		}		len--;		p++;	}	strcpy(d->msgbuf, "No response from modem");	return found ? Found : Noise;}/* *  get baud rate from a connect message */intgetspeed(char *msg, int speed){	char *p;	int s;	p = msg + sizeof("CONNECT") - 1;	while(*p == ' ' || *p == '\t')		p++;	s = atoi(p);	if(s <= 0)		return speed;	else		return s;}/* *  set speed and RTS/CTS modem flow control */voidsetspeed(Dev *d, int baud){	char buf[32];	if(d->ctl < 0)		return;	sprint(buf, "b%d", baud);	write(d->ctl, buf, strlen(buf));	write(d->ctl, "m1", 2);}

⌨️ 快捷键说明

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