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

📄 tftp.c

📁 unix下tftp服务器源码
💻 C
字号:
/* $Id: tftp.c,v 1.17 2004/01/08 20:47:00 hpa Exp $ *//* $OpenBSD: tftp.c,v 1.4 1997/08/06 06:43:45 deraadt Exp $	*//* $NetBSD: tftp.c,v 1.5 1995/04/29 05:55:25 cgd Exp $	*//* * Copyright (c) 1983, 1993 *	The Regents of the University of California.  All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#include "tftpsubs.h"#ifndef lint/* static char sccsid[] = "@(#)tftp.c	8.1 (Berkeley) 6/6/93"; *//* static char rcsid[] = "$OpenBSD: tftp.c,v 1.4 1997/08/06 06:43:45 deraadt Exp $"; */static const char *rcsid UNUSED ="tftp-hpa $Id: tftp.c,v 1.17 2004/01/08 20:47:00 hpa Exp $";#endif /* not lint *//* Many bug fixes are from Jim Guyton <guyton@rand-unix> *//* * TFTP User Program -- Protocol Machines */#include "extern.h"extern  struct sockaddr_in peeraddr;	/* filled in by main */extern  int     f;			/* the opened socket */extern  int     trace;extern  int     verbose;extern  int     rexmtval;extern  int     maxtimeout;#define PKTSIZE    SEGSIZE+4char    ackbuf[PKTSIZE];int	timeout;sigjmp_buf	toplevel;sigjmp_buf	timeoutbuf;static void nak(int, const char *);static int makerequest(int, const char *, struct tftphdr *, const char *);static void printstats(const char *, unsigned long);static void startclock(void);static void stopclock(void);static void timer(int);static void tpacket(const char *, struct tftphdr *, int);/* * Send the requested file. */voidtftp_sendfile(int fd, const char *name, const char *mode){	struct tftphdr *ap;	   /* data and ack packets */	struct tftphdr *dp;	int n;	volatile int is_request;	volatile u_short block;	volatile int size, convert;	volatile off_t amount;	struct sockaddr_in from;	int fromlen;	FILE *file;	u_short ap_opcode, ap_block;	startclock();		/* start stat's clock */	dp = r_init();		/* reset fillbuf/read-ahead code */	ap = (struct tftphdr *)ackbuf;	convert = !strcmp(mode, "netascii");	file = fdopen(fd, convert ? "rt" : "rb");	block = 0;	is_request = 1;		/* First packet is the actual WRQ */	amount = 0;	bsd_signal(SIGALRM, timer);	do {		if (is_request) {			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, NULL);				break;			}			dp->th_opcode = htons((u_short)DATA);			dp->th_block = htons((u_short)block);		}		timeout = 0;		(void) sigsetjmp(timeoutbuf,1);		if (trace)			tpacket("sent", dp, size + 4);		n = sendto(f, dp, size + 4, 0,		    (struct sockaddr *)&peeraddr, sizeof(peeraddr));		if (n != size + 4) {			perror("tftp: sendto");			goto abort;		}		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;			}			peeraddr.sin_port = from.sin_port;	/* added */			if (trace)				tpacket("received", ap, n);			/* should verify packet came from server */			ap_opcode = ntohs((u_short)ap->th_opcode);			ap_block = ntohs((u_short)ap->th_block);			if (ap_opcode == ERROR) {				printf("Error code %d: %s\n", ap_block,					ap->th_msg);				goto abort;			}			if (ap_opcode == ACK) {				int j;				if (ap_block == block) {					break;				}				/* On an error, try to synchronize				 * both sides.				 */				j = synchnet(f);				if (j && trace) {					printf("discarded %d packets\n",							j);				}				/*				 * RFC1129/RFC1350: We MUST NOT re-send the DATA				 * packet in response to an invalid ACK.  Doing so				 * would cause the Sorcerer's Apprentice bug.				 */			}		}		if ( !is_request )			amount += size;		is_request = 0;		block++;	} while (size == SEGSIZE || block == 1);abort:	fclose(file);	stopclock();	if (amount > 0)		printstats("Sent", amount);}/* * Receive a file. */voidtftp_recvfile(int fd, const char *name, const char *mode){	struct tftphdr *ap;	struct tftphdr *dp;	int n;	volatile u_short block;	volatile int size, firsttrip;	volatile unsigned long amount;	struct sockaddr_in from;	int fromlen;	FILE *file;	volatile int convert;		/* true if converting crlf -> lf */	u_short dp_opcode, dp_block;	startclock();	dp = w_init();	ap = (struct tftphdr *)ackbuf;	convert = !strcmp(mode, "netascii");	file = fdopen(fd, convert ?"wt":"wb");	block = 1;	firsttrip = 1;	amount = 0;	bsd_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((u_short)block);			size = 4;			block++;		}		timeout = 0;		(void) sigsetjmp(timeoutbuf,1);send_ack:		if (trace)			tpacket("sent", ap, size);		if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&peeraddr,		    sizeof(peeraddr)) != size) {			alarm(0);			perror("tftp: sendto");			goto abort;		}		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;			}			peeraddr.sin_port = from.sin_port;	/* added */			if (trace)				tpacket("received", dp, n);			/* should verify client address */			dp_opcode = ntohs((u_short)dp->th_opcode);			dp_block = ntohs((u_short)dp->th_block);			if (dp_opcode == ERROR) {			  printf("Error code %d: %s\n", dp_block, dp->th_msg);			  goto abort;			}			if (dp_opcode == DATA) {				int j;				if (dp_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_block == (block-1)) {					goto send_ack;	/* resend ack */				}			}		}	/*	size = write(fd, dp->th_data, n - 4); */		size = writeit(file, &dp, n - 4, convert);		if (size < 0) {			nak(errno + 100, NULL);			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((u_short)block);	(void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peeraddr,	    sizeof(peeraddr));	write_behind(file, convert);		/* flush last buffer */	fclose(file);	stopclock();	if (amount > 0)		printstats("Received", amount);}static intmakerequest(int request, const char *name,	    struct tftphdr *tp, const char *mode){	char *cp;	tp->th_opcode = htons((u_short)request);	cp = (char *) &(tp->th_stuff);	strcpy(cp, name);	cp += strlen(name);	*cp++ = '\0';	strcpy(cp, mode);	cp += strlen(mode);	*cp++ = '\0';	return (cp - (char *)tp);}static const char * const errmsgs[] ={  "Undefined error code", 			/* 0 - EUNDEF */  "File not found",				/* 1 - ENOTFOUND */  "Access denied",				/* 2 - EACCESS */  "Disk full or allocation exceeded", 		/* 3 - ENOSPACE */  "Illegal TFTP operation",			/* 4 - EBADOP */  "Unknown transfer ID",			/* 5 - EBADID */  "File already exists",			/* 6 - EEXISTS */  "No such user",				/* 7 - ENOUSER */  "Failure to negotiate RFC2347 options" 	/* 8 - EOPTNEG */};#define ERR_CNT (sizeof(errmsgs)/sizeof(const char *))/* * Send a nak packet (error message). * Error code passed in is one of the * standard TFTP codes, or a UNIX errno * offset by 100. */static voidnak(int error, const char *msg){  struct tftphdr *tp;  int length;    tp = (struct tftphdr *)ackbuf;  tp->th_opcode = htons((u_short)ERROR);  tp->th_code = htons((u_short)error);  if ( error >= 100 ) {    /* This is a Unix errno+100 */    if ( !msg )      msg = strerror(error - 100);    error = EUNDEF;  } else {    if ( (unsigned)error >= ERR_CNT )      error = EUNDEF;        if ( !msg )      msg = errmsgs[error];  }  tp->th_code = htons((u_short)error);  length = strlen(msg)+1;  memcpy(tp->th_msg, msg, length);  length += 4;			/* Add space for header */  if (trace)    tpacket("sent", tp, length);  if (sendto(f, ackbuf, length, 0, (struct sockaddr *)&peeraddr,	     sizeof(peeraddr)) != length)    perror("nak");}static voidtpacket(const char *s, struct tftphdr *tp, int n){	static const char *opcodes[] =	   { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" };	char *cp, *file;	u_short op = ntohs((u_short)tp->th_opcode);	if (op < RRQ || op > ERROR)		printf("%s opcode=%x ", s, op);	else		printf("%s %s ", s, opcodes[op]);	switch (op) {	case RRQ:	case WRQ:		n -= 2;		file = cp = (char *) &(tp->th_stuff);		cp = strchr(cp, '\0');		printf("<file=%s, mode=%s>\n", file, cp + 1);		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;	}}struct timeval tstart;struct timeval tstop;static voidstartclock(void){	(void)gettimeofday(&tstart, NULL);}static voidstopclock(void){	(void)gettimeofday(&tstop, NULL);}static voidprintstats(const char *direction, unsigned long amount){	double delta;	delta = (tstop.tv_sec+(tstop.tv_usec/100000.0)) -		(tstart.tv_sec+(tstart.tv_usec/100000.0));	if (verbose) {	  printf("%s %lu bytes in %.1f seconds", direction, amount, delta);	  printf(" [%.0f bit/s]", (amount*8.)/delta);	  putchar('\n');	}}static voidtimer(int sig){	int save_errno = errno;	(void)sig;		/* Shut up unused warning */	timeout += rexmtval;	if (timeout >= maxtimeout) {		printf("Transfer timed out.\n");		errno = save_errno;		siglongjmp(toplevel, -1);	}	errno = save_errno;	siglongjmp(timeoutbuf, 1);}

⌨️ 快捷键说明

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