📄 tftp.cpp
字号:
// Tftp.cpp: implementation of the CTftp class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Tftp.h"
#include "resource.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CTftp::CTftp()
{
Sock = INVALID_SOCKET;
strcpy(DestHost,"127.0.0.1");
FileMode=TFTP_Octet;
ReviceSendBytes=0;
}
CTftp::~CTftp()
{
}
//////////////////////////////////////////////////////////////////////////
// 初始化windows winsock环境,如果不能正确初始化则返回错误
//////////////////////////////////////////////////////////////////////////
BOOL CTftp::InitSock(void)
{
sockaddr_in addr;
WSADATA stWSAData;
if(WSAStartup(WSA_VERSION, &stWSAData)!=0)return false;
Sock = socket(PF_INET,SOCK_DGRAM,0);
if(Sock==INVALID_SOCKET)return false;
addr.sin_family = PF_INET;
addr.sin_port = INADDR_ANY;
addr.sin_addr.s_addr = INADDR_ANY;
if(bind(Sock,(struct sockaddr *)&addr,sizeof(addr))!=0)return false;
return true;
}
//////////////////////////////////////////////////////////////////////////
// 向主机获得文件
//////////////////////////////////////////////////////////////////////////
UINT CTftp::GetFile(char *FileName)
{
char sendbuf[1024] = {0};
char recvbuf[1024] = {0};
sockaddr_in addr;
sockaddr_in from;
int fromlen = 0;
int ret = 0;
int len = 0 ;
fd_set fdr;
int retry = 0;
struct timeval timeout = {5,0};
int stat = 0;
int lastdata = 0;
FILE *file;
int flen = 0;
if(!InitSock())
{
return TFTP_INIT_WINSOCK_ERROR;
}
if((file=fopen(FileName,"rb"))!=NULL)
{
char str[256];
sprintf(str,"File %s already exits,overwrite?",FileName);
if(MessageBox(NULL,str,"File Exites Error",MB_YESNO)==IDOK)
{
fclose(file);
}
else
{
fclose(file);
return TFTP_FILE_EXITES_ERROR;
}
}
if((file=fopen(FileName,"w+b"))==NULL)
{
return TFTP_FILE_EXITES_ERROR;
}
fseek(file,0,SEEK_END);
ftell(file);
if(sb)sb->SetRange(0,UINT(ftell(file)/10000));
fseek(file,0,SEEK_SET);
len = MakeReq(TFTP_RRQ,FileMode,FileName,sendbuf);
addr.sin_family =PF_INET;
from.sin_family =PF_INET;
addr.sin_port = htons(TFTP_PORT_NUMBER);
addr.sin_addr.s_addr = inet_addr(DestHost);
ret = sendto(Sock,sendbuf,len,0,(sockaddr *)&addr,sizeof(addr));
while(true)
{
FD_ZERO(&fdr);
FD_SET(Sock, &fdr);
ret = select(Sock, &fdr, NULL,NULL, &timeout);
if(SOCKET_ERROR==ret)
{
fclose(file);
return TFTP_WINSOCK_ERROR;
}
else if(0==ret)
{
if(MAX_RETRY==retry)
{
fclose(file);
return TFTP_TIMEOUT_ERROR;
}
sendto(Sock,sendbuf,len,0,(sockaddr *)&addr,sizeof(addr));
retry++;
}
else
{
if (FD_ISSET(Sock,&fdr))
{
retry = 0;
fromlen = sizeof(sockaddr);
ret = recvfrom(Sock,recvbuf,sizeof(recvbuf),0,(sockaddr *)&from,&fromlen);
if(TFTP_ERROR==recvbuf[1])
{
fclose(file);
return TFTP_ACK_ERROR;
}
if(0==stat)
{
addr.sin_port = from.sin_port ;
stat = 1;
}
if(TFTP_DATA==recvbuf[1])
{
lastdata = recvbuf[2]*256 + recvbuf[3];
len = MakeAck(lastdata,sendbuf);
sendto(Sock,sendbuf,len,0,(sockaddr *)&addr,sizeof(addr));
if(ret<TFTP_NOTEND_DATALEN)
{
fwrite(&recvbuf[4],1,ret-4,file);
flen = flen + ret -4;
fclose(file);
ReviceSendBytes=flen;
if(sb)sb->SetPos(flen/10000);
return TFTP_OK;
}
else
{
fwrite(&recvbuf[4],1,512,file);
flen = flen + 512;
ReviceSendBytes=flen;
if(sb)sb->SetPos(flen/10000);
}
}
}
}
}
}
//////////////////////////////////////////////////////////////////////////
// 由从机向主机传送文件
//////////////////////////////////////////////////////////////////////////
UINT CTftp::PutFile(char *localfile,char *remotefile)
{
CHAR sendbuf[1024] = {0};
CHAR recvbuf[1024] = {0};
CHAR databuf[1024] = {0};
sockaddr_in addr;
sockaddr_in from;
int fromlen = 0;
long ret = 0;
long len = 0 ;
fd_set fdr;
int retry = 0;
struct timeval timeout = {8,0};
long stat = TFTP_WSTAT_FIRSTACK;
LONG lastack= 0;
FILE *file;
long flen = 0;
long blocknum = 0;
long rlen = 0;
if(!InitSock())
{
return TFTP_INIT_WINSOCK_ERROR;
}
if((file=fopen(localfile,"rb"))==NULL)
{
return TFTP_FILE_NOEXITES_ERROR;
}
len = MakeReq(TFTP_WRQ,FileMode,remotefile,sendbuf);
addr.sin_family =PF_INET;
addr.sin_port = htons(TFTP_PORT_NUMBER);
addr.sin_addr.s_addr = inet_addr(DestHost);
ret = sendto(Sock,sendbuf,len,0,(sockaddr *)&addr,sizeof(addr));
if((file=fopen(localfile,"rb"))==NULL)
{
return TFTP_INPUT_FILE_ERROR;
}
fseek(file,0,SEEK_END);
ftell(file);
if(sb)sb->SetRange(0,UINT(ftell(file)/10000));
fseek(file,0,SEEK_SET);
while(true)
{
FD_ZERO(&fdr);
FD_SET(Sock, &fdr);
ret = select(Sock, &fdr, NULL,NULL, &timeout);
if(SOCKET_ERROR==ret)
{
fclose(file);
return TFTP_WINSOCK_ERROR;
}
else if(0==ret)
{
if(MAX_RETRY==retry)
{
fclose(file);
return TFTP_TIMEOUT_ERROR;
}
sendto(Sock,sendbuf,len,0,(sockaddr *)&addr,sizeof(addr));
retry++;
}
else
{
retry = 0;
fromlen = sizeof(sockaddr);
ret = recvfrom(Sock,recvbuf,sizeof(recvbuf),0,(sockaddr *)&from,&fromlen);
if(TFTP_ERROR==recvbuf[1]) //TFP返回错误的应答信号
{
fclose(file);
return TFTP_ACK_ERROR;
}
if(TFTP_ACK==recvbuf[1]) //返回正确的ACK信号
{
lastack = (UCHAR)recvbuf[2]*256 + (UCHAR)recvbuf[3];
switch(stat)
{
case TFTP_WSTAT_FIRSTACK:
if(0==lastack)
{
stat = TFTP_WSTAT_NEXTACK;
addr.sin_port = from.sin_port ;
fseek(file,0,SEEK_SET);
rlen = fread(databuf,1,512,file);//每次发送512字节的数据
flen = flen + rlen;
if(rlen<512 && feof(file))//如果到了文件结尾则发送结束ACK信号
{
stat = TFTP_WSTAT_LASTACK;
}
else if(ferror(file))
{
fclose(file);
return TFTP_FILE_READ_ERROR;
}
blocknum++;
len = MakeData(blocknum,databuf,rlen,sendbuf);
sendto(Sock,sendbuf,len,0,(sockaddr *)&addr,sizeof(addr));
ReviceSendBytes=flen;
if(sb)sb->SetPos(flen/10000);
}
else
{
fclose(file);
return TFTP_ACK_ERROR;
}
break;
case TFTP_WSTAT_NEXTACK:
if(lastack==blocknum)
{
rlen = fread(databuf,1,512,file);
flen = flen + rlen;
if(rlen<512 && feof(file))
{
stat = TFTP_WSTAT_LASTACK;
}
else if(ferror(file))
{
fclose(file);
return TFTP_FILE_READ_ERROR;
}
blocknum++;
len = MakeData(blocknum,databuf,rlen,sendbuf);
sendto(Sock,sendbuf,len,0,(sockaddr *)&addr,sizeof(addr));
ReviceSendBytes=flen;
if(sb)sb->SetPos(flen/10000);
}
else
{
fclose(file);
return TFTP_ACK_ERROR;
}
break;
case TFTP_WSTAT_LASTACK:
if(lastack==blocknum)
{
return TFTP_OK;
}
else
{
fclose(file);
return TFTP_ACK_ERROR;
}
break;
}
}
}
}
}
//////////////////////////////////////////////////////////////////////////
// 生成读写请求数据包
// 2 bytes string 1 byte string 1 byte
// ------------------------------------------------
// | Opcode | Filename | 0 | Mode | 0 |
// ------------------------------------------------
//////////////////////////////////////////////////////////////////////////
int CTftp::MakeReq(char type,int mode,char *filename,char *buffer)
{
int pos = 0;
unsigned int i = 0;
char s[32] = "";
if(mode==TFTP_NETASCII)
strcpy(s,"netascii");
else
strcpy(s,"octet");
buffer[pos] = 0;
pos++;
buffer[pos] = type;//Read request: TFTP_RRQ=1 Write request: TFTP_WRQ=2
pos++;
for(i=0;i<strlen(filename);i++) //填充文件名
{
buffer[pos] = filename[i];
pos++;
}
buffer[pos] = 0;
pos++;
for(i=0;i<strlen(s);i++) //填充传送模式代码(ASCII OCTET)
{
buffer[pos] = s[i];
pos++;
}
buffer[pos] = 0;
pos++;
return pos;
}
//////////////////////////////////////////////////////////////////////////
// 生成ACK应答数据包
// 2 bytes 2 bytes n bytes
// ----------------------------------
// | Opcode | Block # |
// ----------------------------------
//////////////////////////////////////////////////////////////////////////
int CTftp::MakeAck(unsigned short BlockNum,char *buffer)
{
int pos = 0;
buffer[pos] = 0;
pos++;
buffer[pos] = TFTP_ACK;
pos++;
buffer[pos] = (char)(BlockNum>>8);
pos++;
buffer[pos] = (char)BlockNum;
pos++;
return pos;
}
//////////////////////////////////////////////////////////////////////////
// 生成DATA数据包
// 2 bytes 2 bytes n bytes
// ----------------------------------
// | Opcode | Block # | Data |
// ----------------------------------
//////////////////////////////////////////////////////////////////////////
int CTftp::MakeData(int num,char *data,int datasize,char *buffer)
{
int pos = 0;
buffer[pos] = 0;
pos++;
buffer[pos] = TFTP_DATA;
pos++;
buffer[pos] = (char)(num>>8);
pos++;
buffer[pos] = (char)num;
pos++;
memcpy(&buffer[pos],data,datasize);
pos = pos + datasize;
return pos;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -