TeamTalk网络模块是自己封装的netlib
#ifndef __NETLIB_H__
#define __NETLIB_H__
#include "ostype.h"
#define NETLIB_OPT_SET_CALLBACK 1
#define NETLIB_OPT_SET_CALLBACK_DATA 2
#define NETLIB_OPT_GET_REMOTE_IP 3
#define NETLIB_OPT_GET_REMOTE_PORT 4
#define NETLIB_OPT_GET_LOCAL_IP 5
#define NETLIB_OPT_GET_LOCAL_PORT 6
#define NETLIB_OPT_SET_SEND_BUF_SIZE 7
#define NETLIB_OPT_SET_RECV_BUF_SIZE 8
#define NETLIB_MAX_SOCKET_BUF_SIZE (128 * 1024)
#ifdef __cplusplus
extern "C" {
#endif
int netlib_init();
int netlib_destroy();
int netlib_listen(
const char* server_ip,
uint16_t port,
callback_t callback,
void* callback_data);
net_handle_t netlib_connect(
const char* server_ip,
uint16_t port,
callback_t callback,
void* callback_data);
int netlib_send(net_handle_t handle, void* buf, int len);
int netlib_recv(net_handle_t handle, void* buf, int len);
int netlib_close(net_handle_t handle);
int netlib_option(net_handle_t handle, int opt, void* optval);
int netlib_register_timer(callback_t callback, void* user_data, uint64_t interval);
int netlib_delete_timer(callback_t callback, void* user_data);
int netlib_add_loop(callback_t callback, void* user_data);
void netlib_eventloop(uint32_t wait_timeout = 100);
void netlib_stop_event();
bool netlib_is_running();
#ifdef __cplusplus
}
#endif
#endif
#include "netlib.h"
#include "BaseSocket.h"
#include "EventDispatch.h"
int netlib_init()
{
int ret = NETLIB_OK;
#ifdef _WIN32
WSADATA wsaData;
WORD wReqest = MAKEWORD(1, 1);
if (WSAStartup(wReqest, &wsaData) != 0)
{
ret = NETLIB_ERROR;
}
#endif
return ret;
}
int netlib_destroy()
{
int ret = NETLIB_OK;
#ifdef _WIN32
if (WSACleanup() != 0)
{
ret = NETLIB_ERROR;
}
#endif
return ret;
}
int netlib_listen(
const char* server_ip,
uint16_t port,
callback_t callback,
void* callback_data)
{
CBaseSocket* pSocket = new CBaseSocket();
if (!pSocket)
return NETLIB_ERROR;
int ret = pSocket->Listen(server_ip, port, callback, callback_data);
if (ret == NETLIB_ERROR)
delete pSocket;
return ret;
}
net_handle_t netlib_connect(
const char* server_ip,
uint16_t port,
callback_t callback,
void* callback_data)
{
CBaseSocket* pSocket = new CBaseSocket();
if (!pSocket)
return NETLIB_INVALID_HANDLE;
net_handle_t handle = pSocket->Connect(server_ip, port, callback, callback_data);
if (handle == NETLIB_INVALID_HANDLE)
delete pSocket;
return handle;
}
int netlib_send(net_handle_t handle, void* buf, int len)
{
CBaseSocket* pSocket = FindBaseSocket(handle);
if (!pSocket)
{
return NETLIB_ERROR;
}
int ret = pSocket->Send(buf, len);
pSocket->ReleaseRef();
return ret;
}
int netlib_recv(net_handle_t handle, void* buf, int len)
{
CBaseSocket* pSocket = FindBaseSocket(handle);
if (!pSocket)
return NETLIB_ERROR;
int ret = pSocket->Recv(buf, len);
pSocket->ReleaseRef();
return ret;
}
int netlib_close(net_handle_t handle)
{
CBaseSocket* pSocket = FindBaseSocket(handle);
if (!pSocket)
return NETLIB_ERROR;
int ret = pSocket->Close();
pSocket->ReleaseRef();
return ret;
}
int netlib_option(net_handle_t handle, int opt, void* optval)
{
CBaseSocket* pSocket = FindBaseSocket(handle);
if (!pSocket)
return NETLIB_ERROR;
if ((opt >= NETLIB_OPT_GET_REMOTE_IP) && !optval)
return NETLIB_ERROR;
switch (opt)
{
case NETLIB_OPT_SET_CALLBACK:
pSocket->SetCallback((callback_t)optval);
break;
case NETLIB_OPT_SET_CALLBACK_DATA:
pSocket->SetCallbackData(optval);
break;
case NETLIB_OPT_GET_REMOTE_IP:
*(string*)optval = pSocket->GetRemoteIP();
break;
case NETLIB_OPT_GET_REMOTE_PORT:
*(uint16_t*)optval = pSocket->GetRemotePort();
break;
case NETLIB_OPT_GET_LOCAL_IP:
*(string*)optval = pSocket->GetLocalIP();
break;
case NETLIB_OPT_GET_LOCAL_PORT:
*(uint16_t*)optval = pSocket->GetLocalPort();
break;
case NETLIB_OPT_SET_SEND_BUF_SIZE:
pSocket->SetSendBufSize(*(uint32_t*)optval);
break;
case NETLIB_OPT_SET_RECV_BUF_SIZE:
pSocket->SetRecvBufSize(*(uint32_t*)optval);
break;
}
pSocket->ReleaseRef();
return NETLIB_OK;
}
int netlib_register_timer(callback_t callback, void* user_data, uint64_t interval)
{
CEventDispatch::Instance()->AddTimer(callback, user_data, interval);
return 0;
}
int netlib_delete_timer(callback_t callback, void* user_data)
{
CEventDispatch::Instance()->RemoveTimer(callback, user_data);
return 0;
}
int netlib_add_loop(callback_t callback, void* user_data)
{
CEventDispatch::Instance()->AddLoop(callback, user_data);
return 0;
}
void netlib_eventloop(uint32_t wait_timeout)
{
CEventDispatch::Instance()->StartDispatch(wait_timeout);
}
void netlib_stop_event()
{
CEventDispatch::Instance()->StopDispatch();
}
bool netlib_is_running()
{
return CEventDispatch::Instance()->isRunning();
}
//socket封装
/*
* a wrap for non-block socket class for Windows, LINUX and MacOS X platform
*/
#ifndef __SOCKET_H__
#define __SOCKET_H__
#include "ostype.h"
#include "util.h"
enum
{
SOCKET_STATE_IDLE,
SOCKET_STATE_LISTENING,
SOCKET_STATE_CONNECTING,
SOCKET_STATE_CONNECTED,
SOCKET_STATE_CLOSING
};
class CBaseSocket : public CRefObject
{
public:
CBaseSocket();
virtual ~CBaseSocket();
SOCKET GetSocket() { return m_socket; }
void SetSocket(SOCKET fd) { m_socket = fd; }
void SetState(uint8_t state) { m_state = state; }
void SetCallback(callback_t callback) { m_callback = callback; }
void SetCallbackData(void* data) { m_callback_data = data; }
void SetRemoteIP(char* ip) { m_remote_ip = ip; }
void SetRemotePort(uint16_t port) { m_remote_port = port; }
void SetSendBufSize(uint32_t send_size);
void SetRecvBufSize(uint32_t recv_size);
const char* GetRemoteIP() { return m_remote_ip.c_str(); }
uint16_t GetRemotePort() { return m_remote_port; }
const char* GetLocalIP() { return m_local_ip.c_str(); }
uint16_t GetLocalPort() { return m_local_port; }
public:
int Listen(
const char* server_ip,
uint16_t port,
callback_t callback,
void* callback_data);
net_handle_t Connect(
const char* server_ip,
uint16_t port,
callback_t callback,
void* callback_data);
int Send(void* buf, int len);
int Recv(void* buf, int len);
int Close();
public:
void OnRead();
void OnWrite();
void OnClose();
private:
int _GetErrorCode();
bool _IsBlock(int error_code);
void _SetNonblock(SOCKET fd);
void _SetReuseAddr(SOCKET fd);
void _SetNoDelay(SOCKET fd);
void _SetAddr(const char* ip, const uint16_t port, sockaddr_in* pAddr);
void _AcceptNewSocket();
private:
string m_remote_ip;
uint16_t m_remote_port;
string m_local_ip;
uint16_t m_local_port;
callback_t m_callback;
void* m_callback_data;
uint8_t m_state;
SOCKET m_socket;
};
CBaseSocket* FindBaseSocket(net_handle_t fd);
#endif
#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("CBaseSocket::CBaseSocket\n");
m_socket = INVALID_SOCKET;
m_state = SOCKET_STATE_IDLE;
}
CBaseSocket::~CBaseSocket()
{
//log("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("bind failed, err_code=%d", _GetErrorCode());
closesocket(m_socket);
return NETLIB_ERROR;
}
ret = listen(m_socket, 64);
if (ret == SOCKET_ERROR)
{
log("listen failed, err_code=%d", _GetErrorCode());
closesocket(m_socket);
return NETLIB_ERROR;
}
m_state = SOCKET_STATE_LISTENING;
log("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)
{
log("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("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("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 _WIN32) || (defined __APPLE__))
CEventDispatch::Instance()->AddEvent(m_socket, SOCKET_WRITE);
#endif
ret = 0;
//log("socket send block fd=%d", m_socket);
}
else
{
log("!!!send failed, error code: %d", err_code);
}
}
return ret;
}
int CBaseSocket::Recv(void* buf, int len)
{
return recv(m_socket, (char*)buf, len, 0);
}
int CBaseSocket::Close()
{
CEventDispatch::Instance()->RemoveEvent(m_socket, SOCKET_ALL);
RemoveBaseSocket(this);
closesocket(m_socket);
ReleaseRef();
return 0;
}
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 _WIN32) || (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 _WIN32
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);
}
void CBaseSocket::SetSendBufSize(uint32_t send_size)
{
int ret = setsockopt(m_socket, SOL_SOCKET, SO_SNDBUF, &send_size, 4);
if (ret == SOCKET_ERROR) {
log("set SO_SNDBUF failed for fd=%d", m_socket);
}
socklen_t len = 4;
int size = 0;
getsockopt(m_socket, SOL_SOCKET, SO_SNDBUF, &size, &len);
log("socket=%d send_buf_size=%d", m_socket, size);
}
void CBaseSocket::SetRecvBufSize(uint32_t recv_size)
{
int ret = setsockopt(m_socket, SOL_SOCKET, SO_RCVBUF, &recv_size, 4);
if (ret == SOCKET_ERROR) {
log("set SO_RCVBUF failed for fd=%d", m_socket);
}
socklen_t len = 4;
int size = 0;
getsockopt(m_socket, SOL_SOCKET, SO_RCVBUF, &size, &len);
log("socket=%d recv_buf_size=%d", m_socket, size);
}
int CBaseSocket::_GetErrorCode()
{
#ifdef _WIN32
return WSAGetLastError();
#else
return errno;
#endif
}
bool CBaseSocket::_IsBlock(int error_code)
{
#ifdef _WIN32
return ( (error_code == WSAEINPROGRESS) || (error_code == WSAEWOULDBLOCK) );
#else
return ( (error_code == EINPROGRESS) || (error_code == EWOULDBLOCK) );
#endif
}
void CBaseSocket::_SetNonblock(SOCKET fd)
{
#ifdef _WIN32
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("_SetNonblock failed, err_code=%d", _GetErrorCode());
}
}
void CBaseSocket::_SetReuseAddr(SOCKET fd)
{
int reuse = 1;
int ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse));
if (ret == SOCKET_ERROR)
{
log("_SetReuseAddr failed, err_code=%d", _GetErrorCode());
}
}
void CBaseSocket::_SetNoDelay(SOCKET fd)
{
int nodelay = 1;
int ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&nodelay, sizeof(nodelay));
if (ret == SOCKET_ERROR)
{
log("_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)
{
log("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("AcceptNewSocket, socket=%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);
}
}
m_callback定义在imconn.cpp中
/*
* imconn.h
*
* Created on: 2013-6-5
* Author: ziteng
*/
#ifndef IMCONN_H_
#define IMCONN_H_
#include "netlib.h"
#include "util.h"
#include "ImPduBase.h"
#define SERVER_HEARTBEAT_INTERVAL 5000
#define SERVER_TIMEOUT 30000
#define CLIENT_HEARTBEAT_INTERVAL 30000
#define CLIENT_TIMEOUT 120000
#define MOBILE_CLIENT_TIMEOUT 60000 * 5
#define READ_BUF_SIZE 2048
class CImConn : public CRefObject
{
public:
CImConn();
virtual ~CImConn();
bool IsBusy() { return m_busy; }
int SendPdu(CImPdu* pPdu) { return Send(pPdu->GetBuffer(), pPdu->GetLength()); }
int Send(void* data, int len);
virtual void OnConnect(net_handle_t handle) { m_handle = handle; }
virtual void OnConfirm() {}
virtual void OnRead();
virtual void OnWrite();
virtual void OnClose() {}
virtual void OnTimer(uint64_t curr_tick) {}
virtual void OnWriteCompelete() {};
virtual void HandlePdu(CImPdu* pPdu) {}
protected:
net_handle_t m_handle;
bool m_busy;
string m_peer_ip;
uint16_t m_peer_port;
CSimpleBuffer m_in_buf;
CSimpleBuffer m_out_buf;
bool m_policy_conn;
uint32_t m_recv_bytes;
uint64_t m_last_send_tick;
uint64_t m_last_recv_tick;
uint64_t m_last_all_user_tick;
};
typedef hash_map<net_handle_t, CImConn*> ConnMap_t;
typedef hash_map<uint32_t, CImConn*> UserMap_t;
void imconn_callback(void* callback_data, uint8_t msg, uint32_t handle, void* pParam);
void ReadPolicyFile();
#endif /* IMCONN_H_ */
/*
* imconn.cpp
*
* Created on: 2013-6-5
* Author: ziteng@mogujie.com
*/
#include "imconn.h"
//static uint64_t g_send_pkt_cnt = 0; // 发送数据包总数
//static uint64_t g_recv_pkt_cnt = 0; // 接收数据包总数
static CImConn* FindImConn(ConnMap_t* imconn_map, net_handle_t handle)
{
CImConn* pConn = NULL;
ConnMap_t::iterator iter = imconn_map->find(handle);
if (iter != imconn_map->end())
{
pConn = iter->second;
pConn->AddRef();
}
return pConn;
}
void imconn_callback(void* callback_data, uint8_t msg, uint32_t handle, void* pParam)
{
NOTUSED_ARG(handle);
NOTUSED_ARG(pParam);
if (!callback_data)
return;
ConnMap_t* conn_map = (ConnMap_t*)callback_data;
CImConn* pConn = FindImConn(conn_map, handle);
if (!pConn)
return;
//log("msg=%d, handle=%d ", msg, handle);
switch (msg)
{
case NETLIB_MSG_CONFIRM:
pConn->OnConfirm();
break;
case NETLIB_MSG_READ:
pConn->OnRead();
break;
case NETLIB_MSG_WRITE:
pConn->OnWrite();
break;
case NETLIB_MSG_CLOSE:
pConn->OnClose();
break;
default:
log("!!!imconn_callback error msg: %d ", msg);
break;
}
pConn->ReleaseRef();
}
//
CImConn::CImConn()
{
//log("CImConn::CImConn ");
m_busy = false;
m_handle = NETLIB_INVALID_HANDLE;
m_recv_bytes = 0;
m_last_send_tick = m_last_recv_tick = get_tick_count();
}
CImConn::~CImConn()
{
//log("CImConn::~CImConn, handle=%d ", m_handle);
}
int CImConn::Send(void* data, int len)
{
m_last_send_tick = get_tick_count();
// ++g_send_pkt_cnt;
if (m_busy)
{
m_out_buf.Write(data, len);
return len;
}
int offset = 0;
int remain = len;
while (remain > 0) {
int send_size = remain;
if (send_size > NETLIB_MAX_SOCKET_BUF_SIZE) {
send_size = NETLIB_MAX_SOCKET_BUF_SIZE;
}
int ret = netlib_send(m_handle, (char*)data + offset , send_size);
if (ret <= 0) {
ret = 0;
break;
}
offset += ret;
remain -= ret;
}
if (remain > 0)
{
m_out_buf.Write((char*)data + offset, remain);
m_busy = true;
log("send busy, remain=%d ", m_out_buf.GetWriteOffset());
}
else
{
OnWriteCompelete();
}
return len;
}
void CImConn::OnRead()
{
for (;;)
{
uint32_t free_buf_len = m_in_buf.GetAllocSize() - m_in_buf.GetWriteOffset();
if (free_buf_len < READ_BUF_SIZE)
m_in_buf.Extend(READ_BUF_SIZE);
int ret = netlib_recv(m_handle, m_in_buf.GetBuffer() + m_in_buf.GetWriteOffset(), READ_BUF_SIZE);
if (ret <= 0)
break;
m_recv_bytes += ret;
m_in_buf.IncWriteOffset(ret);
m_last_recv_tick = get_tick_count();
}
CImPdu* pPdu = NULL;
try
{
while ( ( pPdu = CImPdu::ReadPdu(m_in_buf.GetBuffer(), m_in_buf.GetWriteOffset()) ) )
{
uint32_t pdu_len = pPdu->GetLength();
HandlePdu(pPdu);
m_in_buf.Read(NULL, pdu_len);
delete pPdu;
pPdu = NULL;
// ++g_recv_pkt_cnt;
}
} catch (CPduException& ex) {
log("!!!catch exception, sid=%u, cid=%u, err_code=%u, err_msg=%s, close the connection ",
ex.GetServiceId(), ex.GetCommandId(), ex.GetErrorCode(), ex.GetErrorMsg());
if (pPdu) {
delete pPdu;
pPdu = NULL;
}
OnClose();
}
}
void CImConn::OnWrite()
{
if (!m_busy)
return;
while (m_out_buf.GetWriteOffset() > 0) {
int send_size = m_out_buf.GetWriteOffset();
if (send_size > NETLIB_MAX_SOCKET_BUF_SIZE) {
send_size = NETLIB_MAX_SOCKET_BUF_SIZE;
}
int ret = netlib_send(m_handle, m_out_buf.GetBuffer(), send_size);
if (ret <= 0) {
ret = 0;
break;
}
m_out_buf.Read(NULL, ret);
}
if (m_out_buf.GetWriteOffset() == 0) {
m_busy = false;
}
log("onWrite, remain=%d ", m_out_buf.GetWriteOffset());
}
CLoginConn、msgconn继承CImConn,数据的读取在基类CImConn中,处理在各种的子类中
缓冲Buffer
/*
* UtilPdu.h
*
* Created on: 2013-8-27
* Author: ziteng@mogujie.com
*/
#ifndef UTILPDU_H_
#define UTILPDU_H_
#include "ostype.h"
#include <set>
#include <map>
#include <list>
#include <string>
using namespace std;
#ifdef WIN32
#ifdef BUILD_PDU
#define DLL_MODIFIER __declspec(dllexport)
#else
#define DLL_MODIFIER __declspec(dllimport)
#endif
#else
#define DLL_MODIFIER
#endif
// exception code
#define ERROR_CODE_PARSE_FAILED 1
#define ERROR_CODE_WRONG_SERVICE_ID 2
#define ERROR_CODE_WRONG_COMMAND_ID 3
#define ERROR_CODE_ALLOC_FAILED 4
class CPduException {
public:
CPduException(uint32_t service_id, uint32_t command_id, uint32_t error_code, const char* error_msg)
{
m_service_id = service_id;
m_command_id = command_id;
m_error_code = error_code;
m_error_msg = error_msg;
}
CPduException(uint32_t error_code, const char* error_msg)
{
m_service_id = 0;
m_command_id = 0;
m_error_code = error_code;
m_error_msg = error_msg;
}
virtual ~CPduException() {}
uint32_t GetServiceId() { return m_service_id; }
uint32_t GetCommandId() { return m_command_id; }
uint32_t GetErrorCode() { return m_error_code; }
char* GetErrorMsg() { return (char*)m_error_msg.c_str(); }
private:
uint32_t m_service_id;
uint32_t m_command_id;
uint32_t m_error_code;
string m_error_msg;
};
class DLL_MODIFIER CSimpleBuffer
{
public:
CSimpleBuffer();
~CSimpleBuffer();
uchar_t* GetBuffer() { return m_buffer; }
uint32_t GetAllocSize() { return m_alloc_size; }
uint32_t GetWriteOffset() { return m_write_offset; }
void IncWriteOffset(uint32_t len) { m_write_offset += len; }
void Extend(uint32_t len);
uint32_t Write(void* buf, uint32_t len);
uint32_t Read(void* buf, uint32_t len);
private:
uchar_t* m_buffer;
uint32_t m_alloc_size;
uint32_t m_write_offset;
};
class CByteStream
{
public:
CByteStream(uchar_t* buf, uint32_t len);
CByteStream(CSimpleBuffer* pSimpBuf, uint32_t pos);
~CByteStream() {}
unsigned char* GetBuf() { return m_pSimpBuf ? m_pSimpBuf->GetBuffer() : m_pBuf; }
uint32_t GetPos() { return m_pos; }
uint32_t GetLen() { return m_len; }
void Skip(uint32_t len)
{
m_pos += len;
if(m_pos > m_len)
{
throw CPduException(ERROR_CODE_PARSE_FAILED, "parase packet failed!");
}
}
static int16_t ReadInt16(uchar_t* buf);
static uint16_t ReadUint16(uchar_t* buf);
static int32_t ReadInt32(uchar_t* buf);
static uint32_t ReadUint32(uchar_t* buf);
static void WriteInt16(uchar_t* buf, int16_t data);
static void WriteUint16(uchar_t* buf, uint16_t data);
static void WriteInt32(uchar_t* buf, int32_t data);
static void WriteUint32(uchar_t* buf, uint32_t data);
void operator << (int8_t data);
void operator << (uint8_t data);
void operator << (int16_t data);
void operator << (uint16_t data);
void operator << (int32_t data);
void operator << (uint32_t data);
void operator >> (int8_t& data);
void operator >> (uint8_t& data);
void operator >> (int16_t& data);
void operator >> (uint16_t& data);
void operator >> (int32_t& data);
void operator >> (uint32_t& data);
void WriteString(const char* str);
void WriteString(const char* str, uint32_t len);
char* ReadString(uint32_t& len);
void WriteData(uchar_t* data, uint32_t len);
uchar_t* ReadData(uint32_t& len);
private:
void _WriteByte(void* buf, uint32_t len);
void _ReadByte(void* buf, uint32_t len);
private:
CSimpleBuffer* m_pSimpBuf;
uchar_t* m_pBuf;
uint32_t m_len;
uint32_t m_pos;
};
char* idtourl(uint32_t id);
uint32_t urltoid(const char* url);
#endif /* UTILPDU_H_ */
/*
* UtilPdu.cpp
*
* Created on: 2013-8-27
* Author: ziteng@mogujie.com
*/
#include "UtilPdu.h"
#include <stdlib.h>
#include <string.h>
/ CSimpleBuffer
CSimpleBuffer::CSimpleBuffer()
{
m_buffer = NULL;
m_alloc_size = 0;
m_write_offset = 0;
}
CSimpleBuffer::~CSimpleBuffer()
{
m_alloc_size = 0;
m_write_offset = 0;
if (m_buffer)
{
free(m_buffer);
m_buffer = NULL;
}
}
void CSimpleBuffer::Extend(uint32_t len)
{
m_alloc_size = m_write_offset + len;
m_alloc_size += m_alloc_size >> 2; // increase by 1/4 allocate size
uchar_t* new_buf = (uchar_t*)realloc(m_buffer, m_alloc_size);
m_buffer = new_buf;
}
uint32_t CSimpleBuffer::Write(void* buf, uint32_t len)
{
if (m_write_offset + len > m_alloc_size)
{
Extend(len);
}
if (buf)
{
memcpy(m_buffer + m_write_offset, buf, len);
}
m_write_offset += len;
return len;
}
uint32_t CSimpleBuffer::Read(void* buf, uint32_t len)
{
if (len > m_write_offset)
len = m_write_offset;
if (buf)
memcpy(buf, m_buffer, len);
m_write_offset -= len;
memmove(m_buffer, m_buffer + len, m_write_offset);
return len;
}
// CByteStream //
CByteStream::CByteStream(uchar_t* buf, uint32_t len)
{
m_pBuf = buf;
m_len = len;
m_pSimpBuf = NULL;
m_pos = 0;
}
CByteStream::CByteStream(CSimpleBuffer* pSimpBuf, uint32_t pos)
{
m_pSimpBuf = pSimpBuf;
m_pos = pos;
m_pBuf = NULL;
m_len = 0;
}
int16_t CByteStream::ReadInt16(uchar_t *buf)
{
int16_t data = (buf[0] << 8) | buf[1];
return data;
}
uint16_t CByteStream::ReadUint16(uchar_t* buf)
{
uint16_t data = (buf[0] << 8) | buf[1];
return data;
}
int32_t CByteStream::ReadInt32(uchar_t *buf)
{
int32_t data = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
return data;
}
uint32_t CByteStream::ReadUint32(uchar_t *buf)
{
uint32_t data = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
return data;
}
void CByteStream::WriteInt16(uchar_t *buf, int16_t data)
{
buf[0] = static_cast<uchar_t>(data >> 8);
buf[1] = static_cast<uchar_t>(data & 0xFF);
}
void CByteStream::WriteUint16(uchar_t *buf, uint16_t data)
{
buf[0] = static_cast<uchar_t>(data >> 8);
buf[1] = static_cast<uchar_t>(data & 0xFF);
}
void CByteStream::WriteInt32(uchar_t *buf, int32_t data)
{
buf[0] = static_cast<uchar_t>(data >> 24);
buf[1] = static_cast<uchar_t>((data >> 16) & 0xFF);
buf[2] = static_cast<uchar_t>((data >> 8) & 0xFF);
buf[3] = static_cast<uchar_t>(data & 0xFF);
}
void CByteStream::WriteUint32(uchar_t *buf, uint32_t data)
{
buf[0] = static_cast<uchar_t>(data >> 24);
buf[1] = static_cast<uchar_t>((data >> 16) & 0xFF);
buf[2] = static_cast<uchar_t>((data >> 8) & 0xFF);
buf[3] = static_cast<uchar_t>(data & 0xFF);
}
void CByteStream::operator << (int8_t data)
{
_WriteByte(&data, 1);
}
void CByteStream::operator << (uint8_t data)
{
_WriteByte(&data, 1);
}
void CByteStream::operator << (int16_t data)
{
unsigned char buf[2];
buf[0] = static_cast<uchar_t>(data >> 8);
buf[1] = static_cast<uchar_t>(data & 0xFF);
_WriteByte(buf, 2);
}
void CByteStream::operator << (uint16_t data)
{
unsigned char buf[2];
buf[0] = static_cast<uchar_t>(data >> 8);
buf[1] = static_cast<uchar_t>(data & 0xFF);
_WriteByte(buf, 2);
}
void CByteStream::operator << (int32_t data)
{
unsigned char buf[4];
buf[0] = static_cast<uchar_t>(data >> 24);
buf[1] = static_cast<uchar_t>((data >> 16) & 0xFF);
buf[2] = static_cast<uchar_t>((data >> 8) & 0xFF);
buf[3] = static_cast<uchar_t>(data & 0xFF);
_WriteByte(buf, 4);
}
void CByteStream::operator << (uint32_t data)
{
unsigned char buf[4];
buf[0] = static_cast<uchar_t>(data >> 24);
buf[1] = static_cast<uchar_t>((data >> 16) & 0xFF);
buf[2] = static_cast<uchar_t>((data >> 8) & 0xFF);
buf[3] = static_cast<uchar_t>(data & 0xFF);
_WriteByte(buf, 4);
}
void CByteStream::operator >> (int8_t& data)
{
_ReadByte(&data, 1);
}
void CByteStream::operator >> (uint8_t& data)
{
_ReadByte(&data, 1);
}
void CByteStream::operator >> (int16_t& data)
{
unsigned char buf[2];
_ReadByte(buf, 2);
data = (buf[0] << 8) | buf[1];
}
void CByteStream::operator >> (uint16_t& data)
{
unsigned char buf[2];
_ReadByte(buf, 2);
data = (buf[0] << 8) | buf[1];
}
void CByteStream::operator >> (int32_t& data)
{
unsigned char buf[4];
_ReadByte(buf, 4);
data = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
}
void CByteStream::operator >> (uint32_t& data)
{
unsigned char buf[4];
_ReadByte(buf, 4);
data = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
}
void CByteStream::WriteString(const char *str)
{
uint32_t size = str ? (uint32_t)strlen(str) : 0;
*this << size;
_WriteByte((void*)str, size);
}
void CByteStream::WriteString(const char *str, uint32_t len)
{
*this << len;
_WriteByte((void*)str, len);
}
char* CByteStream::ReadString(uint32_t& len)
{
*this >> len;
char* pStr = (char*)GetBuf() + GetPos();
Skip(len);
return pStr;
}
void CByteStream::WriteData(uchar_t *data, uint32_t len)
{
*this << len;
_WriteByte(data, len);
}
uchar_t* CByteStream::ReadData(uint32_t &len)
{
*this >> len;
uchar_t* pData = (uchar_t*)GetBuf() + GetPos();
Skip(len);
return pData;
}
void CByteStream::_ReadByte(void* buf, uint32_t len)
{
if (m_pos + len > m_len)
{
throw CPduException(ERROR_CODE_PARSE_FAILED, "parase packet failed!");
}
if (m_pSimpBuf)
m_pSimpBuf->Read((char*)buf, len);
else
memcpy(buf, m_pBuf + m_pos, len);
m_pos += len;
}
void CByteStream::_WriteByte(void* buf, uint32_t len)
{
if (m_pBuf && (m_pos + len > m_len))
return;
if (m_pSimpBuf)
m_pSimpBuf->Write((char*)buf, len);
else
memcpy(m_pBuf + m_pos, buf, len);
m_pos += len;
}
/*
* Warning!!!
* This function return a static char pointer, caller must immediately copy the string to other place
*/
char* idtourl(uint32_t id)
{
static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
static char buf[64];
char *ptr;
uint32_t value = id * 2 + 56;
// convert to 36 number system
ptr = buf + sizeof(buf) - 1;
*ptr = '\0';
do {
*--ptr = digits[value % 36];
value /= 36;
} while (ptr > buf && value);
*--ptr = '1'; // add version number
return ptr;
}
uint32_t urltoid(const char* url)
{
uint32_t url_len = strlen(url);
char c;
uint32_t number = 0;
for (uint32_t i = 1; i < url_len; i++) {
c = url[i];
if (c >= '0' && c <='9') {
c -= '0';
} else if (c >= 'a' && c <= 'z') {
c -= 'a' - 10;
} else if (c >= 'A' && c <= 'Z') {
c -= 'A' - 10;
} else {
continue;
}
number = number * 36 + c;
}
return (number - 56) >> 1;
}
//上层又封装了一层CImPdu
/*
* ImPduBase.h
*
* Created on: 2013-8-27
* Author: ziteng@mogujie.com
*/
#ifndef IMPDUBASE_H_
#define IMPDUBASE_H_
#include "UtilPdu.h"
#include "pb/google/protobuf/message_lite.h"
#define IM_PDU_HEADER_LEN 16
#define IM_PDU_VERSION 1
#define ALLOC_FAIL_ASSERT(p) if (p == NULL) { \
throw CPduException(m_pdu_header.service_id, m_pdu_header.command_id, ERROR_CODE_ALLOC_FAILED, "allocate failed"); \
}
#define CHECK_PB_PARSE_MSG(ret) { \
if (ret == false) \
{\
log("parse pb msg failed.");\
return;\
}\
}
#ifdef WIN32
#ifdef BUILD_PDU
#define DLL_MODIFIER __declspec(dllexport)
#else
#define DLL_MODIFIER __declspec(dllimport)
#endif
#else
#define DLL_MODIFIER
#endif
//
typedef struct {
uint32_t length; // the whole pdu length
uint16_t version; // pdu version number
uint16_t flag; // not used
uint16_t service_id; //
uint16_t command_id; //
uint16_t seq_num; // 包序号
uint16_t reversed; // 保留
} PduHeader_t;
class DLL_MODIFIER CImPdu
{
public:
CImPdu();
virtual ~CImPdu() {}
uchar_t* GetBuffer();
uint32_t GetLength();
uchar_t* GetBodyData();
uint32_t GetBodyLength();
uint16_t GetVersion() { return m_pdu_header.version; }
uint16_t GetFlag() { return m_pdu_header.flag; }
uint16_t GetServiceId() { return m_pdu_header.service_id; }
uint16_t GetCommandId() { return m_pdu_header.command_id; }
uint16_t GetSeqNum() { return m_pdu_header.seq_num; }
uint32_t GetReversed() { return m_pdu_header.reversed; }
void SetVersion(uint16_t version);
void SetFlag(uint16_t flag);
void SetServiceId(uint16_t service_id);
void SetCommandId(uint16_t command_id);
void SetSeqNum(uint16_t seq_num);
void SetReversed(uint32_t reversed);
void WriteHeader();
static bool IsPduAvailable(uchar_t* buf, uint32_t len, uint32_t& pdu_len);
static CImPdu* ReadPdu(uchar_t* buf, uint32_t len);
void Write(uchar_t* buf, uint32_t len) { m_buf.Write((void*)buf, len); }
int ReadPduHeader(uchar_t* buf, uint32_t len);
void SetPBMsg(google::protobuf::MessageLite* msg);
protected:
CSimpleBuffer m_buf;
PduHeader_t m_pdu_header;
};
#endif /* IMPDUBASE_H_ */
/*
* ImPduBase.cpp
*
* Created on: 2013-8-27
* Author: ziteng@mogujie.com
*/
#include "util.h"
#include "ImPduBase.h"
#include "IM.BaseDefine.pb.h"
using namespace IM::BaseDefine;
CImPdu::CImPdu()
{
m_pdu_header.version = IM_PDU_VERSION;
m_pdu_header.flag = 0;
m_pdu_header.service_id = SID_OTHER;
m_pdu_header.command_id = 0;
m_pdu_header.seq_num = 0;
m_pdu_header.reversed = 0;
}
uchar_t* CImPdu::GetBuffer()
{
return m_buf.GetBuffer();
}
uint32_t CImPdu::GetLength()
{
return m_buf.GetWriteOffset();
}
uchar_t* CImPdu::GetBodyData()
{
return m_buf.GetBuffer() + sizeof(PduHeader_t);
}
uint32_t CImPdu::GetBodyLength()
{
uint32_t body_length = 0;
body_length = m_buf.GetWriteOffset() - sizeof(PduHeader_t);
return body_length;
}
void CImPdu::WriteHeader()
{
uchar_t* buf = GetBuffer();
CByteStream::WriteInt32(buf, GetLength());
CByteStream::WriteUint16(buf + 4, m_pdu_header.version);
CByteStream::WriteUint16(buf + 6, m_pdu_header.flag);
CByteStream::WriteUint16(buf + 8, m_pdu_header.service_id);
CByteStream::WriteUint16(buf + 10, m_pdu_header.command_id);
CByteStream::WriteUint16(buf + 12, m_pdu_header.seq_num);
CByteStream::WriteUint16(buf + 14, m_pdu_header.reversed);
}
void CImPdu::SetVersion(uint16_t version)
{
uchar_t* buf = GetBuffer();
CByteStream::WriteUint16(buf + 4, version);
}
void CImPdu::SetFlag(uint16_t flag)
{
uchar_t* buf = GetBuffer();
CByteStream::WriteUint16(buf + 6, flag);
}
void CImPdu::SetServiceId(uint16_t service_id)
{
uchar_t* buf = GetBuffer();
CByteStream::WriteUint16(buf + 8, service_id);
}
void CImPdu::SetCommandId(uint16_t command_id)
{
uchar_t* buf = GetBuffer();
CByteStream::WriteUint16(buf + 10, command_id);
}
void CImPdu::SetSeqNum(uint16_t seq_num)
{
uchar_t* buf = GetBuffer();
CByteStream::WriteUint16(buf + 12, seq_num);
}
void CImPdu::SetReversed(uint32_t reversed)
{
uchar_t* buf = GetBuffer();
CByteStream::WriteUint16(buf+14, reversed);
}
int CImPdu::ReadPduHeader(uchar_t* buf, uint32_t len)
{
int ret = -1;
if (len >= IM_PDU_HEADER_LEN && buf) {
CByteStream is(buf, len);
is >> m_pdu_header.length;
is >> m_pdu_header.version;
is >> m_pdu_header.flag;
is >> m_pdu_header.service_id;
is >> m_pdu_header.command_id;
is >> m_pdu_header.seq_num;
is >> m_pdu_header.reversed;
ret = 0;
}
return ret;
}
CImPdu* CImPdu::ReadPdu(uchar_t *buf, uint32_t len)
{
uint32_t pdu_len = 0;
if (!IsPduAvailable(buf, len, pdu_len))
return NULL;
uint16_t service_id = CByteStream::ReadUint16(buf + 8);
uint16_t command_id = CByteStream::ReadUint16(buf + 10);
CImPdu* pPdu = NULL;
pPdu = new CImPdu();
//pPdu->_SetIncomingLen(pdu_len);
//pPdu->_SetIncomingBuf(buf);
pPdu->Write(buf, pdu_len);
pPdu->ReadPduHeader(buf, IM_PDU_HEADER_LEN);
return pPdu;
}
bool CImPdu::IsPduAvailable(uchar_t* buf, uint32_t len, uint32_t& pdu_len)
{
if (len < IM_PDU_HEADER_LEN)
return false;
pdu_len = CByteStream::ReadUint32(buf);
if (pdu_len > len)
{
//log("pdu_len=%d, len=%d\n", pdu_len, len);
return false;
}
if(0 == pdu_len)
{
throw CPduException(1, "pdu_len is 0");
}
return true;
}
void CImPdu::SetPBMsg(google::protobuf::MessageLite* msg)
{
//设置包体,则需要重置下空间
m_buf.Read(NULL, m_buf.GetWriteOffset());
m_buf.Write(NULL, sizeof(PduHeader_t));
uint32_t msg_size = msg->ByteSize();
uchar_t* szData = new uchar_t[msg_size];
//ALLOC_FAIL_ASSERT(szData)
if (!msg->SerializeToArray(szData, msg_size))
{
log("pb msg miss required fields.");
}
m_buf.Write(szData, msg_size);
delete []szData;
WriteHeader();
}