8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / usr.bin / tftp / tftp.c
blob83d80d306fe1c6aca9d2fcf87bb5f851532b63e0
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
32 * All Rights Reserved
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
36 * contributors.
39 #pragma ident "%Z%%M% %I% %E% SMI"
42 * TFTP User Program -- Protocol Machines
44 #include <sys/types.h>
45 #include <sys/socket.h>
46 #include <sys/time.h>
47 #include <sys/stat.h>
49 #include <signal.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <unistd.h>
53 #include <errno.h>
54 #include <string.h>
55 #include <stddef.h>
56 #include <inttypes.h>
58 #include "tftpcommon.h"
59 #include "tftpprivate.h"
61 static char *blksize_str(void);
62 static char *timeout_str(void);
63 static char *tsize_str(void);
64 static int blksize_handler(char *);
65 static int timeout_handler(char *);
66 static int tsize_handler(char *);
67 static int add_options(char *, char *);
68 static int process_oack(tftpbuf *, int);
69 static void nak(int);
70 static void startclock(void);
71 static void stopclock(void);
72 static void printstats(char *, off_t);
73 static int makerequest(int, char *, struct tftphdr *, char *);
74 static void tpacket(char *, struct tftphdr *, int);
76 static struct options {
77 char *opt_name;
78 char *(*opt_str)(void);
79 int (*opt_handler)(char *);
80 } options[] = {
81 { "blksize", blksize_str, blksize_handler },
82 { "timeout", timeout_str, timeout_handler },
83 { "tsize", tsize_str, tsize_handler },
84 { NULL }
87 static char optbuf[MAX_OPTVAL_LEN];
88 static boolean_t tsize_set;
90 static tftpbuf ackbuf;
91 static int timeout;
92 static off_t tsize;
93 static jmp_buf timeoutbuf;
95 int blocksize = SEGSIZE; /* Number of data bytes in a DATA packet */
97 /*ARGSUSED*/
98 static void
99 timer(int signum)
101 timeout += rexmtval;
102 if (timeout >= maxtimeout) {
103 (void) fputs("Transfer timed out.\n", stderr);
104 longjmp(toplevel, -1);
106 (void) signal(SIGALRM, timer);
107 longjmp(timeoutbuf, 1);
111 * Send the requested file.
113 void
114 tftp_sendfile(int fd, char *name, char *mode)
116 struct tftphdr *ap; /* data and ack packets */
117 struct tftphdr *dp;
118 int count = 0, size, n;
119 ushort_t block = 0;
120 off_t amount = 0;
121 struct sockaddr_in6 from;
122 socklen_t fromlen;
123 int convert; /* true if doing nl->crlf conversion */
124 FILE *file;
125 struct stat statb;
126 int errcode;
128 startclock(); /* start stat's clock */
129 dp = r_init(); /* reset fillbuf/read-ahead code */
130 ap = &ackbuf.tb_hdr;
131 file = fdopen(fd, "r");
132 convert = (strcmp(mode, "netascii") == 0);
134 tsize_set = ((tsize_opt != 0) && !convert && (fstat(fd, &statb) == 0));
135 if (tsize_set)
136 tsize = statb.st_size;
138 do {
139 (void) signal(SIGALRM, timer);
140 if (count == 0) {
141 if ((size = makerequest(WRQ, name, dp, mode)) == -1) {
142 (void) fprintf(stderr,
143 "tftp: Error: Write request packet too "
144 "big\n");
145 (void) fclose(file);
146 return;
148 size -= 4;
149 } else {
150 size = readit(file, &dp, convert);
151 if (size < 0) {
152 nak(errno + 100);
153 break;
155 dp->th_opcode = htons((ushort_t)DATA);
156 dp->th_block = htons((ushort_t)block);
158 timeout = 0;
159 (void) setjmp(timeoutbuf);
160 if (trace)
161 tpacket("sent", dp, size + 4);
162 n = sendto(f, dp, size + 4, 0,
163 (struct sockaddr *)&sin6, sizeof (sin6));
164 if (n != size + 4) {
165 perror("tftp: sendto");
166 goto abort;
168 /* Can't read-ahead first block as OACK may change blocksize */
169 if (count != 0)
170 read_ahead(file, convert);
171 (void) alarm(rexmtval);
172 for (; ; ) {
173 (void) sigrelse(SIGALRM);
174 do {
175 fromlen = (socklen_t)sizeof (from);
176 n = recvfrom(f, ackbuf.tb_data,
177 sizeof (ackbuf.tb_data), 0,
178 (struct sockaddr *)&from, &fromlen);
179 if (n < 0) {
180 perror("tftp: recvfrom");
181 goto abort;
183 } while (n < offsetof(struct tftphdr, th_data));
184 (void) sighold(SIGALRM);
185 sin6.sin6_port = from.sin6_port; /* added */
186 if (trace)
187 tpacket("received", ap, n);
188 /* should verify packet came from server */
189 ap->th_opcode = ntohs(ap->th_opcode);
190 if (ap->th_opcode == ERROR) {
191 ap->th_code = ntohs(ap->th_code);
192 (void) fprintf(stderr,
193 "Error code %d", ap->th_code);
194 if (n > offsetof(struct tftphdr, th_data))
195 (void) fprintf(stderr, ": %.*s", n -
196 offsetof(struct tftphdr, th_data),
197 ap->th_msg);
198 (void) fputc('\n', stderr);
199 goto abort;
201 if ((count == 0) && (ap->th_opcode == OACK)) {
202 errcode = process_oack(&ackbuf, n);
203 if (errcode >= 0) {
204 nak(errcode);
205 (void) fputs("Rejected OACK\n",
206 stderr);
207 goto abort;
209 break;
211 if (ap->th_opcode == ACK) {
212 ap->th_block = ntohs(ap->th_block);
213 if (ap->th_block == block) {
214 break;
217 * Never resend the current DATA packet on
218 * receipt of a duplicate ACK, doing so would
219 * cause the "Sorcerer's Apprentice Syndrome".
223 cancel_alarm();
224 if (count > 0)
225 amount += size;
226 block++;
227 count++;
228 } while (size == blocksize || count == 1);
229 abort:
230 cancel_alarm();
231 (void) fclose(file);
232 stopclock();
233 if (amount > 0)
234 printstats("Sent", amount);
238 * Receive a file.
240 void
241 tftp_recvfile(int fd, char *name, char *mode)
243 struct tftphdr *ap;
244 struct tftphdr *dp;
245 ushort_t block = 1;
246 int n, size;
247 unsigned long amount = 0;
248 struct sockaddr_in6 from;
249 socklen_t fromlen;
250 boolean_t firsttrip = B_TRUE;
251 FILE *file;
252 int convert; /* true if converting crlf -> lf */
253 int errcode;
255 startclock();
256 dp = w_init();
257 ap = &ackbuf.tb_hdr;
258 file = fdopen(fd, "w");
259 convert = (strcmp(mode, "netascii") == 0);
261 tsize_set = (tsize_opt != 0);
262 if (tsize_set)
263 tsize = 0;
265 if ((size = makerequest(RRQ, name, ap, mode)) == -1) {
266 (void) fprintf(stderr,
267 "tftp: Error: Read request packet too big\n");
268 (void) fclose(file);
269 return;
272 do {
273 (void) signal(SIGALRM, timer);
274 if (firsttrip) {
275 firsttrip = B_FALSE;
276 } else {
277 ap->th_opcode = htons((ushort_t)ACK);
278 ap->th_block = htons((ushort_t)(block));
279 size = 4;
280 block++;
283 send_oack_ack:
284 timeout = 0;
285 (void) setjmp(timeoutbuf);
286 send_ack:
287 if (trace)
288 tpacket("sent", ap, size);
289 if (sendto(f, ackbuf.tb_data, size, 0, (struct sockaddr *)&sin6,
290 sizeof (sin6)) != size) {
291 (void) alarm(0);
292 perror("tftp: sendto");
293 goto abort;
295 if (write_behind(file, convert) < 0) {
296 nak(errno + 100);
297 goto abort;
299 (void) alarm(rexmtval);
300 for (; ; ) {
301 (void) sigrelse(SIGALRM);
302 do {
303 fromlen = (socklen_t)sizeof (from);
304 n = recvfrom(f, dp, blocksize + 4, 0,
305 (struct sockaddr *)&from, &fromlen);
306 if (n < 0) {
307 perror("tftp: recvfrom");
308 goto abort;
310 } while (n < offsetof(struct tftphdr, th_data));
311 (void) sighold(SIGALRM);
312 sin6.sin6_port = from.sin6_port; /* added */
313 if (trace)
314 tpacket("received", dp, n);
315 /* should verify client address */
316 dp->th_opcode = ntohs(dp->th_opcode);
317 if (dp->th_opcode == ERROR) {
318 dp->th_code = ntohs(dp->th_code);
319 (void) fprintf(stderr, "Error code %d",
320 dp->th_code);
321 if (n > offsetof(struct tftphdr, th_data))
322 (void) fprintf(stderr, ": %.*s", n -
323 offsetof(struct tftphdr, th_data),
324 dp->th_msg);
325 (void) fputc('\n', stderr);
326 goto abort;
328 if ((block == 1) && (dp->th_opcode == OACK)) {
329 errcode = process_oack((tftpbuf *)dp, n);
330 if (errcode >= 0) {
331 cancel_alarm();
332 nak(errcode);
333 (void) fputs("Rejected OACK\n",
334 stderr);
335 (void) fclose(file);
336 return;
338 ap->th_opcode = htons((ushort_t)ACK);
339 ap->th_block = htons(0);
340 size = 4;
341 goto send_oack_ack;
343 if (dp->th_opcode == DATA) {
344 int j;
346 dp->th_block = ntohs(dp->th_block);
347 if (dp->th_block == block) {
348 break; /* have next packet */
351 * On an error, try to synchronize
352 * both sides.
354 j = synchnet(f);
355 if (j < 0) {
356 perror("tftp: recvfrom");
357 goto abort;
359 if ((j > 0) && trace) {
360 (void) printf("discarded %d packets\n",
363 if (dp->th_block == (block-1)) {
364 goto send_ack; /* resend ack */
368 cancel_alarm();
369 size = writeit(file, &dp, n - 4, convert);
370 if (size < 0) {
371 nak(errno + 100);
372 goto abort;
374 amount += size;
375 } while (size == blocksize);
377 cancel_alarm();
378 if (write_behind(file, convert) < 0) { /* flush last buffer */
379 nak(errno + 100);
380 goto abort;
382 n = fclose(file);
383 file = NULL;
384 if (n == EOF) {
385 nak(errno + 100);
386 goto abort;
389 /* ok to ack, since user has seen err msg */
390 ap->th_opcode = htons((ushort_t)ACK);
391 ap->th_block = htons((ushort_t)block);
392 if (trace)
393 tpacket("sent", ap, 4);
394 if (sendto(f, ackbuf.tb_data, 4, 0,
395 (struct sockaddr *)&sin6, sizeof (sin6)) != 4)
396 perror("tftp: sendto");
398 abort:
399 cancel_alarm();
400 if (file != NULL)
401 (void) fclose(file);
402 stopclock();
403 if (amount > 0)
404 printstats("Received", amount);
407 static int
408 makerequest(int request, char *name, struct tftphdr *tp, char *mode)
410 char *cp, *cpend;
411 int len;
413 tp->th_opcode = htons((ushort_t)request);
414 cp = (char *)&tp->th_stuff;
416 /* Maximum size of a request packet is 512 bytes (RFC 2347) */
417 cpend = (char *)tp + SEGSIZE;
419 len = strlcpy(cp, name, cpend - cp) + 1;
420 cp += len;
421 if (cp > cpend)
422 return (-1);
424 len = strlcpy(cp, mode, cpend - cp) + 1;
425 cp += len;
426 if (cp > cpend)
427 return (-1);
429 len = add_options(cp, cpend);
430 if (len == -1)
431 return (-1);
432 cp += len;
434 return (cp - (char *)tp);
438 * Return the blksize option value string to include in the request packet.
440 static char *
441 blksize_str(void)
443 blocksize = SEGSIZE;
444 if (blksize == 0)
445 return (NULL);
447 (void) snprintf(optbuf, sizeof (optbuf), "%d", blksize);
448 return (optbuf);
452 * Return the timeout option value string to include in the request packet.
454 static char *
455 timeout_str(void)
457 if (srexmtval == 0)
458 return (NULL);
460 (void) snprintf(optbuf, sizeof (optbuf), "%d", srexmtval);
461 return (optbuf);
465 * Return the tsize option value string to include in the request packet.
467 static char *
468 tsize_str(void)
470 if (tsize_set == B_FALSE)
471 return (NULL);
473 (void) snprintf(optbuf, sizeof (optbuf), OFF_T_FMT, tsize);
474 return (optbuf);
478 * Validate and action the blksize option value string from the OACK packet.
479 * Returns -1 on success or an error code on failure.
481 static int
482 blksize_handler(char *optstr)
484 char *endp;
485 int value;
487 /* Make sure the option was requested */
488 if (blksize == 0)
489 return (EOPTNEG);
490 errno = 0;
491 value = (int)strtol(optstr, &endp, 10);
492 if (errno != 0 || value < MIN_BLKSIZE || value > blksize ||
493 *endp != '\0')
494 return (EOPTNEG);
495 blocksize = value;
496 return (-1);
500 * Validate and action the timeout option value string from the OACK packet.
501 * Returns -1 on success or an error code on failure.
503 static int
504 timeout_handler(char *optstr)
506 char *endp;
507 int value;
509 /* Make sure the option was requested */
510 if (srexmtval == 0)
511 return (EOPTNEG);
512 errno = 0;
513 value = (int)strtol(optstr, &endp, 10);
514 if (errno != 0 || value != srexmtval || *endp != '\0')
515 return (EOPTNEG);
517 * Nothing to set, client and server retransmission intervals are
518 * set separately in the client.
520 return (-1);
524 * Validate and action the tsize option value string from the OACK packet.
525 * Returns -1 on success or an error code on failure.
527 static int
528 tsize_handler(char *optstr)
530 char *endp;
531 longlong_t value;
533 /* Make sure the option was requested */
534 if (tsize_set == B_FALSE)
535 return (EOPTNEG);
536 errno = 0;
537 value = strtoll(optstr, &endp, 10);
538 if (errno != 0 || value < 0 || *endp != '\0')
539 return (EOPTNEG);
540 #if _FILE_OFFSET_BITS == 32
541 if (value > MAXOFF_T)
542 return (ENOSPACE);
543 #endif
545 * Don't bother checking the tsize value we specified in a write
546 * request is echoed back in the OACK.
548 if (tsize == 0)
549 tsize = value;
550 return (-1);
554 * Add TFTP options to a request packet.
556 static int
557 add_options(char *obuf, char *obufend)
559 int i;
560 char *cp, *ostr;
562 cp = obuf;
563 for (i = 0; options[i].opt_name != NULL; i++) {
564 ostr = options[i].opt_str();
565 if (ostr != NULL) {
566 cp += strlcpy(cp, options[i].opt_name, obufend - cp)
567 + 1;
568 if (cp > obufend)
569 return (-1);
571 cp += strlcpy(cp, ostr, obufend - cp) + 1;
572 if (cp > obufend)
573 return (-1);
576 return (cp - obuf);
580 * Process OACK packet sent by server in response to options in the request
581 * packet. Returns -1 on success or an error code on failure.
583 static int
584 process_oack(tftpbuf *oackbuf, int n)
586 char *cp, *oackend, *optname, *optval;
587 struct tftphdr *oackp;
588 int i, errcode;
590 oackp = &oackbuf->tb_hdr;
591 cp = (char *)&oackp->th_stuff;
592 oackend = (char *)oackbuf + n;
594 while (cp < oackend) {
595 optname = cp;
596 if ((optval = next_field(optname, oackend)) == NULL)
597 return (EOPTNEG);
598 if ((cp = next_field(optval, oackend)) == NULL)
599 return (EOPTNEG);
600 for (i = 0; options[i].opt_name != NULL; i++) {
601 if (strcasecmp(optname, options[i].opt_name) == 0)
602 break;
604 if (options[i].opt_name == NULL)
605 return (EOPTNEG);
606 errcode = options[i].opt_handler(optval);
607 if (errcode >= 0)
608 return (errcode);
610 return (-1);
614 * Send a nak packet (error message).
615 * Error code passed in is one of the
616 * standard TFTP codes, or a UNIX errno
617 * offset by 100.
619 static void
620 nak(int error)
622 struct tftphdr *tp;
623 int length;
624 struct errmsg *pe;
626 tp = &ackbuf.tb_hdr;
627 tp->th_opcode = htons((ushort_t)ERROR);
628 tp->th_code = htons((ushort_t)error);
629 for (pe = errmsgs; pe->e_code >= 0; pe++)
630 if (pe->e_code == error)
631 break;
632 if (pe->e_code < 0) {
633 pe->e_msg = strerror(error - 100);
634 tp->th_code = EUNDEF;
636 (void) strlcpy(tp->th_msg, pe->e_msg,
637 sizeof (ackbuf) - sizeof (struct tftphdr));
638 length = strlen(pe->e_msg) + 4;
639 if (trace)
640 tpacket("sent", tp, length);
641 if (sendto(f, ackbuf.tb_data, length, 0,
642 (struct sockaddr *)&sin6, sizeof (sin6)) != length)
643 perror("nak");
646 static void
647 tpacket(char *s, struct tftphdr *tp, int n)
649 static char *opcodes[] = \
650 { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" };
651 char *cp, *file, *mode;
652 ushort_t op = ntohs(tp->th_opcode);
653 char *tpend;
655 if (op < RRQ || op > OACK)
656 (void) printf("%s opcode=%x ", s, op);
657 else
658 (void) printf("%s %s ", s, opcodes[op]);
660 switch (op) {
661 case RRQ:
662 case WRQ:
663 tpend = (char *)tp + n;
664 n -= sizeof (tp->th_opcode);
665 file = (char *)&tp->th_stuff;
666 if ((mode = next_field(file, tpend)) == NULL) {
667 (void) printf("<file=%.*s>\n", n, file);
668 break;
670 n -= mode - file;
671 if ((cp = next_field(mode, tpend)) == NULL) {
672 (void) printf("<file=%s, mode=%.*s>\n", file, n, mode);
673 break;
675 (void) printf("<file=%s, mode=%s", file, mode);
676 n -= cp - mode;
677 if (n > 0) {
678 (void) printf(", options: ");
679 print_options(stdout, cp, n);
681 (void) puts(">");
682 break;
684 case DATA:
685 (void) printf("<block=%d, %d bytes>\n", ntohs(tp->th_block),
686 n - sizeof (tp->th_opcode) - sizeof (tp->th_block));
687 break;
689 case ACK:
690 (void) printf("<block=%d>\n", ntohs(tp->th_block));
691 break;
693 case OACK:
694 (void) printf("<options: ");
695 print_options(stdout, (char *)&tp->th_stuff,
696 n - sizeof (tp->th_opcode));
697 (void) puts(">");
698 break;
700 case ERROR:
701 (void) printf("<code=%d", ntohs(tp->th_code));
702 n = n - sizeof (tp->th_opcode) - sizeof (tp->th_code);
703 if (n > 0)
704 (void) printf(", msg=%.*s", n, tp->th_msg);
705 (void) puts(">");
706 break;
710 static hrtime_t tstart, tstop;
712 static void
713 startclock(void)
715 tstart = gethrtime();
718 static void
719 stopclock(void)
721 tstop = gethrtime();
724 static void
725 printstats(char *direction, off_t amount)
727 hrtime_t delta, tenths;
729 delta = tstop - tstart;
730 tenths = delta / (NANOSEC / 10);
731 (void) printf("%s " OFF_T_FMT " bytes in %" PRId64 ".%" PRId64
732 " seconds", direction, amount, tenths / 10, tenths % 10);
733 if (verbose)
734 (void) printf(" [%" PRId64 " bits/sec]\n",
735 ((hrtime_t)amount * 8 * NANOSEC) / delta);
736 else
737 (void) putchar('\n');