?? transporttcpip.cpp
字號:
// ========================================================
// TCP/IP Transport (connecting) implementation
//
// Design and Implementation by Floris van den Berg
// ========================================================
#pragma warning (disable : 4275)
#pragma warning (disable : 4786)
#include <winsock2.h>
#include <windows.h>
#include <process.h>
#include "Agent.h"
#include "OpenNet.h"
#include "EventDispatcher.h"
#include "TransportTCPIP.h"
#include "Utilities.h"
// --------------------------------------------------------
const int BUFFER_SIZE = 4096;
// --------------------------------------------------------
class CTransportTCPIP : public ITransport {
friend void CALLBACK RecvCompletion(DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags);
friend void CALLBACK SendCompletion(DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags);
public :
CTransportTCPIP();
virtual ~CTransportTCPIP();
public :
virtual bool DLL_CALLCONV Open(PROPERTYGROUP_HANDLE group);
virtual void DLL_CALLCONV PassHandleIndirect(long handle);
virtual void DLL_CALLCONV Close();
virtual void DLL_CALLCONV Connect(const char *host, int port);
virtual void DLL_CALLCONV Disconnect();
virtual bool DLL_CALLCONV SupportsSending();
virtual void* DLL_CALLCONV GetReferenceData(int id);
virtual bool DLL_CALLCONV GetOption(int option, void *value, int *size);
virtual bool DLL_CALLCONV SetOption(int option, void *value);
virtual bool DLL_CALLCONV CanBeBalanced();
virtual void DLL_CALLCONV PollProgress();
virtual void DLL_CALLCONV IncActionCount();
private :
bool GetOptionA(int option, void *value, int *size);
bool GetOptionB(int option, void *value, int *size);
void PollProgressSend();
void PollProgressRecv(WSANETWORKEVENTS &ne);
void PollProgressConnect(WSANETWORKEVENTS &ne);
void PollProgressClose(WSANETWORKEVENTS &ne);
void PostErrorEvent(DWORD error);
void PostSentPercentageEvent(DWORD percentage);
void DestroySocket();
private :
int m_ref_count;
boost::mutex m_cs;
Action *m_action;
bool m_connected;
SOCKET m_socket;
OVERLAPPED m_read_overlapped;
OVERLAPPED m_send_overlapped;
HANDLE m_wait_event;
WSABUF m_recv_buffer;
WSABUF m_send_buffer;
bool m_send_pending;
sockaddr_in m_sockaddr_in;
DWORD m_bytes_sent;
DWORD m_percentage_sent;
LONG m_action_count;
};
// --------------------------------------------------------
static void CALLBACK
RecvCompletion(DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags) {
CTransportTCPIP *object = (CTransportTCPIP *)lpOverlapped->hEvent;
if (object) {
if ((cbTransferred > 0) && (object->m_recv_buffer.buf)) {
EpDispatchSystemEvent(object, SYSTEM_DATA_IN, object->m_recv_buffer.buf, cbTransferred);
}
}
}
static void CALLBACK
SendCompletion(DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags) {
}
// --------------------------------------------------------
CTransportTCPIP::CTransportTCPIP() :
m_cs(),
m_action(NULL),
m_connected(false),
m_socket(NULL),
m_read_overlapped(),
m_send_overlapped(),
m_wait_event(),
m_recv_buffer(),
m_send_buffer(),
m_send_pending(false),
m_sockaddr_in(),
m_bytes_sent(0),
m_percentage_sent(0),
m_action_count(0) {
memset(&m_send_buffer, 0, sizeof(WSABUF));
memset(&m_recv_buffer, 0, sizeof(WSABUF));
memset(&m_read_overlapped, 0, sizeof(OVERLAPPED));
memset(&m_send_overlapped, 0, sizeof(OVERLAPPED));
m_read_overlapped.hEvent = this;
m_send_overlapped.hEvent = this;
memset(&m_recv_buffer, 0, sizeof(WSABUF));
m_recv_buffer.len = BUFFER_SIZE;
m_recv_buffer.buf = new char[BUFFER_SIZE];
m_wait_event = WSACreateEvent();
}
CTransportTCPIP::~CTransportTCPIP() {
WSACloseEvent(m_wait_event);
delete [] m_recv_buffer.buf;
}
// --------------------------------------------------------
// Open/Close/Connect/Disconnect a Plug
// --------------------------------------------------------
bool DLL_CALLCONV
CTransportTCPIP::Open(PROPERTYGROUP_HANDLE group) {
return (m_wait_event != WSA_INVALID_EVENT);
}
void DLL_CALLCONV
CTransportTCPIP::PassHandleIndirect(long handle) {
boost::mutex::scoped_lock scoped_lock(m_cs);
m_socket = (SOCKET)handle;
WSAEventSelect(m_socket, m_wait_event, FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE);
EpDispatchSystemEvent(this, SYSTEM_CONNECTED, NULL, 0);
}
void DLL_CALLCONV
CTransportTCPIP::Close() {
// be gone with thou socket!
DestroySocket();
// delete pending recv data
if (m_recv_buffer.buf)
delete [] m_recv_buffer.buf;
memset(&m_send_buffer, 0, sizeof(WSABUF));
memset(&m_recv_buffer, 0, sizeof(WSABUF));
}
void DLL_CALLCONV
CTransportTCPIP::Connect(const char *host, int port) {
EpEvent pm_event;
pm_event.reference_id = 0;
pm_event.protocol = CLSID_SYSTEM_PROTOCOL;
pm_event.msg = 0;
pm_event.size = 0;
pm_event.data = 0;
if (!m_connected) {
// if there is already a socket open, close it first
DestroySocket();
// create a socket and try to connect it
if ((m_socket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_IP, NULL, NULL, WSA_FLAG_OVERLAPPED)) != INVALID_SOCKET) {
if (WSAEventSelect(m_socket, m_wait_event, FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE) == 0) {
WSABUF callee_data;
memset(&callee_data, 0, sizeof(WSABUF));
memset(&m_sockaddr_in, 0, sizeof(sockaddr_in));
m_sockaddr_in.sin_family = PF_INET;
m_sockaddr_in.sin_port = htons(port);
m_sockaddr_in.sin_addr.s_addr = TCPIPResolveHost(host);
if (WSAConnect(m_socket, (sockaddr *)&m_sockaddr_in, sizeof(sockaddr_in), NULL, &callee_data, NULL, NULL) == SOCKET_ERROR) {
DWORD error_code = WSAGetLastError();
if (error_code != WSAEWOULDBLOCK) {
PostErrorEvent(error_code);
} else {
return;
}
} else {
m_connected = true;
return;
}
}
// and close the socket again
DestroySocket();
}
}
}
void DLL_CALLCONV
CTransportTCPIP::Disconnect() {
if ((m_socket) && (m_connected)) {
boost::mutex::scoped_lock scoped_lock(m_cs);
// close the socket
DestroySocket();
// we are now disconnected
m_connected = false;
// send disconnect event
EpDispatchSystemEvent(this, SYSTEM_DISCONNECTED, 0, NULL);
}
}
bool DLL_CALLCONV
CTransportTCPIP::SupportsSending() {
return true;
}
void * DLL_CALLCONV
CTransportTCPIP::GetReferenceData(int id) {
return NULL;
}
bool DLL_CALLCONV
CTransportTCPIP::GetOption(int option, void *value, int *size) {
boost::mutex::scoped_lock scoped_lock(m_cs);
if ((value == 0) && (size != 0))
return GetOptionA(option, value, size);
else
return GetOptionB(option, value, size);
}
bool DLL_CALLCONV
CTransportTCPIP::SetOption(int option, void *value) {
return false;
}
bool DLL_CALLCONV
CTransportTCPIP::CanBeBalanced() {
return true;
}
void
CTransportTCPIP::PollProgressSend() {
if (m_action) {
if (!m_send_pending) {
m_bytes_sent = 0;
m_percentage_sent = 0;
DWORD bytes_sent = 0;
memset(&m_send_buffer, 0, sizeof(WSABUF));
m_send_buffer.len = m_action->send_size;
m_send_buffer.buf = (char *)m_action->send_data;
if (WSASend(m_socket, &m_send_buffer, 1, &bytes_sent, 0, &m_send_overlapped, SendCompletion) == SOCKET_ERROR) {
DWORD error_code = WSAGetLastError();
if (error_code != WSA_IO_PENDING) {
switch(error_code) {
case WSAENETDOWN :
EpDispatchSystemEvent(this, SYSTEM_TCPIP_SUBSYSTEM_FAILED);
break;
case WSAENETRESET :
EpDispatchSystemEvent(this, SYSTEM_TCPIP_NET_RESET);
break;
case WSAENOBUFS :
EpDispatchSystemEvent(this, SYSTEM_TCPIP_NO_BUFFERSPACE);
break;
case WSAENOTCONN :
EpDispatchSystemEvent(this, SYSTEM_TCPIP_NOT_CONNECTED);
break;
case WSAECONNRESET :
EpDispatchSystemEvent(this, SYSTEM_TCPIP_CONNECTION_RESET);
break;
case WSAECONNABORTED :
EpDispatchSystemEvent(this, SYSTEM_TCPIP_CONNECTION_ABORTED);
break;
case WSA_OPERATION_ABORTED :
EpDispatchSystemEvent(this, SYSTEM_TCPIP_OPERATION_ABORTED);
break;
default :
EpDispatchSystemEvent(this, SYSTEM_TCPIP_UNIMPLEMENTED, &error_code, sizeof(DWORD));
break;
};
// post a generic SYSTEM_IO_ERROR after the specific TCP error
PostErrorEvent(error_code);
// tell the agent the sending failed
EpPacketSent(this, false);
// send a disconnect event
if (m_connected)
EpDispatchSystemEvent(this, SYSTEM_DISCONNECTED);
// abort! abort! abort!
DestroySocket();
} else {
m_send_pending = true;
}
} else {
DWORD transferred = 0;
DWORD flags = 0;
if (WSAGetOverlappedResult(m_socket, &m_send_overlapped, &transferred, FALSE, &flags)) {
if (transferred > 0) {
// update the size
m_bytes_sent += transferred;
// send an event for the number of bytes we sent
// send an event for the percentage we sent
EpDispatchSystemEvent(this, SYSTEM_SENT_PROGRESS_BYTES, &m_bytes_sent, 4);
PostSentPercentageEvent(100 * m_bytes_sent / m_action->send_size);
// finished sending. if so, sent an event and get ready
// to send the next action
if (m_bytes_sent == m_action->send_size) {
m_action = NULL;
m_send_pending = false;
EpPacketSent(this, true);
}
}
}
}
}
}
}
void
CTransportTCPIP::PollProgressRecv(WSANETWORKEVENTS &ne) {
if ((ne.lNetworkEvents & FD_READ) == FD_READ) {
if (ne.iErrorCode[FD_READ_BIT] != 0) {
switch(ne.iErrorCode[FD_READ_BIT]) {
case WSAENETDOWN :
EpDispatchSystemEvent(this, SYSTEM_TCPIP_SUBSYSTEM_FAILED);
break;
default :
EpDispatchSystemEvent(this, SYSTEM_TCPIP_UNIMPLEMENTED, &ne.iErrorCode[FD_READ_BIT], 4);
break;
};
// post a generic SYSTEM_IO_ERROR after the specific TCP error
PostErrorEvent(WSAGetLastError());
// disconnect since we can't do anything anymore on an error socket
DestroySocket();
} else {
DWORD flags = 0;
u_long read = 0;
WSARecv(m_socket, &m_recv_buffer, 1, &read, &flags, &m_read_overlapped, RecvCompletion);
}
}
}
void
CTransportTCPIP::PollProgressConnect(WSANETWORKEVENTS &ne) {
if ((ne.lNetworkEvents & FD_CONNECT) == FD_CONNECT) {
if (ne.iErrorCode[FD_CONNECT_BIT] != 0) {
switch(ne.iErrorCode[FD_CONNECT_BIT]) {
case WSAEADDRNOTAVAIL :
EpDispatchSystemEvent(this, SYSTEM_TCPIP_ADDRESS_UNAVAILABLE);
break;
case WSAEAFNOSUPPORT :
EpDispatchSystemEvent(this, SYSTEM_TCPIP_NO_SUPPORT);
break;
case WSAECONNREFUSED :
EpDispatchSystemEvent(this, SYSTEM_TCPIP_CONNECTION_REFUSED);
break;
case WSAENETUNREACH :
EpDispatchSystemEvent(this, SYSTEM_TCPIP_NET_UNREACHABLE);
break;
case WSAENOBUFS :
EpDispatchSystemEvent(this, SYSTEM_TCPIP_NO_BUFFERSPACE);
break;
case WSAETIMEDOUT :
EpDispatchSystemEvent(this, SYSTEM_TCPIP_CONNECTION_TIMEOUT);
break;
default :
EpDispatchSystemEvent(this, SYSTEM_TCPIP_UNIMPLEMENTED, &ne.iErrorCode[FD_CONNECT_BIT], 4);
break;
};
// post a generic SYSTEM_IO_ERROR after the specific TCP error
PostErrorEvent(WSAGetLastError());
// abort! abort! abort!
DestroySocket();
} else {
EpDispatchSystemEvent(this, SYSTEM_CONNECTED, NULL, 0);
m_connected = true;
}
}
}
void
CTransportTCPIP::PollProgressClose(WSANETWORKEVENTS &ne) {
if ((ne.lNetworkEvents & FD_CLOSE) == FD_CLOSE) {
if (ne.iErrorCode[FD_CLOSE_BIT] != 0) {
switch (ne.iErrorCode[FD_CLOSE_BIT]) {
case WSAECONNRESET :
EpDispatchSystemEvent(this, SYSTEM_TCPIP_CONNECTION_RESET);
break;
case WSAECONNABORTED :
EpDispatchSystemEvent(this, SYSTEM_TCPIP_CONNECTION_ABORTED);
break;
default :
EpDispatchSystemEvent(this, SYSTEM_TCPIP_UNIMPLEMENTED, &ne.iErrorCode[FD_CLOSE_BIT], 4);
break;
}
}
DestroySocket();
}
}
void
CTransportTCPIP::PostErrorEvent(DWORD error) {
if (error != ERROR_SUCCESS)
EpDispatchSystemEvent(this, SYSTEM_IO_ERROR, &error, 4);
}
void
CTransportTCPIP::PostSentPercentageEvent(DWORD percentage) {
if (percentage != m_percentage_sent)
EpDispatchSystemEvent(this, SYSTEM_SENT_PROGRESS_PERCENTAGE, &percentage, 4);
}
void
CTransportTCPIP::DestroySocket() {
if (m_socket) {
// cancel all pending actions
if (m_action) {
m_action = NULL;
m_send_pending = false;
m_action_count = 0;
EpPacketSent(this, false);
}
// destroy the socket
unsigned long bio = 0;
WSAEventSelect(m_socket, m_wait_event, 0);
ioctlsocket(m_socket, FIONBIO, &bio);
shutdown(m_socket, SD_SEND);
closesocket(m_socket);
m_socket = NULL;
m_connected = false;
}
}
void DLL_CALLCONV
CTransportTCPIP::PollProgress() {
if (m_socket) {
boost::mutex::scoped_lock scoped_lock(m_cs);
// check for a new action to send, if we aren't sending anything
if ((m_action == NULL) && (!m_send_pending) && (m_action_count > 0)) {
--m_action_count;
m_action = EpGetNextAction(this);
}
// try to send
PollProgressSend();
// then check for received status messages or errors
WSANETWORKEVENTS ne;
memset(&ne, 0, sizeof(ne));
if (WSAEnumNetworkEvents(m_socket, m_wait_event, &ne) == 0) {
PollProgressRecv(ne);
PollProgressConnect(ne);
PollProgressClose(ne);
}
} else if (m_action) {
m_action = NULL;
m_send_pending = false;
EpPacketSent(this, false);
if (!m_connected)
EpDispatchSystemEvent(this, SYSTEM_TCPIP_NOT_CONNECTED, 0, NULL);
}
}
// --------------------------------------------------------
// Own class methods
// --------------------------------------------------------
bool
CTransportTCPIP::GetOptionA(int option, void *value, int *size) {
switch(option) {
case TCP_LOCALHOST :
*size = TCPIPGetLocalHost(m_socket).length() + 1;;
break;
case TCP_PEERNAME :
return false;
};
return false;
}
bool
CTransportTCPIP::GetOptionB(int option, void *value, int *size) {
switch(option) {
case TCP_LOCALHOST :
strcpy((char *)value, TCPIPGetLocalHost(m_socket).c_str());
return true;
case TCP_PEERNAME :
return false;
}
return false;
}
void DLL_CALLCONV
CTransportTCPIP::IncActionCount() {
boost::mutex::scoped_lock scoped_lock(m_cs);
++m_action_count;
}
// --------------------------------------------------------
// Instantation function
// --------------------------------------------------------
HRESULT DLL_CALLCONV
TCPIPCreate(void **iif) {
CTransportTCPIP *object = new CTransportTCPIP;
if (object) {
*iif = object;
return S_OK;
}
return E_FAIL;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -