2 * Copyright (c) 1983 Regents of the University of California.
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 static char sccsid
[] = "@(#)tftp.c 5.7 (Berkeley) 6/29/88";
22 /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
25 * TFTP User Program -- Protocol Machines
27 #include <sys/types.h>
28 #include <sys/socket.h>
31 #include <netinet/in.h>
33 #include <arpa/tftp.h>
42 extern struct sockaddr_in sin
; /* filled in by main */
43 extern int f
; /* the opened socket */
47 extern int maxtimeout
;
50 #define PKTSIZE (1432+4) /* SEGSIZE+4 */
63 signal(SIGALRM
, timer
);
65 if (timeout
>= maxtimeout
) {
66 printf("Transfer timed out.\n");
67 longjmp(toplevel
, -1);
69 longjmp(timeoutbuf
, 1);
78 while (n
-- > 0 && *s
++) i
++;
83 * Parse an OACK package and set blocksize accordingly
92 while (sz
> 0 && *cp
) {
94 if (n
== 7 && !strncmp("blksize", cp
, 7)) {
99 for (segsize
= 0, n
= strnlen(cp
, sz
); n
> 0;
101 if (*cp
< '0' || *cp
> '9')
103 segsize
= 10*segsize
+ *cp
- '0'; }
108 if (segsize
< 8 || segsize
> 1432) {
109 printf("Remote host negotiated illegal blocksize %d\n",
112 longjmp(timeoutbuf
, -1);
117 * Send the requested file.
119 sendfile(fd
, name
, mode
)
124 register struct tftphdr
*ap
; /* data and ack packets */
125 struct tftphdr
*r_init(), *dp
;
126 register int size
, n
;
128 register unsigned long amount
= 0;
129 struct sockaddr_in from
;
131 int convert
; /* true if doing nl->crlf conversion */
134 startclock(); /* start stat's clock */
135 dp
= r_init(); /* reset fillbuf/read-ahead code */
136 ap
= (struct tftphdr
*)ackbuf
;
137 file
= fdopen(fd
, "r");
138 convert
= !strcmp(mode
, "netascii");
140 signal(SIGALRM
, timer
);
143 size
= makerequest(WRQ
, name
, dp
, mode
) - 4;
145 /* size = read(fd, dp->th_data, SEGSIZE); */
146 size
= readit(file
, &dp
, convert
);
151 dp
->th_opcode
= htons((u_short
)DATA
);
152 dp
->th_block
= htons(block
);
155 (void) setjmp(timeoutbuf
);
158 tpacket("sent", dp
, size
+ 4);
159 n
= sendto(f
, dp
, size
+ 4, 0, (struct sockaddr
*)&sin
,
162 perror("tftp: sendto");
165 if (block
) /* do not start reading until the blocksize
166 has been negotiated */
167 read_ahead(file
, convert
);
171 fromlen
= sizeof (from
);
172 n
= recvfrom(f
, ackbuf
, sizeof (ackbuf
), 0,
173 (struct sockaddr
*)&from
,
178 perror("tftp: recvfrom");
181 sin
.sin_port
= from
.sin_port
; /* added */
183 tpacket("received", ap
, n
);
184 /* should verify packet came from server */
185 ap
->th_opcode
= ntohs(ap
->th_opcode
);
186 if (ap
->th_opcode
== ERROR
) {
187 printf("Error code %d: %s\n", ap
->th_code
,
191 if (ap
->th_opcode
== ACK
) {
194 ap
->th_block
= ntohs(ap
->th_block
);
198 printf("server does not know "
199 "about RFC1782; reset"
203 if (ap
->th_block
== block
) {
206 /* On an error, try to synchronize
211 printf("discarded %d packets\n",
214 if (ap
->th_block
== (block
-1)) {
218 else if (ap
->th_opcode
== OACK
) {
220 printf("protocol violation\n");
221 longjmp(toplevel
, -1);
223 parseoack(&ap
->th_stuff
, n
- 2);
230 read_ahead(file
, convert
);
232 } while (size
== segsize
|| block
== 1);
237 printstats("Sent", amount
);
243 recvfile(fd
, name
, mode
)
248 register struct tftphdr
*ap
;
249 struct tftphdr
*dp
, *w_init();
250 register int n
, size
;
252 unsigned long amount
= 0;
253 struct sockaddr_in from
;
254 int fromlen
, firsttrip
= 1;
256 int convert
; /* true if converting crlf -> lf */
261 ap
= (struct tftphdr
*)ackbuf
;
262 file
= fdopen(fd
, "w");
263 convert
= !strcmp(mode
, "netascii");
265 signal(SIGALRM
, timer
);
268 size
= makerequest(RRQ
, name
, ap
, mode
);
271 ap
->th_opcode
= htons((u_short
)ACK
);
272 ap
->th_block
= htons(block
);
277 (void) setjmp(timeoutbuf
);
280 tpacket("sent", ap
, size
);
281 if (sendto(f
, ackbuf
, size
, 0, (struct sockaddr
*)&sin
,
282 sizeof (sin
)) != size
) {
284 perror("tftp: sendto");
288 write_behind(file
, convert
);
292 fromlen
= sizeof (from
);
293 n
= recvfrom(f
, dp
, PKTSIZE
, 0,
294 (struct sockaddr
*)&from
, &fromlen
);
298 perror("tftp: recvfrom");
301 sin
.sin_port
= from
.sin_port
; /* added */
303 tpacket("received", dp
, n
);
304 /* should verify client address */
305 dp
->th_opcode
= ntohs(dp
->th_opcode
);
306 if (dp
->th_opcode
== ERROR
) {
307 printf("Error code %d: %s\n", dp
->th_code
,
311 if (dp
->th_opcode
== DATA
) {
316 printf("server does not know "
317 "about RFC1782; reset"
322 dp
->th_block
= ntohs(dp
->th_block
);
323 if (dp
->th_block
== block
) {
324 break; /* have next packet */
326 /* On an error, try to synchronize
331 printf("discarded %d packets\n", j
);
333 if (dp
->th_block
== (block
-1)) {
334 goto send_ack
; /* resend ack */
337 else if (dp
->th_opcode
== OACK
) {
338 if (block
!= 1 || !waitforoack
) {
339 printf("protocol violation\n");
340 longjmp(toplevel
, -1);
343 parseoack(&dp
->th_stuff
, n
- 2);
344 ap
->th_opcode
= htons((u_short
)ACK
);
345 ap
->th_block
= htons(0);
350 /* size = write(fd, dp->th_data, n - 4); */
351 size
= writeit(file
, &dp
, n
- 4, convert
);
357 } while (size
== segsize
);
358 abort
: /* ok to ack, since user */
359 ap
->th_opcode
= htons((u_short
)ACK
); /* has seen err msg */
360 ap
->th_block
= htons(block
);
361 (void) sendto(f
, ackbuf
, 4, 0, (struct sockaddr
*)&sin
, sizeof (sin
));
362 write_behind(file
, convert
); /* flush last buffer */
366 printstats("Received", amount
);
369 makerequest(request
, name
, tp
, mode
)
376 tp
->th_opcode
= htons((u_short
)request
);
384 strcpy(cp
, "blksize");
387 sprintf(cp
, "%d", segsize
);
388 cp
+= strlen(cp
) + 1;
389 return (cp
- (char *)tp
);
396 { EUNDEF
, "Undefined error code" },
397 { ENOTFOUND
, "File not found" },
398 { EACCESS
, "Access violation" },
399 { ENOSPACE
, "Disk full or allocation exceeded" },
400 { EBADOP
, "Illegal TFTP operation" },
401 { EBADID
, "Unknown transfer ID" },
402 { EEXISTS
, "File already exists" },
403 { ENOUSER
, "No such user" },
408 * Send a nak packet (error message).
409 * Error code passed in is one of the
410 * standard TFTP codes, or a UNIX errno
416 register struct tftphdr
*tp
;
418 register struct errmsg
*pe
;
419 /* extern char *sys_errlist[]; */
421 tp
= (struct tftphdr
*)ackbuf
;
422 tp
->th_opcode
= htons((u_short
)ERROR
);
423 tp
->th_code
= htons((u_short
)error
);
424 for (pe
= errmsgs
; pe
->e_code
>= 0; pe
++)
425 if (pe
->e_code
== error
)
427 if (pe
->e_code
< 0) {
428 pe
->e_msg
= sys_errlist
[error
- 100];
429 tp
->th_code
= EUNDEF
;
431 strcpy(tp
->th_msg
, pe
->e_msg
);
432 length
= strlen(pe
->e_msg
) + 4;
434 tpacket("sent", tp
, length
);
435 if (sendto(f
, ackbuf
, length
, 0, (struct sockaddr
*)&sin
, sizeof (sin
))
446 while (sz
> 0 && *cp
) {
449 printf("%s%s=", i
++ ? ", " : "", cp
);
468 static char *opcodes
[] =
469 { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" };
470 register char *cp
, *file
;
471 u_short op
= ntohs(tp
->th_opcode
);
474 if (op
< RRQ
|| op
> OACK
)
475 printf("%s opcode=%x ", s
, op
);
477 printf("%s %s ", s
, opcodes
[op
]);
483 file
= cp
= tp
->th_stuff
;
484 cp
= index(cp
, '\0');
485 printf("<file=%s, mode=%s, opts: ", file
, cp
+ 1);
486 topts(index(cp
+ 1, '\000') + 1, n
- strlen(file
)
487 - strlen(cp
+ 1) - 2);
492 printf("<block=%d, %d bytes>\n", ntohs(tp
->th_block
), n
- 4);
496 printf("<block=%d>\n", ntohs(tp
->th_block
));
500 printf("<code=%d, msg=%s>\n", ntohs(tp
->th_code
), tp
->th_msg
);
504 topts(tp
->th_stuff
, n
- 2);
510 struct timeval tstart
;
511 struct timeval tstop
;
512 struct timezone zone
;
515 gettimeofday(&tstart
, &zone
);
519 gettimeofday(&tstop
, &zone
);
522 printstats(direction
, amount
)
524 unsigned long amount
;
527 /* compute delta in 1/10's second units */
528 delta
= ((tstop
.tv_sec
*10.)+(tstop
.tv_usec
/100000)) -
529 ((tstart
.tv_sec
*10.)+(tstart
.tv_usec
/100000));
530 delta
= delta
/10.; /* back to seconds */
531 printf("%s %ld bytes in %.1f seconds", direction
, amount
, delta
);
532 if ((verbose
) && (delta
>= 0.1))
533 printf(" [%.0f bits/sec]", (amount
*8.)/delta
);