home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / NETKIT-B.05 / NETKIT-B / NetKit-B-0.05 / tftp / tftp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-17  |  10.2 KB  |  423 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[] = "from: @(#)tftp.c    5.10 (Berkeley) 3/1/91";*/
  36. static char rcsid[] = "$Id: tftp.c,v 1.3 1993/08/01 18:07:06 mycroft Exp $";
  37. #endif /* not lint */
  38.  
  39. /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
  40.  
  41. /*
  42.  * TFTP User Program -- Protocol Machines
  43.  */
  44. #include <sys/types.h>
  45. #include <sys/socket.h>
  46. #include <sys/time.h>
  47.  
  48. #include <netinet/in.h>
  49.  
  50. #include <arpa/tftp.h>
  51.  
  52. #include <signal.h>
  53. #include <stdio.h>
  54. #include <errno.h>
  55. #include <setjmp.h>
  56.  
  57. extern    int errno;
  58.  
  59. extern  struct sockaddr_in s_in;         /* filled in by main */
  60. extern  int     f;                      /* the opened socket */
  61. extern  int     trace;
  62. extern  int     verbose;
  63. extern  int     rexmtval;
  64. extern  int     maxtimeout;
  65.  
  66. #define PKTSIZE    SEGSIZE+4
  67. char    ackbuf[PKTSIZE];
  68. int    timeout;
  69. jmp_buf    toplevel;
  70. jmp_buf    timeoutbuf;
  71.  
  72. void
  73. timer()
  74. {
  75.     timeout += rexmtval;
  76.     if (timeout >= maxtimeout) {
  77.         printf("Transfer timed out.\n");
  78.         longjmp(toplevel, -1);
  79.     }
  80.     longjmp(timeoutbuf, 1);
  81. }
  82.  
  83. /*
  84.  * Send the requested file.
  85.  */
  86. sendfile(fd, name, mode)
  87.     int fd;
  88.     char *name;
  89.     char *mode;
  90. {
  91.     register struct tftphdr *ap;       /* data and ack packets */
  92.     struct tftphdr *r_init(), *dp;
  93.     register int block = 0, size, n;
  94.     register unsigned long amount = 0;
  95.     struct sockaddr_in from;
  96.     int fromlen;
  97.     int convert;            /* true if doing nl->crlf conversion */
  98.     FILE *file;
  99.  
  100.     startclock();           /* start stat's clock */
  101.     dp = r_init();          /* reset fillbuf/read-ahead code */
  102.     ap = (struct tftphdr *)ackbuf;
  103.     file = fdopen(fd, "r");
  104.     convert = !strcmp(mode, "netascii");
  105.  
  106.     signal(SIGALRM, timer);
  107.     do {
  108.         if (block == 0)
  109.             size = makerequest(WRQ, name, dp, mode) - 4;
  110.         else {
  111.         /*      size = read(fd, dp->th_data, SEGSIZE);   */
  112.             size = readit(file, &dp, convert);
  113.             if (size < 0) {
  114.                 nak(errno + 100);
  115.                 break;
  116.             }
  117.             dp->th_opcode = htons((u_short)DATA);
  118.             dp->th_block = htons((u_short)block);
  119.         }
  120.         timeout = 0;
  121.         (void) setjmp(timeoutbuf);
  122. send_data:
  123.         if (trace)
  124.             tpacket("sent", dp, size + 4);
  125.         n = sendto(f, dp, size + 4, 0,
  126.             (struct sockaddr *)&s_in, sizeof (s_in));
  127.         if (n != size + 4) {
  128.             perror("tftp: sendto");
  129.             goto abort;
  130.         }
  131.         read_ahead(file, convert);
  132.         for ( ; ; ) {
  133.             alarm(rexmtval);
  134.             do {
  135.                 fromlen = sizeof (from);
  136.                 n = recvfrom(f, ackbuf, sizeof (ackbuf), 0,
  137.                     (struct sockaddr *)&from, &fromlen);
  138.             } while (n <= 0);
  139.             alarm(0);
  140.             if (n < 0) {
  141.                 perror("tftp: recvfrom");
  142.                 goto abort;
  143.             }
  144.             s_in.sin_port = from.sin_port;   /* added */
  145.             if (trace)
  146.                 tpacket("received", ap, n);
  147.             /* should verify packet came from server */
  148.             ap->th_opcode = ntohs(ap->th_opcode);
  149.             ap->th_block = ntohs(ap->th_block);
  150.             if (ap->th_opcode == ERROR) {
  151.                 printf("Error code %d: %s\n", ap->th_code,
  152.                     ap->th_msg);
  153.                 goto abort;
  154.             }
  155.             if (ap->th_opcode == ACK) {
  156.                 int j;
  157.  
  158.                 if (ap->th_block == block) {
  159.                     break;
  160.                 }
  161.                 /* On an error, try to synchronize
  162.                  * both sides.
  163.                  */
  164.                 j = synchnet(f);
  165.                 if (j && trace) {
  166.                     printf("discarded %d packets\n",
  167.                             j);
  168.                 }
  169.                 if (ap->th_block == (block-1)) {
  170.                     goto send_data;
  171.                 }
  172.             }
  173.         }
  174.         if (block > 0)
  175.             amount += size;
  176.         block++;
  177.     } while (size == SEGSIZE || block == 1);
  178. abort:
  179.     fclose(file);
  180.     stopclock();
  181.     if (amount > 0)
  182.         printstats("Sent", amount);
  183. }
  184.  
  185. /*
  186.  * Receive a file.
  187.  */
  188. recvfile(fd, name, mode)
  189.     int fd;
  190.     char *name;
  191.     char *mode;
  192. {
  193.     register struct tftphdr *ap;
  194.     struct tftphdr *dp, *w_init();
  195.     register int block = 1, n, size;
  196.     unsigned long amount = 0;
  197.     struct sockaddr_in from;
  198.     int fromlen, firsttrip = 1;
  199.     FILE *file;
  200.     int convert;                    /* true if converting crlf -> lf */
  201.  
  202.     startclock();
  203.     dp = w_init();
  204.     ap = (struct tftphdr *)ackbuf;
  205.     file = fdopen(fd, "w");
  206.     convert = !strcmp(mode, "netascii");
  207.  
  208.     signal(SIGALRM, timer);
  209.     do {
  210.         if (firsttrip) {
  211.             size = makerequest(RRQ, name, ap, mode);
  212.             firsttrip = 0;
  213.         } else {
  214.             ap->th_opcode = htons((u_short)ACK);
  215.             ap->th_block = htons((u_short)(block));
  216.             size = 4;
  217.             block++;
  218.         }
  219.         timeout = 0;
  220.         (void) setjmp(timeoutbuf);
  221. send_ack:
  222.         if (trace)
  223.             tpacket("sent", ap, size);
  224.         if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&s_in,
  225.             sizeof (s_in)) != size) {
  226.             alarm(0);
  227.             perror("tftp: sendto");
  228.             goto abort;
  229.         }
  230.         write_behind(file, convert);
  231.         for ( ; ; ) {
  232.             alarm(rexmtval);
  233.             do  {
  234.                 fromlen = sizeof (from);
  235.                 n = recvfrom(f, dp, PKTSIZE, 0,
  236.                     (struct sockaddr *)&from, &fromlen);
  237.             } while (n <= 0);
  238.             alarm(0);
  239.             if (n < 0) {
  240.                 perror("tftp: recvfrom");
  241.                 goto abort;
  242.             }
  243.             s_in.sin_port = from.sin_port;   /* added */
  244.             if (trace)
  245.                 tpacket("received", dp, n);
  246.             /* should verify client address */
  247.             dp->th_opcode = ntohs(dp->th_opcode);
  248.             dp->th_block = ntohs(dp->th_block);
  249.             if (dp->th_opcode == ERROR) {
  250.                 printf("Error code %d: %s\n", dp->th_code,
  251.                     dp->th_msg);
  252.                 goto abort;
  253.             }
  254.             if (dp->th_opcode == DATA) {
  255.                 int j;
  256.  
  257.                 if (dp->th_block == block) {
  258.                     break;          /* have next packet */
  259.                 }
  260.                 /* On an error, try to synchronize
  261.                  * both sides.
  262.                  */
  263.                 j = synchnet(f);
  264.                 if (j && trace) {
  265.                     printf("discarded %d packets\n", j);
  266.                 }
  267.                 if (dp->th_block == (block-1)) {
  268.                     goto send_ack;  /* resend ack */
  269.                 }
  270.             }
  271.         }
  272.     /*      size = write(fd, dp->th_data, n - 4); */
  273.         size = writeit(file, &dp, n - 4, convert);
  274.         if (size < 0) {
  275.             nak(errno + 100);
  276.             break;
  277.         }
  278.         amount += size;
  279.     } while (size == SEGSIZE);
  280. abort:                                          /* ok to ack, since user */
  281.     ap->th_opcode = htons((u_short)ACK);    /* has seen err msg */
  282.     ap->th_block = htons((u_short)block);
  283.     (void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&s_in, sizeof (s_in));
  284.     write_behind(file, convert);            /* flush last buffer */
  285.     fclose(file);
  286.     stopclock();
  287.     if (amount > 0)
  288.         printstats("Received", amount);
  289. }
  290.  
  291. makerequest(request, name, tp, mode)
  292.     int request;
  293.     char *name, *mode;
  294.     struct tftphdr *tp;
  295. {
  296.     register char *cp;
  297.  
  298.     tp->th_opcode = htons((u_short)request);
  299.     cp = tp->th_stuff;
  300.     strcpy(cp, name);
  301.     cp += strlen(name);
  302.     *cp++ = '\0';
  303.     strcpy(cp, mode);
  304.     cp += strlen(mode);
  305.     *cp++ = '\0';
  306.     return (cp - (char *)tp);
  307. }
  308.  
  309. struct errmsg {
  310.     int    e_code;
  311.     char    *e_msg;
  312. } errmsgs[] = {
  313.     { EUNDEF,    "Undefined error code" },
  314.     { ENOTFOUND,    "File not found" },
  315.     { EACCESS,    "Access violation" },
  316.     { ENOSPACE,    "Disk full or allocation exceeded" },
  317.     { EBADOP,    "Illegal TFTP operation" },
  318.     { EBADID,    "Unknown transfer ID" },
  319.     { EEXISTS,    "File already exists" },
  320.     { ENOUSER,    "No such user" },
  321.     { -1,        0 }
  322. };
  323.  
  324. /*
  325.  * Send a nak packet (error message).
  326.  * Error code passed in is one of the
  327.  * standard TFTP codes, or a UNIX errno
  328.  * offset by 100.
  329.  */
  330. nak(error)
  331.     int error;
  332. {
  333.     register struct errmsg *pe;
  334.     register struct tftphdr *tp;
  335.     int length;
  336.     char *strerror();
  337.  
  338.     tp = (struct tftphdr *)ackbuf;
  339.     tp->th_opcode = htons((u_short)ERROR);
  340.     tp->th_code = htons((u_short)error);
  341.     for (pe = errmsgs; pe->e_code >= 0; pe++)
  342.         if (pe->e_code == error)
  343.             break;
  344.     if (pe->e_code < 0) {
  345.         pe->e_msg = strerror(error - 100);
  346.         tp->th_code = EUNDEF;
  347.     }
  348.     strcpy(tp->th_msg, pe->e_msg);
  349.     length = strlen(pe->e_msg) + 4;
  350.     if (trace)
  351.         tpacket("sent", tp, length);
  352.     if (sendto(f, ackbuf, length, 0, (struct sockaddr *)&s_in,
  353.         sizeof (s_in)) != length)
  354.         perror("nak");
  355. }
  356.  
  357. tpacket(s, tp, n)
  358.     char *s;
  359.     struct tftphdr *tp;
  360.     int n;
  361. {
  362.     static char *opcodes[] =
  363.        { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR" };
  364.     register char *cp, *file;
  365.     u_short op = ntohs(tp->th_opcode);
  366.     char *index();
  367.  
  368.     if (op < RRQ || op > ERROR)
  369.         printf("%s opcode=%x ", s, op);
  370.     else
  371.         printf("%s %s ", s, opcodes[op]);
  372.     switch (op) {
  373.  
  374.     case RRQ:
  375.     case WRQ:
  376.         n -= 2;
  377.         file = cp = tp->th_stuff;
  378.         cp = index(cp, '\0');
  379.         printf("<file=%s, mode=%s>\n", file, cp + 1);
  380.         break;
  381.  
  382.     case DATA:
  383.         printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);
  384.         break;
  385.  
  386.     case ACK:
  387.         printf("<block=%d>\n", ntohs(tp->th_block));
  388.         break;
  389.  
  390.     case ERROR:
  391.         printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);
  392.         break;
  393.     }
  394. }
  395.  
  396. struct timeval tstart;
  397. struct timeval tstop;
  398. struct timezone zone;
  399.  
  400. startclock() {
  401.     gettimeofday(&tstart, &zone);
  402. }
  403.  
  404. stopclock() {
  405.     gettimeofday(&tstop, &zone);
  406. }
  407.  
  408. printstats(direction, amount)
  409. char *direction;
  410. unsigned long amount;
  411. {
  412.     double delta;
  413.             /* compute delta in 1/10's second units */
  414.     delta = ((tstop.tv_sec*10.)+(tstop.tv_usec/100000)) -
  415.         ((tstart.tv_sec*10.)+(tstart.tv_usec/100000));
  416.     delta = delta/10.;      /* back to seconds */
  417.     printf("%s %d bytes in %.1f seconds", direction, amount, delta);
  418.     if (verbose)
  419.         printf(" [%.0f bits/sec]", (amount*8.)/delta);
  420.     putchar('\n');
  421. }
  422.  
  423.