Page MenuHomePhorge

SocketNetworkSystem.cpp
No OneTemporary

Size
30 KB
Referenced Files
None
Subscribers
None

SocketNetworkSystem.cpp

#include <echo/Network/SocketNetworkSystem.h>
#include <echo/Network/TCPConnection.h>
#include <echo/Network/UDPConnection.h>
#include <echo/Util/StringUtils.h>
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <sstream>
#include <errno.h>
#include <unistd.h>
#include <algorithm>
namespace Echo
{
//////////////////////////////////////////////////////////////////////////
//SocketNetworkSystem::SocketThreadTask::SocketThreadTask
//////////////////////////////////////////////////////////////////////////
SocketNetworkSystem::SocketThreadTask::SocketThreadTask(SocketNetworkSystem* s) : mSystem(s)
{
FD_ZERO(&mReadSet);
FD_ZERO(&mWriteSet);
FD_ZERO(&mExceptSet);
mHighestSocket = 0;
mCount = 0;
}
SocketNetworkSystem::SocketThreadTask::~SocketThreadTask()
{
FD_ZERO(&mReadSet);
FD_ZERO(&mWriteSet);
FD_ZERO(&mExceptSet);
mHighestSocket = 0;
mCount = 0;
}
bool SocketNetworkSystem::SocketThreadTask::AddSocket(Socket s)
{
if(mCount == FD_SETSIZE)
return false;
mPendingSocketsMutex.lock();
mPendingSockets.push_back(s);
mCount++;
mPendingSocketsMutex.unlock();
return true;
}
bool SocketNetworkSystem::SocketThreadTask::RemoveSocket(Socket s)
{
mPendingSocketsMutex.lock();
mPendingRemovalSockets.push_back(s);
mCount--;
mPendingSocketsMutex.unlock();
return true;
}
void SocketNetworkSystem::SocketThreadTask::EnableWriteCheck(Socket s)
{
mPendingSocketsMutex.lock();
//Make sure the same socket isn't added twice.
if(std::find(mPendingWriteEnableSockets.begin(), mPendingWriteEnableSockets.end(), s) == mPendingWriteEnableSockets.end())
mPendingWriteEnableSockets.push_back(s);
mPendingSocketsMutex.unlock();
}
void SocketNetworkSystem::SocketThreadTask::DisableWriteCheck(Socket s)
{
mPendingSocketsMutex.lock();
//Make sure the same socket isn't added twice.
if(std::find(mPendingWriteDisableSockets.begin(), mPendingWriteDisableSockets.end(), s) == mPendingWriteDisableSockets.end())
mPendingWriteDisableSockets.push_back(s);
mPendingSocketsMutex.unlock();
}
void SocketNetworkSystem::SocketThreadTask::Update(Seconds lastFrameTime)
{
if(!mAllSockets.empty())
{
timeval timeOut;
timeOut.tv_sec = 10;
timeOut.tv_usec = 0;
fd_set readSet = mReadSet;
fd_set writeSet = mWriteSet;
fd_set exceptSet = mExceptSet;
int r = select(mHighestSocket, &readSet, &writeSet, &exceptSet, &timeOut);
//std::cout << "Post select" << std::endl;
if(r >= 0)
{
std::list< Socket >::iterator it = mAllSockets.begin();
std::list< Socket >::iterator itEnd = mAllSockets.end();
while(it != itEnd)
{
Socket s = (*it);
if(FD_ISSET(s, &exceptSet))
{
//std::cout << "ExceptNotify" << std::endl;
mSystem->ExceptNotify(s);
mPendingSocketsMutex.lock();
mPendingRemovalSockets.push_back(s);
mPendingSocketsMutex.unlock();
} else
{
if(FD_ISSET(s, &writeSet))
{
//std::cout << "WriteNotify" << std::endl;
DisableWriteCheck(s); //For unix systems that continually report write,
//it is re-enabled in connection write error
mSystem->WriteNotify(s);
}
if(FD_ISSET(s, &readSet))
{
//std::cout << "ReadNotify" << std::endl;
mSystem->ReadNotify(s);
}
}
++it;
}
} else
{
HandleError(r);
//some error
std::cout << "Select error" << std::endl;
}
}
mPendingSocketsMutex.lock();
bool findHighest = false;
//Remove any sockets that are pending removal
while(!mPendingRemovalSockets.empty())
{
Socket s = mPendingRemovalSockets.back();
mPendingRemovalSockets.pop_back();
if(s == mHighestSocket - 1)
{
findHighest = true;
}
FD_CLR(s, &mReadSet);
FD_CLR(s, &mWriteSet);
FD_CLR(s, &mExceptSet);
mAllSockets.remove(s);
}
//Remove any write sockets that are pending write notification removal
for(u32 wds = 0; wds < mPendingWriteDisableSockets.size(); ++wds)
{
//We don't need to go and find the highest after this because the socket will still be in the read set
FD_CLR(mPendingWriteDisableSockets[wds], &mWriteSet);
}
//Add any write sockets that are pending writing notifications
for(u32 wds = 0; wds < mPendingWriteEnableSockets.size(); ++wds)
{
//We don't need to go and find the highest after this because the socket will still be in the read set
FD_SET(mPendingWriteEnableSockets[wds], &mWriteSet);
}
if(findHighest)
{
mHighestSocket = 0;
std::list< Socket >::iterator it = mAllSockets.begin();
std::list< Socket >::iterator itEnd = mAllSockets.end();
while(it != itEnd)
{
Socket s = (*it);
if(s >= (Socket)mHighestSocket)
mHighestSocket = s + 1;
++it;
}
}
while(!mPendingSockets.empty())
{
int s = mPendingSockets.back();
mPendingSockets.pop_back();
if(s >= mHighestSocket)
mHighestSocket = s + 1;
mAllSockets.push_back(s);
FD_SET(s, &mReadSet);
FD_SET(s, &mWriteSet);
FD_SET(s, &mExceptSet);
}
mPendingSocketsMutex.unlock();
}
bool SocketNetworkSystem::SocketThreadTask::HandleError(int code)
{
#ifdef ECHO_PLATFORM_WINDOWS
if(code == SOCKET_ERROR)
{
int e = WSAGetLastError();
switch(e)
{
case WSANOTINITIALISED:
std::cout << "WSANOTINITIALISED - application will now close.\n" << std::endl;
PostQuitMessage(1);
break;
case WSAENETDOWN:
std::cout << "WSAENETDOWN - A Problem with the network has been encountered.\n" << std::endl;
break;
case WSAEINTR:
std::cout << "WSAEINTR - Blocking function canceled.\n" << std::endl;
break;
case WSAEADDRNOTAVAIL:
std::cout << "WSAEADDRNOTAVAIL - Invalid address\n" << std::endl;
break;
case WSAECONNREFUSED:
std::cout << "WSAECONNREFUSED - Connection was refused by host\n" << std::endl;
break;
case WSAEISCONN:
std::cout << "WSAEISCONN - Socket already connected\n" << std::endl;
break;
case WSAENETUNREACH:
std::cout << "WSAENETUNREACH - Network unreachable\n" << std::endl;
break;
case WSAEHOSTUNREACH:
std::cout << "WSAEHOSTUNREACH - Host unreachable\n" << std::endl;
break;
case WSAETIMEDOUT:
std::cout << "WSAETIMEDOUT - Attempt to connect timed out\n" << std::endl;
break;
case WSAEINVAL:
std::cout << "WSAEINVAL - One of the specified parameters was invalid such as the window handle not referring to an existing window, or the specified socket is in an invalid state. " << std::endl;
break;
case WSAEINPROGRESS:
std::cout << "WSAEINPROGRESS - A blocking Winsock call is in progress, or the service provider is still processing a callback function. " << std::endl;
break;
case WSAENOTSOCK:
std::cout << "WSAENOTSOCK - The descriptor is not a socket. " << std::endl;
break;
case WSAEADDRINUSE:
std::cout << "WSAEADDRINUSE - Address already in use" << std::endl;
break;
case WSAENOTCONN:
std::cout << "WSAENOTCONN - Socket not connected" << std::endl;
break;
case WSAEAFNOSUPPORT:
std::cout << "WSAEAFNOSUPPORT - Address family not supported by protocol family" << std::endl;
break;
case WSAENOBUFS:
std::cout << "WSAENOBUFS - No buffer space available. An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full." << std::endl;
break;
case WSAEWOULDBLOCK:
//This one is ok :)
//#ifdef _DEBUG
// std::cout << "WSAEWOULDBLOCK - Resource temporarily unavailable." << std::endl;
//#endif
return true;
break;
default:
std::cout << "Unknown Error: " << e << " : " << std::hex << e << std::dec << std::endl;
break;
}
return false;
}
return true;
#endif
#ifdef ECHO_PLATFORM_LINUX
if(code != -1)
return true;
switch(errno)
{
case EACCES:
std::cout << "Permission to create a socket of the specified type and/or protocol is denied." << std::endl;
break;
case EAFNOSUPPORT:
std::cout << "The implementation does not support the specified address family." << std::endl;
break;
case EINVAL:
std::cout << "Unknown protocol, or protocol family not available." << std::endl;
break;
case EMFILE:
std::cout << "Process file table overflow." << std::endl;
break;
case ENFILE:
std::cout << "The system limit on the total number of open files has been reached." << std::endl;
break;
case ENOBUFS:
case ENOMEM:
std::cout << "Insufficient memory is available. The socket cannot be created until sufficient resources are freed." << std::endl;
break;
case EPROTONOSUPPORT:
std::cout << "The protocol type or the specified protocol is not supported within this domain." << std::endl;
break;
default:
return true;
break;
}
return false;
#endif
#ifdef ECHO_PLATFORM_MAC
if(code != -1)
return true;
switch(errno)
{
case EACCES:
std::cout << "Permission to create a socket of the specified type and/or protocol is denied." << std::endl;
break;
case EAFNOSUPPORT:
std::cout << "The specified address family is not supported." << std::endl;
break;
case EISCONN:
std::cout << "The per-process descriptor table is full." << std::endl;
break;
case EMFILE:
std::cout << "The per-process descriptor table is full." << std::endl;
break;
case ENFILE:
std::cout << "The system file table is full." << std::endl;
break;
case ENOBUFS:
std::cout << "Insufficient buffer space is available. The socket cannot be created until sufficient resources are freed." << std::endl;
break;
case ENOMEM:
std::cout << "Insufficient memory was available to fulfill the request." << std::endl;
break;
case EPROTONOSUPPORT:
std::cout << "The protocol type or the specified protocol is not supported within this domain." << std::endl;
break;
case EPROTOTYPE:
std::cout << "The socket type is not supported by the protocol." << std::endl;
break;
default:
return true;
break;
}
return false;
#endif
}
//////////////////////////////////////////////////////////////////////////
SocketNetworkSystem::SocketNetworkSystem(NetworkManager& networkManager) : NetworkSystem("Socket", networkManager)
{
mStarted = false;
}
SocketNetworkSystem::~SocketNetworkSystem() {
}
bool SocketNetworkSystem::Initialise()
{
//Need to initialise Winsock on windows
#ifdef ECHO_PLATFORM_WINDOWS
WSADATA wsaData;
std::cout << "Starting Winsock v2.2...";
int wsaErr = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(!HandleError(wsaErr))
{
std::cout << "Error: " << wsaErr << "(0x" << std::hex << wsaErr << std::dec << ")" << std::endl;
WSACleanup();
return false;
}
if(wsaData.wVersion != MAKEWORD(2, 2))
{
WSACleanup();
std::cout << "Unable to start!" << std::endl;
std::cout << "Starting Winsock v1.1...";
if(!HandleError(WSAStartup(MAKEWORD(1, 1), &wsaData)))
{
WSACleanup();
std::cout << "Unable to start. Networking is unavailable..." << std::endl;
return false;
}
return false;
}
std::cout << "Done!" << std::endl;
#endif
return true;
}
bool SocketNetworkSystem::Start()
{
//We'll just start threads when we need to
std::vector< Thread* >::iterator it = mThreads.begin();
std::vector< Thread* >::iterator itEnd = mThreads.end();
while(it != itEnd)
{
(*it)->Execute();
++it;
}
mStarted = true;
return true;
}
void SocketNetworkSystem::DisconnectAll()
{
std::map< Socket, shared_ptr<Connection> >::iterator cit=mConnections.begin();
std::map< Socket, shared_ptr<Connection> >::iterator citEnd=mConnections.end();
while(cit!=citEnd)
{
cit->second->Disconnect();
++cit;
}
}
void SocketNetworkSystem::CleanUp()
{
DisconnectAll();
std::vector< Thread* >::iterator it = mThreads.begin();
std::vector< Thread* >::iterator itEnd = mThreads.end();
while(it != itEnd)
{
(*it)->Terminate(true);
++it;
}
mStarted = false;
#ifdef ECHO_PLATFORM_WINDOWS
WSACleanup();
#endif
}
void SocketNetworkSystem::GetSupportedConnectionTypes(std::vector< std::string >& outSupportedConnectionTypes)
{
outSupportedConnectionTypes.push_back("passive");
outSupportedConnectionTypes.push_back("direct");
outSupportedConnectionTypes.push_back("broadcast");
}
void SocketNetworkSystem::GetAdditionalConnectionInformationFormat(std::vector< std::string >& outAdditionalInformation)
{
outAdditionalInformation.push_back("port,BROADCAST(optional)");
outAdditionalInformation.push_back("port");
outAdditionalInformation.push_back("port");
}
bool SocketNetworkSystem::GetInterfaceInformation(std::vector<SocketNetworkSystem::InterfaceInformation>& outInterfaceInformation)
{
InterfaceInformation interfaceInformation;
char ac[80];
if(gethostname(ac, sizeof (ac)) == -1)
{
return false;
}
interfaceInformation.mHostname = ac;
struct hostent *phe = gethostbyname(ac);
if(phe == 0)
{
return false;
}
for(int i = 0; phe->h_addr_list[i] != 0; ++i)
{
struct in_addr addr;
memcpy(&addr, phe->h_addr_list[i], sizeof (struct in_addr));
interfaceInformation.mIPAddress = inet_ntoa(addr);
//cout << "Address " << i << ": " << inet_ntoa(addr) << endl;
//Determine the subnet mask
outInterfaceInformation.push_back(interfaceInformation);
}
return 0;
}
void SocketNetworkSystem::AcceptConnection(Socket s)
{
sockaddr_in sockaddrFrom;
socklen_t len = sizeof (sockaddr_in);
memset(&sockaddrFrom, 0, len);
Socket newSocket = accept(s, (SocketAddress*) & sockaddrFrom, &len);
IncomingConnectionListener* listener = 0;
mConnectionsMutex.lock();
std::map< Socket, IncomingConnectionListener* >::iterator it = mIncomingConnectionListeners.find(s);
if(it != mIncomingConnectionListeners.end())
{
listener = it->second;
}
mConnectionsMutex.unlock();
if(listener == 0)
return;
shared_ptr<TCPConnection> connection(new TCPConnection(*this));
connection->SetIP(sockaddrFrom.sin_addr.s_addr);
connection->SetPort_(sockaddrFrom.sin_port);
connection->mSocket = newSocket;
connection->mSocketAddress = sockaddrFrom;
connection->mConnected = true; //We are connected
shared_ptr<Connection> connectionptr=shared_ptr<Connection>(connection);
std::stringstream friendlyName;
friendlyName << "(Socket)direct:" << inet_ntoa(sockaddrFrom.sin_addr) << ":" << sockaddrFrom.sin_port;
ConnectionDetails details(friendlyName.str());
connection->SetConnectionDetails(details);
UpdateSocket(newSocket, connectionptr);
UpdateIncoming(connectionptr, listener);
}
void SocketNetworkSystem::ReadNotify(Socket s)
{
mConnectionsMutex.lock();
std::map< Socket, shared_ptr<Connection> >::iterator it = mConnections.find(s);
if(it == mConnections.end())
{
std::cout << "SocketNetworkSystem::ReadNotify(): Socket not associated with a connection." << std::endl;
mConnectionsMutex.unlock();
return;
}
shared_ptr<Connection> connection = it->second;
mConnectionsMutex.unlock();
if(!connection->IsConnected())
{
//A new incoming connection
AcceptConnection(s);
} else
{
UpdateReceive(it->second);
}
}
void SocketNetworkSystem::WriteNotify(Socket s)
{
mConnectionsMutex.lock();
std::map< Socket, shared_ptr<Connection> >::iterator it = mConnections.find(s);
if(it == mConnections.end())
{
std::cout << "SocketNetworkSystem::WriteNotify(): Socket not associated with a connection." << std::endl;
mConnectionsMutex.unlock();
return;
}
shared_ptr<Connection> connection = it->second;
mConnectionsMutex.unlock();
if(!connection->IsConnected())
{
it->second->SetConnected(true);
UpdateConnect(it->second);
} else
{
UpdateWrite(it->second);
}
}
void SocketNetworkSystem::ExceptNotify(Socket s)
{
mConnectionsMutex.lock();
std::map< Socket, shared_ptr<Connection> >::iterator it = mConnections.find(s);
if(it == mConnections.end())
{
std::cout << "SocketNetworkSystem::ReadNotify(): Socket not associated with a connection." << std::endl;
mConnectionsMutex.unlock();
return;
}
//TODO: Sean you need to do some more work here
UpdateConnect(it->second);
mConnectionsMutex.unlock();
}
/** Returns true on success, or false if there was an error */
bool SocketNetworkSystem::SetSocketBlockingEnabled(int fd, bool blocking)
{
if(fd < 0)
{
return false;
}
#ifdef WIN32
unsigned long mode = blocking ? 0 : 1;
return (ioctlsocket(fd, FIONBIO, &mode) == 0) ? true : false;
#else
int flags = fcntl(fd, F_GETFL, 0);
if(flags < 0) return false;
flags = blocking ? (flags&~O_NONBLOCK) : (flags | O_NONBLOCK);
return (fcntl(fd, F_SETFL, flags) == 0) ? true : false;
#endif
}
bool SocketNetworkSystem::HandleError(int code)
{
#ifdef ECHO_PLATFORM_WINDOWS
if(code == SOCKET_ERROR)
{
int e = WSAGetLastError();
switch(e)
{
case WSANOTINITIALISED:
std::cout << "WSANOTINITIALISED - application will now close.\n" << std::endl;
PostQuitMessage(1);
break;
case WSAENETDOWN:
std::cout << "WSAENETDOWN - A Problem with the network has been encountered.\n" << std::endl;
break;
case WSAEINTR:
std::cout << "WSAEINTR - Blocking function canceled.\n" << std::endl;
break;
case WSAEADDRNOTAVAIL:
std::cout << "WSAEADDRNOTAVAIL - Invalid address\n" << std::endl;
break;
case WSAECONNREFUSED:
std::cout << "WSAECONNREFUSED - Connection was refused by host\n" << std::endl;
break;
case WSAEISCONN:
std::cout << "WSAEISCONN - Socket already connected\n" << std::endl;
break;
case WSAENETUNREACH:
std::cout << "WSAENETUNREACH - Network unreachable\n" << std::endl;
break;
case WSAEHOSTUNREACH:
std::cout << "WSAEHOSTUNREACH - Host unreachable\n" << std::endl;
break;
case WSAETIMEDOUT:
std::cout << "WSAETIMEDOUT - Attempt to connect timed out\n" << std::endl;
break;
case WSAEINVAL:
std::cout << "WSAEINVAL - One of the specified parameters was invalid such as the window handle not referring to an existing window, or the specified socket is in an invalid state. " << std::endl;
break;
case WSAEINPROGRESS:
std::cout << "WSAEINPROGRESS - A blocking Winsock call is in progress, or the service provider is still processing a callback function. " << std::endl;
break;
case WSAENOTSOCK:
std::cout << "WSAENOTSOCK - The descriptor is not a socket. " << std::endl;
break;
case WSAEADDRINUSE:
std::cout << "WSAEADDRINUSE - Address already in use" << std::endl;
break;
case WSAENOTCONN:
std::cout << "WSAENOTCONN - Socket not connected" << std::endl;
break;
case WSAEAFNOSUPPORT:
std::cout << "WSAEAFNOSUPPORT - Address family not supported by protocol family" << std::endl;
break;
case WSAENOBUFS:
std::cout << "WSAENOBUFS - No buffer space available. An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full." << std::endl;
break;
case WSAEWOULDBLOCK:
//This one is ok :)
//#ifdef _DEBUG
// std::cout << "WSAEWOULDBLOCK - Resource temporarily unavailable." << std::endl;
//#endif
return true;
break;
default:
std::cout << "Unknown Error: " << e << " : " << std::hex << e << std::dec << std::endl;
break;
}
return false;
}
#endif
#ifdef ECHO_PLATFORM_LINUX
if(code != -1)
return true;
switch(errno)
{
case EACCES:
std::cout << "Permission to create a socket of the specified type and/or protocol is denied." << std::endl;
break;
case EAFNOSUPPORT:
std::cout << "The implementation does not support the specified address family." << std::endl;
break;
case EINVAL:
std::cout << "Unknown protocol, or protocol family not available." << std::endl;
break;
case EMFILE:
std::cout << "Process file table overflow." << std::endl;
break;
case ENFILE:
std::cout << "The system limit on the total number of open files has been reached." << std::endl;
break;
case ENOBUFS:
case ENOMEM:
std::cout << "Insufficient memory is available. The socket cannot be created until sufficient resources are freed." << std::endl;
break;
case EPROTONOSUPPORT:
std::cout << "The protocol type or the specified protocol is not supported within this domain." << std::endl;
break;
default:
return true;
break;
}
return false;
#endif
#ifdef ECHO_PLATFORM_MAC
if(code != -1)
return true;
switch(errno)
{
case EBADF:
std::cout << "The socket argument is not a valid file descriptor." << std::endl;
break;
case EDESTADDRREQ:
std::cout << "The socket is not bound to a local address, and the protocol does not support listening on an unbound socket." << std::endl;
break;
case EINVAL:
std::cout << "The socket is already connected or has been shut down" << std::endl;
break;
case ENOTSOCK:
std::cout << "The socket argument does not refer to a socket." << std::endl;
break;
case EOPNOTSUPP:
std::cout << "The socket protocol does not support listen()" << std::endl;
break;
case EACCES:
std::cout << "Permission to create a socket of the specified type and/or protocol is denied." << std::endl;
break;
case EAFNOSUPPORT:
std::cout << "The specified address family is not supported." << std::endl;
break;
case EISCONN:
std::cout << "The per-process descriptor table is full." << std::endl;
break;
case EMFILE:
std::cout << "The per-process descriptor table is full." << std::endl;
break;
case ENFILE:
std::cout << "The system file table is full." << std::endl;
break;
case ENOBUFS:
std::cout << "Insufficient buffer space is available. The socket cannot be created until sufficient resources are freed." << std::endl;
break;
case ENOMEM:
std::cout << "Insufficient memory was available to fulfill the request." << std::endl;
break;
case EPROTONOSUPPORT:
std::cout << "The protocol type or the specified protocol is not supported within this domain." << std::endl;
break;
case EPROTOTYPE:
std::cout << "The socket type is not supported by the protocol." << std::endl;
break;
default:
return true;
break;
}
#endif
return true;
}
void SocketNetworkSystem::CleanSocket(Socket s)
{
int bOptVal = 1;
int bOptLen = sizeof (int);
if(!HandleError(echo_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&bOptVal, bOptLen)))
{
std::cout << "Error: SocketNetworkSystem::CleanSocket(): Could not set socket for reuse" << std::endl;
}
echo_closesocket(s);
}
void SocketNetworkSystem::EnableSocketWriteCheck(Socket s)
{
std::map< Socket, SocketThreadTask* >::iterator sttit = mSocketThreadTaskConnectionLookup.find(s);
if(sttit != mSocketThreadTaskConnectionLookup.end())
{
sttit->second->EnableWriteCheck(s);
}
}
void SocketNetworkSystem::DisableSocketWriteCheck(Socket s)
{
std::map< Socket, SocketThreadTask* >::iterator sttit = mSocketThreadTaskConnectionLookup.find(s);
if(sttit != mSocketThreadTaskConnectionLookup.end())
{
sttit->second->DisableWriteCheck(s);
}
}
SocketNetworkSystem::SocketThreadTask* SocketNetworkSystem::CreateThreadTask()
{
Thread* t = new Thread();
SocketThreadTask* task = new SocketThreadTask(this);
t->AddTask(task);
//gEchoKernel().AddThread(t);
if(mStarted)
t->Execute();
mThreads.push_back(t);
mSocketThreadTasks.push_back(task);
return task;
}
bool SocketNetworkSystem::Listen(IncomingConnectionListener* listener, const ConnectionDetails& connectionDetails)
{
if(!connectionDetails.HasAddress() || !connectionDetails.HasAdditionalInfo())
{
return false;
}
//Type defaults to Direct
//Type
Socket s = -1;
std::vector< std::string > options;
if(!connectionDetails.HasAdditionalInfo())
return false;
Utils::String::Split(connectionDetails.GetAdditionalInfo(), ":", options);
if(options.empty())
return false;
u16 port = boost::lexical_cast<u16>(options[0]);
std::string connectionType;
if(connectionDetails.HasType())
{
connectionType = connectionDetails.GetType();
} else
{
connectionType = "direct";
}
if(connectionType == "passive")
{
//Setup the UDP Socket
shared_ptr<UDPConnection> udpConnection(new UDPConnection(*this));
udpConnection->SetConnectionDetails(connectionDetails);
//udpConnection->SetTo(connectionDetails.GetAddress());
udpConnection->SetPort_(port);
//udpConnection->SetSocket(s);
//udpConnection->mToSockName = sockinfo;
udpConnection->Connect();
s = udpConnection->mSocket;
mConnectionsMutex.lock();
mConnections[s] = shared_ptr<Connection>(udpConnection);
mConnectionsMutex.unlock();
} else
if(connectionType == "direct")
{
s = echo_socket(AF_INET, SOCK_STREAM, 0);
if(!HandleError(s))
{
std::cout << "Unable to create socket" << std::endl;
return false;
}
shared_ptr<TCPConnection> tcpConnection(new TCPConnection(*this));
u32 addr;
if(connectionDetails.GetAddress() == "ANY")
addr = INADDR_ANY;
else
addr = inet_addr(connectionDetails.GetAddress().c_str());
tcpConnection->SetPort_(htons(port));
tcpConnection->SetIP(addr);
tcpConnection->mSocket = s;
tcpConnection->mSocketAddress.sin_family = AF_INET;
tcpConnection->mSocketAddress.sin_port = htons(port);
tcpConnection->mSocketAddress.sin_addr.s_addr = tcpConnection->mIP;
if(!HandleError(echo_bind(s, (SocketAddress*) & tcpConnection->mSocketAddress, sizeof (tcpConnection->mSocketAddress))))
{
std::cout << "Unable To Bind Listen Socket on port. " << port << std::endl;
echo_closesocket(s);
return false;
}
if(!HandleError(echo_listen(s, 0)))
{
std::cout << "ERROR: setting socket for listening." << std::endl;
return false;
}
if(!SetSocketBlockingEnabled(s, false))
{
std::cout << "ERROR: setting socket to non-blocking" << std::endl;
CleanSocket(s);
return false;
}
std::cout << "Listening on port: " << port << std::endl;
if(mConnections.find(s) != mConnections.end())
{
std::cout << "ERROR: !!!!!!!!!!!!!Socket Collision!!!!!!!!!" << std::endl;
}
mConnectionsMutex.lock();
mConnections[s] = shared_ptr<Connection>(tcpConnection);
mIncomingConnectionListeners[s] = listener;
mConnectionsMutex.unlock();
} else
{
std::cout << "Error: SocketNetworkSystem::Listen(): Unsupported connection type. '" << connectionDetails.GetType() << "'" << std::endl;
return false;
}
if(s == -1)
return 0;
SocketThreadTask* task = 0;
if(!mSocketThreadTasks.empty())
{
task = mSocketThreadTasks.back();
}
if(task == 0)
{
task = CreateThreadTask();
}
if(!task->AddSocket(s))
{
task = CreateThreadTask();
if(!task->AddSocket(s))
{
std::cout << "Error: SocketNetworkSystem::Listen(): unable to queue socket for checking." << std::endl;
}
}
return true;
}
shared_ptr<Connection> SocketNetworkSystem::Connect(const ConnectionDetails& connectionDetails)
{
if(!connectionDetails.HasAddress() || !connectionDetails.HasAdditionalInfo())
{
return shared_ptr<Connection>();
}
//Type defaults to Direct
//Type
shared_ptr<Connection> connection;
std::vector< std::string > options;
if(!connectionDetails.HasAdditionalInfo())
return shared_ptr<Connection>();
Utils::String::Split(connectionDetails.GetAdditionalInfo(), ":", options);
if(options.empty())
return shared_ptr<Connection>();
u16 port = boost::lexical_cast<u16>(options[0]);
std::string connectionType;
if(connectionDetails.HasType())
{
connectionType = connectionDetails.GetType();
} else
{
connectionType = "direct";
}
if(connectionType == "passive")
{
if(port == 0)
return shared_ptr<Connection>();
shared_ptr<UDPConnection> udpConnection(new UDPConnection(*this));
udpConnection->SetConnectionDetails(connectionDetails);
udpConnection->Connect();
connection = shared_ptr<Connection>(udpConnection);
} else
if(connectionType == "direct")
{
shared_ptr<TCPConnection> tcpConnection(new TCPConnection(*this));
tcpConnection->SetConnectionDetails(connectionDetails);
tcpConnection->Connect();
connection = shared_ptr<Connection>(tcpConnection);
} else
{
std::cout << "Error: SocketNetworkSystem::Listen(): Unsupported connection type. '" << connectionDetails.GetType() << "'" << std::endl;
return shared_ptr<Connection>();
}
return connection;
}
void SocketNetworkSystem::UpdateSocket(Socket s, shared_ptr<Connection> connection)
{
Socket originalSocket = -1;
mConnectionsMutex.lock();
//Update the connection lookup and find the original socket
std::map< Socket, shared_ptr<Connection> >::iterator it = mConnections.begin();
std::map< Socket, shared_ptr<Connection> >::iterator itEnd = mConnections.end();
while(it != itEnd)
{
if(it->second == connection)
{
originalSocket = it->first;
mConnections.erase(it);
break;
}
++it;
}
if(s != -1)
mConnections[s] = connection;
mConnectionsMutex.unlock();
//Find Thread Task that has the connection and update it
std::map< Socket, SocketThreadTask* >::iterator sttit = mSocketThreadTaskConnectionLookup.find(originalSocket);
if(sttit != mSocketThreadTaskConnectionLookup.end())
{
sttit->second->RemoveSocket(originalSocket);
if(s != -1)
sttit->second->AddSocket(s);
} else
{
if(s == -1)
return;
SocketThreadTask* task = 0;
if(!mSocketThreadTasks.empty())
{
task = mSocketThreadTasks.back();
}
if(task == 0)
{
task = CreateThreadTask();
}
bool added = task->AddSocket(s);
if(!added)
{
task = CreateThreadTask();
if(!task->AddSocket(s))
{
std::cout << "Error: SocketNetworkSystem::Connect(): unable to queue socket for checking." << std::endl;
} else
{
added = true;
}
}
if(added)
{
mSocketThreadTaskConnectionLookup[s] = task;
}
}
}
}

File Metadata

Mime Type
text/x-c++
Expires
Thu, Dec 5, 6:49 PM (23 h, 49 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
63578
Default Alt Text
SocketNetworkSystem.cpp (30 KB)

Event Timeline