added "more" command
[unix-history] / usr / src / usr.bin / tftp / tftp.c
index cc3584b..e1a7e76 100644 (file)
@@ -1,36 +1,52 @@
-/*     tftp.c  4.2     82/08/17        */
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * 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%";
+#endif not lint
 
 /*
  * TFTP User Program -- Protocol Machines
  */
 #include <sys/types.h>
 
 /*
  * TFTP User Program -- Protocol Machines
  */
 #include <sys/types.h>
-#include <net/in.h>
 #include <sys/socket.h>
 #include <sys/socket.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 <signal.h>
 #include <stdio.h>
 #include <errno.h>
 #include <setjmp.h>
-#include "tftp.h"
+#include <netdb.h>
 
 extern int errno;
 extern struct sockaddr_in sin;
 extern char mode[];
 int    f;
 int    trace;
 
 extern int errno;
 extern struct sockaddr_in sin;
 extern char mode[];
 int    f;
 int    trace;
-int    verbose;
 int    connected;
 int    connected;
-char   buf[BUFSIZ];
+char   sbuf[BUFSIZ];                   /* send buffer */
+char   rbuf[BUFSIZ];                   /* receive buffer */
+int    rexmtval;
+int    maxtimeout;
 int    timeout;
 jmp_buf        toplevel;
 int    timeout;
 jmp_buf        toplevel;
+jmp_buf        timeoutbuf;
 
 timer()
 {
 
 timer()
 {
-       timeout += TIMEOUT;
-       if (timeout >= MAXTIMEOUT) {
+
+       timeout += rexmtval;
+       if (timeout >= maxtimeout) {
                printf("Transfer timed out.\n");
                longjmp(toplevel, -1);
        }
                printf("Transfer timed out.\n");
                longjmp(toplevel, -1);
        }
-       alarm(TIMEOUT);
+       longjmp(timeoutbuf, 1);
 }
 
 /*
 }
 
 /*
@@ -40,68 +56,86 @@ sendfile(fd, name)
        int fd;
        char *name;
 {
        int fd;
        char *name;
 {
-       register struct tftphdr *tp = (struct tftphdr *)buf;
+       register struct tftphdr *stp = (struct tftphdr *)sbuf;
+       register struct tftphdr *rtp = (struct tftphdr *)rbuf;
        register int block = 0, size, n, amount = 0;
        register int block = 0, size, n, amount = 0;
-       struct sockaddr_in from;
+       struct sockaddr_in from, to;
        time_t start = time(0), delta;
        time_t start = time(0), delta;
+       int fromlen, aborted = 0;
 
 
-       size = makerequest(WRQ, name) - 4;
-       timeout = 0;
-       sigset(SIGALRM, timer);
+       to = sin;
+       signal(SIGALRM, timer);
        do {
        do {
-               if (block != 0) {
-                       size = read(fd, tp->th_data, SEGSIZE);
+               if (block == 0)
+                       size = makerequest(WRQ, name) - 4;
+               else {
+                       size = read(fd, stp->th_data, SEGSIZE);
                        if (size < 0) {
                        if (size < 0) {
-                               nak(errno + 100);
+                               nak(&to, errno + 100);
                                break;
                        }
                                break;
                        }
-                       tp->th_opcode = htons((u_short)DATA);
-                       tp->th_block = htons((u_short)block);
+                       stp->th_opcode = htons((u_short)DATA);
+                       stp->th_block = htons((u_short)block);
                }
                timeout = 0;
                }
                timeout = 0;
-               alarm(TIMEOUT);
-rexmt:
+               (void) setjmp(timeoutbuf);
                if (trace)
                if (trace)
-                       tpacket("sent", tp, size + 4);
-               if (send(f, &sin, buf, size + 4) != size + 4) {
-                       perror("send");
-                       break;
+                       tpacket("sent", &to, stp, size + 4);
+               n = sendto(f, sbuf, size + 4, 0, (caddr_t)&to, sizeof (to));
+               if (n != size + 4) {
+                       perror("tftp: sendto");
+                       aborted = 1;
+                       goto done;
                }
                }
+               do {
 again:
 again:
-               n = receive(f, &from, buf, sizeof (buf));
-               if (n <= 0) {
-                       if (n == 0)
-                               goto again;
-                       if (errno == EINTR)
-                               goto rexmt;
+                       alarm(rexmtval);
+                       do {
+                               fromlen = sizeof (from);
+                               n = recvfrom(f, rbuf, sizeof (rbuf), 0,
+                                   (caddr_t)&from, &fromlen);
+                       } while (n <= 0);
                        alarm(0);
                        alarm(0);
-                       perror("receive");
-                       break;
-               }
-               alarm(0);
-               if (trace)
-                       tpacket("received", tp, n);
-#if vax || pdp11
-               tp->th_opcode = ntohs(tp->th_opcode);
-               tp->th_block = ntohs(tp->th_block);
-#endif
-               if (tp->th_opcode == ERROR) {
-                       printf("Error code %d: %s\n", tp->th_code,
-                               tp->th_msg);
-                       break;
-               }
-               if (tp->th_opcode != ACK || block != tp->th_block)
-                       goto again;
+                       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;
+                       }
+                       if (trace)
+                               tpacket("received", &from, rtp, n);
+                       /* 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;
+                       }
+               } while (rtp->th_opcode != ACK && block != rtp->th_block);
                if (block > 0)
                        amount += size;
                block++;
        } while (size == SEGSIZE || block == 1);
                if (block > 0)
                        amount += size;
                block++;
        } while (size == SEGSIZE || block == 1);
-       alarm(0);
-       (void) close(fd);
-       if (amount > 0) {
+       if (!aborted && amount > 0) {
                delta = time(0) - start;
                printf("Sent %d bytes in %d seconds.\n", amount, delta);
        }
                delta = time(0) - start;
                printf("Sent %d bytes in %d seconds.\n", amount, delta);
        }
+done:
+       (void) close(fd);
+       return (aborted);
 }
 
 /*
 }
 
 /*
@@ -111,91 +145,112 @@ recvfile(fd, name)
        int fd;
        char *name;
 {
        int fd;
        char *name;
 {
-       register struct tftphdr *tp = (struct tftphdr *)buf;
+       register struct tftphdr *stp = (struct tftphdr *)sbuf;
+       register struct tftphdr *rtp = (struct tftphdr *)rbuf;
        register int block = 1, n, size, amount = 0;
        register int block = 1, n, size, amount = 0;
-       struct sockaddr_in from;
+       struct sockaddr_in from, to;
        time_t start = time(0), delta;
        time_t start = time(0), delta;
+       int fromlen, firsttrip = 1, aborted = 0;
 
 
-       size = makerequest(RRQ, name);
-       timeout = 0;
-       sigset(SIGALRM, timer);
-       alarm(TIMEOUT);
-       goto rexmt;
+       to = sin;
+       signal(SIGALRM, timer);
        do {
        do {
+               if (firsttrip) {
+                       size = makerequest(RRQ, name);
+                       firsttrip = 0;
+               } else {
+                       stp->th_opcode = htons((u_short)ACK);
+                       stp->th_block = htons((u_short)(block));
+                       size = 4;
+                       block++;
+               }
                timeout = 0;
                timeout = 0;
-               alarm(TIMEOUT);
-               tp->th_opcode = htons((u_short)ACK);
-               tp->th_block = htons((u_short)(block));
-               size = 4;
-               block++;
-rexmt:
+               (void) setjmp(timeoutbuf);
                if (trace)
                if (trace)
-                       tpacket("sent", tp, size);
-               if (send(f, &sin, buf, size) != size) {
-                       perror("send");
-                       break;
+                       tpacket("sent", &to, stp, size);
+               if (sendto(f, sbuf, size, 0, (caddr_t)&to,
+                   sizeof (to)) != size) {
+                       alarm(0);
+                       perror("tftp: sendto");
+                       aborted = 1;
+                       goto done;
                }
                }
+               do {
 again:
 again:
-               n = receive(f, &from, buf, sizeof (buf));
-               if (n <= 0) {
-                       if (n == 0)
-                               goto again;
-                       if (errno == EINTR)
-                               goto rexmt;
+                       alarm(rexmtval);
+                       do {
+                               fromlen = sizeof (from);
+                               n = recvfrom(f, rbuf, sizeof (rbuf), 0,
+                                   (caddr_t)&from, &fromlen);
+                       } while (n <= 0);
                        alarm(0);
                        alarm(0);
-                       perror("receive");
-                       break;
-               }
-               alarm(0);
-               if (trace)
-                       tpacket("received", tp, n);
-#if vax || pdp11
-               tp->th_opcode = ntohs(tp->th_opcode);
-               tp->th_block = ntohs(tp->th_block);
-#endif
-               if (tp->th_opcode == ERROR) {
-                       printf("Error code %d: %s\n", tp->th_code,
-                               tp->th_msg);
-                       break;
-               }
-               if (tp->th_opcode != DATA || block != tp->th_block)
-                       goto again;
-               size = write(fd, tp->th_data, n - 4);
+                       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;
+                       }
+                       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;
+                       }
+               } while (rtp->th_opcode != DATA && rtp->th_block != block);
+               size = write(fd, rtp->th_data, n - 4);
                if (size < 0) {
                if (size < 0) {
-                       nak(errno + 100);
-                       break;
+                       perror("tftp: write");
+                       nak(&to, errno + 100);
+                       aborted = 1;
+                       goto done;
                }
                amount += size;
        } while (size == SEGSIZE);
                }
                amount += size;
        } while (size == SEGSIZE);
-       alarm(0);
-       tp->th_opcode = htons((u_short)ACK);
-       tp->th_block = htons((u_short)block);
-       (void) send(f, &sin, buf, 4);
+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);
        (void) close(fd);
-       if (amount > 0) {
+       if (!aborted && amount > 0) {
                delta = time(0) - start;
                printf("Received %d bytes in %d seconds.\n", amount, delta);
        }
                delta = time(0) - start;
                printf("Received %d bytes in %d seconds.\n", amount, delta);
        }
+       return (aborted);
 }
 
 makerequest(request, name)
        int request;
        char *name;
 {
 }
 
 makerequest(request, name)
        int request;
        char *name;
 {
-       register struct tftphdr *tp;
+       register struct tftphdr *stp;
        int size;
        register char *cp;
 
        int size;
        register char *cp;
 
-       tp = (struct tftphdr *)buf;
-       tp->th_opcode = htons((u_short)request);
-       strcpy(tp->th_stuff, name);
+       stp = (struct tftphdr *)sbuf;
+       stp->th_opcode = htons((u_short)request);
+       strcpy(stp->th_stuff, name);
        size = strlen(name);
        size = strlen(name);
-       cp = tp->th_stuff + strlen(name);
+       cp = stp->th_stuff + strlen(name);
        *cp++ = '\0';
        strcpy(cp, mode);
        cp += sizeof ("netascii") - 1;
        *cp++ = '\0';
        *cp++ = '\0';
        strcpy(cp, mode);
        cp += sizeof ("netascii") - 1;
        *cp++ = '\0';
-       return (cp - buf);
+       return (cp - sbuf);
 }
 
 struct errmsg {
 }
 
 struct errmsg {
@@ -219,31 +274,33 @@ struct errmsg {
  * standard TFTP codes, or a UNIX errno
  * offset by 100.
  */
  * standard TFTP codes, or a UNIX errno
  * offset by 100.
  */
-nak(error)
+nak(to, error)
+       struct sockaddr_in *to;
        int error;
 {
        int error;
 {
-       register struct tftphdr *tp;
+       register struct tftphdr *stp;
        int length;
        register struct errmsg *pe;
        extern char *sys_errlist[];
 
        int length;
        register struct errmsg *pe;
        extern char *sys_errlist[];
 
-       tp = (struct tftphdr *)buf;
-       tp->th_opcode = htons((u_short)ERROR);
-       tp->th_code = htons((u_short)error);
+       stp = (struct tftphdr *)sbuf;
+       stp->th_opcode = htons((u_short)ERROR);
+       stp->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];
        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];
-       strcpy(tp->th_msg, pe->e_msg);
+       strcpy(stp->th_msg, pe->e_msg);
        length = strlen(pe->e_msg) + 4;
        if (trace)
        length = strlen(pe->e_msg) + 4;
        if (trace)
-               tpacket("sent", tp, length);
-       if (send(f, &sin, buf, length) != length)
-               perror("nak");
+               tpacket("sent", to, stp, length);
+       if (sendto(f, sbuf, length, 0, to, sizeof (*to)) != length)
+               perror("tftp: nak");
 }
 
 }
 
-tpacket(s, tp, n)
+tpacket(s, sin, tp, n)
+       struct sockaddr_in *sin;
        struct tftphdr *tp;
        int n;
 {
        struct tftphdr *tp;
        int n;
 {
@@ -253,10 +310,19 @@ tpacket(s, 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("%s opcode=%x ", s, op);
+               printf("opcode=%x ", op);
        else
        else
-               printf("%s %s ", s, opcodes[op]);
+               printf("%s ", opcodes[op]);
        switch (op) {
 
        case RRQ:
        switch (op) {
 
        case RRQ:
@@ -278,5 +344,9 @@ tpacket(s, 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;
        }
 }
        }
 }