text: #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);
  	}
  }
  
  