2 * Copyright (c) 1983 Regents of the University of California.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
35 * From: @(#)tftp.c 5.10 (Berkeley) 3/1/91
38 "$Id: tftp.c,v 1.6 1996/08/29 22:25:27 dholland Exp $";
40 /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
43 * TFTP User Program -- Protocol Machines
45 #include <sys/types.h>
46 #include <sys/socket.h>
49 #include <netinet/in.h>
50 #include <netinet/ip.h>
51 #include <arpa/tftp.h>
62 extern struct sockaddr_in s_inn; /* filled in by main */
63 extern int f; /* the opened socket */
67 extern int maxtimeout;
68 extern sigjmp_buf toplevel;
69 void sendfile(int fd, char *name, char *modestr);
70 void recvfile(int fd, char *name, char *modestr);
73 #define PKTSIZE SEGSIZE+4
74 static char ackbuf[PKTSIZE];
76 static sigjmp_buf timeoutbuf;
79 static int makerequest(int request, char *name,
80 struct tftphdr *tp, char *mode);
81 static void nak(int errnor);
82 static void tpacket(const char *s, struct tftphdr *tp, int n);
83 static void startclock(void);
84 static void stopclock(void);
85 static void printstats(const char *direction, unsigned long amount);
94 if (timeout >= maxtimeout) {
95 printf("Transfer timed out.\n");
96 siglongjmp(toplevel, -1);
98 siglongjmp(timeoutbuf, 1);
102 * Send the requested file.
105 sendfile(int fd, char *name, char *mode)
107 register struct tftphdr *ap; /* data and ack packets */
109 volatile int block = 0, size = 0;
111 volatile unsigned long amount = 0;
112 struct sockaddr_in from;
114 volatile int convert; /* true if doing nl->crlf conversion */
117 startclock(); /* start stat's clock */
118 dp = r_init(); /* reset fillbuf/read-ahead code */
119 ap = (struct tftphdr *)ackbuf;
120 file = fdopen(fd, "r");
121 convert = !strcmp(mode, "netascii");
123 signal(SIGALRM, timer);
126 size = makerequest(WRQ, name, dp, mode) - 4;
128 /* size = read(fd, dp->th_data, SEGSIZE); */
129 size = readit(file, &dp, convert);
134 dp->th_opcode = htons((u_short)DATA);
135 dp->th_block = htons((u_short)block);
138 (void) sigsetjmp(timeoutbuf, 1);
141 tpacket("sent", dp, size + 4);
142 n = sendto(f, dp, size + 4, 0,
143 (struct sockaddr *)&s_inn, sizeof(s_inn));
145 perror("tftp: sendto");
148 read_ahead(file, convert);
152 fromlen = sizeof (from);
153 n = recvfrom(f, ackbuf, sizeof (ackbuf), 0,
154 (struct sockaddr *)&from, &fromlen);
158 perror("tftp: recvfrom");
161 s_inn.sin_port = from.sin_port; /* added */
163 tpacket("received", ap, n);
164 /* should verify packet came from server */
165 ap->th_opcode = ntohs(ap->th_opcode);
166 ap->th_block = ntohs(ap->th_block);
167 if (ap->th_opcode == ERROR) {
168 printf("Error code %d: %s\n", ap->th_code,
172 if (ap->th_opcode == ACK) {
175 if (ap->th_block == block) {
178 /* On an error, try to synchronize
183 printf("discarded %d packets\n",
186 if (ap->th_block == (block-1)) {
194 } while (size == SEGSIZE || block == 1);
199 printstats("Sent", amount);
206 recvfile(int fd, char *name, char *mode)
208 register struct tftphdr *ap;
210 volatile int block = 1, size = 0;
212 volatile unsigned long amount = 0;
213 struct sockaddr_in from;
215 volatile int firsttrip = 1;
217 volatile int convert; /* true if converting crlf -> lf */
221 ap = (struct tftphdr *)ackbuf;
222 file = fdopen(fd, "w");
223 convert = !strcmp(mode, "netascii");
225 signal(SIGALRM, timer);
228 size = makerequest(RRQ, name, ap, mode);
231 ap->th_opcode = htons((u_short)ACK);
232 ap->th_block = htons((u_short)(block));
237 (void) sigsetjmp(timeoutbuf, 1);
240 tpacket("sent", ap, size);
241 if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&s_inn,
242 sizeof (s_inn)) != size) {
244 perror("tftp: sendto");
247 write_behind(file, convert);
251 fromlen = sizeof (from);
252 n = recvfrom(f, dp, PKTSIZE, 0,
253 (struct sockaddr *)&from, &fromlen);
257 perror("tftp: recvfrom");
260 s_inn.sin_port = from.sin_port; /* added */
262 tpacket("received", dp, n);
263 /* should verify client address */
264 dp->th_opcode = ntohs(dp->th_opcode);
265 dp->th_block = ntohs(dp->th_block);
266 if (dp->th_opcode == ERROR) {
267 printf("Error code %d: %s\n", dp->th_code,
271 if (dp->th_opcode == DATA) {
274 if (dp->th_block == block) {
275 break; /* have next packet */
277 /* On an error, try to synchronize
282 printf("discarded %d packets\n", j);
284 if (dp->th_block == (block-1)) {
285 goto send_ack; /* resend ack */
289 /* size = write(fd, dp->th_data, n - 4); */
290 size = writeit(file, &dp, n - 4, convert);
296 } while (size == SEGSIZE);
297 abort: /* ok to ack, since user */
298 ap->th_opcode = htons((u_short)ACK); /* has seen err msg */
299 ap->th_block = htons((u_short)block);
300 (void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&s_inn, sizeof(s_inn));
301 write_behind(file, convert); /* flush last buffer */
305 printstats("Received", amount);
309 makerequest(int request, char *name, struct tftphdr *tp, char *mode)
313 tp->th_opcode = htons((u_short)request);
321 return (cp - (char *)tp);
328 { EUNDEF, "Undefined error code" },
329 { ENOTFOUND, "File not found" },
330 { EACCESS, "Access violation" },
331 { ENOSPACE, "Disk full or allocation exceeded" },
332 { EBADOP, "Illegal TFTP operation" },
333 { EBADID, "Unknown transfer ID" },
334 { EEXISTS, "File already exists" },
335 { ENOUSER, "No such user" },
340 * Send a nak packet (error message).
341 * Error code passed in is one of the
342 * standard TFTP codes, or a UNIX errno
348 register struct errmsg *pe;
349 register struct tftphdr *tp;
352 tp = (struct tftphdr *)ackbuf;
353 tp->th_opcode = htons((u_short)ERROR);
354 tp->th_code = htons((u_short)error);
355 for (pe = errmsgs; pe->e_code >= 0; pe++)
356 if (pe->e_code == error)
358 if (pe->e_code < 0) {
359 pe->e_msg = strerror(error - 100);
360 tp->th_code = EUNDEF;
362 strcpy(tp->th_msg, pe->e_msg);
363 length = strlen(pe->e_msg) + 4;
365 tpacket("sent", tp, length);
366 if (sendto(f, ackbuf, length, 0, (struct sockaddr *)&s_inn,
367 sizeof (s_inn)) != length)
373 tpacket(const char *s, struct tftphdr *tp, int n)
375 static const char *opcodes[] =
376 { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR" };
377 register char *cp, *file;
378 u_short op = ntohs(tp->th_opcode);
380 if (op < RRQ || op > ERROR)
381 printf("%s opcode=%x ", s, op);
383 printf("%s %s ", s, opcodes[op]);
389 file = cp = tp->th_stuff;
390 cp = cp + strlen(cp);
391 printf("<file=%s, mode=%s>\n", file, cp + 1);
395 printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);
399 printf("<block=%d>\n", ntohs(tp->th_block));
403 printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);
408 struct timeval tstart;
409 struct timeval tstop;
410 struct timezone zone;
414 gettimeofday(&tstart, &zone);
419 gettimeofday(&tstop, &zone);
423 printstats(const char *direction, unsigned long amount)
426 /* compute delta in 1/10's second units */
427 delta = ((tstop.tv_sec*10.)+(tstop.tv_usec/100000)) -
428 ((tstart.tv_sec*10.)+(tstart.tv_usec/100000));
429 delta = delta/10.; /* back to seconds */
430 printf("%s %ld bytes in %.1f seconds", direction, amount, delta);
432 printf(" [%.0f bits/sec]", (amount*8.)/delta);