[BACK]Return to tftp.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tftp

Diff for /src/usr.bin/tftp/tftp.c between version 1.18 and 1.19

version 1.18, 2006/07/20 09:42:44 version 1.19, 2006/07/24 17:29:58
Line 47 
Line 47 
 #include <sys/types.h>  #include <sys/types.h>
 #include <sys/socket.h>  #include <sys/socket.h>
 #include <sys/time.h>  #include <sys/time.h>
   #include <sys/stat.h>
   
 #include <netinet/in.h>  #include <netinet/in.h>
 #include <arpa/tftp.h>  #include <arpa/tftp.h>
Line 57 
Line 58 
 #include <signal.h>  #include <signal.h>
 #include <stdio.h>  #include <stdio.h>
 #include <stddef.h>  #include <stddef.h>
   #include <stdlib.h>
 #include <string.h>  #include <string.h>
 #include <unistd.h>  #include <unistd.h>
   
 #include "extern.h"  #include "extern.h"
 #include "tftpsubs.h"  #include "tftpsubs.h"
   
 #define PKTSIZE SEGSIZE + 4  
   
 static int      makerequest(int, const char *, struct tftphdr *, const char *);  static int      makerequest(int, const char *, struct tftphdr *, const char *);
 static void     nak(int);  static void     nak(int);
 static void     tpacket(const char *, struct tftphdr *, int);  static void     tpacket(const char *, struct tftphdr *, int);
Line 72 
Line 72 
 static void     stopclock(void);  static void     stopclock(void);
 static void     printstats(const char *, unsigned long);  static void     printstats(const char *, unsigned long);
 static void     printtimeout(void);  static void     printtimeout(void);
   static void     oack(struct tftphdr *, int, int);
   static int      oack_set(const char *, const char *);
   
 extern struct sockaddr_in        peeraddr;      /* filled in by main */  extern struct sockaddr_in        peeraddr;      /* filled in by main */
 extern int                       f;             /* the opened socket */  extern int                       f;             /* the opened socket */
Line 81 
Line 83 
 extern int                       maxtimeout;  extern int                       maxtimeout;
 extern FILE                     *file;  extern FILE                     *file;
 extern volatile sig_atomic_t     intrflag;  extern volatile sig_atomic_t     intrflag;
   extern char                     *ackbuf;
   extern int                       has_options;
   extern int                       opt_tsize;
   extern int                       opt_tout;
   extern int                       opt_blksize;
   
 char            ackbuf[PKTSIZE];  
 struct timeval  tstart;  struct timeval  tstart;
 struct timeval  tstop;  struct timeval  tstop;
   unsigned int    segment_size = SEGSIZE;
   unsigned int    packet_size = SEGSIZE + 4;
   
 struct errmsg {  struct errmsg {
         int      e_code;          int      e_code;
Line 98 
Line 106 
         { EBADID,       "Unknown transfer ID" },          { EBADID,       "Unknown transfer ID" },
         { EEXISTS,      "File already exists" },          { EEXISTS,      "File already exists" },
         { ENOUSER,      "No such user" },          { ENOUSER,      "No such user" },
           { EOPTNEG,      "Option negotiation failed" },
         { -1,           NULL }          { -1,           NULL }
 };  };
   
   struct options {
           const char      *o_type;
   } options[] = {
           { "tsize" },
           { "timeout" },
           { "blksize" },
           { NULL }
   };
   
   enum opt_enum {
           OPT_TSIZE = 0,
           OPT_TIMEOUT,
           OPT_BLKSIZE
   };
   
 /*  /*
  * Send the requested file.   * Send the requested file.
  */   */
Line 127 
Line 151 
                 if (!block)                  if (!block)
                         size = makerequest(WRQ, name, dp, mode) - 4;                          size = makerequest(WRQ, name, dp, mode) - 4;
                 else {                  else {
                         size = readit(file, &dp, convert, SEGSIZE);                          size = readit(file, &dp, convert, segment_size);
                         if (size < 0) {                          if (size < 0) {
                                 nak(errno + 100);                                  nak(errno + 100);
                                 break;                                  break;
Line 152 
Line 176 
                                         warn("sendto");                                          warn("sendto");
                                         goto abort;                                          goto abort;
                                 }                                  }
                                 read_ahead(file, convert, SEGSIZE);                                  if (block > 0)
                                           read_ahead(file, convert, segment_size);
                         }                          }
                         error = 0;                          error = 0;
   
