home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / tftp / tftp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-18  |  10.1 KB  |  422 lines

  1. /*
  2.  * Copyright (c) 1983 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char sccsid[] = "@(#)tftp.c    5.10 (Berkeley) 3/1/91";
  36. #endif /* not lint */
  37.  
  38. /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
  39.  
  40. /*
  41.  * TFTP User Program -- Protocol Machines
  42.  */
  43. #include <sys/types.h>
  44. #include <sys/socket.h>
  45. #include <sys/time.h>
  46.  
  47. #include <netinet/in.h>
  48.  
  49. #include <arpa/tftp.h>
  50.  
  51. #include <signal.h>
  52. #include <stdio.h>
  53. #include <errno.h>
  54. #include <setjmp.h>
  55.  
  56. extern    int errno;
  57.  
  58. extern  struct sockaddr_in sin;         /* filled in by main */
  59. extern  int     f;                      /* the opened socket */
  60. extern  int     trace;
  61. extern  int     verbose;
  62. extern  int     rexmtval;
  63. extern  int     maxtimeout;
  64.  
  65. #define PKTSIZE    SEGSIZE+4
  66. char    ackbuf[PKTSIZE];
  67. int    timeout;
  68. jmp_buf    toplevel;
  69. jmp_buf    timeoutbuf;
  70.  
  71. void
  72. timer()
  73. {
  74.     timeout += rexmtval;
  75.     if (timeout >= maxtimeout) {
  76.         printf("Transfer timed out.\n");
  77.         longjmp(toplevel, -1);
  78.     }
  79.     longjmp(timeoutbuf, 1);
  80. }
  81.  
  82. /*
  83.  * Send the requested file.
  84.  */
  85. sendfile(fd, name, mode)
  86.     int fd;
  87.     char *name;
  88.     char *mode;
  89. {
  90.     register struct tftphdr *ap;       /* data and ack packets */
  91.     struct tftphdr *r_init(), *dp;
  92.     register int block = 0, size, n;
  93.     register unsigned long amount = 0;
  94.     struct sockaddr_in from;
  95.     int fromlen;
  96.     int convert;            /* true if doing nl->crlf conversion */
  97.     FILE *file;
  98.  
  99.     startclock();           /* start stat's clock */
  100.     dp = r_init();          /* reset fillbuf/read-ahead code */
  101.     ap = (struct tftphdr *)ackbuf;
  102.     file = fdopen(fd, "r");
  103.     convert = !strcmp(mode, "netascii");
  104.  
  105.     signal(SIGALRM, timer);
  106.     do {
  107.         if (block == 0)
  108.             size = makerequest(WRQ, name, dp, mode) - 4;
  109.         else {
  110.         /*      size = read(fd, dp->th_data, SEGSIZE);   */
  111.             size = readit(file, &dp, convert);
  112.             if (size < 0) {
  113.                 nak(errno + 100);
  114.                 break;
  115.             }
  116.             dp->th_opcode = htons((u_short)DATA);
  117.             dp->th_block = htons((u_short)block);
  118.         }
  119.         timeout = 0;
  120.         (void) setjmp(timeoutbuf);
  121. send_data:
  122.         if (trace)
  123.             tpacket("sent", dp, size + 4);
  124.         n = sendto(f, dp, size + 4, 0,
  125.             (struct sockaddr *)&sin, sizeof (sin));
  126.         if (n != size + 4) {
  127.             perror("tftp: sendto");
  128.             goto abort;
  129.         }
  130.         read_ahead(file, convert);
  131.         for ( ; ; ) {
  132.             alarm(rexmtval);
  133.             do {
  134.                 fromlen = sizeof (from);
  135.                 n = recvfrom(f, ackbuf, sizeof (ackbuf), 0,
  136.                     (struct sockaddr *)&from, &fromlen);
  137.             } while (n <= 0);
  138.             alarm(0);
  139.             if (n < 0) {
  140.                 perror("tftp: recvfrom");
  141.                 goto abort;
  142.             }
  143.             sin.sin_port = from.sin_port;   /* added */
  144.             if (trace)
  145.                 tpacket("received", ap, n);
  146.             /* should verify packet came from server */
  147.             ap->th_opcode = ntohs(ap->th_opcode);
  148.             ap->th_block = ntohs(ap->th_block);
  149.             if (ap->th_opcode == ERROR) {
  150.                 printf("Error code %d: %s\n", ap->th_code,
  151.                     ap->th_msg);
  152.                 goto abort;
  153.             }
  154.             if (ap->th_opcode == ACK) {
  155.                 int j;
  156.  
  157.                 if (ap->th_block == block) {
  158.                     break;
  159.                 }
  160.                 /* On an error, try to synchronize
  161.                  * both sides.
  162.                  */
  163.                 j = synchnet(f);
  164.                 if (j && trace) {
  165.                     printf("discarded %d packets\n",
  166.                             j);
  167.                 }
  168.                 if (ap->th_block == (block-1)) {
  169.                     goto send_data;
  170.                 }
  171.             }
  172.         }
  173.         if (block > 0)
  174.             amount += size;
  175.         block++;
  176.     } while (size == SEGSIZE || block == 1);
  177. abort:
  178.     fclose(file);
  179.     stopclock();
  180.     if (amount > 0)
  181.         printstats("Sent", amount);
  182. }
  183.  
  184. /*
  185.  * Receive a file.
  186.  */
  187. recvfile(fd, name, mode)
  188.     int fd;
  189.     char *name;
  190.     char *mode;
  191. {
  192.     register struct tftphdr *ap;
  193.     struct tftphdr *dp, *w_init();
  194.     register int block = 1, n, size;
  195.     unsigned long amount = 0;
  196.     struct sockaddr_in from;
  197.     int fromlen, firsttrip = 1;
  198.     FILE *file;
  199.     int convert;                    /* true if converting crlf -> lf */
  200.  
  201.     startclock();
  202.     dp = w_init();
  203.     ap = (struct tftphdr *)ackbuf;
  204.     file = fdopen(fd, "w");
  205.     convert = !strcmp(mode, "netascii");
  206.  
  207.     signal(SIGALRM, timer);
  208.     do {
  209.         if (firsttrip) {
  210.             size = makerequest(RRQ, name, ap, mode);
  211.             firsttrip = 0;
  212.         } else {
  213.             ap->th_opcode = htons((u_short)ACK);
  214.             ap->th_block = htons((u_short)(block));
  215.             size = 4;
  216.             block++;
  217.         }
  218.         timeout = 0;
  219.         (void) setjmp(timeoutbuf);
  220. send_ack:
  221.         if (trace)
  222.             tpacket("sent", ap, size);
  223.         if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&sin,
  224.             sizeof (sin)) != size) {
  225.             alarm(0);
  226.             perror("tftp: sendto");
  227.             goto abort;
  228.         }
  229.         write_behind(file, convert);
  230.         for ( ; ; ) {
  231.             alarm(rexmtval);
  232.             do  {
  233.                 fromlen = sizeof (from);
  234.                 n = recvfrom(f, dp, PKTSIZE, 0,
  235.                     (struct sockaddr *)&from, &fromlen);
  236.             } while (n <= 0);
  237.             alarm(0);
  238.             if (n < 0) {
  239.                 perror("tftp: recvfrom");
  240.                 goto abort;
  241.             }
  242.             sin.sin_port = from.sin_port;   /* added */
  243.             if (trace)
  244.                 tpacket("received", dp, n);
  245.             /* should verify client address */
  246.             dp->th_opcode = ntohs(dp->th_opcode);
  247.             dp->th_block = ntohs(dp->th_block);
  248.             if (dp->th_opcode == ERROR) {
  249.                 printf("Error code %d: %s\n", dp->th_code,
  250.                     dp->th_msg);
  251.                 goto abort;
  252.             }
  253.             if (dp->th_opcode == DATA) {
  254.                 int j;
  255.  
  256.                 if (dp->th_block == block) {
  257.                     break;          /* have next packet */
  258.                 }
  259.                 /* On an error, try to synchronize
  260.                  * both sides.
  261.                  */
  262.                 j = synchnet(f);
  263.                 if (j && trace) {
  264.                     printf("discarded %d packets\n", j);
  265.                 }
  266.                 if (dp->th_block == (block-1)) {
  267.                     goto send_ack;  /* resend ack */
  268.                 }
  269.             }
  270.         }
  271.     /*      size = write(fd, dp->th_data, n - 4); */
  272.         size = writeit(file, &dp, n - 4, convert);
  273.         if (size < 0) {
  274.             nak(errno + 100);
  275.             break;
  276.         }
  277.         amount += size;
  278.     } while (size == SEGSIZE);
  279. abort:                                          /* ok to ack, since user */
  280.     ap->th_opcode = htons((u_short)ACK);    /* has seen err msg */
  281.     ap->th_block = htons((u_short)block);
  282.     (void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&sin, sizeof (sin));
  283.     write_behind(file, convert);            /* flush last buffer */
  284.     fclose(file);
  285.     stopclock();
  286.     if (amount > 0)
  287.         printstats("Received", amount);
  288. }
  289.  
  290. makerequest(request, name, tp, mode)
  291.     int request;
  292.     char *name, *mode;
  293.     struct tftphdr *tp;
  294. {
  295.     register char *cp;
  296.  
  297.     tp->th_opcode = htons((u_short)request);
  298.     cp = tp->th_stuff;
  299.     strcpy(cp, name);
  300.     cp += strlen(name);
  301.     *cp++ = '\0';
  302.     strcpy(cp, mode);
  303.     cp += strlen(mode);
  304.     *cp++ = '\0';
  305.     return (cp - (char *)tp);
  306. }
  307.  
  308. struct errmsg {
  309.     int    e_code;
  310.     char    *e_msg;
  311. } errmsgs[] = {
  312.     { EUNDEF,    "Undefined error code" },
  313.     { ENOTFOUND,    "File not found" },
  314.     { EACCESS,    "Access violation" },
  315.     { ENOSPACE,    "Disk full or allocation exceeded" },
  316.     { EBADOP,    "Illegal TFTP operation" },
  317.     { EBADID,    "Unknown transfer ID" },
  318.     { EEXISTS,    "File already exists" },
  319.     { ENOUSER,    "No such user" },
  320.     { -1,        0 }
  321. };
  322.  
  323. /*
  324.  * Send a nak packet (error message).
  325.  * Error code passed in is one of the
  326.  * standard TFTP codes, or a UNIX errno
  327.  * offset by 100.
  328.  */
  329. nak(error)
  330.     int error;
  331. {
  332.     register struct errmsg *pe;
  333.     register struct tftphdr *tp;
  334.     int length;
  335.     char *strerror();
  336.  
  337.     tp = (struct tftphdr *)ackbuf;
  338.     tp->th_opcode = htons((u_short)ERROR);
  339.     tp->th_code = htons((u_short)error);
  340.     for (pe = errmsgs; pe->e_code >= 0; pe++)
  341.         if (pe->e_code == error)
  342.             break;
  343.     if (pe->e_code < 0) {
  344.         pe->e_msg = strerror(error - 100);
  345.         tp->th_code = EUNDEF;
  346.     }
  347.     strcpy(tp->th_msg, pe->e_msg);
  348.     length = strlen(pe->e_msg) + 4;
  349.     if (trace)
  350.         tpacket("sent", tp, length);
  351.     if (sendto(f, ackbuf, length, 0, (struct sockaddr *)&sin,
  352.         sizeof (sin)) != length)
  353.         perror("nak");
  354. }
  355.  
  356. tpacket(s, tp, n)
  357.     char *s;
  358.     struct tftphdr *tp;
  359.     int n;
  360. {
  361.     static char *opcodes[] =
  362.        { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR" };
  363.     register char *cp, *file;
  364.     u_short op = ntohs(tp->th_opcode);
  365.     char *index();
  366.  
  367.     if (op < RRQ || op > ERROR)
  368.         printf("%s opcode=%x ", s, op);
  369.     else
  370.         printf("%s %s ", s, opcodes[op]);
  371.     switch (op) {
  372.  
  373.     case RRQ:
  374.     case WRQ:
  375.         n -= 2;
  376.         file = cp = tp->th_stuff;
  377.         cp = index(cp, '\0');
  378.         printf("<file=%s, mode=%s>\n", file, cp + 1);
  379.         break;
  380.  
  381.     case DATA:
  382.         printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);
  383.         break;
  384.  
  385.     case ACK:
  386.         printf("<block=%d>\n", ntohs(tp->th_block));
  387.         break;
  388.  
  389.     case ERROR:
  390.         printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);
  391.         break;
  392.     }
  393. }
  394.  
  395. struct timeval tstart;
  396. struct timeval tstop;
  397. struct timezone zone;
  398.  
  399. startclock() {
  400.     gettimeofday(&tstart, &zone);
  401. }
  402.  
  403. stopclock() {
  404.     gettimeofday(&tstop, &zone);
  405. }
  406.  
  407. printstats(direction, amount)
  408. char *direction;
  409. unsigned long amount;
  410. {
  411.     double delta;
  412.             /* compute delta in 1/10's second units */
  413.     delta = ((tstop.tv_sec*10.)+(tstop.tv_usec/100000)) -
  414.         ((tstart.tv_sec*10.)+(tstart.tv_usec/100000));
  415.     delta = delta/10.;      /* back to seconds */
  416.     printf("%s %d bytes in %.1f seconds", direction, amount, delta);
  417.     if (verbose)
  418.         printf(" [%.0f bits/sec]", (amount*8.)/delta);
  419.     putchar('\n');
  420. }
  421.  
  422.