?? tftp.c
字號:
/* * 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. * 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. */#ifndef lintstatic char sccsid[] = "@(#)tftp.c 8.1 (Berkeley) 6/6/93";#endif /* not lint *//* Many bug fixes are from Jim Guyton <guyton@rand-unix> *//* * TFTP User Program -- Protocol Machines */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <sys/types.h>#include <sys/socket.h>#ifdef TIME_WITH_SYS_TIME# include <sys/time.h># include <time.h>#else# ifdef HAVE_SYS_TIME_H# include <sys/time.h># else# include <time.h># endif#endif#include <netinet/in.h>#include <arpa/tftp.h>#include <errno.h>#include <setjmp.h>#include <signal.h>#include <stdio.h>#include <string.h>#include <unistd.h>#include "extern.h"#include "tftpsubs.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;jmp_buf timeoutbuf;static void nak (int);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. */voidsend_file (int fd, char *name, char *mode){ register struct tftphdr *ap; /* data and ack packets */ struct tftphdr *r_init (), *dp; register int n; volatile int block, size, convert; volatile unsigned long amount; struct sockaddr_in from; int fromlen; 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"); block = 0; amount = 0; 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 ((u_short) block); } timeout = 0; setjmp (timeoutbuf); send_data: if (trace) tpacket ("sent", dp, size + 4); n = sendto (f, (const char *) 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->th_opcode = ntohs (ap->th_opcode); ap->th_block = ntohs (ap->th_block); 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; 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; } } if (block > 0) amount += size; block++; } while (size == SEGSIZE || block == 1); abort: fclose (file); stopclock (); if (amount > 0) printstats ("Sent", amount);}/* * Receive a file. */voidrecvfile (int fd, char *name, char *mode){ register struct tftphdr *ap; struct tftphdr *dp, *w_init (); register int n; volatile int block, size, firsttrip; volatile unsigned long amount; struct sockaddr_in from; int fromlen; FILE *file; volatile int convert; /* true if converting crlf -> lf */ startclock (); dp = w_init (); ap = (struct tftphdr *) ackbuf; file = fdopen (fd, "w"); convert = !strcmp (mode, "netascii"); block = 1; firsttrip = 1; amount = 0; 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; setjmp (timeoutbuf); 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, (char *) 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->th_opcode = ntohs (dp->th_opcode); dp->th_block = ntohs (dp->th_block); 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 (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 */ } } /* 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 ((u_short) block); 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){ 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'; 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. */static voidnak (int error){ register struct errmsg *pe; register struct tftphdr *tp; int length; 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 = strerror (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 *) &peeraddr, sizeof (peeraddr)) != length) perror ("nak");}static voidtpacket (const char *s, struct tftphdr *tp, int n){ static char *opcodes[] = { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR" }; register char *cp, *file; u_short op = ntohs (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 = 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 (){ gettimeofday (&tstart, NULL);}static voidstopclock (){ gettimeofday (&tstop, NULL);}static voidprintstats (const 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 %d bytes in %.1f seconds", direction, amount, delta); if (verbose) printf (" [%.0f bits/sec]", (amount * 8.) / delta); putchar ('\n');}static voidtimer (int sig){ timeout += rexmtval; if (timeout >= maxtimeout) { printf ("Transfer timed out.\n"); longjmp (toplevel, -1); } longjmp (timeoutbuf, 1);}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -