|
Lines 79-88
Link Here
|
| 79 |
#include "tftpsubs.h" |
79 |
#include "tftpsubs.h" |
| 80 |
|
80 |
|
| 81 |
#define TIMEOUT 5 |
81 |
#define TIMEOUT 5 |
|
|
82 |
#define MAX_TIMEOUTS 5 |
| 82 |
|
83 |
|
| 83 |
int peer; |
84 |
int peer; |
| 84 |
int rexmtval = TIMEOUT; |
85 |
int rexmtval = TIMEOUT; |
| 85 |
int maxtimeout = 5*TIMEOUT; |
86 |
int max_rexmtval = 2*TIMEOUT; |
| 86 |
|
87 |
|
| 87 |
#define PKTSIZE SEGSIZE+4 |
88 |
#define PKTSIZE SEGSIZE+4 |
| 88 |
char buf[PKTSIZE]; |
89 |
char buf[PKTSIZE]; |
|
Lines 110-115
Link Here
|
| 110 |
|
111 |
|
| 111 |
static char *errtomsg __P((int)); |
112 |
static char *errtomsg __P((int)); |
| 112 |
static void nak __P((int)); |
113 |
static void nak __P((int)); |
|
|
114 |
static void oack __P(()); |
| 113 |
|
115 |
|
| 114 |
int |
116 |
int |
| 115 |
main(argc, argv) |
117 |
main(argc, argv) |
|
Lines 311-316
Link Here
|
| 311 |
{ 0 } |
313 |
{ 0 } |
| 312 |
}; |
314 |
}; |
| 313 |
|
315 |
|
|
|
316 |
struct options { |
| 317 |
char *o_type; |
| 318 |
char *o_request; |
| 319 |
int o_reply; /* turn into union if need be */ |
| 320 |
} options[] = { |
| 321 |
{ "tsize" }, /* OPT_TSIZE */ |
| 322 |
{ "timeout" }, /* OPT_TIMEOUT */ |
| 323 |
{ NULL } |
| 324 |
}; |
| 325 |
|
| 326 |
enum opt_enum { |
| 327 |
OPT_TSIZE = 0, |
| 328 |
OPT_TIMEOUT, |
| 329 |
}; |
| 330 |
|
| 314 |
/* |
331 |
/* |
| 315 |
* Handle initial connection protocol. |
332 |
* Handle initial connection protocol. |
| 316 |
*/ |
333 |
*/ |
|
Lines 320-328
Link Here
|
| 320 |
int size; |
337 |
int size; |
| 321 |
{ |
338 |
{ |
| 322 |
register char *cp; |
339 |
register char *cp; |
| 323 |
int first = 1, ecode; |
340 |
int i, first = 1, has_options = 0, ecode; |
| 324 |
register struct formats *pf; |
341 |
register struct formats *pf; |
| 325 |
char *filename, *mode; |
342 |
char *filename, *mode, *option, *ccp; |
| 326 |
|
343 |
|
| 327 |
filename = cp = tp->th_stuff; |
344 |
filename = cp = tp->th_stuff; |
| 328 |
again: |
345 |
again: |
|
Lines 350-356
Link Here
|
| 350 |
nak(EBADOP); |
367 |
nak(EBADOP); |
| 351 |
exit(1); |
368 |
exit(1); |
| 352 |
} |
369 |
} |
|
|
370 |
while (++cp < buf + size) { |
| 371 |
for (i = 2, ccp = cp; i > 0; ccp++) { |
| 372 |
if (ccp >= buf + size) { |
| 373 |
nak(EBADOP); |
| 374 |
exit(1); |
| 375 |
} else if (*ccp == '\0') |
| 376 |
i--; |
| 377 |
} |
| 378 |
for (option = cp; *cp; cp++) |
| 379 |
if (isupper(*cp)) |
| 380 |
*cp = tolower(*cp); |
| 381 |
for (i = 0; options[i].o_type != NULL; i++) |
| 382 |
if (strcmp(option, options[i].o_type) == 0) { |
| 383 |
options[i].o_request = ++cp; |
| 384 |
has_options = 1; |
| 385 |
} |
| 386 |
cp = ccp-1; |
| 387 |
} |
| 388 |
|
| 389 |
if (options[OPT_TIMEOUT].o_request) { |
| 390 |
int to = atoi(options[OPT_TIMEOUT].o_request); |
| 391 |
if (to < 1 || to > 255) { |
| 392 |
nak(EBADOP); |
| 393 |
exit(1); |
| 394 |
} |
| 395 |
else if (to <= max_rexmtval) |
| 396 |
options[OPT_TIMEOUT].o_reply = rexmtval = to; |
| 397 |
else |
| 398 |
options[OPT_TIMEOUT].o_request = NULL; |
| 399 |
} |
| 400 |
|
| 353 |
ecode = (*pf->f_validate)(&filename, tp->th_opcode); |
401 |
ecode = (*pf->f_validate)(&filename, tp->th_opcode); |
|
|
402 |
if (has_options) |
| 403 |
oack(); |
| 354 |
if (logging) { |
404 |
if (logging) { |
| 355 |
char host[MAXHOSTNAMELEN]; |
405 |
char host[MAXHOSTNAMELEN]; |
| 356 |
|
406 |
|
|
Lines 468-473
Link Here
|
| 468 |
return (err); |
518 |
return (err); |
| 469 |
*filep = filename = pathname; |
519 |
*filep = filename = pathname; |
| 470 |
} |
520 |
} |
|
|
521 |
if (options[OPT_TSIZE].o_request) { |
| 522 |
if (mode == RRQ) |
| 523 |
options[OPT_TSIZE].o_reply = stbuf.st_size; |
| 524 |
else |
| 525 |
/* XXX Allows writes of all sizes. */ |
| 526 |
options[OPT_TSIZE].o_reply = |
| 527 |
atoi(options[OPT_TSIZE].o_request); |
| 528 |
} |
| 471 |
fd = open(filename, mode == RRQ ? O_RDONLY : O_WRONLY|O_TRUNC); |
529 |
fd = open(filename, mode == RRQ ? O_RDONLY : O_WRONLY|O_TRUNC); |
| 472 |
if (fd < 0) |
530 |
if (fd < 0) |
| 473 |
return (errno + 100); |
531 |
return (errno + 100); |
|
Lines 478-492
Link Here
|
| 478 |
return (0); |
536 |
return (0); |
| 479 |
} |
537 |
} |
| 480 |
|
538 |
|
| 481 |
int timeout; |
539 |
int timeouts; |
| 482 |
jmp_buf timeoutbuf; |
540 |
jmp_buf timeoutbuf; |
| 483 |
|
541 |
|
| 484 |
void |
542 |
void |
| 485 |
timer() |
543 |
timer() |
| 486 |
{ |
544 |
{ |
| 487 |
|
545 |
if (++timeouts > MAX_TIMEOUTS) |
| 488 |
timeout += rexmtval; |
|
|
| 489 |
if (timeout >= maxtimeout) |
| 490 |
exit(1); |
546 |
exit(1); |
| 491 |
longjmp(timeoutbuf, 1); |
547 |
longjmp(timeoutbuf, 1); |
| 492 |
} |
548 |
} |
|
Lines 515-521
Link Here
|
| 515 |
} |
571 |
} |
| 516 |
dp->th_opcode = htons((u_short)DATA); |
572 |
dp->th_opcode = htons((u_short)DATA); |
| 517 |
dp->th_block = htons((u_short)block); |
573 |
dp->th_block = htons((u_short)block); |
| 518 |
timeout = 0; |
574 |
timeouts = 0; |
| 519 |
(void)setjmp(timeoutbuf); |
575 |
(void)setjmp(timeoutbuf); |
| 520 |
|
576 |
|
| 521 |
send_data: |
577 |
send_data: |
|
Lines 578-584
Link Here
|
| 578 |
ap = (struct tftphdr *)ackbuf; |
634 |
ap = (struct tftphdr *)ackbuf; |
| 579 |
block = 0; |
635 |
block = 0; |
| 580 |
do { |
636 |
do { |
| 581 |
timeout = 0; |
637 |
timeouts = 0; |
| 582 |
ap->th_opcode = htons((u_short)ACK); |
638 |
ap->th_opcode = htons((u_short)ACK); |
| 583 |
ap->th_block = htons((u_short)block); |
639 |
ap->th_block = htons((u_short)block); |
| 584 |
block++; |
640 |
block++; |
|
Lines 651-656
Link Here
|
| 651 |
{ EBADID, "Unknown transfer ID" }, |
707 |
{ EBADID, "Unknown transfer ID" }, |
| 652 |
{ EEXISTS, "File already exists" }, |
708 |
{ EEXISTS, "File already exists" }, |
| 653 |
{ ENOUSER, "No such user" }, |
709 |
{ ENOUSER, "No such user" }, |
|
|
710 |
{ EOPTNEG, "Option negotiation" }, |
| 654 |
{ -1, 0 } |
711 |
{ -1, 0 } |
| 655 |
}; |
712 |
}; |
| 656 |
|
713 |
|
|
Lines 699-702
Link Here
|
| 699 |
length += 5; |
756 |
length += 5; |
| 700 |
if (send(peer, buf, length, 0) != length) |
757 |
if (send(peer, buf, length, 0) != length) |
| 701 |
syslog(LOG_ERR, "nak: %m"); |
758 |
syslog(LOG_ERR, "nak: %m"); |
|
|
759 |
} |
| 760 |
|
| 761 |
/* |
| 762 |
* Send an oack packet (option acknowledgement). |
| 763 |
*/ |
| 764 |
static void |
| 765 |
oack() |
| 766 |
{ |
| 767 |
struct tftphdr *tp, *ap; |
| 768 |
int size, i, n; |
| 769 |
char *bp; |
| 770 |
|
| 771 |
tp = (struct tftphdr *)buf; |
| 772 |
bp = buf + 2; |
| 773 |
size = sizeof(buf) - 2; |
| 774 |
tp->th_opcode = htons((u_short)OACK); |
| 775 |
for (i = 0; options[i].o_type != NULL; i++) { |
| 776 |
if (options[i].o_request) { |
| 777 |
n = snprintf(bp, size, "%s%c%d", options[i].o_type, |
| 778 |
0, options[i].o_reply); |
| 779 |
bp += n+1; |
| 780 |
size -= n+1; |
| 781 |
if (size < 0) { |
| 782 |
syslog(LOG_ERR, "oack: buffer overflow"); |
| 783 |
exit(1); |
| 784 |
} |
| 785 |
} |
| 786 |
} |
| 787 |
size = bp - buf; |
| 788 |
ap = (struct tftphdr *)ackbuf; |
| 789 |
signal(SIGALRM, timer); |
| 790 |
timeouts = 0; |
| 791 |
|
| 792 |
(void)setjmp(timeoutbuf); |
| 793 |
if (send(peer, buf, size, 0) != size) { |
| 794 |
syslog(LOG_INFO, "oack: %m"); |
| 795 |
exit(1); |
| 796 |
} |
| 797 |
|
| 798 |
for (;;) { |
| 799 |
alarm(rexmtval); |
| 800 |
n = recv(peer, ackbuf, sizeof (ackbuf), 0); |
| 801 |
alarm(0); |
| 802 |
if (n < 0) { |
| 803 |
syslog(LOG_ERR, "recv: %m"); |
| 804 |
exit(1); |
| 805 |
} |
| 806 |
ap->th_opcode = ntohs((u_short)ap->th_opcode); |
| 807 |
ap->th_block = ntohs((u_short)ap->th_block); |
| 808 |
if (ap->th_opcode == ERROR) |
| 809 |
exit(1); |
| 810 |
if (ap->th_opcode == ACK && ap->th_block == 0) |
| 811 |
break; |
| 812 |
} |
| 702 |
} |
813 |
} |