Install version from Jim Guyton <guyton@rand-unix>.
authorGregory Minshall <minshall@ucbvax.Berkeley.EDU>
Fri, 7 Feb 1986 07:01:45 +0000 (23:01 -0800)
committerGregory Minshall <minshall@ucbvax.Berkeley.EDU>
Fri, 7 Feb 1986 07:01:45 +0000 (23:01 -0800)
SCCS-vsn: usr.bin/tftp/Makefile 5.2
SCCS-vsn: usr.bin/tftp/tftp.c 5.2
SCCS-vsn: usr.bin/tftp/main.c 5.3

usr/src/usr.bin/tftp/Makefile
usr/src/usr.bin/tftp/main.c
usr/src/usr.bin/tftp/tftp.c

index c89c69e..c01ada8 100644 (file)
@@ -3,7 +3,7 @@
 # All rights reserved.  The Berkeley software License Agreement
 # specifies the terms and conditions for redistribution.
 #
 # All rights reserved.  The Berkeley software License Agreement
 # specifies the terms and conditions for redistribution.
 #
-#      @(#)Makefile    5.1 (Berkeley) %G%
+#      @(#)Makefile    5.2 (Berkeley) %G%
 #
 ALL=   tftp
 DESTDIR=
 #
 ALL=   tftp
 DESTDIR=
@@ -11,8 +11,8 @@ CFLAGS=-O
 
 all: ${ALL}
 
 
 all: ${ALL}
 
-tftp:  main.o tftp.o
-       ${CC} main.o tftp.o -o tftp
+tftp:  main.o tftp.o tftpsubs.o
+       ${CC} main.o tftp.o tftpsubs.o -o tftp
 
 clean:
        rm -f ${ALL} *.o *.s errs core a.out t.?
 
 clean:
        rm -f ${ALL} *.o *.s errs core a.out t.?
index 8606b15..429c30e 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 1983 Regents of the University of California.
+ * Copyright (c) 1985 Regents of the University of California.
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  */
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  */
@@ -11,9 +11,11 @@ char copyright[] =
 #endif not lint
 
 #ifndef lint
 #endif not lint
 
 #ifndef lint
-static char sccsid[] = "@(#)main.c     5.2 (Berkeley) %G%";
+static char sccsid[] = "@(#)main.c     5.3 (Berkeley) %G%";
 #endif not lint
 
 #endif not lint
 
+/* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
+
 /*
  * TFTP User Program -- Command Interface.
  */
 /*
  * TFTP User Program -- Command Interface.
  */
@@ -32,9 +34,11 @@ static char sccsid[] = "@(#)main.c   5.2 (Berkeley) %G%";
 
 #define        TIMEOUT         5               /* secs between rexmt's */
 
 
 #define        TIMEOUT         5               /* secs between rexmt's */
 
-struct sockaddr_in sin = { AF_INET };
+struct sockaddr_in sin;
 int    f;
 int    f;
+short   port;
 int    trace;
 int    trace;
+int    verbose;
 int    connected;
 char   mode[32];
 char   line[200];
 int    connected;
 char   mode[32];
 char   line[200];
@@ -45,8 +49,9 @@ jmp_buf       toplevel;
 int    intr();
 struct servent *sp;
 
 int    intr();
 struct servent *sp;
 
-int    quit(), help(), settrace(), status();
-int    get(), put(), setpeer(), setmode(), setrexmt(), settimeout();
+int    quit(), help(), setverbose(), settrace(), status();
+int     get(), put(), setpeer(), modecmd(), setrexmt(), settimeout();
+int     setbinary(), setascii();
 
 #define HELPINDENT (sizeof("connect"))
 
 
 #define HELPINDENT (sizeof("connect"))
 
@@ -56,6 +61,7 @@ struct cmd {
        int     (*handler)();
 };
 
        int     (*handler)();
 };
 
+char   vhelp[] = "toggle verbose mode";
 char   thelp[] = "toggle packet tracing";
 char   chelp[] = "connect to remote tftp";
 char   qhelp[] = "exit tftp";
 char   thelp[] = "toggle packet tracing";
 char   chelp[] = "connect to remote tftp";
 char   qhelp[] = "exit tftp";
@@ -66,15 +72,20 @@ char        mhelp[] = "set file transfer mode";
 char   sthelp[] = "show current status";
 char   xhelp[] = "set per-packet retransmission timeout";
 char   ihelp[] = "set total retransmission timeout";
 char   sthelp[] = "show current status";
 char   xhelp[] = "set per-packet retransmission timeout";
 char   ihelp[] = "set total retransmission timeout";
+char    ashelp[] = "set mode to netascii";
+char    bnhelp[] = "set mode to octet";
 
 struct cmd cmdtab[] = {
        { "connect",    chelp,          setpeer },
 
 struct cmd cmdtab[] = {
        { "connect",    chelp,          setpeer },
-       { "mode",       mhelp,          setmode },
+       { "mode",       mhelp,          modecmd },
        { "put",        shelp,          put },
        { "get",        rhelp,          get },
        { "quit",       qhelp,          quit },
        { "put",        shelp,          put },
        { "get",        rhelp,          get },
        { "quit",       qhelp,          quit },
+       { "verbose",    vhelp,          setverbose },
        { "trace",      thelp,          settrace },
        { "status",     sthelp,         status },
        { "trace",      thelp,          settrace },
        { "status",     sthelp,         status },
+       { "binary",     bnhelp,         setbinary },
+       { "ascii",      ashelp,         setascii },
        { "rexmt",      xhelp,          setrexmt },
        { "timeout",    ihelp,          settimeout },
        { "?",          hhelp,          help },
        { "rexmt",      xhelp,          setrexmt },
        { "timeout",    ihelp,          settimeout },
        { "?",          hhelp,          help },
@@ -89,6 +100,7 @@ char *rindex();
 main(argc, argv)
        char *argv[];
 {
 main(argc, argv)
        char *argv[];
 {
+       struct sockaddr_in sin;
        int top;
 
        sp = getservbyname("tftp", "udp");
        int top;
 
        sp = getservbyname("tftp", "udp");
@@ -101,11 +113,13 @@ main(argc, argv)
                perror("tftp: socket");
                exit(3);
        }
                perror("tftp: socket");
                exit(3);
        }
+       bzero((char *)&sin, sizeof (sin));
+       sin.sin_family = AF_INET;
        if (bind(f, &sin, sizeof (sin)) < 0) {
                perror("tftp: bind");
                exit(1);
        }
        if (bind(f, &sin, sizeof (sin)) < 0) {
                perror("tftp: bind");
                exit(1);
        }
-       strcpy(mode, "octet");
+       strcpy(mode, "netascii");
        signal(SIGINT, intr);
        if (argc > 1) {
                if (setjmp(toplevel) != 0)
        signal(SIGINT, intr);
        if (argc > 1) {
                if (setjmp(toplevel) != 0)
@@ -117,14 +131,12 @@ main(argc, argv)
                command(top);
 }
 
                command(top);
 }
 
-char   *hostname;
-char   hnamebuf[32];
+char    hostname[100];
 
 setpeer(argc, argv)
        int argc;
        char *argv[];
 {
 
 setpeer(argc, argv)
        int argc;
        char *argv[];
 {
-       register int c;
        struct hostent *host;
 
        if (argc < 2) {
        struct hostent *host;
 
        if (argc < 2) {
@@ -143,7 +155,7 @@ setpeer(argc, argv)
        if (host) {
                sin.sin_family = host->h_addrtype;
                bcopy(host->h_addr, &sin.sin_addr, host->h_length);
        if (host) {
                sin.sin_family = host->h_addrtype;
                bcopy(host->h_addr, &sin.sin_addr, host->h_length);
-               hostname = host->h_name;
+               strcpy(hostname, host->h_name);
        } else {
                sin.sin_family = AF_INET;
                sin.sin_addr.s_addr = inet_addr(argv[1]);
        } else {
                sin.sin_family = AF_INET;
                sin.sin_addr.s_addr = inet_addr(argv[1]);
@@ -152,18 +164,17 @@ setpeer(argc, argv)
                        printf("%s: unknown host\n", argv[1]);
                        return;
                }
                        printf("%s: unknown host\n", argv[1]);
                        return;
                }
-               strcpy(hnamebuf, argv[1]);
-               hostname = hnamebuf;
+               strcpy(hostname, argv[1]);
        }
        }
-       sin.sin_port = sp->s_port;
+       port = sp->s_port;
        if (argc == 3) {
        if (argc == 3) {
-               sin.sin_port = atoi(argv[2]);
-               if (sin.sin_port < 0) {
+               port = atoi(argv[2]);
+               if (port < 0) {
                        printf("%s: bad port number\n", argv[2]);
                        connected = 0;
                        return;
                }
                        printf("%s: bad port number\n", argv[2]);
                        connected = 0;
                        return;
                }
-               sin.sin_port = htons((u_short)sin.sin_port);
+               port = htons(port);
        }
        connected = 1;
 }
        }
        connected = 1;
 }
@@ -172,43 +183,67 @@ struct    modes {
        char *m_name;
        char *m_mode;
 } modes[] = {
        char *m_name;
        char *m_mode;
 } modes[] = {
-       { "binary",     "octet" },
-       { "image",      "octet" },
-       { "octet",      "octet" },
+       { "ascii",      "netascii" },
+       { "netascii",   "netascii" },
+       { "binary",     "octet" },
+       { "image",      "octet" },
+       { "octect",     "octet" },
+/*      { "mail",       "mail" },       */
        { 0,            0 }
 };
 
        { 0,            0 }
 };
 
-setmode(argc, argv)
+modecmd(argc, argv)
        char *argv[];
 {
        register struct modes *p;
        char *argv[];
 {
        register struct modes *p;
+       char *sep;
 
 
-       if (argc > 2) {
-               char *sep;
-
-               printf("usage: %s [", argv[0]);
-               sep = " ";
-               for (p = modes; p->m_name; p++) {
-                       printf("%s%s", sep, p->m_name);
-                       if (*sep == ' ')
-                               sep = " | ";
-               }
-               printf(" ]\n");
-               return;
-       }
        if (argc < 2) {
                printf("Using %s mode to transfer files.\n", mode);
                return;
        }
        if (argc < 2) {
                printf("Using %s mode to transfer files.\n", mode);
                return;
        }
-       for (p = modes; p->m_name; p++)
-               if (strcmp(argv[1], p->m_name) == 0)
-                       break;
-       if (p->m_name)
-               strcpy(mode, p->m_mode);
-       else
+       if (argc == 2) {
+               for (p = modes; p->m_name; p++)
+                       if (strcmp(argv[1], p->m_name) == 0)
+                               break;
+               if (p->m_name) {
+                       setmode(p->m_mode);
+                       return;
+               }
                printf("%s: unknown mode\n", argv[1]);
                printf("%s: unknown mode\n", argv[1]);
+               /* drop through and print usage message */
+       }
+
+       printf("usage: %s [", argv[0]);
+       sep = " ";
+       for (p = modes; p->m_name; p++) {
+               printf("%s%s", sep, p->m_name);
+               if (*sep == ' ')
+                       sep = " | ";
+       }
+       printf(" ]\n");
+       return;
+}
+
+setbinary(argc, argv)
+char *argv[];
+{       setmode("octet");
+}
+
+setascii(argc, argv)
+char *argv[];
+{       setmode("netascii");
 }
 
 }
 
+setmode(newmode)
+char *newmode;
+{
+       strcpy(mode, newmode);
+       if (verbose)
+               printf("mode set to %s\n", mode);
+}
+
+
 /*
  * Send file(s).
  */
 /*
  * Send file(s).
  */
@@ -216,7 +251,7 @@ put(argc, argv)
        char *argv[];
 {
        int fd;
        char *argv[];
 {
        int fd;
-       register int n, addr;
+       register int n;
        register char *cp, *targ;
 
        if (argc < 2) {
        register char *cp, *targ;
 
        if (argc < 2) {
@@ -252,7 +287,7 @@ put(argc, argv)
                bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
                sin.sin_family = hp->h_addrtype;
                connected = 1;
                bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
                sin.sin_family = hp->h_addrtype;
                connected = 1;
-               hostname = hp->h_name;
+               strcpy(hostname, hp->h_name);
        }
        if (!connected) {
                printf("No target machine specified.\n");
        }
        if (!connected) {
                printf("No target machine specified.\n");
@@ -265,9 +300,15 @@ put(argc, argv)
                        fprintf(stderr, "tftp: "); perror(cp);
                        return;
                }
                        fprintf(stderr, "tftp: "); perror(cp);
                        return;
                }
-               (void) sendfile(fd, targ);
+               if (verbose)
+                       printf("putting %s to %s:%s [%s]\n",
+                               cp, hostname, targ, mode);
+               sin.sin_port = port;
+               sendfile(fd, targ, mode);
                return;
        }
                return;
        }
+                               /* this assumes the target is a directory */
+                               /* on a remote unix system.  hmmmm.  */
        cp = index(targ, '\0'); 
        *cp++ = '/';
        for (n = 1; n < argc - 1; n++) {
        cp = index(targ, '\0'); 
        *cp++ = '/';
        for (n = 1; n < argc - 1; n++) {
@@ -277,7 +318,11 @@ put(argc, argv)
                        fprintf(stderr, "tftp: "); perror(argv[n]);
                        continue;
                }
                        fprintf(stderr, "tftp: "); perror(argv[n]);
                        continue;
                }
-               (void) sendfile(fd, targ);
+               if (verbose)
+                       printf("putting %s to %s:%s [%s]\n",
+                               argv[n], hostname, targ, mode);
+               sin.sin_port = port;
+               sendfile(fd, targ, mode);
        }
 }
 
        }
 }
 
@@ -295,7 +340,7 @@ get(argc, argv)
        char *argv[];
 {
        int fd;
        char *argv[];
 {
        int fd;
-       register int n, addr;
+       register int n;
        register char *cp;
        char *src;
 
        register char *cp;
        char *src;
 
@@ -311,13 +356,14 @@ get(argc, argv)
                getusage(argv[0]);
                return;
        }
                getusage(argv[0]);
                return;
        }
-       if (!connected)
-               for (n = 1; n < argc - 1; n++)
+       if (!connected) {
+               for (n = 1; n < argc ; n++)
                        if (index(argv[n], ':') == 0) {
                                getusage(argv[0]);
                                return;
                        }
                        if (index(argv[n], ':') == 0) {
                                getusage(argv[0]);
                                return;
                        }
-       for (n = 1; argc == 2 || n < argc - 1; n++) {
+       }
+       for (n = 1; n < argc ; n++) {
                src = index(argv[n], ':');
                if (src == NULL)
                        src = argv[n];
                src = index(argv[n], ':');
                if (src == NULL)
                        src = argv[n];
@@ -333,7 +379,7 @@ get(argc, argv)
                        bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
                        sin.sin_family = hp->h_addrtype;
                        connected = 1;
                        bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
                        sin.sin_family = hp->h_addrtype;
                        connected = 1;
-                       hostname = hp->h_name;
+                       strcpy(hostname, hp->h_name);
                }
                if (argc < 4) {
                        cp = argc == 3 ? argv[2] : tail(src);
                }
                if (argc < 4) {
                        cp = argc == 3 ? argv[2] : tail(src);
@@ -342,18 +388,24 @@ get(argc, argv)
                                fprintf(stderr, "tftp: "); perror(cp);
                                return;
                        }
                                fprintf(stderr, "tftp: "); perror(cp);
                                return;
                        }
-                       (void) recvfile(fd, src);
+                       if (verbose)
+                               printf("getting from %s:%s to %s [%s]\n",
+                                       hostname, src, cp, mode);
+                       sin.sin_port = port;
+                       recvfile(fd, src, mode);
                        break;
                }
                        break;
                }
-               cp = index(argv[argc - 1], '\0');
-               *cp++ = '/';
-               strcpy(cp, tail(src));
-               fd = creat(src, 0644);
+               cp = tail(src);         /* new .. jdg */
+               fd = creat(cp, 0644);
                if (fd < 0) {
                if (fd < 0) {
-                       fprintf(stderr, "tftp: "); perror(src);
+                       fprintf(stderr, "tftp: "); perror(cp);
                        continue;
                }
                        continue;
                }
-               (void) recvfile(fd, src);
+               if (verbose)
+                       printf("getting from %s:%s to %s [%s]\n",
+                               hostname, src, cp, mode);
+               sin.sin_port = port;
+               recvfile(fd, src, mode);
        }
 }
 
        }
 }
 
@@ -422,14 +474,15 @@ status(argc, argv)
                printf("Connected to %s.\n", hostname);
        else
                printf("Not connected.\n");
                printf("Connected to %s.\n", hostname);
        else
                printf("Not connected.\n");
-       printf("Mode: %s Tracing: %s\n", mode, trace ? "on" : "off");
+       printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
+               verbose ? "on" : "off", trace ? "on" : "off");
        printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
                rexmtval, maxtimeout);
 }
 
 intr()
 {
        printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
                rexmtval, maxtimeout);
 }
 
 intr()
 {
-
+       signal(SIGALRM, SIG_IGN);
        alarm(0);
        longjmp(toplevel, -1);
 }
        alarm(0);
        longjmp(toplevel, -1);
 }
@@ -463,12 +516,8 @@ command(top)
                putchar('\n');
        for (;;) {
                printf("%s> ", prompt);
                putchar('\n');
        for (;;) {
                printf("%s> ", prompt);
-               if (gets(line) == 0) {
-                       if (feof(stdin))
-                               quit();
-                       else
-                               continue;
-               }
+               if (gets(line) == 0)
+                       continue;
                if (line[0] == 0)
                        continue;
                makeargv();
                if (line[0] == 0)
                        continue;
                makeargv();
@@ -579,3 +628,10 @@ settrace()
        trace = !trace;
        printf("Packet tracing %s.\n", trace ? "on" : "off");
 }
        trace = !trace;
        printf("Packet tracing %s.\n", trace ? "on" : "off");
 }
+
+/*VARARGS*/
+setverbose()
+{
+       verbose = !verbose;
+       printf("Verbose mode %s.\n", verbose ? "on" : "off");
+}
index e1a7e76..a2d5c47 100644 (file)
@@ -1,39 +1,42 @@
 /*
 /*
- * Copyright (c) 1983 Regents of the University of California.
+ * Copyright (c) 1985 Regents of the University of California.
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  */
 
 #ifndef lint
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)tftp.c     5.1 (Berkeley) %G%";
+static char sccsid[] = "@(#)tftp.c     5.2 (Berkeley) %G%";
 #endif not lint
 
 #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>
 /*
  * TFTP User Program -- Protocol Machines
  */
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/time.h>
 
 #include <netinet/in.h>
 
 #include <netinet/in.h>
-#include <arpa/inet.h>
+
 #include <arpa/tftp.h>
 
 #include <signal.h>
 #include <stdio.h>
 #include <errno.h>
 #include <setjmp.h>
 #include <arpa/tftp.h>
 
 #include <signal.h>
 #include <stdio.h>
 #include <errno.h>
 #include <setjmp.h>
-#include <netdb.h>
 
 extern int errno;
 
 extern int errno;
-extern struct sockaddr_in sin;
-extern char mode[];
-int    f;
-int    trace;
-int    connected;
-char   sbuf[BUFSIZ];                   /* send buffer */
-char   rbuf[BUFSIZ];                   /* receive buffer */
-int    rexmtval;
-int    maxtimeout;
+
+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;
+
+#define PKTSIZE    SEGSIZE+4
+char    ackbuf[PKTSIZE];
 int    timeout;
 jmp_buf        toplevel;
 jmp_buf        timeoutbuf;
 int    timeout;
 jmp_buf        toplevel;
 jmp_buf        timeoutbuf;
@@ -52,205 +55,196 @@ timer()
 /*
  * Send the requested file.
  */
 /*
  * Send the requested file.
  */
-sendfile(fd, name)
+sendfile(fd, name, mode)
        int fd;
        char *name;
        int fd;
        char *name;
+       char *mode;
 {
 {
-       register struct tftphdr *stp = (struct tftphdr *)sbuf;
-       register struct tftphdr *rtp = (struct tftphdr *)rbuf;
-       register int block = 0, size, n, amount = 0;
-       struct sockaddr_in from, to;
-       time_t start = time(0), delta;
-       int fromlen, aborted = 0;
-
-       to = sin;
+       register struct tftphdr *ap;       /* data and ack packets */
+       struct tftphdr *r_init(), *dp;
+       register int block = 0, size, n;
+       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)
        signal(SIGALRM, timer);
        do {
                if (block == 0)
-                       size = makerequest(WRQ, name) - 4;
+                       size = makerequest(WRQ, name, dp, mode) - 4;
                else {
                else {
-                       size = read(fd, stp->th_data, SEGSIZE);
+               /*      size = read(fd, dp->th_data, SEGSIZE);   */
+                       size = readit(file, &dp, convert);
                        if (size < 0) {
                        if (size < 0) {
-                               nak(&to, errno + 100);
+                               nak(errno + 100);
                                break;
                        }
                                break;
                        }
-                       stp->th_opcode = htons((u_short)DATA);
-                       stp->th_block = htons((u_short)block);
+                       dp->th_opcode = htons((u_short)DATA);
+                       dp->th_block = htons((u_short)block);
                }
                timeout = 0;
                (void) setjmp(timeoutbuf);
                if (trace)
                }
                timeout = 0;
                (void) setjmp(timeoutbuf);
                if (trace)
-                       tpacket("sent", &to, stp, size + 4);
-               n = sendto(f, sbuf, size + 4, 0, (caddr_t)&to, sizeof (to));
+                       tpacket("sent", dp, size + 4);
+               n = sendto(f, dp, size + 4, 0, (caddr_t)&sin, sizeof (sin));
                if (n != size + 4) {
                        perror("tftp: sendto");
                if (n != size + 4) {
                        perror("tftp: sendto");
-                       aborted = 1;
-                       goto done;
+                       goto abort;
                }
                }
+               read_ahead(file, convert);
                do {
                do {
-again:
                        alarm(rexmtval);
                        do {
                                fromlen = sizeof (from);
                        alarm(rexmtval);
                        do {
                                fromlen = sizeof (from);
-                               n = recvfrom(f, rbuf, sizeof (rbuf), 0,
+                               n = recvfrom(f, ackbuf, sizeof (ackbuf), 0,
                                    (caddr_t)&from, &fromlen);
                        } while (n <= 0);
                        alarm(0);
                        if (n < 0) {
                                perror("tftp: recvfrom");
                                    (caddr_t)&from, &fromlen);
                        } while (n <= 0);
                        alarm(0);
                        if (n < 0) {
                                perror("tftp: recvfrom");
-                               aborted = 1;
-                               goto done;
-                       }
-                       if (to.sin_addr.s_addr != from.sin_addr.s_addr) {
-                               tpacket("discarded (wrong host)",
-                                   &from, rtp, n);
-                               goto again;
-                       }
-                       if (to.sin_port = sin.sin_port)
-                               to.sin_port = from.sin_port;
-                       if (to.sin_port != from.sin_port) {
-                               tpacket("discarded (wrong port)",
-                                   &from, rtp, n);
-                               goto again;
+                               goto abort;
                        }
                        }
+                       sin.sin_port = from.sin_port;   /* added */
                        if (trace)
                        if (trace)
-                               tpacket("received", &from, rtp, n);
+                               tpacket("received", ap, n);
                        /* should verify packet came from server */
                        /* should verify packet came from server */
-                       rtp->th_opcode = ntohs(rtp->th_opcode);
-                       rtp->th_block = ntohs(rtp->th_block);
-                       if (rtp->th_opcode == ERROR) {
-                               printf("Error code %d: %s\n", rtp->th_code,
-                                       rtp->th_msg);
-                               aborted = 1;
-                               goto done;
+                       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;
                        }
                        }
-               } while (rtp->th_opcode != ACK && block != rtp->th_block);
+               } while (ap->th_opcode != ACK || block != ap->th_block);
                if (block > 0)
                        amount += size;
                block++;
        } while (size == SEGSIZE || block == 1);
                if (block > 0)
                        amount += size;
                block++;
        } while (size == SEGSIZE || block == 1);
-       if (!aborted && amount > 0) {
-               delta = time(0) - start;
-               printf("Sent %d bytes in %d seconds.\n", amount, delta);
-       }
-done:
-       (void) close(fd);
-       return (aborted);
+abort:
+       fclose(file);
+       stopclock();
+       if (amount > 0)
+               printstats("Sent", amount);
 }
 
 /*
  * Receive a file.
  */
 }
 
 /*
  * Receive a file.
  */
-recvfile(fd, name)
+recvfile(fd, name, mode)
        int fd;
        char *name;
        int fd;
        char *name;
