Page MenuHomePhorge

TCPConnection.cpp
No OneTemporary

Size
20 KB
Referenced Files
None
Subscribers
None

TCPConnection.cpp

#include <echo/Network/NetRedefinitions.h>
#include <echo/Network/TCPConnection.h>
#include <echo/Network/DataPacket.h>
#include <echo/Network/SocketNetworkSystem.h>
#include <echo/Util/StringUtils.h>
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <errno.h>
#include <unistd.h>
namespace Echo
{
TCPConnection::TCPConnection(SocketNetworkSystem& manager) : Connection(manager.GetNetworkManager()), mManager(manager)
{
memset(&mSocketAddress, 0, sizeof (SocketAddressIn));
mSocket = -1;
}
TCPConnection::~TCPConnection() { }
void TCPConnection::SetIP(u32 ip)
{
mIP = ip;
}
void TCPConnection::SetPort_(u16 port)
{
mPort = port;
}
bool TCPConnection::_Connect()
{
if(!(IsConnected()))
{
SetState(States::CONNECTING);
u16 port = mSocketAddress.sin_port;
mSocket = echo_socket(AF_INET, SOCK_STREAM, 0);
if(!SocketNetworkSystem::HandleError(mSocket))
{
mSocket = -1;
std::cout << "Unable to create socket" << std::endl;
SetState(States::DISCONNECTED);
mManager.UpdateSocket(mSocket, shared_from_this());
return false;
}
if(!mManager.SetSocketBlockingEnabled(mSocket, false))
{
SetState(States::DISCONNECTED);
mManager.CleanSocket(mSocket);
mSocket = -1;
mManager.UpdateSocket(mSocket, shared_from_this());
return false;
}
std::vector< std::string > options;
if(mConnectionDetails.HasAdditionalInfo())
{
Utils::String::Split(mConnectionDetails.GetAdditionalInfo(), ":", options);
if(options.empty())
{
SetState(States::DISCONNECTED);
return false;
}
port = boost::lexical_cast<u16>(options[0]);
}
u32 addr;
if(mConnectionDetails.GetAddress() == "ANY")
{
addr = INADDR_ANY;
}else
{
if(!SocketNetworkSystem::GetHostByName(mConnectionDetails.GetAddress(),addr))
{
std::cout << "Error: Unable to resolve hostname " << mConnectionDetails.GetAddress() << std::endl;
return false;
}
}
SetIP(addr);
mSocketAddress.sin_family = AF_INET;
mSocketAddress.sin_port = htons(port);
mSocketAddress.sin_addr.s_addr = mIP;
std::cout << "Connecting to " << mConnectionDetails.GetAddress() << "... ";
if(!_HandleError(echo_connect(mSocket, (const sockaddr*)&mSocketAddress, sizeof (SocketAddressIn))))
{
std::cout << "ERROR initiating connection attempt." << std::endl;
SetState(States::DISCONNECTED);
mManager.CleanSocket(mSocket);
mSocket = -1;
return false;
}
mManager.UpdateSocket(mSocket, shared_from_this());
return true;
}
return false;
}
bool TCPConnection::_Disconnect()
{
if(mState!=States::DISCONNECTED)
{
SetState(States::DISCONNECTED);
mManager.UpdateSocket(-1, shared_from_this());
mManager.CleanSocket(mSocket);
mSocket = -1;
mManager.UpdateConnect(shared_from_this());
return true;
}
return false;
}
void TCPConnection::_dropped()
{
std::cout << "Disconnected: " << GetFriendlyIdentifier() << std::endl;
if(mSocket != -1)
mManager.CleanSocket(mSocket);
Connection::_dropped();
}
void TCPConnection::_established()
{
std::cout << "Connected: " << GetFriendlyIdentifier() << std::endl;
Connection::_established();
}
int TCPConnection::_send(const u8 * buf, int len, int flags)
{
return echo_send(mSocket, (char*)buf, len, flags);
}
int TCPConnection::_recv(u8 * buf, int len, int flags)
{
return echo_recv(mSocket, (char*)buf, len, flags);
}
bool TCPConnection::_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 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;
case WSAENOTSOCK:
//std::cout << "WSAENOTSOCK - The descriptor is not a socket. " << std::endl;
case WSAENETUNREACH:
case WSAENETDOWN:
case WSAECONNABORTED:
case WSAECONNRESET:
_Disconnect();
break;
default:
std::cout << "Unknown Error: " << e << " : " << std::hex << e << std::dec << std::endl;
break;
}
return false;
}
return true;
#else //( ECHO_PLATFORM_LINUX ) || defined (ECHO_PLATFORM_MAC) and all others
switch(code)
{
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
}
bool TCPConnection::_HandleRecvError(int code)
{
if(code == 0)
{
_Disconnect();
return false;
}
#ifdef ECHO_PLATFORM_WINDOWS
if(code == SOCKET_ERROR)
{
int e = WSAGetLastError();
switch(e)
{
//case WSAENETDOWN:
// std::cout << "WSAENETDOWN - A Problem with the network has been encountered.\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 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 false;
break;
case WSAENETUNREACH:
case WSAENETDOWN:
case WSAECONNABORTED:
case WSAECONNRESET:
_Disconnect();
break;
default:
std::cout << "Unknown Error: " << e << " : " << std::hex << e << std::dec << std::endl;
break;
}
return false;
}
return true;
#elif defined (ECHO_PLATFORM_MAC)
if(code != -1)
return true;
switch(errno)
{
case EAGAIN:
std::cout << "The socket is marked non-blocking, and the receive operation would block, or a receive timeout had been set, and the timeout expired before data were received." << std::endl;
break;
case EBADF:
std::cout << "The argument socket is an invalid descriptor." << std::endl;
break;
case ECONNRESET:
//Disconnect
_Disconnect();
std::cout << "The connection is closed by the peer during a receive attempt on a socket." << std::endl;
break;
case EFAULT:
std::cout << "The receive buffer pointer(s) point outside the process's address space." << std::endl;
break;
case EINTR:
std::cout << "The receive was interrupted by delivery of a signal before any data were available." << std::endl;
break;
case EINVAL:
std::cout << "MSG_OOB is set, but no out-of-band data is available." << std::endl;
break;
case ENOBUFS:
std::cout << "An attempt to allocate a memory buffer fails." << std::endl;
break;
case ENOTCONN:
std::cout << "The socket is associated with a connection-oriented protocol and has not been connected (see connect(2) and accept(2))." << std::endl;
break;
case ENOTSOCK:
std::cout << "The argument socket does not refer to a socket." << std::endl;
break;
case EOPNOTSUPP:
std::cout << "The type and/or protocol of socket do not support the option(s) specified in flags." << std::endl;
break;
case ETIMEDOUT:
std::cout << "The connection timed out." << std::endl;
break;
default:
break;
}
return false;
#else //ECHO_PLATFORM_LINUX and all other platforms
if(code != -1)
return true;
switch(errno)
{
case EAGAIN:
std::cout << "The socket is marked non-blocking and the receive operation would block, or a receive timeout had been set and the timeout expired before data was received." << std::endl;
break;
case EBADF:
std::cout << "The argument s is an invalid descriptor." << std::endl;
break;
case ECONNREFUSED:
std::cout << "A remote host refused to allow the network connection (typically because it is not running the requested service)." << std::endl;
break;
case EFAULT:
std::cout << "The receive buffer pointer(s) point outside the process's address space." << std::endl;
break;
case EINTR:
std::cout << "The receive was interrupted by delivery of a signal before any data were available." << std::endl;
break;
case EINVAL:
std::cout << "Invalid argument passed." << std::endl;
break;
case ENOMEM:
std::cout << "Could not allocate memory for recvmsg()." << std::endl;
break;
case ENOTCONN:
std::cout << "The socket is associated with a connection-oriented protocol and has not been connected (see connect(2) and accept(2))." << std::endl;
break;
case ENOTSOCK:
std::cout << "The argument s does not refer to a socket." << std::endl;
break;
default:
break;
}
_Disconnect();
return false;
#endif
}
bool TCPConnection::_HandleWriteError(int code)
{
#ifdef ECHO_PLATFORM_WINDOWS
if(code == SOCKET_ERROR)
{
int e = WSAGetLastError();
switch(e)
{
case WSAEADDRNOTAVAIL:
std::cout << "WSAEADDRNOTAVAIL - Invalid address" << std::endl;
break;
case WSAECONNREFUSED:
std::cout << "WSAECONNREFUSED - Connection was refused by host" << std::endl;
break;
case WSAEISCONN:
std::cout << "WSAEISCONN - Socket already connected" << std::endl;
break;
case WSAEHOSTUNREACH:
std::cout << "WSAEHOSTUNREACH - Host unreachable" << 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 false;
break;
case WSAENETUNREACH:
case WSAENETDOWN:
case WSAECONNABORTED:
case WSAECONNRESET:
if(e == WSAECONNRESET)
std::cout << "WSAECONNRESET - The connection was reset" << std::endl;
if(e == WSAENETUNREACH)
std::cout << "WSAENETUNREACH - Network unreachable" << std::endl;
if(e == WSAENETDOWN)
std::cout << "WSAENETDOWN - A Problem with the network has been encountered." << std::endl;
_Disconnect();
break;
default:
std::cout << "Unknown Error: " << e << " : " << std::hex << e << std::dec << std::endl;
break;
}
return false;
}
return true;
#elif defined (ECHO_PLATFORM_MAC)
if(code != -1)
return true;
switch(errno)
{
case EACCES:
std::cout << "The SO_BROADCAST option is not set on the socket and a broadcast address is given as the destination." << std::endl;
break;
case EAGAIN:
std::cout << "The socket is marked non-blocking and the requested operation would block." << std::endl;
break;
case EBADF:
std::cout << "An invalid descriptor is specified." << std::endl;
break;
case ECONNRESET:
std::cout << "A connection is forcibly closed by a peer." << std::endl;
break;
case EFAULT:
std::cout << "An invalid user space address is specified for a parameter." << std::endl;
break;
case EHOSTUNREACH:
std::cout << "The destination address specifies an unreachable host." << std::endl;
break;
case EINTR:
std::cout << "A signal interrupts the system call before any data is transmitted." << std::endl;
break;
case EMSGSIZE:
std::cout << "The socket requires that message be sent atomically, and the size of the message to be sent makes this impossible. IOV_MAX." << std::endl;
break;
case ENETDOWN:
std::cout << "The local network interface used to reach the destination is down." << std::endl;
break;
case ENETUNREACH:
std::cout << "No route to the network is present." << std::endl;
break;
case ENOBUFS:
mManager.EnableSocketWriteCheck(mSocket);
std::cout << "Either: The system is unable to allocate an internal buffer. The operation may succeed when buffers become available." << std::endl;
std::cout << "OR: The output queue for a network interface is full. This generally indicates that the interface has stopped sending, but may be caused by transient congestion." << std::endl;
break;
case ENOTSOCK:
std::cout << "The argument socket is not a socket." << std::endl;
break;
case EOPNOTSUPP:
std::cout << "socket does not support (some of) the option(s) specified in flags." << std::endl;
break;
case EPIPE:
std::cout << "The socket is shut down for writing or the socket is connection-mode and is no \
longer connected. In the latter case, and if the socket is of type SOCK_STREAM, the \
SIGPIPE signal is generated to the calling thread." << std::endl;
break;
case EDESTADDRREQ:
std::cout << "The socket is not connection-mode and no peer address is set." << std::endl;
break;
case ENOTCONN:
std::cout << "The socket is not connected or otherwise has not had the peer pre-specified." << std::endl;
break;
default:
break;
}
return false;
#else //ECHO_PLATFORM_LINUX and all other platforms (assuming default.)
if(code != -1)
return true;
std::cout << "Write error" << std::endl;
switch(errno)
{
case EACCES:
std::cout << "(For Unix domain sockets, which are identified by pathname) Write permission is denied on the destination socket file, or search permission is denied for one of the directories the path prefix. (See path_resolution(2).)" << std::endl;
_Disconnect();
break;
//case EAGAIN:
case EWOULDBLOCK:
//This is ok, we'll just try again.
//std::cout << "The socket is marked non-blocking and the requested operation would block." << std::endl;
break;
case EBADF:
std::cout << "An invalid descriptor was specified." << std::endl;
_Disconnect();
break;
case ECONNRESET:
std::cout << "Connection reset by peer." << std::endl;
_Disconnect();
break;
case EDESTADDRREQ:
std::cout << "The socket is not connection-mode, and no peer address is set." << std::endl;
_Disconnect();
break;
case EFAULT:
std::cout << "An invalid user space address was specified for a parameter." << std::endl;
_Disconnect();
break;
case EINTR:
std::cout << "A signal occurred before any data was transmitted." << std::endl;
_Disconnect();
break;
case EINVAL:
std::cout << "Invalid argument passed." << std::endl;
_Disconnect();
break;
case EISCONN:
std::cout << "The connection-mode socket was connected already but a recipient was specified. (Now either this error is returned, or the recipient specification is ignored.)" << std::endl;
break;
case EMSGSIZE:
std::cout << "The socket type requires that message be sent atomically, and the size of the message to be sent made this impossible." << std::endl;
break;
case ENOBUFS:
std::cout << "The output queue for a network interface was full. This generally indicates that the interface has stopped sending, but may be caused by transient congestion. (Normally, this does not occur in Linux. Packets are just silently dropped when a device queue overflows.)" << std::endl;
break;
case ENOMEM:
std::cout << "No memory available." << std::endl;
_Disconnect();
break;
case ENOTCONN:
std::cout << "The socket is not connected, and no target has been given." << std::endl;
_Disconnect();
break;
case ENOTSOCK:
std::cout << "The argument s is not a socket." << std::endl;
_Disconnect();
break;
case EOPNOTSUPP:
std::cout << "Some bit in the flags argument is inappropriate for the socket type." << std::endl;
_Disconnect();
break;
case EPIPE:
std::cout << "The local end has been shut down on a connection oriented socket. In this case the process will also receive a SIGPIPE unless MSG_NOSIGNAL is set." << std::endl;
_Disconnect();
break;
default:
break;
}
return false;
#endif
}
}

File Metadata

Mime Type
text/x-c++
Expires
Thu, Dec 5, 2:04 AM (7 h, 19 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
63570
Default Alt Text
TCPConnection.cpp (20 KB)

Event Timeline