* at offset 0. The limit of 32 chars is arbitrary.
*/
fprintf(stderr, "Error: %.32s\n", pkt);
- return -3;
+ return -2;
} else if (!opcode || opcode > ERR) {
fprintf(stderr, "Received invalid packet: ");
pkt_print(pkt, stderr);
fprintf(stderr, ".\n");
- return -2;
+ return -1;
}
if (verbosity > 2) {
struct sockaddr_in addr;
uint16_t block, port;
ssize_t len, last_len;
- int fd, sock, ret, timeout;
+ int fd, sock, ret, timeout, errors, ackblock;
char rx[TFTP_PKT_SIZE], tx[TFTP_PKT_SIZE];
sock = -1;
block = 0;
last_len = -1;
len = 0;
+ errors = 0;
/* Not really, but this way the loop sends our WRQ before receiving */
timeout = 1;
pkt_mkwrq(tx, args->filename);
do {
- if (timeout || (pkt_num(rx) == ACK && pkt_num(rx + 2) == block)) {
+ ackblock = pkt_num(rx) == ACK ? pkt_num(rx + 2) : -1;
+
+ if (timeout || ackblock == block) {
if (!timeout) {
++block;
pkt_mknum(tx, DATA);
ret = len;
goto cleanup;
} else if (!len) {
- if (last_len != 512) {
+ if (last_len != 512 && last_len != -1) {
break;
}
}
if (ret < 0) {
goto cleanup;
}
- } else if (pkt_num(rx) != ACK) {
- fprintf(stderr, "Expected ACK(%d), got ", block);
- pkt_print(rx, stderr);
- fprintf(stderr, "!\n");
+ } else if (pkt_num(rx) != ACK || ackblock > block) {
+ if (verbosity) {
+ fprintf(stderr, "Expected ACK(%d), got ", block);
+ pkt_print(rx, stderr);
+ fprintf(stderr, ".\n");
+ }
+
+ if (ackblock != -1 && ++errors > 5) {
+ fprintf(stderr, "Protocol error; bailing out.\n");
+ ret = -1;
+ goto cleanup;
+ }
}
ret = tftp_recvfrom(sock, rx, &port, args->rx_timeout);
} else if (!ret) {
if (++timeout < 5) {
continue;
+ } else if (block) {
+ fprintf(stderr, "Timeout while waiting for ACK(%d).\n", block);
+ } else {
+ fprintf(stderr, "Timeout while waiting for initial reply.\n");
}
- fprintf(stderr, "Timeout while waiting for ACK(%d).\n", block);
+ ret = -1;
goto cleanup;
} else {
timeout = 0;