Line 171 
Line 196 
                                 goto abort;                                  goto abort;
                         }                          }
                         fromlen = sizeof(from);                          fromlen = sizeof(from);
                         n = recvfrom(f, ackbuf, sizeof(ackbuf), 0,                          n = recvfrom(f, ackbuf, packet_size, 0,
                             (struct sockaddr *)&from, &fromlen);                              (struct sockaddr *)&from, &fromlen);
                         if (n == 0) {                          if (n == 0) {
                                 warn("recvfrom");                                  warn("recvfrom");
Line 187 
Line 212 
                         peeraddr.sin_port = from.sin_port;      /* added */                          peeraddr.sin_port = from.sin_port;      /* added */
                         if (trace)                          if (trace)
                                 tpacket("received", ap, n);                                  tpacket("received", ap, n);
   
                         ap->th_opcode = ntohs(ap->th_opcode);                          ap->th_opcode = ntohs(ap->th_opcode);
   
                           if (ap->th_opcode == OACK) {
                                   oack(ap, n, 0);
                                   break;
                           }
   
                         ap->th_block = ntohs(ap->th_block);                          ap->th_block = ntohs(ap->th_block);
   
                         if (ap->th_opcode == ERROR) {                          if (ap->th_opcode == ERROR) {
Line 212 
Line 244 
                 if (block > 0)                  if (block > 0)
                         amount += size;                          amount += size;
                 block++;                  block++;
         } while ((size == SEGSIZE || block == 1) && !intrflag);          } while ((size == segment_size || block == 1) && !intrflag);
   
 abort:  abort:
         fclose(file);          fclose(file);
Line 248 
Line 280 
         amount = 0;          amount = 0;
         firsttrip = 1;          firsttrip = 1;
   
   options:
         do {          do {
                 /* create new ACK packet */                  /* create new ACK packet */
                 if (firsttrip) {                  if (firsttrip) {
Line 295 
Line 328 
                                 goto abort;                                  goto abort;
                         }                          }
                         fromlen = sizeof(from);                          fromlen = sizeof(from);
                         n = recvfrom(f, dp, PKTSIZE, 0,                          n = recvfrom(f, dp, packet_size, 0,
                             (struct sockaddr *)&from, &fromlen);                              (struct sockaddr *)&from, &fromlen);
                         if (n == 0) {                          if (n == 0) {
                                 warn("recvfrom");                                  warn("recvfrom");
Line 311 
Line 344 
                         peeraddr.sin_port = from.sin_port;      /* added */                          peeraddr.sin_port = from.sin_port;      /* added */
                         if (trace)                          if (trace)
                                 tpacket("received", dp, n);                                  tpacket("received", dp, n);
   
                         dp->th_opcode = ntohs(dp->th_opcode);                          dp->th_opcode = ntohs(dp->th_opcode);
   
                           if (dp->th_opcode == OACK) {
                                   oack(dp, n, 0);
                                   block = 0;
                                   goto options;
                           }
   
                         dp->th_block = ntohs(dp->th_block);                          dp->th_block = ntohs(dp->th_block);
   
                         if (dp->th_opcode == ERROR) {                          if (dp->th_opcode == ERROR) {
Line 340 
Line 381 
                         break;                          break;
                 }                  }
                 amount += size;                  amount += size;
         } while (size == SEGSIZE && !intrflag);          } while (size == segment_size && !intrflag);
   
 abort:  abort:
         /* ok to ack, since user has seen err msg */          /* ok to ack, since user has seen err msg */
Line 363 
Line 404 
 makerequest(int request, const char *name, struct tftphdr *tp,  makerequest(int request, const char *name, struct tftphdr *tp,
     const char *mode)      const char *mode)
 {  {
         char    *cp;          char            *cp;
         int      len, pktlen;          int              len, pktlen;
           off_t            fsize = 0;
           struct stat      st;
   
         tp->th_opcode = htons((u_short)request);          tp->th_opcode = htons((u_short)request);
         cp = tp->th_stuff;          cp = tp->th_stuff;
         pktlen = PKTSIZE - offsetof(struct tftphdr, th_stuff);          pktlen = packet_size - offsetof(struct tftphdr, th_stuff);
         len = strlen(name) + 1;          len = strlen(name) + 1;
         strlcpy(cp, name, pktlen);          strlcpy(cp, name, pktlen);
         strlcpy(cp + len, mode, pktlen - len);          strlcpy(cp + len, mode, pktlen - len);
         len += strlen(mode) + 1;          len += strlen(mode) + 1;
   
           if (opt_tsize) {
                   if (request == WRQ) {
                           stat(name, &st);
                           fsize = st.st_size;
                   }
                   len += snprintf(cp + len, pktlen - len, "%s%c%lld%c",
                       options[OPT_TSIZE].o_type, 0, fsize, 0);
           }
           if (opt_tout)
                   len += snprintf(cp + len, pktlen - len, "%s%c%d%c",
                       options[OPT_TIMEOUT].o_type, 0, rexmtval, 0);
           if (opt_blksize)
                   len += snprintf(cp + len, pktlen - len, "%s%c%d%c",
                       options[OPT_BLKSIZE].o_type, 0, opt_blksize, 0);
   
         return (cp + len - (char *)tp);          return (cp + len - (char *)tp);
 }  }
   
Line 400 
Line 458 
                 pe->e_msg = strerror(error - 100);                  pe->e_msg = strerror(error - 100);
                 tp->th_code = EUNDEF;                  tp->th_code = EUNDEF;
         }          }
         length = strlcpy(tp->th_msg, pe->e_msg, sizeof(ackbuf)) + 5;          length = strlcpy(tp->th_msg, pe->e_msg, packet_size) + 5;
         if (length > sizeof(ackbuf))          if (length > packet_size)
                 length = sizeof(ackbuf);                  length = packet_size;
         if (trace)          if (trace)
                 tpacket("sent", tp, length);                  tpacket("sent", tp, length);
         if (sendto(f, ackbuf, length, 0, (struct sockaddr *)&peeraddr,          if (sendto(f, ackbuf, length, 0, (struct sockaddr *)&peeraddr,
Line 415 
Line 473 
 {  {
         char            *cp, *file;          char            *cp, *file;
         static char     *opcodes[] =          static char     *opcodes[] =
             { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR" };              { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" };
   
         u_short op = ntohs(tp->th_opcode);          u_short op = ntohs(tp->th_opcode);
   
         if (op < RRQ || op > ERROR)          if (op < RRQ || op > OACK)
                 printf("%s opcode=%x ", s, op);                  printf("%s opcode=%x ", s, op);
         else          else
                 printf("%s %s ", s, opcodes[op]);                  printf("%s %s ", s, opcodes[op]);
Line 430 
Line 488 
                 n -= 2;                  n -= 2;
                 file = cp = tp->th_stuff;                  file = cp = tp->th_stuff;
                 cp = strchr(cp, '\0');                  cp = strchr(cp, '\0');
                 printf("<file=%s, mode=%s>\n", file, cp + 1);                  printf("<file=%s, mode=%s", file, cp + 1);
                   if (has_options)
                           oack(tp, n, 1);
                   printf(">\n");
                 break;                  break;
         case DATA:          case DATA:
                 printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);                  printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);
Line 441 
Line 502 
         case ERROR:          case ERROR:
                 printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);                  printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);
                 break;                  break;
           case OACK:
                   printf("<");
                   oack(tp, n, 1);
                   printf(">\n");
                   break;
         }          }
 }  }
   
Line 475 
Line 541 
 printtimeout(void)  printtimeout(void)
 {  {
         printf("Transfer timed out.\n");          printf("Transfer timed out.\n");
   }
   
   static void
   oack(struct tftphdr *tp, int size, int trace)
   {
           int      i, len, off;
           char    *opt, *val;
   
           u_short op = ntohs(tp->th_opcode);
   
           opt = tp->th_u.tu_stuff;
           val = tp->th_u.tu_stuff;
   
           if (op == RRQ || op == WRQ) {
                   len = strlen(opt) + 1;
                   opt = strchr(opt, '\0');
                   opt++;
                   len += strlen(opt) + 1;
                   opt = strchr(opt, '\0');
                   opt++;
                   val = opt;
                   off = len;
                   if (trace)
                           printf(", ");
           } else
                   off = 2;
   
           for (i = off, len = 0; i < size - 1; i++) {
                   if (*val != '\0') {
                           val++;
                           continue;
                   }
                   /* got option and value */
                   val++;
                   if (trace)
                           printf("%s=%s", opt, val);
                   else
                           if (oack_set(opt, val) == -1)
                                   break;
                   len = strlen(val) + 1;
                   val += len;
                   opt = val;
                   i += len;
                   if (trace && i < size - 1)
                           printf(", ");
           }
   }
   
   int
   oack_set(const char *option, const char *value)
   {
           int              i, n;
           const char      *errstr;
   
           for (i = 0; options[i].o_type != NULL; i++) {
                   if (!strcasecmp(options[i].o_type, option)) {
                           if (i == OPT_TSIZE) {
                                   /* XXX verify OACK response */
                           }
                           if (i == OPT_TIMEOUT) {
                                   /* verify OACK response */
                                   n = strtonum(value, 1, 255, &errstr);
                                   if (errstr || rexmtval != n ||
                                       opt_tout == 0) {
                                           nak(EOPTNEG);
                                           intrflag = 1;
                                           return (-1);
                                   }
                                   /* OK */
                           }
                           if (i == OPT_BLKSIZE) {
                                   /* verify OACK response */
                                   n = strtonum(value, SEGSIZE_MIN, SEGSIZE_MAX,
                                       &errstr);
                                   if (errstr || opt_blksize != n ||
                                       opt_blksize == 0) {
                                           nak(EOPTNEG);
                                           intrflag = 1;
                                           return (-1);
                                   }
                                   /* OK, set option */
                                   segment_size = n;
                                   packet_size = segment_size + 4;
                           }
                   }
           }
   
           return (1);
 }  }

Legend:
Removed from v.1.18  
changed lines
  Added in v.1.19