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

📄 tftp.c

📁 linux下从网卡远程启动
💻 C
字号:
/* * Copyright (c) 1983 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley.  The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */#ifndef lintstatic char sccsid[] = "@(#)tftp.c	5.7 (Berkeley) 6/29/88";#endif /* not lint *//* Many bug fixes are from Jim Guyton <guyton@rand-unix> *//* * TFTP User Program -- Protocol Machines */#include <sys/types.h>#include <sys/socket.h>#include <sys/time.h>#include <netinet/in.h>#include <arpa/tftp.h>#include <signal.h>#include <stdio.h>#include <errno.h>#include <setjmp.h>extern	int errno;extern  struct sockaddr_in sin;         /* filled in by main */extern  int     f;                      /* the opened socket */extern  int     trace;extern  int     verbose;extern  int     rexmtval;extern  int     maxtimeout;extern	int	segsize;#define PKTSIZE    (1432+4) /* SEGSIZE+4 */char    ackbuf[PKTSIZE];int	timeout;jmp_buf	toplevel;jmp_buf	timeoutbuf;#ifndef OACK#define OACK	6#endifvoid timer(int sig){	signal(SIGALRM, timer);	timeout += rexmtval;	if (timeout >= maxtimeout) {		printf("Transfer timed out.\n");		longjmp(toplevel, -1);	}	longjmp(timeoutbuf, 1);}strnlen(s, n)	char *s;	int n;{	int i = 0;	while (n-- > 0 && *s++) i++;	return(i);}/* * Parse an OACK package and set blocksize accordingly */parseoack(cp, sz)	char *cp;	int sz;{	int n;		segsize = 512;	while (sz > 0 && *cp) {		n = strnlen(cp, sz);		if (n == 7 && !strncmp("blksize", cp, 7)) {			cp += 8;			sz -= 8;			if (sz <= 0)				break;			for (segsize = 0, n = strnlen(cp, sz); n > 0;			     n--, cp++, sz--) {				if (*cp < '0' || *cp > '9')					break;				segsize = 10*segsize + *cp - '0'; }		}		cp += n + 1;		sz -= n + 1;	}	if (segsize < 8 || segsize > 1432) {		printf("Remote host negotiated illegal blocksize %d\n",		       segsize);		segsize = 512;		longjmp(timeoutbuf, -1);	}}/* * Send the requested file. */sendfile(fd, name, mode)	int fd;	char *name;	char *mode;{	register struct tftphdr *ap;       /* data and ack packets */	struct tftphdr *r_init(), *dp;	register int size, n;	u_short block = 0;	register unsigned long amount = 0;	struct sockaddr_in from;	int fromlen;	int convert;            /* true if doing nl->crlf conversion */	FILE *file;	startclock();           /* start stat's clock */	dp = r_init();          /* reset fillbuf/read-ahead code */	ap = (struct tftphdr *)ackbuf;	file = fdopen(fd, "r");	convert = !strcmp(mode, "netascii");	signal(SIGALRM, timer);	do {		if (block == 0)			size = makerequest(WRQ, name, dp, mode) - 4;		else {		/*      size = read(fd, dp->th_data, SEGSIZE);   */			size = readit(file, &dp, convert);			if (size < 0) {				nak(errno + 100);				break;			}			dp->th_opcode = htons((u_short)DATA);			dp->th_block = htons(block);		}		timeout = 0;		(void) setjmp(timeoutbuf);send_data:		if (trace)			tpacket("sent", dp, size + 4);		n = sendto(f, dp, size + 4, 0, (struct sockaddr *)&sin,			   sizeof (sin));		if (n != size + 4) {			perror("tftp: sendto");			goto abort;		}		if (block) /* do not start reading until the blocksize			      has been negotiated */			read_ahead(file, convert);		for ( ; ; ) {			alarm(rexmtval);			do {				fromlen = sizeof (from);				n = recvfrom(f, ackbuf, sizeof (ackbuf), 0,					     (struct sockaddr *)&from,					     &fromlen);			} while (n <= 0);			alarm(0);			if (n < 0) {				perror("tftp: recvfrom");				goto abort;			}			sin.sin_port = from.sin_port;   /* added */			if (trace)				tpacket("received", ap, n);			/* should verify packet came from server */			ap->th_opcode = ntohs(ap->th_opcode);			if (ap->th_opcode == ERROR) {				printf("Error code %d: %s\n", ap->th_code,					ap->th_msg);				goto abort;			}			if (ap->th_opcode == ACK) {				int j;				ap->th_block = ntohs(ap->th_block);				if (block == 0) {					if (trace)						printf("server does not know "						       "about RFC1782; reset"						       "ting blocksize\n");					segsize = 512;				}				if (ap->th_block == block) {					break;				}				/* On an error, try to synchronize				 * both sides.				 */				j = synchnet(f);				if (j && trace) {					printf("discarded %d packets\n",							j);				}				if (ap->th_block == (block-1)) {					goto send_data;				}			}			else if (ap->th_opcode == OACK) {				if (block) {					printf("protocol violation\n");					longjmp(toplevel, -1);				}				parseoack(&ap->th_stuff, n - 2);				break;			}		}		if (block > 0)			amount += size;		else			read_ahead(file, convert);		block++;	} while (size == segsize || block == 1);abort:	fclose(file);	stopclock();	if (amount > 0)		printstats("Sent", amount);}/* * Receive a file. */recvfile(fd, name, mode)	int fd;	char *name;	char *mode;{	register struct tftphdr *ap;	struct tftphdr *dp, *w_init();	register int n, size;	u_short block = 1;	unsigned long amount = 0;	struct sockaddr_in from;	int fromlen, firsttrip = 1;	FILE *file;	int convert;                    /* true if converting crlf -> lf */	int waitforoack = 1;	startclock();	dp = w_init();	ap = (struct tftphdr *)ackbuf;	file = fdopen(fd, "w");	convert = !strcmp(mode, "netascii");	signal(SIGALRM, timer);	do {		if (firsttrip) {			size = makerequest(RRQ, name, ap, mode);			firsttrip = 0;		} else {			ap->th_opcode = htons((u_short)ACK);			ap->th_block = htons(block);			size = 4;			block++;		}		timeout = 0;		(void) setjmp(timeoutbuf);send_ack:		if (trace)			tpacket("sent", ap, size);		if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&sin,		    sizeof (sin)) != size) {			alarm(0);			perror("tftp: sendto");			goto abort;		}		if (!waitforoack)			write_behind(file, convert);		for ( ; ; ) {			alarm(rexmtval);			do  {				fromlen = sizeof (from);				n = recvfrom(f, dp, PKTSIZE, 0,				    (struct sockaddr *)&from, &fromlen);			} while (n <= 0);			alarm(0);			if (n < 0) {				perror("tftp: recvfrom");				goto abort;			}			sin.sin_port = from.sin_port;   /* added */			if (trace)				tpacket("received", dp, n);			/* should verify client address */			dp->th_opcode = ntohs(dp->th_opcode);			if (dp->th_opcode == ERROR) {				printf("Error code %d: %s\n", dp->th_code,					dp->th_msg);				goto abort;			}			if (dp->th_opcode == DATA) {				int j;				if (waitforoack) {					if (trace)						printf("server does not know "						       "about RFC1782; reset"						       "ting blocksize\n");					waitforoack = 0;					segsize = 512;				}				dp->th_block = ntohs(dp->th_block);				if (dp->th_block == block) {					break;          /* have next packet */				}				/* On an error, try to synchronize				 * both sides.				 */				j = synchnet(f);				if (j && trace) {					printf("discarded %d packets\n", j);				}				if (dp->th_block == (block-1)) {					goto send_ack;  /* resend ack */				}			}			else if (dp->th_opcode == OACK) {				if (block != 1 || !waitforoack) {					printf("protocol violation\n");					longjmp(toplevel, -1);				}				waitforoack = 0;				parseoack(&dp->th_stuff, n - 2);				ap->th_opcode = htons((u_short)ACK);				ap->th_block = htons(0);				size = 4;				goto send_ack;			}		}		/* size = write(fd, dp->th_data, n - 4); */		size = writeit(file, &dp, n - 4, convert);		if (size < 0) {			nak(errno + 100);			break;		}		amount += size;	} while (size == segsize);abort:                                          /* ok to ack, since user */	ap->th_opcode = htons((u_short)ACK);    /* has seen err msg */	ap->th_block = htons(block);	(void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&sin, sizeof (sin));	write_behind(file, convert);            /* flush last buffer */	fclose(file);	stopclock();	if (amount > 0)		printstats("Received", amount);}makerequest(request, name, tp, mode)	int request;	char *name, *mode;	struct tftphdr *tp;{	register char *cp;	tp->th_opcode = htons((u_short)request);	cp = tp->th_stuff;	strcpy(cp, name);	cp += strlen(name);	*cp++ = '\0';	strcpy(cp, mode);	cp += strlen(mode);	*cp++ = '\0';	strcpy(cp, "blksize");	cp += 7;	*cp++ = '\0';	sprintf(cp, "%d", segsize);	cp += strlen(cp) + 1;	return (cp - (char *)tp);}struct errmsg {	int	e_code;	const char	*e_msg;} errmsgs[] = {	{ EUNDEF,	"Undefined error code" },	{ ENOTFOUND,	"File not found" },	{ EACCESS,	"Access violation" },	{ ENOSPACE,	"Disk full or allocation exceeded" },	{ EBADOP,	"Illegal TFTP operation" },	{ EBADID,	"Unknown transfer ID" },	{ EEXISTS,	"File already exists" },	{ ENOUSER,	"No such user" },	{ -1,		0 }};/* * Send a nak packet (error message). * Error code passed in is one of the * standard TFTP codes, or a UNIX errno * offset by 100. */nak(error)	int error;{	register struct tftphdr *tp;	int length;	register struct errmsg *pe;/*	extern char *sys_errlist[]; */	tp = (struct tftphdr *)ackbuf;	tp->th_opcode = htons((u_short)ERROR);	tp->th_code = htons((u_short)error);	for (pe = errmsgs; pe->e_code >= 0; pe++)		if (pe->e_code == error)			break;	if (pe->e_code < 0) {		pe->e_msg = sys_errlist[error - 100];		tp->th_code = EUNDEF;	}	strcpy(tp->th_msg, pe->e_msg);	length = strlen(pe->e_msg) + 4;	if (trace)		tpacket("sent", tp, length);	if (sendto(f, ackbuf, length, 0, (struct sockaddr *)&sin, sizeof (sin))	    != length)		perror("nak");}topts(cp, sz)	char *cp;	int sz;{	int n, i = 0;		while (sz > 0 && *cp) {		n = strnlen(cp, sz);		if (n > 0) {			printf("%s%s=", i++ ? ", " : "", cp);			cp += n + 1;			sz -= n + 1;			if (sz <= 0)				break;			n = strnlen(cp, sz);			if (n > 0)				printf("%s", cp);		}		cp += n + 1;		sz -= n + 1;	}}tpacket(s, tp, n)	char *s;	struct tftphdr *tp;	int n;{	static char *opcodes[] =	   { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" };	register char *cp, *file;	u_short op = ntohs(tp->th_opcode);	char *index();	if (op < RRQ || op > OACK)		printf("%s opcode=%x ", s, op);	else		printf("%s %s ", s, opcodes[op]);	switch (op) {	case RRQ:	case WRQ:		n -= 2;		file = cp = tp->th_stuff;		cp = index(cp, '\0');		printf("<file=%s, mode=%s, opts: ", file, cp + 1);		topts(index(cp + 1, '\000') + 1, n - strlen(file)		      - strlen(cp + 1) - 2);		printf(">\n");		break;	case DATA:		printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);		break;	case ACK:		printf("<block=%d>\n", ntohs(tp->th_block));		break;	case ERROR:		printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);		break;	case OACK:		printf("<");		topts(tp->th_stuff, n - 2);		printf(">\n");		break;	}}struct timeval tstart;struct timeval tstop;struct timezone zone;startclock() {	gettimeofday(&tstart, &zone);}stopclock() {	gettimeofday(&tstop, &zone);}printstats(direction, amount)char *direction;unsigned long amount;{	double delta;			/* compute delta in 1/10's second units */	delta = ((tstop.tv_sec*10.)+(tstop.tv_usec/100000)) -		((tstart.tv_sec*10.)+(tstart.tv_usec/100000));	delta = delta/10.;      /* back to seconds */	printf("%s %ld bytes in %.1f seconds", direction, amount, delta);	if ((verbose) && (delta >= 0.1))			printf(" [%.0f bits/sec]", (amount*8.)/delta);	putchar('\n');}

⌨️ 快捷键说明

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