📄 tftp.c
字号:
/* achieve base function of tftp client.Some bugs are in the file,
* if you know how to correct them,please tell me,thank you!
* All rights reserved.
* Author : xiaoleng
* Email : flylgh@163.com
* create date: 2008-11-1
*
* 实现TFTP客户端基本功能,但本实现未设置接收超时!
* BUG(如果设置了超时,将在接收到8M数据的时候出错)
* 如果你知道如何改正,或者你有更好的建议,请通知我。
* 对你无私的精神,我表示衷心的感谢!
* 你可以随意发布、修改,但请别用于学习或者交流的其他
* 用途!
* 作者 : xiaoleng
* Email : flylgh@163.com
* 创建时间: 2008-11-1
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <time.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include "tftpc.h"
typedef struct
{
unsigned short option;
unsigned short number;
char data[512];
}tftp_package;
typedef struct
{
struct timeval timeout;
struct sockaddr_in server_addr;
int sockfd;
char trans_mode[10];
}tftp_information;
tftp_information tftp_info;
static int create_req_buf(int option,char *file_name,char *buf_out)
{
char *pre_addr = buf_out;
*buf_out++ = 0;
*buf_out++ = option;
strcpy(buf_out,file_name);
buf_out += strlen(file_name);
*buf_out++ = 0;
strcpy(buf_out,tftp_info.trans_mode);
buf_out += strlen(tftp_info.trans_mode);
*buf_out++ = 0;
return (buf_out-pre_addr);
}
static int send_ack(unsigned short ack_num)
{
tftp_package package;
int retval;
memset(&package,0,sizeof(package));
package.option = htons(OP_ACK);
package.number = ack_num;
retval = sendto(tftp_info.sockfd,&package,4,0,(struct sockaddr *)&tftp_info.server_addr,sizeof(struct sockaddr));
if(retval == -1){
return -1;
}
return 0;
}
static int read_file(char *file_name)
{
int retval,fd,len,size,n_read,seq_no=1;
int datalen;
char buf[520];
tftp_package package;
fd_set readfd;
memset(buf,0,520);
len = create_req_buf(OP_READ,file_name,buf);
retval = sendto(tftp_info.sockfd,buf,len,0,(struct sockaddr *)&tftp_info.server_addr,sizeof(struct sockaddr));
if(retval == -1){
perror("send to errno:");
return -1;
}
chdir(DEFAULT_DIR);
fd = open(file_name,O_CREAT | O_RDWR |O_TRUNC,0666);
len = sizeof(struct sockaddr);
size = sizeof(package);
memset(&package,0,size);
FD_ZERO(&readfd);
FD_SET(tftp_info.sockfd,&readfd);
do{
//retval = select(tftp_info.sockfd+1,&readfd,NULL,NULL,&tftp_info.timeout);
retval = 1;
if(retval > 0){
n_read = recvfrom(tftp_info.sockfd,&package,size,0,(struct sockaddr *)&tftp_info.server_addr,(unsigned int *)&len);
if(ntohs(package.option) == OP_DATA){
datalen = n_read - 4;
if(ntohs(package.number) != seq_no){
continue;
}
if(send_ack(package.number) == -1){
printf("send ack error!\n");
continue;
}
if(seq_no == 65535){
seq_no = 0;
}else{
seq_no ++;
}
if(datalen > 0){
write(fd,package.data,datalen);
}
if(datalen < 512){
printf("receive complete\n");
retval = 0;
break;
}
}
else if(ntohs(package.option) == OP_ERROR){
seq_no ++;
printf("%s\n",package.data);
retval = -1;
break;
}
}
else if(retval == 0){
printf("receive time out!\n");
retval = -1;
}
else{
perror("function[select]error:");
retval = -1;
}
}while(retval > 0);
printf("seq_no[%d]\n",seq_no);
close(fd);
return retval;
}
static int write_file(char *file_name)
{
return 0;
}
static void tftp_init(char *server_ip)
{
tftp_info.sockfd = socket(AF_INET,SOCK_DGRAM,0);
tftp_info.timeout.tv_sec = TFTP_SEND_RECV_TIMEOUT;
tftp_info.timeout.tv_usec = 0;
tftp_info.server_addr.sin_family = AF_INET;
tftp_info.server_addr.sin_port = htons(69);
tftp_info.server_addr.sin_addr.s_addr = inet_addr(server_ip);
memset(tftp_info.trans_mode,0,sizeof(tftp_info.trans_mode));
strcpy(tftp_info.trans_mode,MODE_OCTET);
}
static void tftp_free(void)
{
close(tftp_info.sockfd);
}
int tftp_user_req(char *server_ip,int option,char *file_name)
{
int result;
tftp_init(server_ip);
switch(option)
{
case OP_READ:
result = read_file(file_name);
break;
case OP_WRITE:
result = write_file(file_name);
break;
default:
result = -1;
break;
}
tftp_free();
return result;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -