]>
git.saurik.com Git - apple/network_cmds.git/blob - tftp.tproj/tftp.c
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
25 * Copyright (c) 1983, 1993
26 * The Regents of the University of California. All rights reserved.
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. All advertising materials mentioning features or use of this software
37 * must display the following acknowledgement:
38 * This product includes software developed by the University of
39 * California, Berkeley and its contributors.
40 * 4. Neither the name of the University nor the names of its contributors
41 * may be used to endorse or promote products derived from this software
42 * without specific prior written permission.
44 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
61 * TFTP User Program -- Protocol Machines
63 #include <sys/types.h>
64 #include <sys/socket.h>
67 #include <netinet/in.h>
69 #include <arpa/tftp.h>
82 extern struct sockaddr_in peeraddr
; /* filled in by main */
83 extern int f
; /* the opened socket */
87 extern int maxtimeout
;
89 extern jmp_buf toplevel
; /* filled in by main */
91 #define PKTSIZE SEGSIZE+4
96 static void nak
__P((int));
97 static int makerequest
__P((int, const char *, struct tftphdr
*, const char *));
98 static void printstats
__P((const char *, unsigned long));
99 static void startclock
__P((void));
100 static void stopclock
__P((void));
101 static void timer
__P((int));
102 static void tpacket
__P((const char *, struct tftphdr
*, int));
105 * Send the requested file.
108 tftp_sendfile(fd
, name
, mode
)
113 register struct tftphdr
*ap
; /* data and ack packets */
114 struct tftphdr
*r_init(), *dp
;
116 volatile int block
, size
, convert
;
117 volatile unsigned long amount
;
118 struct sockaddr_in from
;
122 startclock(); /* start stat's clock */
123 dp
= r_init(); /* reset fillbuf/read-ahead code */
124 ap
= (struct tftphdr
*)ackbuf
;
125 file
= fdopen(fd
, "r");
126 convert
= !strcmp(mode
, "netascii");
130 signal(SIGALRM
, timer
);
133 size
= makerequest(WRQ
, name
, dp
, mode
) - 4;
135 /* size = read(fd, dp->th_data, SEGSIZE); */
136 size
= readit(file
, &dp
, convert
);
141 dp
->th_opcode
= htons((u_short
)DATA
);
142 dp
->th_block
= htons((u_short
)block
);
145 (void) setjmp(timeoutbuf
);
148 tpacket("sent", dp
, size
+ 4);
149 n
= sendto(f
, dp
, size
+ 4, 0,
150 (struct sockaddr
*)&peeraddr
, sizeof(peeraddr
));
152 perror("tftp: sendto");
155 read_ahead(file
, convert
);
159 fromlen
= sizeof(from
);
160 n
= recvfrom(f
, ackbuf
, sizeof(ackbuf
), 0,
161 (struct sockaddr
*)&from
, &fromlen
);
165 perror("tftp: recvfrom");
168 peeraddr
.sin_port
= from
.sin_port
; /* added */
170 tpacket("received", ap
, n
);
171 /* should verify packet came from server */
172 ap
->th_opcode
= ntohs(ap
->th_opcode
);
173 ap
->th_block
= ntohs(ap
->th_block
);
174 if (ap
->th_opcode
== ERROR
) {
175 printf("Error code %d: %s\n", ap
->th_code
,
179 if (ap
->th_opcode
== ACK
) {
182 if (ap
->th_block
== block
) {
185 /* On an error, try to synchronize
190 printf("discarded %d packets\n",
193 if (ap
->th_block
== (block
-1)) {
201 } while (size
== SEGSIZE
|| block
== 1);
206 printstats("Sent", amount
);
213 recvfile(fd
, name
, mode
)
218 register struct tftphdr
*ap
;
219 struct tftphdr
*dp
, *w_init();
221 volatile int block
, size
, firsttrip
;
222 volatile unsigned long amount
;
223 struct sockaddr_in from
;
226 volatile int convert
; /* true if converting crlf -> lf */
230 ap
= (struct tftphdr
*)ackbuf
;
231 file
= fdopen(fd
, "w");
232 convert
= !strcmp(mode
, "netascii");
237 signal(SIGALRM
, timer
);
240 size
= makerequest(RRQ
, name
, ap
, mode
);
243 ap
->th_opcode
= htons((u_short
)ACK
);
244 ap
->th_block
= htons((u_short
)(block
));
249 (void) setjmp(timeoutbuf
);
252 tpacket("sent", ap
, size
);
253 if (sendto(f
, ackbuf
, size
, 0, (struct sockaddr
*)&peeraddr
,
254 sizeof(peeraddr
)) != size
) {
256 perror("tftp: sendto");
259 write_behind(file
, convert
);
263 fromlen
= sizeof(from
);
264 n
= recvfrom(f
, dp
, PKTSIZE
, 0,
265 (struct sockaddr
*)&from
, &fromlen
);
269 perror("tftp: recvfrom");
272 peeraddr
.sin_port
= from
.sin_port
; /* added */
274 tpacket("received", dp
, n
);
275 /* should verify client address */
276 dp
->th_opcode
= ntohs(dp
->th_opcode
);
277 dp
->th_block
= ntohs(dp
->th_block
);
278 if (dp
->th_opcode
== ERROR
) {
279 printf("Error code %d: %s\n", dp
->th_code
,
283 if (dp
->th_opcode
== DATA
) {
286 if (dp
->th_block
== block
) {
287 break; /* have next packet */
289 /* On an error, try to synchronize
294 printf("discarded %d packets\n", j
);
296 if (dp
->th_block
== (block
-1)) {
297 goto send_ack
; /* resend ack */
301 /* size = write(fd, dp->th_data, n - 4); */
302 size
= writeit(file
, &dp
, n
- 4, convert
);
308 } while (size
== SEGSIZE
);
309 abort
: /* ok to ack, since user */
310 ap
->th_opcode
= htons((u_short
)ACK
); /* has seen err msg */
311 ap
->th_block
= htons((u_short
)block
);
312 (void) sendto(f
, ackbuf
, 4, 0, (struct sockaddr
*)&peeraddr
,
314 write_behind(file
, convert
); /* flush last buffer */
318 printstats("Received", amount
);
322 makerequest(request
, name
, tp
, mode
)
330 tp
->th_opcode
= htons((u_short
)request
);
338 return (cp
- (char *)tp
);
345 { EUNDEF
, "Undefined error code" },
346 { ENOTFOUND
, "File not found" },
347 { EACCESS
, "Access violation" },
348 { ENOSPACE
, "Disk full or allocation exceeded" },
349 { EBADOP
, "Illegal TFTP operation" },
350 { EBADID
, "Unknown transfer ID" },
351 { EEXISTS
, "File already exists" },
352 { ENOUSER
, "No such user" },
357 * Send a nak packet (error message).
358 * Error code passed in is one of the
359 * standard TFTP codes, or a UNIX errno
366 register struct errmsg
*pe
;
367 register struct tftphdr
*tp
;
371 tp
= (struct tftphdr
*)ackbuf
;
372 tp
->th_opcode
= htons((u_short
)ERROR
);
373 tp
->th_code
= htons((u_short
)error
);
374 for (pe
= errmsgs
; pe
->e_code
>= 0; pe
++)
375 if (pe
->e_code
== error
)
377 if (pe
->e_code
< 0) {
378 pe
->e_msg
= strerror(error
- 100);
379 tp
->th_code
= EUNDEF
;
381 strcpy(tp
->th_msg
, pe
->e_msg
);
382 length
= strlen(pe
->e_msg
) + 4;
384 tpacket("sent", tp
, length
);
385 if (sendto(f
, ackbuf
, length
, 0, (struct sockaddr
*)&peeraddr
,
386 sizeof(peeraddr
)) != length
)
396 static char *opcodes
[] =
397 { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR" };
398 register char *cp
, *file
;
399 u_short op
= ntohs(tp
->th_opcode
);
402 if (op
< RRQ
|| op
> ERROR
)
403 printf("%s opcode=%x ", s
, op
);
405 printf("%s %s ", s
, opcodes
[op
]);
411 file
= cp
= tp
->th_stuff
;
412 cp
= index(cp
, '\0');
413 printf("<file=%s, mode=%s>\n", file
, cp
+ 1);
417 printf("<block=%d, %d bytes>\n", ntohs(tp
->th_block
), n
- 4);
421 printf("<block=%d>\n", ntohs(tp
->th_block
));
425 printf("<code=%d, msg=%s>\n", ntohs(tp
->th_code
), tp
->th_msg
);
430 struct timeval tstart
;
431 struct timeval tstop
;
437 (void)gettimeofday(&tstart
, NULL
);
444 (void)gettimeofday(&tstop
, NULL
);
448 printstats(direction
, amount
)
449 const char *direction
;
450 unsigned long amount
;
453 /* compute delta in 1/10's second units */
454 delta
= ((tstop
.tv_sec
*10.)+(tstop
.tv_usec
/100000)) -
455 ((tstart
.tv_sec
*10.)+(tstart
.tv_usec
/100000));
456 delta
= delta
/10.; /* back to seconds */
457 printf("%s %d bytes in %.1f seconds", direction
, amount
, delta
);
459 printf(" [%.0f bits/sec]", (amount
*8.)/delta
);
469 if (timeout
>= maxtimeout
) {
470 printf("Transfer timed out.\n");
471 longjmp(toplevel
, -1);
473 longjmp(timeoutbuf
, 1);