📄 tftpc.c
字号:
*
* This function is responsible for receiving data from a TFTP
* server. NU_Select is used to timeout.
*
* INPUTS
*
* *tftp_con The pointer to TFTP Control Block
*
* OUTPUTS
*
* The number of bytes received when successful.
* NU_NO_DATA when NU_Select fails to find a data ready socket.
*
*************************************************************************/
INT32 TFTPC_Recv(TFTP_CB *tftp_con)
{
FD_SET readfs, writefs, exceptfs;
INT32 bytes_received;
INT16 status, clilen;
/* Do a select on this socket. In the case that the foreign port
* fails to respond we don't want to suspend on receive forever.
*/
NU_FD_Init(&readfs);
NU_FD_Set(tftp_con->socket_number, &readfs);
if((status = (INT16)(NU_Select(NSOCKETS, &readfs, &writefs, &exceptfs,
(tftp_con->options.timeout * SCK_Ticks_Per_Second)))) != NU_SUCCESS)
{
return(status);
}
/* We must have received something. Go get the server's response. */
bytes_received = (INT32)(NU_Recv_From(tftp_con->socket_number,
tftp_con->trans_buf,
(UINT16)(tftp_con->options.blksize + TFTP_HEADER_SIZE),
0, &tftp_con->server_addr, &clilen));
return(bytes_received);
} /* end TFTPC_Recv */
/*************************************************************************
*
* FUNCTION
*
* TFTPC_Process_Data
*
* DESCRIPTION
*
* This function is responsible for processing a data packet
* whenever a read request is in progress.
*
* INPUTS
*
* *tftp_con The pointer to TFTP Control Block.
* *bytes_received Number of bytes in the packet.
*
* OUTPUTS
*
* NU_SUCCESS whenever the expected data was received, -1 otherwise.
*
*************************************************************************/
STATUS TFTPC_Process_Data(TFTP_CB *tftp_con, INT32 bytes_received)
{
UINT16 data_size;
INT32 bytes = 0;
/* What kind of packet is this. */
switch(GET16(tftp_con->trans_buf, 0))
{
case TFTP_OACK_OPCODE:
/* Check that the returned options are valid */
TFTPC_Check_Options(tftp_con, bytes_received);
/* Acknowledge that we received the OACK */
TFTPC_Ack(tftp_con);
/* Increment the block number */
tftp_con->block_number++;
break;
case TFTP_DATA_OPCODE:
/* Received a DATA packet that has already be acknowledged,
* because our current block number is greater than the block
* number of the packet - we do not want to exit, error, or
* confirm this packet (because it has already been confirmed),
* but go get the next packet
*/
if((tftp_con->block_number > GET16(tftp_con->trans_buf, 2))
&& (tftp_con->tid == tftp_con->server_addr.port))
break;
/* If data was received make sure block number and TID are
* correct.
*/
else if((tftp_con->block_number == GET16(tftp_con->trans_buf, 2))
&& (tftp_con->tid == tftp_con->server_addr.port))
{
/* Calculate the amount of data in this packet. */
data_size = (UINT16)(bytes_received - TFTP_HEADER_SIZE);
if (data_size > 0)
{
/* Write the data to the file */
if ((bytes = (INT32)FAL_Fwrite(&(tftp_con->trans_buf[4]), data_size,
tftp_con->file_desc)) <=0 )
return (FAL_Get_Last_Error());
}
/* If blksize bytes of data were copied, send an ACK. We know
* the other side will send at least one more data packet
* and that all data in the current packet was accepted.
*/
if (bytes == tftp_con->options.blksize)
{
TFTPC_Ack(tftp_con);
}
/* Else if less data was copied than was received, we have
* filled the user's buffer and can accept no more data.
* Send an error condition indicating that no more data can
* be accepted.
*/
else if (bytes < (bytes_received - TFTP_HEADER_SIZE))
{
tftp_con->status = TRANSFER_COMPLETE;
TFTPC_Error(tftp_con, 3, "Buffer Full. ");
}
/* Else the last data packet has been received.
* We are done. Send the last ACK.
*/
else
{
tftp_con->status = TRANSFER_COMPLETE;
TFTPC_Ack(tftp_con);
}
/* Increment the block number. */
tftp_con->block_number++;
}
else
return(TFTP_CON_FAILURE);
break;
case TFTP_ERROR_OPCODE:
if (GET16(tftp_con->trans_buf, 2) <= 8)
return (tftp_errors[GET16(tftp_con->trans_buf, 2)]);
else
return(TFTP_CON_FAILURE);
case TFTP_ACK_OPCODE:
case TFTP_RRQ_OPCODE:
case TFTP_WRQ_OPCODE:
default:
return (TFTP_CON_FAILURE);
}
return (NU_SUCCESS);
} /* TFTPC_Process_Data */
/*************************************************************************
*
* FUNCTION
*
* TFTPC_Ack
*
* DESCRIPTION
*
* This function is responsible for sending an acknowledgement of
* a TFTP data packet.
*
* INPUTS
*
* *tftp_con The pointer to TFTP Control Block
*
* OUTPUTS
*
* The Number of bytes sent on success.
*
*************************************************************************/
STATUS TFTPC_Ack(TFTP_CB *tftp_con)
{
/* Setup the ACK packet - a client always returns an ACK packet,
* regardless of the presence of options - only servers return
* OACK packets
*/
PUT16(tftp_con->trans_buf, 0, TFTP_ACK_OPCODE);
PUT16(tftp_con->trans_buf, 2, tftp_con->block_number);
/* Send the ACK packet. */
return ((INT)NU_Send_To(tftp_con->socket_number,
tftp_con->trans_buf, 4, 0,
&tftp_con->server_addr, 0));
} /* end TFTPC_Ack */
/*************************************************************************
*
* FUNCTION
*
* TFTPC_Process_Ack
*
* DESCRIPTION
*
* This function is responsible processing an ACK packet whenever
* a write request is in progress.
*
* INPUTS
*
* *tftp_con The pointer to TFTP Control Block.
* bytes_received The number of bytes received in the last packet
* received.
*
* OUTPUTS
*
* NU_SUCCESS whenever the expected data was received, -1 otherwise.
*
*************************************************************************/
STATUS TFTPC_Process_Ack(TFTP_CB *tftp_con, INT32 bytes_received)
{
STATUS status;
/* What kind of packet is this. */
switch(GET16(tftp_con->trans_buf, 0))
{
case TFTP_OACK_OPCODE:
/* Received an OACK packet that has already be acknowledged,
* because our block number is greater than 0, and we only
* receive one OACK when our block number is equal to 0
*/
if((tftp_con->block_number > 0)
&& (tftp_con->tid == tftp_con->server_addr.port))
{
status = NU_SUCCESS;
break;
}
/* Check that the options returned are valid */
else if ((status = TFTPC_Check_Options(tftp_con, bytes_received)) != NU_SUCCESS)
break;
else
{
/* Increment block number */
tftp_con->block_number++;
status = NU_SUCCESS;
}
break;
case TFTP_ACK_OPCODE:
/* Received an ACK packet that has already be acknowledged,
* because our current block number is greater than the block
* number of the packet - we do not want to exit, error, or
* confirm this packet (because it has already been confirmed),
* but go get the next packet
*/
if((tftp_con->block_number > GET16(tftp_con->trans_buf, 2))
&& (tftp_con->tid == tftp_con->server_addr.port))
{
status = NU_SUCCESS;
break;
}
/* Make sure the block number and TID are correct. */
else if((tftp_con->block_number ==
GET16(tftp_con->trans_buf, 2))
&& (tftp_con->tid == tftp_con->server_addr.port))
tftp_con->block_number++;
else
{
status = TFTP_CON_FAILURE;
break;
}
status = NU_SUCCESS;
break;
case TFTP_ERROR_OPCODE:
if (GET16(tftp_con->trans_buf, 2) <= 8)
status = (tftp_errors[GET16(tftp_con->trans_buf, 2)]);
else
status = TFTP_CON_FAILURE;
break;
case TFTP_RRQ_OPCODE:
case TFTP_WRQ_OPCODE:
case TFTP_DATA_OPCODE:
default:
status = TFTP_CON_FAILURE;
break;
}
return (status);
} /* TFTPC_Process_Ack */
/*************************************************************************
*
* FUNCTION
*
* TFTPC_Send_Data
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -