📄 ctrlsocket.cpp
字号:
#include <strings.h>
#include "Tools.h"
#include "CtrlSocket.h"
CCtrlSocket::CMD_INFO CCtrlSocket::m_arrCmd[]=
{
{"SYST",&CCtrlSocket::DoSyst,"Get operating system type: SYST"},
{"PWD", &CCtrlSocket::DoPwd,"Get current directory: PWD"},
{"CWD", &CCtrlSocket::DoCwd,"Change working directory: CWD [directory-name]"},
{"USER",&CCtrlSocket::DoUser,"Supply a username: USER username"},
{"PASS",&CCtrlSocket::DoPass,"Supply a user password: PASS password"},
{"TYPE",&CCtrlSocket::DoType,"Set filetype: TYPE [A | I]"},
{"CDUP",&CCtrlSocket::DoCdup,"Change to parent directory: CDUP"},
{"NOOP",&CCtrlSocket::DoNoop,"Do nothing: NOOP"},
{"RETR",&CCtrlSocket::DoRetr,"Get file: RETR file-name"},
{"STOR",&CCtrlSocket::DoStor,"Store file: STOR file-name"},
{"LIST",&CCtrlSocket::DoList,"Get directory listing: LIST [path-name]"},
{"DIR", &CCtrlSocket::DoList,"Get directory listing: DIR [path-name]"},
{"PASV",&CCtrlSocket::DoPasv,"Set server in passive mode: PASV"},
{"PORT",&CCtrlSocket::DoPort,"Specify the client port number: PORT a0,a1,a2,a3,a4,a5"},
{"ABOR",&CCtrlSocket::DoAbor,"Abort transfer: ABOR"},
{"QUIT",&CCtrlSocket::DoQuit,"Logout or break the connection: QUIT"},
{"DELE",&CCtrlSocket::DoDele,"Delete file: DELE file-name"},
{"MKD", &CCtrlSocket::DoMkd,"Make directory: MKD path-name"},
{"RMD", &CCtrlSocket::DoRmd,"Remove directory: RMD path-name"},
{"SIZE",&CCtrlSocket::DoSize,"Get filesize: SIZE file-name"},
{"RNFR",&CCtrlSocket::DoRefr,"Specify old path name of file to be renamed: RNFR file-name"},
{"RNTO",&CCtrlSocket::DoReto,"Specify new path name of file to be renamed: RNTO file-name"},
{"HELP",&CCtrlSocket::DoHelp,"Show help: HELP [command]"},
{"REST",NULL,"Set restart transfer marker: REST marker"}//断点续传尚未实现
};
CCtrlSocket::CCtrlSocket()
{
m_sSend=m_sRecv="";
m_sockData.m_pSockCtrl=this;
pthread_mutex_init(&m_mutex,NULL);
}
CCtrlSocket::~CCtrlSocket()
{
pthread_mutex_destroy(&m_mutex);
}
int CCtrlSocket::Start()
{
char szBuf[1024];
int iRet;
int iCmdIndex,iTimeout=0;
//
SetTimeout(100);//每0.1秒循环一次
m_sockData.m_iTimeout=m_iTimeout;//给数据通道套接字也设置超时
Response(WELCOME);
//
while(true){
//提取命令,追加接收队列
iRet=Recv(szBuf,sizeof(szBuf)-1);
if(iRet==0){
break;//对方断开连接
}else if(iRet>0){
szBuf[iRet]=0;//这一句必须加上!!
m_sRecv+=szBuf;
iTimeout=0;
}else if(errno!=EWOULDBLOCK){
perror("recv fail");//出现异常
break;
}
//从接收队列中提取命令,追加响应队列
iCmdIndex=GetCmd(szBuf,sizeof(szBuf));
if(iCmdIndex>=0){//提取了一个命令
ReplyCmd(iCmdIndex,szBuf);
}else if(iCmdIndex<-1){//提取失败,-1表示命令未接收完
Response(CMD_ERR);
}
//读取响应队列,提交响应.
//(响应队列由本线程和数据通道子线程互斥追加)
if(CommitResponse()<0 && errno!=EWOULDBLOCK){
break;//发送失败!
}
if(++iTimeout>(m_iTimeout/100)){//超时退出
TRACE("timeout:%d",m_iTimeout);
break;
}
}
return 0;
}
int CCtrlSocket::ReplyCmd(int iCmdIndex,const char *pszArg)
{
CMD_INFO *pCmdInfo=m_arrCmd+iCmdIndex;
FN_DO pfnDo;
//
if(!m_user.IsLoaded() &&
strcmp(pCmdInfo->pszCmd,"USER")!=0 &&
strcmp(pCmdInfo->pszCmd,"PASS")!=0){
Response(LOGIN_ERR);
return -1;
}
pfnDo=pCmdInfo->pfnDo;
if(pfnDo){
return (this->*pfnDo)(pszArg);
}else{
Response(IMPL_ERR);
return 0;
}
}
int CCtrlSocket::DoUser(const char *pszArg)
{
m_user.m_sUser=pszArg;
Response(USER_OK);
return 0;
}
int CCtrlSocket::DoPass(const char *pszArg)
{
int iRet;
if(m_user.m_sUser==""){
Response(LOGIN_ERR);
return -1;
}
iRet=m_user.Load(pszArg);
if(iRet==0){
Response(LOGIN_OK);
}else if(iRet==-1){
Response(LOGIN_ERR);
}else{
Response(INTER_ERR);
}
return iRet;
}
int CCtrlSocket::DoSyst(const char *pszArg)
{
Response(SYST_OK);
return 0;
}
int CCtrlSocket::DoRetr(const char *pszArg)
{
if(m_user.BuildRetr(m_sockData.m_sFile,pszArg)<0){
Response(FILE_ERR);
return -1;
}
return m_sockData.Run(CDataSocket::RETR);
}
int CCtrlSocket::DoStor(const char *pszArg)
{
int iRet=m_user.BuildStor(m_sockData.m_sFile,pszArg);
if(iRet<0){
Response(FILE_ERR);
return -1;
}
return m_sockData.Run(CDataSocket::STOR);
}
int CCtrlSocket::DoList(const char *pszArg)
{
if(m_user.BuildList(m_sockData.m_sList)<0){
Response(FILE_ERR);
return -1;
}
return m_sockData.Run(CDataSocket::LIST);
}
int CCtrlSocket::DoPwd(const char *pszArg)
{
Response("257 \"%s\" is current directory.",
m_user.GetDir());
return 0;
}
int CCtrlSocket::DoCwd(const char *pszArg)
{
if(m_user.ChangeDir(pszArg)<0){
Response(DIR_ERR);
return -1;
}
Response(DIR_OK);
return 0;
}
int CCtrlSocket::DoDele(const char *pszArg)
{
if(m_user.DeleFile(pszArg)<0){
Response(FILE_ERR);
return -1;
}
Response(FILE_OK);
return 0;
}
int CCtrlSocket::DoMkd(const char *pszArg)
{
if(m_user.Mkdir(pszArg)<0){
Response(DIR_ERR);
return -1;
}
Response(DIR_OK);
return 0;
}
int CCtrlSocket::DoRmd(const char *pszArg)
{
if(m_user.Rmdir(pszArg)<0){
Response(DIR_ERR);
return -1;
}
Response(DIR_OK);
return 0;
}
int CCtrlSocket::DoSize(const char *pszArg)
{
int iSize=m_user.GetFileSize(pszArg);
if(iSize<0){
Response(FILE_ERR);
return -1;
}
Response("213 %d",iSize);
return 0;
}
//rename file/direcory from ...
int CCtrlSocket::DoRefr(const char *pszArg)
{
if(m_user.RenameFrom(pszArg)<0){
Response(FILE_ERR);
return -1;
}
Response(RNFR_OK);
return 0;
}
//rename file/directory to ...
int CCtrlSocket::DoReto(const char *pszArg)
{
if(m_user.RenameTo(pszArg)<0){
Response(FILE_ERR);
return -1;
}
Response(RNTO_OK);
return 0;
}
int CCtrlSocket::DoCdup(const char *pszArg)
{
return DoCwd("..");
}
int CCtrlSocket::DoType(const char *pszArg)
{
Response(CMD_OK);
return 0;
}
int CCtrlSocket::DoNoop(const char *pszArg)
{
Response(CMD_OK);
return 0;
}
int CCtrlSocket::DoPasv(const char *pszArg)
{
return m_sockData.PreparePasv();
}
int CCtrlSocket::DoPort(const char *pszArg)
{
return m_sockData.PreparePort(pszArg);
}
int CCtrlSocket::DoQuit(const char *pszArg)
{
Response(QUIT_OK);
CommitResponse();
exit(0);
return 0;
}
int CCtrlSocket::DoAbor(const char *pszArg)
{
return m_sockData.Stop();//中断传输线程
}
int CCtrlSocket::DoHelp(const char *pszArg)
{
int iCmdIndex,iCount;
//
iCount=sizeof(m_arrCmd)/sizeof(m_arrCmd[0]);
if(*pszArg){
iCmdIndex=FindCmdInfo(pszArg);
if(iCmdIndex<0){
Response(CMD_ERR);
}else{
Response("214 %s",m_arrCmd[iCmdIndex].pszInfo);
}
}else{
for(iCmdIndex=0; iCmdIndex<iCount; ++iCmdIndex)
Response(m_arrCmd[iCmdIndex].pszCmd);
Response("214 HELP command successful.");
}
return 0;
}
int CCtrlSocket::FindCmdInfo(const char *pszCmd)
{
int i,iCount;
//
iCount=sizeof(m_arrCmd)/sizeof(m_arrCmd[0]);
for(i=0;i<iCount;i++)
if(strcasecmp(m_arrCmd[i].pszCmd,pszCmd) == 0)
return i;
return -1;
}
int CCtrlSocket::GetCmd(char *pszArg,int iArgSize)
{
size_t nDelim;
char *pszTail,*pszMid;
int iCmdIndex;
//
nDelim=m_sRecv.find("\r\n");
if(nDelim==string::npos)
return -1;
if(nDelim<3 || (int)nDelim>iArgSize-1){//命令肯定有问题
m_sRecv.erase(0,nDelim+2);
return -2;
}
memcpy(pszArg,m_sRecv.c_str(),nDelim);
pszArg[nDelim]=0;
m_sRecv.erase(0,nDelim+2);
pszTail=pszArg+nDelim;
if((pszMid=strchr(pszArg,' ')))
*pszMid=0;
else
pszMid=pszTail-1;
iCmdIndex=FindCmdInfo(pszArg);
if(iCmdIndex>=0){
memmove(pszArg,pszMid+1,pszTail-pszMid);
return iCmdIndex;
}
return -3;
}
void CCtrlSocket::Response(RPS_NO iRpsNo)
{
static const RPS_INFO arrRps[]=
{
{CONN_OK, "150 Connection accepted"},
{ASC_OK, "150 Opening ASCII mode data connection for transfer."},
{BIN_OK, "150 Opening BINARY mode data connection for transfer."},
{PORT_OK, "200 Port command successful"},
{CMD_OK, "200 OK"},
{QUIT_OK, "200 GoodBye!"},
{SYST_OK, "215 UNIX emulated by Gotter FTP Server."},
{WELCOME, "220 Gotter FTP Server v1.0,you are welcome!."},
{TRAN_OK, "226 Transfer complete"},
{ABOR_OK, "226 ABOR command successful."},
{LOGIN_OK, "230 User successfully logged in."},
{FILE_OK, "250 File operated successfully."},
{DIR_OK, "250 Directory operated successfully."},
{RNTO_OK, "250 renamed."},
{USER_OK, "331 User name ok, need password."},
{RNFR_OK, "350 ready for destination name."},
{CONN_ERR, "426 connection error."},
{INTER_ERR, "450 Internal error."},
{ARG_ERR, "501 Invalid parameter."},
{CMD_ERR, "501 Unknown command."},
{IMPL_ERR, "502 Command not implemented."},
{SEQ_ERR, "503 Bad sequence of commands."},
{LOGIN_ERR, "530 Not logged in."},
{RIGHT_ERR, "550 Permission denied"},
{FILE_ERR, "550 File operated unsuccessfully."},
{DIR_ERR, "550 Directory operated unsuccessfully."}
};
int i,iCount=sizeof(arrRps)/sizeof(arrRps[0]);
for(i=0;i<iCount;i++){
if(arrRps[i].iRpsNo==iRpsNo){
Response(arrRps[i].pszInfo);
break;
}
}
if(i>=iCount){//不要出现这种情况
Response(INTER_ERR);
TRACE("Not response code!\n");
}
}
void CCtrlSocket::Response(const char *pszFormat,...)
{
static char szBuf[1024];
va_list args;
va_start(args,pszFormat);
vsnprintf(szBuf,sizeof(szBuf)-3,pszFormat,args);
va_end(args);
strcat(szBuf,"\r\n");
AppendResponse(szBuf);
}
void CCtrlSocket::AppendResponse(const char *pszResponse)
{
pthread_mutex_lock(&m_mutex);
m_sSend+=pszResponse;
pthread_mutex_unlock(&m_mutex);
}
int CCtrlSocket::CommitResponse()
{
pthread_mutex_lock(&m_mutex);
int iRet=0;
if(m_sSend.length()>0){
iRet=Send(m_sSend.c_str(),m_sSend.length());
if(iRet>0){
m_sSend.erase(0,iRet);
}
}
pthread_mutex_unlock(&m_mutex);
return iRet;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -