Files
2017-05-30 22:09:10 +08:00

333 lines
7.6 KiB
C++

#include "BaseSocket.h"
#include "EventDispatch.h"
typedef hash_map<net_handle_t, CBaseSocket*> SocketMap;
SocketMap g_socket_map;
void AddBaseSocket(CBaseSocket* pSocket)
{
g_socket_map.insert(make_pair((net_handle_t)pSocket->GetSocket(), pSocket));
}
void RemoveBaseSocket(CBaseSocket* pSocket)
{
g_socket_map.erase((net_handle_t)pSocket->GetSocket());
}
CBaseSocket* FindBaseSocket(net_handle_t fd)
{
CBaseSocket* pSocket = NULL;
SocketMap::iterator iter = g_socket_map.find(fd);
if (iter != g_socket_map.end())
{
pSocket = iter->second;
pSocket->AddRef();
}
return pSocket;
}
//////////////////////////////
CBaseSocket::CBaseSocket()
{
//LOG__(NET, "CBaseSocket::CBaseSocket");
m_socket = INVALID_SOCKET;
m_state = SOCKET_STATE_IDLE;
}
CBaseSocket::~CBaseSocket()
{
//LOG__(NET, "CBaseSocket::~CBaseSocket, socket=%d\n", m_socket);
}
int CBaseSocket::Listen(const char* server_ip, uint16_t port, callback_t callback, void* callback_data)
{
m_local_ip = server_ip;
m_local_port = port;
m_callback = callback;
m_callback_data = callback_data;
m_socket = socket(AF_INET, SOCK_STREAM, 0);
if (m_socket == INVALID_SOCKET)
{
printf("socket failed, err_code=%d\n", _GetErrorCode());
return NETLIB_ERROR;
}
_SetReuseAddr(m_socket);
_SetNonblock(m_socket);
sockaddr_in serv_addr;
_SetAddr(server_ip, port, &serv_addr);
int ret = ::bind(m_socket, (sockaddr*)&serv_addr, sizeof(serv_addr));
if (ret == SOCKET_ERROR)
{
LOG__(NET, _T("bind failed, err_code=%d"), _GetErrorCode());
closesocket(m_socket);
return NETLIB_ERROR;
}
ret = listen(m_socket, 64);
if (ret == SOCKET_ERROR)
{
LOG__(NET, _T("listen failed, err_code=%d"), _GetErrorCode());
closesocket(m_socket);
return NETLIB_ERROR;
}
m_state = SOCKET_STATE_LISTENING;
LOGA__(NET, "CBaseSocket::Listen on %s:%d", server_ip, port);
AddBaseSocket(this);
CEventDispatch::Instance()->AddEvent(m_socket, SOCKET_READ | SOCKET_EXCEP);
return NETLIB_OK;
}
net_handle_t CBaseSocket::Connect(const char* server_ip, uint16_t port, callback_t callback, void* callback_data)
{
LOGA__(NET, "CBaseSocket::Connect, server_ip=%s, port=%d", server_ip, port);
m_remote_ip = server_ip;
m_remote_port = port;
m_callback = callback;
m_callback_data = callback_data;
m_socket = socket(AF_INET, SOCK_STREAM, 0);
if (m_socket == INVALID_SOCKET)
{
LOG__(NET, _T("socket failed, err_code=%d"), _GetErrorCode());
return NETLIB_INVALID_HANDLE;
}
_SetNonblock(m_socket);
_SetNoDelay(m_socket);
sockaddr_in serv_addr;
_SetAddr(server_ip, port, &serv_addr);
int ret = connect(m_socket, (sockaddr*)&serv_addr, sizeof(serv_addr));
if ( (ret == SOCKET_ERROR) && (!_IsBlock(_GetErrorCode())) )
{
LOG__(NET, _T("connect failed, err_code=%d"), _GetErrorCode());
closesocket(m_socket);
return NETLIB_INVALID_HANDLE;
}
m_state = SOCKET_STATE_CONNECTING;
AddBaseSocket(this);
CEventDispatch::Instance()->AddEvent(m_socket, SOCKET_ALL);
return (net_handle_t)m_socket;
}
int CBaseSocket::Send(void* buf, int len)
{
if (m_state != SOCKET_STATE_CONNECTED)
return NETLIB_ERROR;
int ret = send(m_socket, (char*)buf, len, 0);
if (ret == SOCKET_ERROR)
{
int err_code = _GetErrorCode();
if (_IsBlock(err_code))
{
#if ((defined _MSC_VER) || (defined __APPLE__))
CEventDispatch::Instance()->AddEvent(m_socket, SOCKET_WRITE);
#endif
ret = 0;
}
else
{
LOG__(NET, _T("!!!send failed, error code: %d"), err_code);
}
}
else
{
LOGBIN_F__(SOCK, "Send", buf, len);
}
return ret;
}
int CBaseSocket::Recv(void* buf, int len)
{
return recv(m_socket, (char*)buf, len, 0);
}
int CBaseSocket::Close()
{
LOG__(APP, _T("close base socket"));
CEventDispatch::Instance()->RemoveEvent(m_socket, SOCKET_ALL);
RemoveBaseSocket(this);
closesocket(m_socket);
ReleaseRef();
return 0;
}
bool CBaseSocket::Shutdown(int nHow /*= sends*/)
{
return (0 == shutdown(m_socket, nHow));
}
void CBaseSocket::OnRead()
{
if (m_state == SOCKET_STATE_LISTENING)
{
_AcceptNewSocket();
}
else
{
u_long avail = 0;
if ( (ioctlsocket(m_socket, FIONREAD, &avail) == SOCKET_ERROR) || (avail == 0) )
{
m_callback(m_callback_data, NETLIB_MSG_CLOSE, (net_handle_t)m_socket, NULL);
}
else
{
m_callback(m_callback_data, NETLIB_MSG_READ, (net_handle_t)m_socket, NULL);
}
}
}
void CBaseSocket::OnWrite()
{
#if ((defined _MSC_VER) || (defined __APPLE__))
CEventDispatch::Instance()->RemoveEvent(m_socket, SOCKET_WRITE);
#endif
if (m_state == SOCKET_STATE_CONNECTING)
{
int error = 0;
socklen_t len = sizeof(error);
#ifdef _MSC_VER
getsockopt(m_socket, SOL_SOCKET, SO_ERROR, (char*)&error, &len);
#else
getsockopt(m_socket, SOL_SOCKET, SO_ERROR, (void*)&error, &len);
#endif
if (error) {
m_callback(m_callback_data, NETLIB_MSG_CLOSE, (net_handle_t)m_socket, NULL);
} else {
m_state = SOCKET_STATE_CONNECTED;
m_callback(m_callback_data, NETLIB_MSG_CONFIRM, (net_handle_t)m_socket, NULL);
}
}
else
{
m_callback(m_callback_data, NETLIB_MSG_WRITE, (net_handle_t)m_socket, NULL);
}
}
void CBaseSocket::OnClose()
{
m_state = SOCKET_STATE_CLOSING;
m_callback(m_callback_data, NETLIB_MSG_CLOSE, (net_handle_t)m_socket, NULL);
}
int CBaseSocket::_GetErrorCode()
{
#ifdef _MSC_VER
return WSAGetLastError();
#else
return errno;
#endif
}
bool CBaseSocket::_IsBlock(int error_code)
{
#ifdef _MSC_VER
return ( (error_code == WSAEINPROGRESS) || (error_code == WSAEWOULDBLOCK) );
#else
return ( (error_code == EINPROGRESS) || (error_code == EWOULDBLOCK) );
#endif
}
void CBaseSocket::_SetNonblock(SOCKET fd)
{
#ifdef _MSC_VER
u_long nonblock = 1;
int ret = ioctlsocket(fd, FIONBIO, &nonblock);
#else
int ret = fcntl(fd, F_SETFL, O_NONBLOCK | fcntl(fd, F_GETFL));
#endif
if (ret == SOCKET_ERROR)
{
LOG__(NET, _T("_SetNonblock failed, err_code=%d"), _GetErrorCode());
}
}
void CBaseSocket::_SetReuseAddr(SOCKET fd)
{
BOOL reuse = TRUE;
int ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse));
if (ret == SOCKET_ERROR)
{
LOG__(NET, _T("_SetReuseAddr failed, err_code=%d"), _GetErrorCode());
}
}
void CBaseSocket::_SetNoDelay(SOCKET fd)
{
BOOL nodelay = TRUE;
int ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&nodelay, sizeof(nodelay));
if (ret == SOCKET_ERROR)
{
LOG__(NET, _T("_SetNoDelay failed, err_code=%d"), _GetErrorCode());
}
}
void CBaseSocket::_SetAddr(const char* ip, const uint16_t port, sockaddr_in* pAddr)
{
memset(pAddr, 0, sizeof(sockaddr_in));
pAddr->sin_family = AF_INET;
pAddr->sin_port = htons(port);
pAddr->sin_addr.s_addr = inet_addr(ip);
if (pAddr->sin_addr.s_addr == INADDR_NONE)
{
hostent* host = gethostbyname(ip);
if (host == NULL)
{
LOGA__(NET, "gethostbyname failed, ip=%s", ip);
return;
}
pAddr->sin_addr.s_addr = *(uint32_t*)host->h_addr;
}
}
void CBaseSocket::_AcceptNewSocket()
{
SOCKET fd = 0;
sockaddr_in peer_addr;
socklen_t addr_len = sizeof(sockaddr_in);
char ip_str[64];
while ( (fd = accept(m_socket, (sockaddr*)&peer_addr, &addr_len)) != INVALID_SOCKET )
{
CBaseSocket* pSocket = new CBaseSocket();
uint32_t ip = ntohl(peer_addr.sin_addr.s_addr);
uint16_t port = ntohs(peer_addr.sin_port);
snprintf(ip_str, sizeof(ip_str), "%d.%d.%d.%d", ip >> 24, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF);
//LOG__(NET, "Accept fd=%d from %s:%d\n", fd, ip_str, port);
pSocket->SetSocket(fd);
pSocket->SetCallback(m_callback);
pSocket->SetCallbackData(m_callback_data);
pSocket->SetState(SOCKET_STATE_CONNECTED);
pSocket->SetRemoteIP(ip_str);
pSocket->SetRemotePort(port);
_SetNoDelay(fd);
_SetNonblock(fd);
AddBaseSocket(pSocket);
CEventDispatch::Instance()->AddEvent(fd, SOCKET_READ | SOCKET_EXCEP);
m_callback(m_callback_data, NETLIB_MSG_CONNECT, (net_handle_t)fd, NULL);
}
}