Purge warnings from prism2 drivers
[gpxe.git] / contrib / tftp / tftp.c
blob894e535e38a5869ea50dc0d6f5b5d03f3bc8eac0
1 /*
2 * Copyright (c) 1983 Regents of the University of California.
3 * All rights reserved.
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.
18 #ifndef lint
19 static char sccsid[] = "@(#)tftp.c 5.7 (Berkeley) 6/29/88";
20 #endif /* not lint */
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>
29 #include <sys/time.h>
31 #include <netinet/in.h>
33 #include <arpa/tftp.h>
35 #include <signal.h>
36 #include <stdio.h>
37 #include <errno.h>
38 #include <setjmp.h>
40 extern int errno;
42 extern struct sockaddr_in sin; /* filled in by main */
43 extern int f; /* the opened socket */
44 extern int trace;
45 extern int verbose;
46 extern int rexmtval;
47 extern int maxtimeout;
48 extern int segsize;
50 #define PKTSIZE (1432+4) /* SEGSIZE+4 */
51 char ackbuf[PKTSIZE];
52 int timeout;
53 jmp_buf toplevel;
54 jmp_buf timeoutbuf;
56 #ifndef OACK
57 #define OACK 6
58 #endif
60 void timer(int sig)
63 signal(SIGALRM, timer);
64 timeout += rexmtval;
65 if (timeout >= maxtimeout) {
66 printf("Transfer timed out.\n");
67 longjmp(toplevel, -1);
69 longjmp(timeoutbuf, 1);
72 strnlen(s, n)
73 char *s;
74 int n;
76 int i = 0;
78 while (n-- > 0 && *s++) i++;
79 return(i);
83 * Parse an OACK package and set blocksize accordingly
85 parseoack(cp, sz)
86 char *cp;
87 int sz;
89 int n;
91 segsize = 512;
92 while (sz > 0 && *cp) {
93 n = strnlen(cp, sz);
94 if (n == 7 && !strncmp("blksize", cp, 7)) {
95 cp += 8;
96 sz -= 8;
97 if (sz <= 0)
98 break;
99 for (segsize = 0, n = strnlen(cp, sz); n > 0;
100 n--, cp++, sz--) {
101 if (*cp < '0' || *cp > '9')
102 break;
103 segsize = 10*segsize + *cp - '0'; }
105 cp += n + 1;
106 sz -= n + 1;
108 if (segsize < 8 || segsize > 1432) {
109 printf("Remote host negotiated illegal blocksize %d\n",
110 segsize);
111 segsize = 512;
112 longjmp(timeoutbuf, -1);
117 * Send the requested file.
119 sendfile(fd, name, mode)
120 int fd;
121 char *name;
122 char *mode;
124 register struct tftphdr *ap; /* data and ack packets */
125 struct tftphdr *r_init(), *dp;
126 register int size, n;
127 u_short block = 0;
128 register unsigned long amount = 0;
129 struct sockaddr_in from;
130 int fromlen;
131 int convert; /* true if doing nl->crlf conversion */
132 FILE *file;
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);
141 do {
142 if (block == 0)
143 size = makerequest(WRQ, name, dp, mode) - 4;
144 else {
145 /* size = read(fd, dp->th_data, SEGSIZE); */
146 size = readit(file, &dp, convert);
147 if (size < 0) {
148 nak(errno + 100);
149 break;
151 dp->th_opcode = htons((u_short)DATA);
152 dp->th_block = htons(block);
154 timeout = 0;
155 (void) setjmp(timeoutbuf);
156 send_data:
157 if (trace)
158 tpacket("sent", dp, size + 4);
159 n = sendto(f, dp, size + 4, 0, (struct sockaddr *)&sin,
160 sizeof (sin));
161 if (n != size + 4) {
162 perror("tftp: sendto");
163 goto abort;
165 if (block) /* do not start reading until the blocksize
166 has been negotiated */
167 read_ahead(file, convert);
168 for ( ; ; ) {
169 alarm(rexmtval);
170 do {
171 fromlen = sizeof (from);
172 n = recvfrom(f, ackbuf, sizeof (ackbuf), 0,
173 (struct sockaddr *)&from,
174 &fromlen);
175 } while (n <= 0);
176 alarm(0);
177 if (n < 0) {
178 perror("tftp: recvfrom");
179 goto abort;
181 sin.sin_port = from.sin_port; /* added */
182 if (trace)
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,
188 ap->th_msg);
189 goto abort;
191 if (ap->th_opcode == ACK) {
192 int j;
194 ap->th_block = ntohs(ap->th_block);
196 if (block == 0) {
197 if (trace)
198 printf("server does not know "
199 "about RFC1782; reset"
200 "ting blocksize\n");
201 segsize = 512;
203 if (ap->th_block == block) {
204 break;
206 /* On an error, try to synchronize
207 * both sides.
209 j = synchnet(f);
210 if (j && trace) {
211 printf("discarded %d packets\n",
214 if (ap->th_block == (block-1)) {
215 goto send_data;
218 else if (ap->th_opcode == OACK) {
219 if (block) {
220 printf("protocol violation\n");
221 longjmp(toplevel, -1);
223 parseoack(&ap->th_stuff, n - 2);
224 break;
227 if (block > 0)
228 amount += size;
229 else
230 read_ahead(file, convert);
231 block++;
232 } while (size == segsize || block == 1);
233 abort:
234 fclose(file);
235 stopclock();
236 if (amount > 0)
237 printstats("Sent", amount);
241 * Receive a file.
243 recvfile(fd, name, mode)
244 int fd;
245 char *name;
246 char *mode;
248 register struct tftphdr *ap;
249 struct tftphdr *dp, *w_init();
250 register int n, size;
251 u_short block = 1;
252 unsigned long amount = 0;
253 struct sockaddr_in from;
254 int fromlen, firsttrip = 1;
255 FILE *file;
256 int convert; /* true if converting crlf -> lf */
257 int waitforoack = 1;
259 startclock();
260 dp = w_init();
261 ap = (struct tftphdr *)ackbuf;
262 file = fdopen(fd, "w");
263 convert = !strcmp(mode, "netascii");
265 signal(SIGALRM, timer);
266 do {
267 if (firsttrip) {
268 size = makerequest(RRQ, name, ap, mode);
269 firsttrip = 0;
270 } else {
271 ap->th_opcode = htons((u_short)ACK);
272 ap->th_block = htons(block);
273 size = 4;
274 block++;
276 timeout = 0;
277 (void) setjmp(timeoutbuf);
278 send_ack:
279 if (trace)
280 tpacket("sent", ap, size);
281 if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&sin,
282 sizeof (sin)) != size) {
283 alarm(0);
284 perror("tftp: sendto");
285 goto abort;
287 if (!waitforoack)
288 write_behind(file, convert);
289 for ( ; ; ) {
290 alarm(rexmtval);
291 do {
292 fromlen = sizeof (from);
293 n = recvfrom(f, dp, PKTSIZE, 0,
294 (struct sockaddr *)&from, &fromlen);
295 } while (n <= 0);
296 alarm(0);
297 if (n < 0) {
298 perror("tftp: recvfrom");
299 goto abort;
301 sin.sin_port = from.sin_port; /* added */
302 if (trace)
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,
308 dp->th_msg);
309 goto abort;
311 if (dp->th_opcode == DATA) {
312 int j;
314 if (waitforoack) {
315 if (trace)
316 printf("server does not know "
317 "about RFC1782; reset"
318 "ting blocksize\n");
319 waitforoack = 0;
320 segsize = 512;
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
327 * both sides.
329 j = synchnet(f);
330 if (j && trace) {
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);
342 waitforoack = 0;
343 parseoack(&dp->th_stuff, n - 2);
344 ap->th_opcode = htons((u_short)ACK);
345 ap->th_block = htons(0);
346 size = 4;
347 goto send_ack;
350 /* size = write(fd, dp->th_data, n - 4); */
351 size = writeit(file, &dp, n - 4, convert);
352 if (size < 0) {
353 nak(errno + 100);
354 break;
356 amount += size;
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 */
363 fclose(file);
364 stopclock();
365 if (amount > 0)
366 printstats("Received", amount);
369 makerequest(request, name, tp, mode)
370 int request;
371 char *name, *mode;
372 struct tftphdr *tp;
374 register char *cp;
376 tp->th_opcode = htons((u_short)request);
377 cp = tp->th_stuff;
378 strcpy(cp, name);
379 cp += strlen(name);
380 *cp++ = '\0';
381 strcpy(cp, mode);
382 cp += strlen(mode);
383 *cp++ = '\0';
384 strcpy(cp, "blksize");
385 cp += 7;
386 *cp++ = '\0';
387 sprintf(cp, "%d", segsize);
388 cp += strlen(cp) + 1;
389 return (cp - (char *)tp);
392 struct errmsg {
393 int e_code;
394 const char *e_msg;
395 } errmsgs[] = {
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" },
404 { -1, 0 }
408 * Send a nak packet (error message).
409 * Error code passed in is one of the
410 * standard TFTP codes, or a UNIX errno
411 * offset by 100.
413 nak(error)
414 int error;
416 register struct tftphdr *tp;
417 int length;
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)
426 break;
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;
433 if (trace)
434 tpacket("sent", tp, length);
435 if (sendto(f, ackbuf, length, 0, (struct sockaddr *)&sin, sizeof (sin))
436 != length)
437 perror("nak");
440 topts(cp, sz)
441 char *cp;
442 int sz;
444 int n, i = 0;
446 while (sz > 0 && *cp) {
447 n = strnlen(cp, sz);
448 if (n > 0) {
449 printf("%s%s=", i++ ? ", " : "", cp);
450 cp += n + 1;
451 sz -= n + 1;
452 if (sz <= 0)
453 break;
454 n = strnlen(cp, sz);
455 if (n > 0)
456 printf("%s", cp);
458 cp += n + 1;
459 sz -= n + 1;
463 tpacket(s, tp, n)
464 char *s;
465 struct tftphdr *tp;
466 int n;
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);
472 char *index();
474 if (op < RRQ || op > OACK)
475 printf("%s opcode=%x ", s, op);
476 else
477 printf("%s %s ", s, opcodes[op]);
478 switch (op) {
480 case RRQ:
481 case WRQ:
482 n -= 2;
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);
488 printf(">\n");
489 break;
491 case DATA:
492 printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);
493 break;
495 case ACK:
496 printf("<block=%d>\n", ntohs(tp->th_block));
497 break;
499 case ERROR:
500 printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);
501 break;
502 case OACK:
503 printf("<");
504 topts(tp->th_stuff, n - 2);
505 printf(">\n");
506 break;
510 struct timeval tstart;
511 struct timeval tstop;
512 struct timezone zone;
514 startclock() {
515 gettimeofday(&tstart, &zone);
518 stopclock() {
519 gettimeofday(&tstop, &zone);
522 printstats(direction, amount)
523 char *direction;
524 unsigned long amount;
526 double delta;
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);
534 putchar('\n');