/* * Receive a file. */ static void recvtftp(struct testcase *test, struct formats *pf) { ssize_t n, size; recvblock = 0; #if defined(HAVE_ALARM) && defined(SIGALRM) mysignal(SIGALRM, timer); #endif rdp = w_init(); rap = (struct tftphdr *)ackbuf; do { timeout = 0; rap->th_opcode = htons((u_short)opcode_ACK); rap->th_block = htons((u_short)recvblock); recvblock++; #ifdef HAVE_SIGSETJMP (void) sigsetjmp(timeoutbuf, 1); #endif send_ack: if (swrite(peer, ackbuf, 4) != 4) { logmsg("write: fail\n"); goto abort; } write_behind(test, pf->f_convert); for ( ; ; ) { #ifdef HAVE_ALARM alarm(rexmtval); #endif n = sread(peer, rdp, PKTSIZE); #ifdef HAVE_ALARM alarm(0); #endif if (n < 0) { /* really? */ logmsg("read: fail\n"); goto abort; } rdp->th_opcode = ntohs((u_short)rdp->th_opcode); rdp->th_block = ntohs((u_short)rdp->th_block); if (rdp->th_opcode == opcode_ERROR) goto abort; if (rdp->th_opcode == opcode_DATA) { if (rdp->th_block == recvblock) { break; /* normal */ } /* Re-synchronize with the other side */ (void) synchnet(peer); if (rdp->th_block == (recvblock-1)) goto send_ack; /* rexmit */ } } size = writeit(test, &rdp, (int)(n - 4), pf->f_convert); if (size != (n-4)) { /* ahem */ if (size < 0) nak(ERRNO + 100); else nak(ENOSPACE); goto abort; } } while (size == SEGSIZE); write_behind(test, pf->f_convert); rap->th_opcode = htons((u_short)opcode_ACK); /* send the "final" ack */ rap->th_block = htons((u_short)recvblock); (void) swrite(peer, ackbuf, 4); #if defined(HAVE_ALARM) && defined(SIGALRM) mysignal(SIGALRM, justtimeout); /* just abort read on timeout */ alarm(rexmtval); #endif n = sread(peer, buf, sizeof(buf)); /* normally times out and quits */ #ifdef HAVE_ALARM alarm(0); #endif if (n >= 4 && /* if read some data */ rdp->th_opcode == opcode_DATA && /* and got a data block */ recvblock == rdp->th_block) { /* then my last ack was lost */ (void) swrite(peer, ackbuf, 4); /* resend final ack */ } abort: return; }
/* * Receive a file. */ static void recvtftp(struct testcase *test, struct formats *pf) { struct tftphdr *dp; struct tftphdr *ap; /* ack buffer */ unsigned short block = 0; int n, size; #if defined(HAVE_ALARM) && defined(SIGALRM) mysignal(SIGALRM, timer); #endif dp = w_init(); ap = (struct tftphdr *)ackbuf; do { timeout = 0; ap->th_opcode = htons((u_short)ACK); ap->th_block = htons((u_short)block); block++; #ifdef HAVE_SIGSETJMP (void) sigsetjmp(timeoutbuf, 1); #endif send_ack: if (send(peer, ackbuf, 4, 0) != 4) { logmsg("write: fail\n"); goto abort; } write_behind(test, pf->f_convert); for ( ; ; ) { #ifdef HAVE_ALARM alarm(rexmtval); #endif n = recv(peer, dp, PKTSIZE, 0); #ifdef HAVE_ALARM alarm(0); #endif if (n < 0) { /* really? */ logmsg("read: fail\n"); goto abort; } dp->th_opcode = ntohs((u_short)dp->th_opcode); dp->th_block = ntohs((u_short)dp->th_block); if (dp->th_opcode == ERROR) goto abort; if (dp->th_opcode == DATA) { if (dp->th_block == block) { break; /* normal */ } /* Re-synchronize with the other side */ (void) synchnet(peer); if (dp->th_block == (block-1)) goto send_ack; /* rexmit */ } } size = writeit(test, &dp, n - 4, pf->f_convert); if (size != (n-4)) { /* ahem */ if (size < 0) nak(errno + 100); else nak(ENOSPACE); goto abort; } } while (size == SEGSIZE); write_behind(test, pf->f_convert); ap->th_opcode = htons((u_short)ACK); /* send the "final" ack */ ap->th_block = htons((u_short)(block)); (void) send(peer, ackbuf, 4, 0); #if defined(HAVE_ALARM) && defined(SIGALRM) mysignal(SIGALRM, justquit); /* just quit on timeout */ alarm(rexmtval); #endif n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */ #ifdef HAVE_ALARM alarm(0); #endif if (n >= 4 && /* if read some data */ dp->th_opcode == DATA && /* and got a data block */ block == dp->th_block) { /* then my last ack was lost */ (void) send(peer, ackbuf, 4, 0); /* resend final ack */ } abort: return; }
/* * Send the requested file. */ static void sendtftp(struct testcase *test, struct formats *pf) { int size; ssize_t n; sendblock = 1; #if defined(HAVE_ALARM) && defined(SIGALRM) mysignal(SIGALRM, timer); #endif sdp = r_init(); sap = (struct tftphdr *)ackbuf; do { size = readit(test, &sdp, pf->f_convert); if (size < 0) { nak(ERRNO + 100); return; } sdp->th_opcode = htons((u_short)opcode_DATA); sdp->th_block = htons((u_short)sendblock); timeout = 0; #ifdef HAVE_SIGSETJMP (void) sigsetjmp(timeoutbuf, 1); #endif send_data: if (swrite(peer, sdp, size + 4) != size + 4) { logmsg("write"); return; } read_ahead(test, pf->f_convert); for ( ; ; ) { #ifdef HAVE_ALARM alarm(rexmtval); /* read the ack */ #endif n = sread(peer, ackbuf, sizeof (ackbuf)); #ifdef HAVE_ALARM alarm(0); #endif if (n < 0) { logmsg("read: fail"); return; } sap->th_opcode = ntohs((u_short)sap->th_opcode); sap->th_block = ntohs((u_short)sap->th_block); if (sap->th_opcode == opcode_ERROR) { logmsg("got ERROR"); return; } if (sap->th_opcode == opcode_ACK) { if (sap->th_block == sendblock) { break; } /* Re-synchronize with the other side */ (void) synchnet(peer); if (sap->th_block == (sendblock-1)) { goto send_data; } } } sendblock++; } while (size == SEGSIZE); }
/* * Send the requested file. */ static void sendtftp(struct testcase *test, struct formats *pf) { int size; ssize_t n; /* These are volatile to live through a siglongjmp */ volatile unsigned short sendblock; /* block count */ struct tftphdr * volatile sdp = r_init(); /* data buffer */ struct tftphdr * const sap = &ackbuf.hdr; /* ack buffer */ sendblock = 1; #if defined(HAVE_ALARM) && defined(SIGALRM) mysignal(SIGALRM, timer); #endif do { size = readit(test, (struct tftphdr **)&sdp, pf->f_convert); if(size < 0) { nak(errno + 100); return; } sdp->th_opcode = htons((unsigned short)opcode_DATA); sdp->th_block = htons(sendblock); timeout = 0; #ifdef HAVE_SIGSETJMP (void) sigsetjmp(timeoutbuf, 1); #endif if(test->writedelay) { logmsg("Pausing %d seconds before %d bytes", test->writedelay, size); wait_ms(1000*test->writedelay); } send_data: if(swrite(peer, sdp, size + 4) != size + 4) { logmsg("write"); return; } read_ahead(test, pf->f_convert); for(;;) { #ifdef HAVE_ALARM alarm(rexmtval); /* read the ack */ #endif n = sread(peer, &ackbuf.storage[0], sizeof(ackbuf.storage)); #ifdef HAVE_ALARM alarm(0); #endif if(got_exit_signal) return; if(n < 0) { logmsg("read: fail"); return; } sap->th_opcode = ntohs((unsigned short)sap->th_opcode); sap->th_block = ntohs(sap->th_block); if(sap->th_opcode == opcode_ERROR) { logmsg("got ERROR"); return; } if(sap->th_opcode == opcode_ACK) { if(sap->th_block == sendblock) { break; } /* Re-synchronize with the other side */ (void) synchnet(peer); if(sap->th_block == (sendblock-1)) { goto send_data; } } } sendblock++; } while(size == SEGSIZE); }
/* * Send the requested file. */ static void sendtftp(struct testcase *test, struct formats *pf) { struct tftphdr *dp; struct tftphdr *ap; /* ack packet */ unsigned short block = 1; int size, n; #if defined(HAVE_ALARM) && defined(SIGALRM) mysignal(SIGALRM, timer); #endif dp = r_init(); ap = (struct tftphdr *)ackbuf; do { size = readit(test, &dp, pf->f_convert); if (size < 0) { nak(errno + 100); return; } dp->th_opcode = htons((u_short)DATA); dp->th_block = htons((u_short)block); timeout = 0; #ifdef HAVE_SIGSETJMP (void) sigsetjmp(timeoutbuf, 1); #endif send_data: if (send(peer, dp, size + 4, 0) != size + 4) { logmsg("write\n"); return; } read_ahead(test, pf->f_convert); for ( ; ; ) { #ifdef HAVE_ALARM alarm(rexmtval); /* read the ack */ #endif n = recv(peer, ackbuf, sizeof (ackbuf), 0); #ifdef HAVE_ALARM alarm(0); #endif if (n < 0) { logmsg("read: fail\n"); return; } ap->th_opcode = ntohs((u_short)ap->th_opcode); ap->th_block = ntohs((u_short)ap->th_block); if (ap->th_opcode == ERROR) { logmsg("got ERROR"); return; } if (ap->th_opcode == ACK) { if (ap->th_block == block) { break; } /* Re-synchronize with the other side */ (void) synchnet(peer); if (ap->th_block == (block -1)) { goto send_data; } } } block++; } while (size == SEGSIZE); }
/* * Send the requested file. */ int tftp_sendfile(int f, union sock_addr *peeraddr, int fd, const char *name, const char *mode) { struct tftphdr *ap; /* data and ack packets */ struct tftphdr *dp; int n; volatile int is_request; volatile u_short block; volatile int size, convert; volatile off_t amount; union sock_addr from; socklen_t fromlen; FILE *file; u_short ap_opcode, ap_block; startclock(); /* start stat's clock */ dp = r_init(); /* reset fillbuf/read-ahead code */ ap = (struct tftphdr *)ackbuf; convert = !strcmp(mode, "netascii"); file = fdopen(fd, convert ? "rt" : "rb"); block = 0; is_request = 1; /* First packet is the actual WRQ */ amount = 0; bsd_signal(SIGALRM, timer); do { if (is_request) { size = makerequest(WRQ, name, dp, mode) - 4; } else { /* size = read(fd, dp->th_data, SEGSIZE); */ size = readit(file, &dp, convert); if (size < 0) { nak(f, peeraddr, errno + 100, NULL); break; } dp->th_opcode = htons((u_short) DATA); dp->th_block = htons((u_short) block); } timeout = 0; (void)sigsetjmp(timeoutbuf, 1); if (trace) tpacket("sent", dp, size + 4); n = sendto(f, dp, size + 4, 0, &(peeraddr->sa), SOCKLEN(peeraddr)); if (n != size + 4) { perror("tftp: sendto"); goto abort; } read_ahead(file, convert); for (;;) { alarm(rexmtval); do { fromlen = sizeof(from); n = recvfrom(f, ackbuf, sizeof(ackbuf), 0, &from.sa, &fromlen); } while (n <= 0); alarm(0); if (n < 0) { perror("tftp: recvfrom"); goto abort; } sa_set_port(peeraddr, SOCKPORT(&from)); /* added */ if (trace) tpacket("received", ap, n); /* should verify packet came from server */ ap_opcode = ntohs((u_short) ap->th_opcode); ap_block = ntohs((u_short) ap->th_block); if (ap_opcode == ERROR) { printf("Error code %d: %s\n", ap_block, ap->th_msg); goto abort; } if (ap_opcode == ACK) { int j; if (ap_block == block) { break; } /* On an error, try to synchronize * both sides. */ j = synchnet(f); if (j && trace) { printf("discarded %d packets\n", j); } /* * RFC1129/RFC1350: We MUST NOT re-send the DATA * packet in response to an invalid ACK. Doing so * would cause the Sorcerer's Apprentice bug. */ } } if (!is_request) amount += size; is_request = 0; block++; } while (size == SEGSIZE || block == 1); abort: fclose(file); stopclock(); //if (amount > 0) // printstats("Sent", amount); return amount; }
/* * Send a file via the TFTP data session. */ void tftp_send(int peer, uint16_t *block, struct tftp_stats *ts) { struct tftphdr *rp; int size, n_data, n_ack, try; uint16_t oldblock; char sendbuffer[MAXPKTSIZE]; char recvbuffer[MAXPKTSIZE]; rp = (struct tftphdr *)recvbuffer; *block = 1; ts->amount = 0; do { if (debug&DEBUG_SIMPLE) tftp_log(LOG_DEBUG, "Sending block %d", *block); size = read_file(sendbuffer, segsize); if (size < 0) { tftp_log(LOG_ERR, "read_file returned %d", size); send_error(peer, errno + 100); goto abort; } for (try = 0; ; try++) { n_data = send_data(peer, *block, sendbuffer, size); if (n_data > 0) { if (try == maxtimeouts) { tftp_log(LOG_ERR, "Cannot send DATA packet #%d, " "giving up", *block); return; } tftp_log(LOG_ERR, "Cannot send DATA packet #%d, trying again", *block); continue; } n_ack = receive_packet(peer, recvbuffer, MAXPKTSIZE, NULL, timeoutpacket); if (n_ack < 0) { if (n_ack == RP_TIMEOUT) { if (try == maxtimeouts) { tftp_log(LOG_ERR, "Timeout #%d send ACK %d " "giving up", try, *block); return; } tftp_log(LOG_WARNING, "Timeout #%d on ACK %d", try, *block); continue; } /* Either read failure or ERROR packet */ if (debug&DEBUG_SIMPLE) tftp_log(LOG_ERR, "Aborting: %s", rp_strerror(n_ack)); goto abort; } if (rp->th_opcode == ACK) { ts->blocks++; if (rp->th_block == *block) { ts->amount += size; break; } /* Re-synchronize with the other side */ (void) synchnet(peer); if (rp->th_block == (*block - 1)) { ts->retries++; continue; } } } oldblock = *block; (*block)++; if (oldblock > *block) { if (options[OPT_ROLLOVER].o_request == NULL) { /* * "rollover" option not specified in * tftp client. Default to rolling block * counter to 0. */ *block = 0; } else { *block = atoi(options[OPT_ROLLOVER].o_request); } ts->rollovers++; } gettimeofday(&(ts->tstop), NULL); } while (size == segsize); abort: return; } /* * Receive a file via the TFTP data session. * * - It could be that the first block has already arrived while * trying to figure out if we were receiving options or not. In * that case it is passed to this function. */ void tftp_receive(int peer, uint16_t *block, struct tftp_stats *ts, struct tftphdr *firstblock, size_t fb_size) { struct tftphdr *rp; uint16_t oldblock; int n_data, n_ack, writesize, i, retry; char recvbuffer[MAXPKTSIZE]; ts->amount = 0; if (firstblock != NULL) { writesize = write_file(firstblock->th_data, fb_size); ts->amount += writesize; for (i = 0; ; i++) { n_ack = send_ack(peer, *block); if (n_ack > 0) { if (i == maxtimeouts) { tftp_log(LOG_ERR, "Cannot send ACK packet #%d, " "giving up", *block); return; } tftp_log(LOG_ERR, "Cannot send ACK packet #%d, trying again", *block); continue; } break; } if (fb_size != segsize) { gettimeofday(&(ts->tstop), NULL); return; } } rp = (struct tftphdr *)recvbuffer; do { oldblock = *block; (*block)++; if (oldblock > *block) { if (options[OPT_ROLLOVER].o_request == NULL) { /* * "rollover" option not specified in * tftp client. Default to rolling block * counter to 0. */ *block = 0; } else { *block = atoi(options[OPT_ROLLOVER].o_request); } ts->rollovers++; } for (retry = 0; ; retry++) { if (debug&DEBUG_SIMPLE) tftp_log(LOG_DEBUG, "Receiving DATA block %d", *block); n_data = receive_packet(peer, recvbuffer, MAXPKTSIZE, NULL, timeoutpacket); if (n_data < 0) { if (retry == maxtimeouts) { tftp_log(LOG_ERR, "Timeout #%d on DATA block %d, " "giving up", retry, *block); return; } if (n_data == RP_TIMEOUT) { tftp_log(LOG_WARNING, "Timeout #%d on DATA block %d", retry, *block); send_ack(peer, oldblock); continue; } /* Either read failure or ERROR packet */ if (debug&DEBUG_SIMPLE) tftp_log(LOG_DEBUG, "Aborting: %s", rp_strerror(n_data)); goto abort; } if (rp->th_opcode == DATA) { ts->blocks++; if (rp->th_block == *block) break; tftp_log(LOG_WARNING, "Expected DATA block %d, got block %d", *block, rp->th_block); /* Re-synchronize with the other side */ (void) synchnet(peer); if (rp->th_block == (*block-1)) { tftp_log(LOG_INFO, "Trying to sync"); *block = oldblock; ts->retries++; goto send_ack; /* rexmit */ } } else { tftp_log(LOG_WARNING, "Expected DATA block, got %s block", packettype(rp->th_opcode)); } } if (n_data > 0) { writesize = write_file(rp->th_data, n_data); ts->amount += writesize; if (writesize <= 0) { tftp_log(LOG_ERR, "write_file returned %d", writesize); if (writesize < 0) send_error(peer, errno + 100); else send_error(peer, ENOSPACE); goto abort; } } send_ack: for (i = 0; ; i++) { n_ack = send_ack(peer, *block); if (n_ack > 0) { if (i == maxtimeouts) { tftp_log(LOG_ERR, "Cannot send ACK packet #%d, " "giving up", *block); return; } tftp_log(LOG_ERR, "Cannot send ACK packet #%d, trying again", *block); continue; } break; } gettimeofday(&(ts->tstop), NULL); } while (n_data == segsize); /* Don't do late packet management for the client implementation */ if (acting_as_client) return; for (i = 0; ; i++) { n_data = receive_packet(peer, (char *)rp, pktsize, NULL, timeoutpacket); if (n_data <= 0) break; if (n_data > 0 && rp->th_opcode == DATA && /* and got a data block */ *block == rp->th_block) /* then my last ack was lost */ send_ack(peer, *block); /* resend final ack */ } abort: return; }
/* * Receive a file. */ int tftp_recvfile(int f, union sock_addr *peeraddr, int fd, const char *name, const char *mode) { struct tftphdr *ap; struct tftphdr *dp; int n; volatile u_short block; volatile int size, firsttrip; volatile unsigned long amount; union sock_addr from; socklen_t fromlen; FILE *file; volatile int convert; /* true if converting crlf -> lf */ u_short dp_opcode, dp_block; startclock(); dp = w_init(); ap = (struct tftphdr *)ackbuf; convert = !strcmp(mode, "netascii"); file = fdopen(fd, convert ? "wt" : "wb"); block = 1; firsttrip = 1; amount = 0; bsd_signal(SIGALRM, timer); do { if (firsttrip) { size = makerequest(RRQ, name, ap, mode); firsttrip = 0; } else { ap->th_opcode = htons((u_short) ACK); ap->th_block = htons((u_short) block); size = 4; block++; } timeout = 0; (void)sigsetjmp(timeoutbuf, 1); send_ack: if (trace) tpacket("sent", ap, size); if (sendto(f, ackbuf, size, 0, &(peeraddr->sa), SOCKLEN(peeraddr)) != size) { alarm(0); perror("tftp: sendto"); goto abort; } write_behind(file, convert); for (;;) { alarm(rexmtval); do { fromlen = sizeof(from); n = recvfrom(f, dp, PKTSIZE, 0, &from.sa, &fromlen); } while (n <= 0); alarm(0); if (n < 0) { perror("tftp: recvfrom"); goto abort; } sa_set_port(peeraddr, SOCKPORT(&from)); /* added */ if (trace) tpacket("received", dp, n); /* should verify client address */ dp_opcode = ntohs((u_short) dp->th_opcode); dp_block = ntohs((u_short) dp->th_block); if (dp_opcode == ERROR) { printf("Error code %d: %s\n", dp_block, dp->th_msg); goto abort; } if (dp_opcode == DATA) { int j; if (dp_block == block) { break; /* have next packet */ } /* On an error, try to synchronize * both sides. */ j = synchnet(f); if (j && trace) { printf("discarded %d packets\n", j); } if (dp_block == (block - 1)) { goto send_ack; /* resend ack */ } } } /* size = write(fd, dp->th_data, n - 4); */ size = writeit(file, &dp, n - 4, convert); if (size < 0) { nak(f, peeraddr, errno + 100, NULL); break; } amount += size; } while (size == SEGSIZE); abort: /* ok to ack, since user */ ap->th_opcode = htons((u_short) ACK); /* has seen err msg */ ap->th_block = htons((u_short) block); (void)sendto(f, ackbuf, 4, 0, (struct sockaddr *)peeraddr, SOCKLEN(peeraddr)); write_behind(file, convert); /* flush last buffer */ fclose(file); stopclock(); //if (amount > 0) // printstats("Received", amount); return amount; }
/* * Send the requested file. */ void sendfile(int fd, char *name, char *mode) { register struct tftphdr *ap; /* data and ack packets */ struct tftphdr *dp; volatile int block = 0, size = 0; int n; volatile unsigned long amount = 0; struct sockaddr_in from; socklen_t fromlen; volatile int convert; /* true if doing nl->crlf conversion */ FILE *file; startclock(); /* start stat's clock */ dp = r_init(); /* reset fillbuf/read-ahead code */ ap = (struct tftphdr *)ackbuf; file = fdopen(fd, "r"); convert = !strcmp(mode, "netascii"); signal(SIGALRM, timer); do { if (block == 0) size = makerequest(WRQ, name, dp, mode) - 4; else { /* size = read(fd, dp->th_data, SEGSIZE); */ size = readit(file, &dp, convert); if (size < 0) { nak(errno + 100); break; } dp->th_opcode = htons((u_short)DATA); dp->th_block = htons((u_short)block); } timeout = 0; (void) sigsetjmp(timeoutbuf, 1); send_data: if (trace) tpacket("sent", dp, size + 4); n = sendto(f, dp, size + 4, 0, (struct sockaddr *)&s_inn, sizeof(s_inn)); if (n != size + 4) { perror("tftp: sendto"); goto abort; } read_ahead(file, convert); for ( ; ; ) { alarm(rexmtval); do { fromlen = sizeof (from); n = recvfrom(f, ackbuf, sizeof (ackbuf), 0, (struct sockaddr *)&from, &fromlen); } while (n <= 0); alarm(0); if (n < 0) { perror("tftp: recvfrom"); goto abort; } s_inn.sin_port = from.sin_port; /* added */ if (trace) tpacket("received", ap, n); /* should verify packet came from server */ ap->th_opcode = ntohs(ap->th_opcode); ap->th_block = ntohs(ap->th_block); if (ap->th_opcode == ERROR) { printf("Error code %d: %s\n", ap->th_code, ap->th_msg); goto abort; } if (ap->th_opcode == ACK) { volatile int j = 0; if (ap->th_block == block) { break; } /* On an error, try to synchronize * both sides. */ j = synchnet(f); if (j && trace) { printf("discarded %d packets\n", j); } if (ap->th_block == (block-1)) { goto send_data; } } } if (block > 0) amount += size; block++; } while (size == SEGSIZE || block == 1); abort: fclose(file); stopclock(); if (amount > 0) printstats("Sent", amount); }
/* * Receive a file. */ void recvfile(struct formats *pf) { struct tftphdr *dp; struct tftphdr *ap; /* ack buffer */ int n, size; volatile unsigned short block; signal(SIGALRM, timer); dp = w_init(); ap = (struct tftphdr *)ackbuf; block = 0; do { timeouts = 0; ap->th_opcode = htons((u_short)ACK); ap->th_block = htons((u_short)block); block++; (void) setjmp(timeoutbuf); send_ack: if (send(peer, ackbuf, 4, 0) != 4) { syslog(LOG_ERR, "write: %m"); goto abort; } write_behind(file, pf->f_convert); for ( ; ; ) { alarm(rexmtval); n = recv(peer, dp, PKTSIZE, 0); alarm(0); if (n < 0) { /* really? */ syslog(LOG_ERR, "read: %m"); goto abort; } dp->th_opcode = ntohs((u_short)dp->th_opcode); dp->th_block = ntohs((u_short)dp->th_block); if (dp->th_opcode == ERROR) goto abort; if (dp->th_opcode == DATA) { if (dp->th_block == block) { break; /* normal */ } /* Re-synchronize with the other side */ (void) synchnet(peer); if (dp->th_block == (block-1)) goto send_ack; /* rexmit */ } } /* size = write(file, dp->th_data, n - 4); */ size = writeit(file, &dp, n - 4, pf->f_convert); if (size != (n-4)) { /* ahem */ if (size < 0) nak(errno + 100); else nak(ENOSPACE); goto abort; } } while (size == SEGSIZE); write_behind(file, pf->f_convert); (void) fclose(file); /* close data file */ ap->th_opcode = htons((u_short)ACK); /* send the "final" ack */ ap->th_block = htons((u_short)(block)); (void) send(peer, ackbuf, 4, 0); signal(SIGALRM, justquit); /* just quit on timeout */ alarm(rexmtval); n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */ alarm(0); if (n >= 4 && /* if read some data */ dp->th_opcode == DATA && /* and got a data block */ block == dp->th_block) { /* then my last ack was lost */ (void) send(peer, ackbuf, 4, 0); /* resend final ack */ } abort: return; }
/* * Send the requested file. */ void xmitfile(struct formats *pf) { struct tftphdr *dp; struct tftphdr *ap; /* ack packet */ int size, n; volatile unsigned short block; signal(SIGALRM, timer); dp = r_init(); ap = (struct tftphdr *)ackbuf; block = 1; do { size = readit(file, &dp, pf->f_convert); if (size < 0) { nak(errno + 100); goto abort; } dp->th_opcode = htons((u_short)DATA); dp->th_block = htons((u_short)block); timeouts = 0; (void)setjmp(timeoutbuf); send_data: { int i, t = 1; for (i = 0; ; i++){ if (send(peer, dp, size + 4, 0) != size + 4) { sleep(t); t = (t < 32) ? t<< 1 : t; if (i >= 12) { syslog(LOG_ERR, "write: %m"); goto abort; } } break; } } read_ahead(file, pf->f_convert); for ( ; ; ) { alarm(rexmtval); /* read the ack */ n = recv(peer, ackbuf, sizeof (ackbuf), 0); alarm(0); if (n < 0) { syslog(LOG_ERR, "read: %m"); goto abort; } ap->th_opcode = ntohs((u_short)ap->th_opcode); ap->th_block = ntohs((u_short)ap->th_block); if (ap->th_opcode == ERROR) goto abort; if (ap->th_opcode == ACK) { if (ap->th_block == block) break; /* Re-synchronize with the other side */ (void) synchnet(peer); if (ap->th_block == (block -1)) goto send_data; } } block++; } while (size == SEGSIZE); abort: (void) fclose(file); }
/* * Send the requested file. */ void send_file (struct formats *pf) { struct tftphdr *dp, *r_init (); register struct tftphdr *ap; /* ack packet */ register int size, n; volatile int block; signal (SIGALRM, timer); dp = r_init (); ap = (struct tftphdr *) ackbuf; block = 1; do { size = readit (file, &dp, pf->f_convert); if (size < 0) { nak (errno + 100); goto abort; } dp->th_opcode = htons ((u_short) DATA); dp->th_block = htons ((u_short) block); timeout = 0; setjmp (timeoutbuf); send_data: if (send (peer, (const char *) dp, size + 4, 0) != size + 4) { syslog (LOG_ERR, "tftpd: write: %m\n"); goto abort; } read_ahead (file, pf->f_convert); for (;;) { alarm (rexmtval); /* read the ack */ n = recv (peer, ackbuf, sizeof (ackbuf), 0); alarm (0); if (n < 0) { syslog (LOG_ERR, "tftpd: read: %m\n"); goto abort; } ap->th_opcode = ntohs ((u_short) ap->th_opcode); ap->th_block = ntohs ((u_short) ap->th_block); if (ap->th_opcode == ERROR) goto abort; if (ap->th_opcode == ACK) { if ((u_short) ap->th_block == (u_short) block) break; /* Re-synchronize with the other side */ synchnet (peer); if ((u_short) ap->th_block == (u_short) (block - 1)) goto send_data; } } block++; } while (size == SEGSIZE); abort: fclose (file); }