?? tftpserver.c
字號:
if (!args)
{
/* unable to allocate memory for tftp args */
tftp_send_error_message(upcb, to, to_port, TFTP_ERR_NOTDEFINED);
/* no need to use tftp_cleanup_rd because no
"tftp_connection_args" struct has been malloc'd */
tftp_cleanup_rd(upcb, args);
return 0;
}
/* initialize connection structure */
args->op = TFTP_RRQ; //操作碼
args->to_ip.addr = to->addr; //目的ip
args->to_port = to_port; //to_port=0
args->block = 1; //接收到讀請求時,塊號從1開始
args->tot_bytes = 0; /* total number of bytes transferred */
/* set callback for receives on this UDP PCB (Protocol Control Block) */
udp_recv(upcb, rrq_recv_callback, args); //得到回復時調用rrq_recv_callback
/* initiate the transaction by sending the first block of data
* further blocks will be sent when ACKs are received
* - the receive callbacks need to get the proper state */
tftp_send_next_block(upcb, args, to, to_port); //file_read要改
return 1;
}
void wrq_recv_callback(void *_args, struct udp_pcb *upcb, struct pbuf *pkt_buf, struct ip_addr *addr, u16_t port)
{
tftp_connection_args *args = (tftp_connection_args *)_args;
int n = 0;
if (pkt_buf->len != pkt_buf->tot_len)
{
return;
}
/* Does this packet have any valid data to write? */
if ((pkt_buf->len > TFTP_DATA_PKT_HDR_LEN) &&
(tftp_extract_block(pkt_buf->payload) == (args->block + 1)))
{
/* write the received data to the file */ //將文件內容寫入
n = file_write(&file_CR,
pkt_buf->len - TFTP_DATA_PKT_HDR_LEN,
(euint8*)pkt_buf->payload + TFTP_DATA_PKT_HDR_LEN);
if (n <= 0)
{
tftp_send_error_message(upcb, addr, port, TFTP_ERR_FILE_NOT_FOUND);
/* close the connection */
tftp_cleanup_wr(upcb, args); /* close the connection */
}
/* update our block number to match the block number just received */
args->block++;
/* update total bytes */
(args->tot_bytes) += (pkt_buf->len - TFTP_DATA_PKT_HDR_LEN); //加上數據部分長度
/* This is a valid pkt but it has no data. This would occur if the file being
written is an exact multiple of 512 bytes. In this case, the args->block
value must still be updated, but we can skip everything else. */
}
else if (tftp_extract_block(pkt_buf->payload) == (args->block + 1))
{
/* update our block number to match the block number just received */
args->block++;
}
/* SEndTransferthe appropriate ACK pkt (the block number sent in the ACK pkt echoes
* the block number of the DATA pkt we just received - see RFC1350)
* NOTE!: If the DATA pkt we received did not have the appropriate block
* number, then the args->block (our block number) is never updated and
* we simply sEndTransfera "duplicate ACK" which has the same block number as the
* last ACK pkt we sent. This lets the host know that we are still waiting
* on block number args->block+1. */
tftp_send_ack_packet(upcb, addr, port, args->block);
/* If the last write returned less than the maximum TFTP data pkt length,
* then we've received the whole file and so we can quit (this is how TFTP
* signals the EndTransferof a transfer!)
*/
if (pkt_buf->len < TFTP_DATA_PKT_LEN_MAX)
{
tftp_cleanup_wr(upcb, args);
pbuf_free(pkt_buf);
}
else
{
pbuf_free(pkt_buf);
return;
}
}
int tftp_process_write(struct udp_pcb *upcb, struct ip_addr *to, int to_port, char *FileName)
{
tftp_connection_args *args = NULL;
/* If Could not open the file which will be transmitted */
if (file_fopen(&file_CR, &efs2.myFs, FileName, 'w') != 0)
{
tftp_send_error_message(upcb, to, to_port, TFTP_ERR_FILE_ALREADY_EXISTS);
tftp_cleanup_wr(upcb, args);
return 0;
}
/* This function is called from a callback,
* therefore interrupts are disabled,
* therefore we can use regular malloc */
args = mem_malloc(sizeof *args);
if (!args)
{
tftp_send_error_message(upcb, to, to_port, TFTP_ERR_NOTDEFINED);
tftp_cleanup_wr(upcb, args);
return 0;
}
args->op = TFTP_WRQ;
args->to_ip.addr = to->addr;
args->to_port = to_port;
/* the block # used as a positive response to a WRQ is _always_ 0!!! (see RFC1350) */
args->block = 0; //接收到的是寫入請求時,包號為0
args->tot_bytes = 0;
/* set callback for receives on this UDP PCB (Protocol Control Block) */
udp_recv(upcb, wrq_recv_callback, args);
/* initiate the write transaction by sending the first ack */
tftp_send_ack_packet(upcb, to, to_port, args->block);
return 0;
}
/* for each new request (data in p->payload) from addr:port,
* create a new port to serve the response, and start the response
* process
*/
void process_tftp_request(struct pbuf *pkt_buf, struct ip_addr *addr, u16_t port)
{
tftp_opcode op = tftp_decode_op(pkt_buf->payload); //取出操作碼
char FileName[30];
struct udp_pcb *upcb;
err_t err;
u32_t IPaddress;
u8_t iptxt[20];
u8_t iptab[4];
IPaddress = addr->addr;
printf("\n\rTFTP RRQ (read request) from: %d.%d.%d.%d\n\r", (u8_t)(IPaddress),
(u8_t)(IPaddress >> 8),(u8_t)(IPaddress >> 16),(u8_t)(IPaddress >> 24));
/* read its IP address */
iptab[0] = (u8_t)(IPaddress >> 24);
iptab[1] = (u8_t)(IPaddress >> 16);
iptab[2] = (u8_t)(IPaddress >> 8);
iptab[3] = (u8_t)(IPaddress);
sprintf((char*)iptxt, "TFTP: %d.%d.%d.%d ", iptab[3], iptab[2], iptab[1], iptab[0]);
LCD_DisplayStringLine(Line7, iptxt);
/* create new UDP PCB structure */
upcb = udp_new();
if (!upcb)
{ /* Error creating PCB. Out of Memory */
return;
}
/* bind to port 0 to receive next available free port */
/* NOTE: This is how TFTP works. There is a UDP PCB for the standard port
* 69 which al transactions begin communication on, however, _all_ subsequent
* transactions for a given "stream" occur on another port! */
err = udp_bind(upcb, IP_ADDR_ANY, 0);
if (err != ERR_OK)
{ /* Unable to bind to port */
return;
}
switch (op)
{
case TFTP_RRQ: /* TFTP RRQ (read request) */
/* Read the name of the file asked by the client
to be sent from the SD card */
tftp_extract_filename(FileName, pkt_buf->payload); //提取文件名
printf("\n\rTFTP RRQ (read request)");
printf("\n\rONLY EFS filesystem(NTFS in WinXp) is support");
/* If Could not open filesystem */
if (efs_init(&efs1, 0) != 0)
{
printf("\n\rIf Could not open filesystem");
return;
}
printf("\n\rCould open filesystem\n\r");
/* If Could not open the selected directory */
if (ls_openDir(&list1, &(efs1.myFs), "/") != 0)
{
printf("\n\rIf Could not open the selected directory");
return;
}
/* Start the TFTP read mode*/ //addr為接收方的IP地址 ,port=0
printf("\n\rStart the TFTP read mode....");
tftp_process_read(upcb, addr, port, FileName); //根據文件名讀取SD卡中的文件,并發送
break;
case TFTP_WRQ: /* TFTP WRQ (write request) */
/* Read the name of the file asked by the client
to received and writen in the SD card */
tftp_extract_filename(FileName, pkt_buf->payload);
/* If Could not open filesystem */
if (efs_init(&efs2, 0) != 0)
{
return;
}
/* If Could not open the selected directory */
if (ls_openDir(&list2, &(efs2.myFs), "/") != 0)
{
return;
}
/* Start the TFTP write mode*/
tftp_process_write(upcb, addr, port, FileName);
break;
default:
/* sEndTransfera generic access violation message */
tftp_send_error_message(upcb, addr, port, TFTP_ERR_ACCESS_VIOLATION);
/* TFTP unknown request op */
/* no need to use tftp_cleanup_wr because no
"tftp_connection_args" struct has been malloc'd */
udp_remove(upcb);
break;
}
}
/* the recv_callback function is called when there is a packet received
* on the main tftp server port (69)
*/
void recv_callback_tftp(void *arg, struct udp_pcb *upcb, struct pbuf *pkt_buf,
struct ip_addr *addr, u16_t port)
{
/* process new connection request */
process_tftp_request(pkt_buf, addr, port);
pbuf_free(pkt_buf);
}
void tftpd_init(void)
{
err_t err;
unsigned port = 69;
/* create a new UDP PCB structure */
UDPpcb = udp_new();
if (!UDPpcb)
{ /* Error creating PCB. Out of Memory */
return;
}
/* Bind this PCB to port 69 */
err = udp_bind(UDPpcb, IP_ADDR_ANY, port);
if (err != ERR_OK)
{ /* Unable to bind to port */
return;
}
/* TFTP server start */ //啟動TFTP服務器
udp_recv(UDPpcb, recv_callback_tftp, NULL); //通知協議棧當69端口有連接請求時調用recv_callback_tftp,
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -