FreeBSD/libexec/tftpd/tftp-transfer.c
/*
 * 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.
 */
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.
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) {
				*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;
				}
				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);
				(void) synchnet(peer);
				if (rp->th_block == (*block-1)) {
					tftp_log(LOG_INFO, "Trying to sync");
					*block = oldblock;
					ts->retries++;
					goto send_ack;	
				}
			} 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);
	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 &&	
		    *block == rp->th_block)	
			send_ack(peer, *block);	
	}
abort:
	return;
}
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 , " " " " , * block ) ; return ; } tftp_log ( LOG_ERR , " " , * 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 ) { * block = 0 ; } else { * block = atoi ( options [ OPT_ROLLOVER ] . o_request ) ; } ts -> rollovers ++ ; } for ( retry = 0 ; ; retry ++ ) { if ( debug & DEBUG_SIMPLE ) tftp_log ( LOG_DEBUG , " " , * block ) ; n_data = receive_packet ( peer , recvbuffer , MAXPKTSIZE , NULL , timeoutpacket ) ; if ( n_data < 0 ) { if ( retry == maxtimeouts ) { tftp_log ( LOG_ERR , " " " " , retry , * block ) ; return ; } if ( n_data == RP_TIMEOUT ) { tftp_log ( LOG_WARNING , " " , retry , * block ) ; send_ack ( peer , oldblock ) ; continue ; } if ( debug & DEBUG_SIMPLE ) tftp_log ( LOG_DEBUG , " " , rp_strerror ( n_data ) ) ; goto abort ; } if ( rp -> th_opcode == DATA ) { ts -> blocks ++ ; if ( rp -> th_block == * block ) break ; tftp_log ( LOG_WARNING , " " , * block , rp -> th_block ) ; ( void ) synchnet ( peer ) ; if ( rp -> th_block == ( * block - 1 ) ) { tftp_log ( LOG_INFO , " " ) ; * block = oldblock ; ts -> retries ++ ; goto send_ack ; } } else { tftp_log ( LOG_WARNING , " " , 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 , " " , 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 , " " " " , * block ) ; return ; } tftp_log ( LOG_ERR , " " , * block ) ; continue ; } break ; } gettimeofday ( & ( ts -> tstop ) , NULL ) ; } while ( n_data == segsize ) ; 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 && * block == rp -> th_block ) send_ack ( peer , * block ) ; } abort : return ; }
Receive a file via the TFTP data session.
Receive a file via the TFTP data session .
/*
				 * "rollover" option not specified in
				 * tftp client.  Default to rolling block
				 * counter to 0.
				 */ /* Either read failure or ERROR packet */ /* Re-synchronize with the other side */ /* rexmit */ /* Don't do late packet management for the client implementation */ /* and got a data block */ /* then my last ack was lost */ /* resend final ack */