+       char *mode;
 {
 {
-       register struct tftphdr *stp = (struct tftphdr *)sbuf;
-       register struct tftphdr *rtp = (struct tftphdr *)rbuf;
-       register int block = 1, n, size, amount = 0;
-       struct sockaddr_in from, to;
-       time_t start = time(0), delta;
-       int fromlen, firsttrip = 1, aborted = 0;
-
-       to = sin;
+       register struct tftphdr *ap;
+       struct tftphdr *dp, *w_init();
+       register int block = 1, n, size;
+       unsigned long amount = 0;
+       struct sockaddr_in from;
+       int fromlen, firsttrip = 1;
+       FILE *file;
+       int convert;                    /* true if converting crlf -> lf */
+
+       startclock();
+       dp = w_init();
+       ap = (struct tftphdr *)ackbuf;
+       file = fdopen(fd, "w");
+       convert = !strcmp(mode, "netascii");
+
        signal(SIGALRM, timer);
        do {
                if (firsttrip) {
        signal(SIGALRM, timer);
        do {
                if (firsttrip) {
-                       size = makerequest(RRQ, name);
+                       size = makerequest(RRQ, name, ap, mode);
                        firsttrip = 0;
                } else {
                        firsttrip = 0;
                } else {
-                       stp->th_opcode = htons((u_short)ACK);
-                       stp->th_block = htons((u_short)(block));
+                       ap->th_opcode = htons((u_short)ACK);
+                       ap->th_block = htons((u_short)(block));
                        size = 4;
                        block++;
                }
                timeout = 0;
                (void) setjmp(timeoutbuf);
                        size = 4;
                        block++;
                }
                timeout = 0;
                (void) setjmp(timeoutbuf);
+send_ack:
                if (trace)
                if (trace)
-                       tpacket("sent", &to, stp, size);
-               if (sendto(f, sbuf, size, 0, (caddr_t)&to,
-                   sizeof (to)) != size) {
+                       tpacket("sent", ap, size);
+               if (sendto(f, ackbuf, size, 0, (caddr_t)&sin,
+                   sizeof (sin)) != size) {
                        alarm(0);
                        perror("tftp: sendto");
                        alarm(0);
                        perror("tftp: sendto");
-                       aborted = 1;
-                       goto done;
+                       goto abort;
                }
                }
-               do {
-again:
+               write_behind(file, convert);
+               for ( ; ; ) {
                        alarm(rexmtval);
                        alarm(rexmtval);
-                       do {
+                       do  {
                                fromlen = sizeof (from);
                                fromlen = sizeof (from);
-                               n = recvfrom(f, rbuf, sizeof (rbuf), 0,
+                               n = recvfrom(f, dp, PKTSIZE, 0,
                                    (caddr_t)&from, &fromlen);
                        } while (n <= 0);
                        alarm(0);
                        if (n < 0) {
                                perror("tftp: recvfrom");
                                    (caddr_t)&from, &fromlen);
                        } while (n <= 0);
                        alarm(0);
                        if (n < 0) {
                                perror("tftp: recvfrom");
-                               aborted = 1;
-                               goto done;
-                       }
-                       if (to.sin_addr.s_addr != from.sin_addr.s_addr) {
-                               tpacket("discarded (wrong host)",
-                                   &from, rtp, n);
-                               goto again;
-                       }
-                       if (to.sin_port = sin.sin_port)
-                               to.sin_port = from.sin_port;
-                       if (to.sin_port != from.sin_port) {
-                               tpacket("discarded (wrong port)",
-                                   &from, rtp, n);
-                               goto again;
+                               goto abort;
                        }
                        }
+                       sin.sin_port = from.sin_port;   /* added */
                        if (trace)
                        if (trace)
-                               tpacket("received", &from, rtp, n);
-                       rtp->th_opcode = ntohs(rtp->th_opcode);
-                       rtp->th_block = ntohs(rtp->th_block);
-                       if (rtp->th_opcode == ERROR) {
-                               printf("Error code %d: %s\n", rtp->th_code,
-                                       rtp->th_msg);
-                               aborted = 1;
-                               goto done;
+                               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) {
+                               if (dp->th_block == block)
+                                       break;          /* have next packet */
+                               if (dp->th_block == (block-1))
+                                       goto send_ack;  /* resend ack */
                        }
                        }
-               } while (rtp->th_opcode != DATA && rtp->th_block != block);
-               size = write(fd, rtp->th_data, n - 4);
+               }
+       /*      size = write(fd, dp->th_data, n - 4); */
+               size = writeit(file, &dp, n - 4, convert);
                if (size < 0) {
                if (size < 0) {
-                       perror("tftp: write");
-                       nak(&to, errno + 100);
-                       aborted = 1;
-                       goto done;
+                       nak(errno + 100);
+                       break;
                }
                amount += size;
        } while (size == SEGSIZE);
                }
                amount += size;
        } while (size == SEGSIZE);
-done:
-       stp->th_opcode = htons((u_short)ACK);
-       stp->th_block = htons((u_short)block);
-       (void) sendto(f, sbuf, 4, 0, &to, sizeof (to));
-       (void) close(fd);
-       if (!aborted && amount > 0) {
-               delta = time(0) - start;
-               printf("Received %d bytes in %d seconds.\n", amount, delta);
-       }
-       return (aborted);
+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, &sin, sizeof (sin));
+       write_behind(file, convert);            /* flush last buffer */
+       fclose(file);
+       stopclock();
+       if (amount > 0)
+               printstats("Received", amount);
 }
 
 }
 
-makerequest(request, name)
+makerequest(request, name, tp, mode)
        int request;
        int request;
-       char *name;
+       char *name, *mode;
+       struct tftphdr *tp;
 {
 {
-       register struct tftphdr *stp;
-       int size;
        register char *cp;
 
        register char *cp;
 
-       stp = (struct tftphdr *)sbuf;
-       stp->th_opcode = htons((u_short)request);
-       strcpy(stp->th_stuff, name);
-       size = strlen(name);
-       cp = stp->th_stuff + strlen(name);
+       tp->th_opcode = htons((u_short)request);
+       cp = tp->th_stuff;
+       strcpy(cp, name);
+       cp += strlen(name);
        *cp++ = '\0';
        strcpy(cp, mode);
        *cp++ = '\0';
        strcpy(cp, mode);
-       cp += sizeof ("netascii") - 1;
+       cp += strlen(mode);
        *cp++ = '\0';
        *cp++ = '\0';
-       return (cp - sbuf);
+       return (cp - (char *)tp);
 }
 
 struct errmsg {
 }
 
 struct errmsg {
@@ -274,33 +268,33 @@ struct errmsg {
  * standard TFTP codes, or a UNIX errno
  * offset by 100.
  */
  * standard TFTP codes, or a UNIX errno
  * offset by 100.
  */
-nak(to, error)
-       struct sockaddr_in *to;
+nak(error)
        int error;
 {
        int error;
 {
-       register struct tftphdr *stp;
+       register struct tftphdr *tp;
        int length;
        register struct errmsg *pe;
        extern char *sys_errlist[];
 
        int length;
        register struct errmsg *pe;
        extern char *sys_errlist[];
 
-       stp = (struct tftphdr *)sbuf;
-       stp->th_opcode = htons((u_short)ERROR);
-       stp->th_code = htons((u_short)error);
+       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;
        for (pe = errmsgs; pe->e_code >= 0; pe++)
                if (pe->e_code == error)
                        break;
-       if (pe->e_code < 0)
+       if (pe->e_code < 0) {
                pe->e_msg = sys_errlist[error - 100];
                pe->e_msg = sys_errlist[error - 100];
-       strcpy(stp->th_msg, pe->e_msg);
+               tp->th_code = EUNDEF;
+       }
+       strcpy(tp->th_msg, pe->e_msg);
        length = strlen(pe->e_msg) + 4;
        if (trace)
        length = strlen(pe->e_msg) + 4;
        if (trace)
-               tpacket("sent", to, stp, length);
-       if (sendto(f, sbuf, length, 0, to, sizeof (*to)) != length)
-               perror("tftp: nak");
+               tpacket("sent", tp, length);
+       if (sendto(f, ackbuf, length, 0, &sin, sizeof (sin)) != length)
+               perror("nak");
 }
 
 }
 
-tpacket(s, sin, tp, n)
-       struct sockaddr_in *sin;
+tpacket(s, tp, n)
        struct tftphdr *tp;
        int n;
 {
        struct tftphdr *tp;
        int n;
 {
@@ -310,19 +304,10 @@ tpacket(s, sin, tp, n)
        u_short op = ntohs(tp->th_opcode);
        char *index();
 
        u_short op = ntohs(tp->th_opcode);
        char *index();
 
-       printf("%s ", s);
-       if (sin) {
-               struct hostent *hp = gethostbyaddr(&sin->sin_addr,
-                    sizeof (sin->sin_addr), AF_INET);
-
-               printf("%s.%d ",
-                   hp == 0 ? inet_ntoa(sin->sin_addr) : hp->h_name,
-                   ntohs(sin->sin_port));
-       }
        if (op < RRQ || op > ERROR)
        if (op < RRQ || op > ERROR)
-               printf("opcode=%x ", op);
+               printf("%s opcode=%x ", s, op);
        else
        else
-               printf("%s ", opcodes[op]);
+               printf("%s %s ", s, opcodes[op]);
        switch (op) {
 
        case RRQ:
        switch (op) {
 
        case RRQ:
@@ -344,9 +329,33 @@ tpacket(s, sin, tp, n)
        case ERROR:
                printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);
                break;
        case ERROR:
                printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);
                break;
-
-       default:
-               putchar('\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 %d bytes in %.1f seconds", direction, amount, delta);
+       if (verbose)
+               printf(" [%.0f bits/sec]", (amount*8.)/delta);
+       putchar('\n');
+}
+