1
0
cuberite-2a/source/cSocket.cpp
faketruth d21e4dacf7 Compiles on Android! Added Eclipse project, import it into your workspace and it should be runnable on Android!
Disabled Squirrel for Android
cLog now logs to Android LogCat as well
Fixed Lua so it compiles on Android
Removed/commented out exceptions in JsonCpp so it compiles on Android

git-svn-id: http://mc-server.googlecode.com/svn/trunk@741 0a769ca7-a7f5-676a-18bf-c427514a06d6
2012-08-15 21:24:11 +00:00

355 lines
5.6 KiB
C++

#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "cSocket.h"
#include "packets/cPacket.h"
#ifndef _WIN32
#include <netdb.h>
#include <unistd.h>
#include <arpa/inet.h> //inet_ntoa()
#else
#define socklen_t int
#endif
cSocket::cSocket(xSocket a_Socket)
: m_Socket(a_Socket)
{
}
cSocket::~cSocket()
{
// Do NOT close the socket; this class is an API wrapper, not a RAII!
}
cSocket::operator cSocket::xSocket() const
{
return m_Socket;
}
cSocket::xSocket cSocket::GetSocket() const
{
return m_Socket;
}
bool cSocket::IsValid(void) const
{
#ifdef _WIN32
return (m_Socket != INVALID_SOCKET);
#else // _WIN32
return (m_Socket >= 0);
#endif // else _WIN32
}
void cSocket::CloseSocket()
{
#ifdef _WIN32
closesocket(m_Socket);
#else // _WIN32
if (shutdown(m_Socket, SHUT_RDWR) != 0)//SD_BOTH);
{
LOGWARN("Error on shutting down socket (%s): %s", m_IPString.c_str(), GetLastErrorString().c_str());
}
if (close(m_Socket) != 0)
{
LOGWARN("Error closing socket (%s): %s", m_IPString.c_str(), GetLastErrorString().c_str());
}
#endif // else _WIN32
// Invalidate the socket so that this object can be re-used for another connection
m_Socket = INVALID_SOCKET;
}
AString cSocket::GetErrorString( int a_ErrNo )
{
char buffer[ 1024 ];
AString Out;
#ifdef _WIN32
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, a_ErrNo, 0, buffer, ARRAYCOUNT(buffer), NULL);
Printf(Out, "%d: %s", a_ErrNo, buffer);
if (!Out.empty() && (Out[Out.length() - 1] == '\n'))
{
Out.erase(Out.length() - 2);
}
return Out;
#else // _WIN32
// According to http://linux.die.net/man/3/strerror_r there are two versions of strerror_r():
#if ( _GNU_SOURCE ) && !defined(ANDROID_NDK) // GNU version of strerror_r()
char * res = strerror_r( errno, buffer, ARRAYCOUNT(buffer) );
if( res != NULL )
{
Printf(Out, "%d: %s", a_ErrNo, res);
return Out;
}
#else // XSI version of strerror_r():
int res = strerror_r( errno, buffer, ARRAYCOUNT(buffer) );
if( res == 0 )
{
Printf(Out, "%d: %s", a_ErrNo, buffer);
return Out;
}
#endif // strerror_r() version
else
{
Printf(Out, "Error %d while getting error string for error #%d!", errno, a_ErrNo);
return Out;
}
#endif // else _WIN32
}
int cSocket::GetLastError()
{
#ifdef _WIN32
return WSAGetLastError();
#else
return errno;
#endif
}
int cSocket::SetReuseAddress()
{
#if defined(_WIN32) || defined(ANDROID_NDK)
char yes = 1;
#else
int yes = 1;
#endif
return setsockopt(m_Socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
}
int cSocket::WSAStartup()
{
#ifdef _WIN32
WSADATA wsaData;
memset(&wsaData, 0, sizeof(wsaData));
return ::WSAStartup(MAKEWORD(2, 2),&wsaData);
#else
return 0;
#endif
}
cSocket cSocket::CreateSocket()
{
return socket(AF_INET,SOCK_STREAM,0);
}
unsigned long cSocket::INTERNET_ADDRESS_LOCALHOST(void)
{
static unsigned long LocalHost = 0;
if (LocalHost == 0)
{
LocalHost = inet_addr("127.0.0.1"); // GCC won't accept this as a global var assignment
}
return LocalHost;
}
int cSocket::Bind(SockAddr_In& a_Address)
{
sockaddr_in local;
memset(&local, 0, sizeof(local));
local.sin_family = a_Address.Family;
local.sin_addr.s_addr = a_Address.Address;
local.sin_port = htons((u_short)a_Address.Port);
return bind(m_Socket, (sockaddr*)&local, sizeof(local));
}
int cSocket::Listen(int a_Backlog)
{
return listen(m_Socket, a_Backlog);
}
cSocket cSocket::Accept()
{
sockaddr_in from;
socklen_t fromlen=sizeof(from);
cSocket SClient = accept(m_Socket, (sockaddr*)&from, &fromlen);
if (from.sin_addr.s_addr && SClient.IsValid()) // Get IP in string form
{
SClient.m_IPString = inet_ntoa(from.sin_addr);
//LOG("cSocket::Accept() %s", SClient.m_IPString);
}
return SClient;
}
int cSocket::Connect(SockAddr_In & a_Address)
{
sockaddr_in local;
local.sin_family = a_Address.Family;
local.sin_addr.s_addr = a_Address.Address;
local.sin_port = htons((u_short)a_Address.Port);
return connect(m_Socket, (sockaddr *)&local, sizeof(local));
}
int cSocket::Connect(const AString & a_HostNameOrAddr, unsigned short a_Port)
{
// First try IP Address string to hostent conversion, because it's faster
unsigned long addr = inet_addr(a_HostNameOrAddr.c_str());
hostent * hp = gethostbyaddr((char*)&addr, sizeof(addr), AF_INET);
if (hp == NULL)
{
// It is not an IP Address string, but rather a regular hostname, resolve:
hp = gethostbyname(a_HostNameOrAddr.c_str());
if (hp == NULL)
{
LOGWARN("cTCPLink: Could not resolve hostname \"%s\"", a_HostNameOrAddr.c_str());
CloseSocket();
return false;
}
}
sockaddr_in server;
server.sin_addr.s_addr = *((unsigned long*)hp->h_addr);
server.sin_family = AF_INET;
server.sin_port = htons( (unsigned short)a_Port );
return connect(m_Socket, (sockaddr *)&server, sizeof(server));
}
int cSocket::Receive(char* a_Buffer, unsigned int a_Length, unsigned int a_Flags)
{
return recv(m_Socket, a_Buffer, a_Length, a_Flags);
}
int cSocket::Send(const char * a_Buffer, unsigned int a_Length)
{
return send(m_Socket, a_Buffer, a_Length, 0);
}
int cSocket::Send(const cPacket * a_Packet)
{
AString Serialized;
a_Packet->Serialize(Serialized);
return Send(Serialized.data(), Serialized.size());
}
int cSocket::Send(const cPacket & a_Packet)
{
AString Serialized;
a_Packet.Serialize(Serialized);
return Send(Serialized.data(), Serialized.size());
}
unsigned short cSocket::GetPort(void) const
{
ASSERT(IsValid());
sockaddr_in Addr;
socklen_t AddrSize = sizeof(Addr);
if (getsockname(m_Socket, (sockaddr *)&Addr, &AddrSize) != 0)
{
return 0;
}
return ntohs(Addr.sin_port);
}