📄 emsocket.cpp
字号:
//this file is part of eMule
//Copyright (C)2002 Merkur ( merkur-@users.sourceforge.net / http://www.emule-project.net )
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either
//version 2 of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include "StdAfx.h"
#include "emsocket.h"
#include "opcodes.h"
#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
namespace {
inline void EMTrace(char* fmt, ...) {
#ifdef EMSOCKET_DEBUG
va_list argptr;
char bufferline[512];
va_start(argptr, fmt);
_vsnprintf(bufferline, 512, fmt, argptr);
va_end(argptr);
//(Ornis+)
char osDate[30],osTime[30];
char temp[1024];
_strtime( osTime );
_strdate( osDate );
int len = _snprintf(temp,1021,"%s %s: %s",osDate,osTime,bufferline);
temp[len++] = 0x0d;
temp[len++] = 0x0a;
temp[len+1] = 0;
HANDLE hFile = CreateFile("c:\\EMSocket.log", // open MYFILE.TXT
GENERIC_WRITE, // open for reading
FILE_SHARE_READ, // share for reading
NULL, // no security
OPEN_ALWAYS, // existing file only
FILE_ATTRIBUTE_NORMAL, // normal file
NULL); // no attr. template
if (hFile != INVALID_HANDLE_VALUE)
{
DWORD nbBytesWritten = 0;
SetFilePointer(hFile, 0, NULL, FILE_END);
BOOL b = WriteFile(
hFile, // handle to file
temp, // data buffer
len, // number of bytes to write
&nbBytesWritten, // number of bytes written
NULL // overlapped buffer
);
CloseHandle(hFile);
}
#else
//va_list argptr;
//va_start(argptr, fmt);
//va_end(argptr);
#endif //EMSOCKET_DEBUG
}
}
CEMSocket::CEMSocket(void){
byConnected = ES_NOTCONNECTED;
// Download (pseudo) rate control
downloadLimit = 0;
downloadLimitEnable = false;
pendingOnReceive = false;
// Download partial header
// memset(pendingHeader, 0, sizeof(pendingHeader));
pendingHeaderSize = 0;
// Download partial packet
pendingPacket = NULL;
pendingPacketSize = 0;
// Upload control
sendbuffer = NULL;
sendblen = 0;
sent = 0;
m_bLinkedPackets = false;
}
CEMSocket::~CEMSocket(){
EMTrace("CEMSocket::~CEMSocket() on %d",(SOCKET)this);
ClearQueues();
AsyncSelect(0);
}
void CEMSocket::ClearQueues(){
EMTrace("CEMSocket::ClearQueues on %d",(SOCKET)this);
for(POSITION pos = controlpacket_queue.GetHeadPosition(); pos != NULL; controlpacket_queue.GetNext(pos))
delete controlpacket_queue.GetAt(pos);
controlpacket_queue.RemoveAll();
for(POSITION pos = standartpacket_queue.GetHeadPosition(); pos != NULL; standartpacket_queue.GetNext(pos))
delete standartpacket_queue.GetAt(pos);
standartpacket_queue.RemoveAll();
// Download (pseudo) rate control
downloadLimit = 0;
downloadLimitEnable = false;
pendingOnReceive = false;
// Download partial header
// memset(pendingHeader, 0, sizeof(pendingHeader));
pendingHeaderSize = 0;
// Download partial packet
if(pendingPacket != NULL){
delete pendingPacket;
pendingPacket = NULL;
pendingPacketSize = 0;
}
// Upload control
if(sendbuffer != NULL){
delete[] sendbuffer;
sendbuffer = NULL;
}
sendblen = 0;
sent = 0;
m_bLinkedPackets = false;
}
void CEMSocket::OnClose(int nErrorCode){
byConnected = ES_DISCONNECTED;
CAsyncSocket::OnClose(nErrorCode);
ClearQueues();
};
BOOL CEMSocket::AsyncSelect(long lEvent){
if (lEvent&FD_READ)
EMTrace(" FD_READ");
if (lEvent&FD_CLOSE)
EMTrace(" FD_CLOSE");
if (lEvent&FD_WRITE)
EMTrace(" FD_WRITE");
if (m_hSocket != INVALID_SOCKET)
return CAsyncSocket::AsyncSelect(lEvent);
return true;
}
void CEMSocket::OnReceive(int nErrorCode){
// the 2 meg size was taken from another place
static char GlobalReadBuffer[2000000];
// Check for an error code
if(nErrorCode != 0){
OnError(nErrorCode);
return;
}
// Check current connection state
if(byConnected == ES_DISCONNECTED){
return;
}
else {
byConnected = ES_CONNECTED; // ES_DISCONNECTED, ES_NOTCONNECTED, ES_CONNECTED
}
// CPU load improvement
if(downloadLimitEnable == true && downloadLimit == 0){
EMTrace("CEMSocket::OnReceive blocked by limit");
pendingOnReceive = true;
return;
}
// Remark: an overflow can not occur here
uint32 readMax = sizeof(GlobalReadBuffer) - pendingHeaderSize;
if(downloadLimitEnable == true && readMax > downloadLimit) {
readMax = downloadLimit;
}
// We attempt to read up to 2 megs at a time (minus whatever is in our internal read buffer)
uint32 ret = Receive(GlobalReadBuffer + pendingHeaderSize, readMax);
if(ret == SOCKET_ERROR || ret == 0){
return;
}
// Bandwidth control
if(downloadLimitEnable == true){
// Update limit
downloadLimit -= ret;
}
// CPU load improvement
// Detect if the socket's buffer is empty (or the size did match...)
pendingOnReceive = (ret == readMax) ? true : false;
// Copy back the partial header into the global read buffer for processing
if(pendingHeaderSize > 0) {
memcpy(GlobalReadBuffer, pendingHeader, pendingHeaderSize);
ret += pendingHeaderSize;
pendingHeaderSize = 0;
}
char *rptr = GlobalReadBuffer; // floating index initialized with begin of buffer
const char *rend = GlobalReadBuffer + ret; // end of buffer
// Loop, processing packets until we run out of them
while((rend - rptr >= PACKET_HEADER_SIZE) ||
((pendingPacket != NULL) && (rend - rptr > 0 ))){
// Two possibilities here:
//
// 1. There is no pending incoming packet
// 2. There is already a partial pending incoming packet
//
// It's important to remember that emule exchange two kinds of packet
// - The control packet
// - The data packet for the transport of the block
//
// The biggest part of the traffic is done with the data packets.
// The default size of one block is 10240 bytes (or less if compressed), but the
// maximal size for one packet on the network is 1300 bytes. It's the reason
// why most of the Blocks are splitted before to be sent.
//
// Conclusion: When the download limit is disabled, this method can be at least
// called 8 times (10240/1300) by the lower layer before a splitted packet is
// rebuild and transfered to the above layer for processing.
//
// The purpose of this algorithm is to limit the amount of data exchanged between buffers
if(pendingPacket == NULL){
pendingPacket = new Packet(rptr); // Create new packet container.
rptr += 6; // Only the header is initialized so far
// Bugfix We still need to check for a valid protocol
// Remark: the default eMule v0.26b had removed this test......
switch (pendingPacket->prot){
case OP_EDONKEYPROT:
case OP_PACKEDPROT:
case OP_EMULEPROT:
break;
default:
EMTrace("CEMSocket::OnReceive ERROR Wrong header");
delete pendingPacket;
pendingPacket = NULL;
OnError(ERR_WRONGHEADER);
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -