diff --git a/src/Network/BluetoothConnection.cpp b/src/Network/BluetoothConnection.cpp --- a/src/Network/BluetoothConnection.cpp +++ b/src/Network/BluetoothConnection.cpp @@ -1,789 +1,787 @@ #include #include #include #include #include #include #include #include #include #include #ifdef ECHO_PLATFORM_ANDROID #include int bachk(const char *str) { if (!str) return -1; if (strlen(str) != 17) return -1; while (*str) { if (!isxdigit(*str++)) return -1; if (!isxdigit(*str++)) return -1; if (*str == 0) break; if (*str++ != ':') return -1; } return 0; } int str2ba(const char *str, bdaddr_t *ba) { int i; if (bachk(str) < 0) { memset(ba, 0, sizeof(*ba)); return -1; } for (i = 5; i >= 0; i--, str += 3) ba->b[i] = strtol(str, NULL, 16); return 0; } #endif namespace Echo { BluetoothConnection::BluetoothConnection(SocketNetworkSystem& manager) : Connection(manager.GetNetworkManager()), mManager(manager) { memset(&mSocketAddress, 0, sizeof (sockaddr_rc)); mSocket = -1; } BluetoothConnection::~BluetoothConnection() { } void BluetoothConnection::SetAddress(std::string address) { - boost::replace_all(address,".", ":"); + boost::replace_all(address,",", ":"); mAddress = address; } void BluetoothConnection::SetPort(u8 port) { mPort = port; } bool BluetoothConnection::_Connect() { if(!(IsConnected())) { SetState(States::CONNECTING); - uint8_t port = mSocketAddress.rc_channel; + uint8_t port = 1; // default port if not specified mSocket = echo_socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); 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)) { std::cout << "Error: Failed to make socket non-blocking." << std::endl; 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()) { std::cout << "Error: could not parse additional options: " << mConnectionDetails.GetAdditionalInfo() << std::endl; SetState(States::DISCONNECTED); return false; } try { - port = boost::lexical_cast(options[0]); + port = static_cast(boost::lexical_cast(options[0])); }catch(...) { std::cout << "Error: could not parse port from additional options: " << mConnectionDetails.GetAdditionalInfo() << std::endl; SetState(States::DISCONNECTED); return false; } } SetAddress(mConnectionDetails.GetAddress()); if(mAddress == "ANY") { // BDADDR_ANY is an address of all zeros, but using the macro for assignment causes compile errors. mSocketAddress.rc_bdaddr = (bdaddr_t) {{0, 0, 0, 0, 0, 0}};; }else { if(str2ba( mAddress.c_str(), &mSocketAddress.rc_bdaddr )) { - std::cout << "Error: cannot convert address " << std::endl; + std::cout << "Error: cannot convert address: " << mAddress << std::endl; SetState(States::DISCONNECTED); return false; } } mSocketAddress.rc_family = AF_BLUETOOTH; mSocketAddress.rc_channel = port; - std::cout << "Connecting to " << mConnectionDetails.GetAddress() << "... "; - + std::cout << "Connecting to " << mConnectionDetails.GetAddress() << " channel " << mSocketAddress.rc_channel << std::endl; + if(!_HandleError(echo_connect(mSocket, (const sockaddr*)&mSocketAddress, sizeof(sockaddr_rc)))) { 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 BluetoothConnection::_Disconnect() { if(mState!=States::DISCONNECTED) { SetState(States::DISCONNECTED); shared_ptr thisConnection=shared_from_this(); mManager.UpdateSocket(-1, thisConnection); mManager.CleanSocket(mSocket); mSocket = -1; mManager.UpdateConnect(thisConnection); return true; } return false; } void BluetoothConnection::_dropped() { std::cout << "Disconnected: " << GetFriendlyIdentifier() << std::endl; if(mSocket != -1) mManager.CleanSocket(mSocket); Connection::_dropped(); } void BluetoothConnection::_established() { std::cout << "Connected: " << GetFriendlyIdentifier() << std::endl; Connection::_established(); } int BluetoothConnection::_send(const u8 * buf, int len, int flags) { return echo_send(mSocket, (char*)buf, len, flags); } int BluetoothConnection::_recv(u8 * buf, int len, int flags) { return echo_recv(mSocket, (char*)buf, len, flags); } bool BluetoothConnection::_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 BluetoothConnection::_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; #elif defined (ECHO_PLATFORM_NINTENDO_GAMECUBE_OR_WII) code=-code; //Transform the code from negative to positive. switch(code) { case EWOULDBLOCK: //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; //This should be ok to continue. return true; 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: std::cout << "Recv error: " << code << std::endl; break; } _Disconnect(); 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 BluetoothConnection::_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; #elif defined (ECHO_PLATFORM_NINTENDO_GAMECUBE_OR_WII) if(code >= 0) { return true; } code=-code; //Transform the code from negative to positive. 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 when write becomes available. //std::cout << "The socket is marked non-blocking and the requested operation would block." << std::endl; mManager.EnableSocketWriteCheck(mSocket); return true; 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: mManager.EnableSocketWriteCheck(mSocket); 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; } #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: mManager.EnableSocketWriteCheck(mSocket); 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 } } diff --git a/src/Network/SocketNetworkSystem.cpp b/src/Network/SocketNetworkSystem.cpp --- a/src/Network/SocketNetworkSystem.cpp +++ b/src/Network/SocketNetworkSystem.cpp @@ -1,1088 +1,1090 @@ #include #include #include #include #include #include #include #include #include #include #include #include #include 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 = 5; timeOut.tv_usec = 0; fd_set readSet = mReadSet; fd_set writeSet = mWriteSet; fd_set exceptSet = mExceptSet; int selectReturn = echo_select(mHighestSocket, &readSet, &writeSet, &exceptSet, &timeOut); //std::cout << "Post select" << std::endl; if(selectReturn >= 0) { std::list< Socket >::iterator it = mAllSockets.begin(); std::list< Socket >::iterator itEnd = mAllSockets.end(); while(it != itEnd) { Socket currentSocket = (*it); if(FD_ISSET(currentSocket, &exceptSet)) { //std::cout << "ExceptNotify" << std::endl; mSystem->ExceptNotify(currentSocket); mPendingSocketsMutex.Lock(); mPendingRemovalSockets.push_back(currentSocket); mPendingSocketsMutex.Unlock(); } else { //We'll process read first as this will allow us to detect bad connections. if(FD_ISSET(currentSocket, &readSet)) { //std::cout << "ReadNotify" << std::endl; mSystem->ReadNotify(currentSocket); } if(FD_ISSET(currentSocket, &writeSet)) { //std::cout << "WriteNotify" << std::endl; DisableWriteCheck(currentSocket); //For unix systems that continually report write, //it is re-enabled in connection write error mSystem->WriteNotify(currentSocket); } } //Check for any connecting timeouts. mSystem->CheckForTimeout(currentSocket); ++it; } } else { (void)SocketNetworkSystem::HandleError(selectReturn); //some error std::cout << "Select error." << std::endl; } } mPendingSocketsMutex.Lock(); bool findHighest = false; //Remove any sockets that are pending removal while(!mPendingRemovalSockets.empty()) { Socket currentSocket = mPendingRemovalSockets.back(); mPendingRemovalSockets.pop_back(); if(currentSocket == mHighestSocket - 1) { findHighest = true; } FD_CLR(currentSocket, &mReadSet); FD_CLR(currentSocket, &mWriteSet); FD_CLR(currentSocket, &mExceptSet); mAllSockets.remove(currentSocket); } //Remove any write sockets that are pending write notification removal for(u32 i = 0; i < mPendingWriteDisableSockets.size(); ++i) { //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[i], &mWriteSet); } //Add any write sockets that are pending writing notifications for(u32 i = 0; i < mPendingWriteEnableSockets.size(); ++i) { //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[i], &mWriteSet); } if(findHighest) { mHighestSocket = 0; std::list< Socket >::iterator it = mAllSockets.begin(); std::list< Socket >::iterator itEnd = mAllSockets.end(); while(it != itEnd) { Socket currentSocket = (*it); if(currentSocket >= (Socket)mHighestSocket) { mHighestSocket = currentSocket + 1; } ++it; } } while(!mPendingSockets.empty()) { int currentSocket = mPendingSockets.back(); mPendingSockets.pop_back(); if(currentSocket >= mHighestSocket) { mHighestSocket = currentSocket + 1; } mAllSockets.push_back(currentSocket); FD_SET(currentSocket, &mReadSet); FD_SET(currentSocket, &mWriteSet); FD_SET(currentSocket, &mExceptSet); } mPendingSocketsMutex.Unlock(); } ////////////////////////////////////////////////////////////////////////// SocketNetworkSystem::SocketNetworkSystem(NetworkManager& networkManager) : NetworkSystem("Socket", networkManager) { mStarted = false; } SocketNetworkSystem::~SocketNetworkSystem() { CleanUp(); } 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 #ifdef ECHO_PLATFORM_NINTENDO_WII std::cout << "Initialising Networking..." << std::endl; //wait_for_network_initialisation(); if(if_config(0,0,0,1) < 0) { std::cout << "Network access unavailable." << std::endl; }else { std::cout << "Network access available." << std::endl; } #endif return true; } bool SocketNetworkSystem::Start() { //We'll just start threads when we need to std::vector< TaskThread* >::iterator it = mThreads.begin(); std::vector< TaskThread* >::iterator itEnd = mThreads.end(); while(it != itEnd) { (*it)->Execute(); ++it; } mStarted = true; return true; } void SocketNetworkSystem::DisconnectAll() { // Create a copy of the connections list since a connect request can affect // the list and we can't hold the lock while attempting to disconnect. A // disconnect will not do anything the connection is already disconnected. mConnectionsMutex.Lock(); std::map< Socket, shared_ptr > connections = mConnections; mConnectionsMutex.Unlock(); std::map< Socket, shared_ptr >::iterator it = connections.begin(); std::map< Socket, shared_ptr >::iterator itEnd = connections.end(); while(it!=itEnd) { it->second->Disconnect(); ++it; } } void SocketNetworkSystem::CleanUp() { DisconnectAll(); std::vector< TaskThread* >::iterator it = mThreads.begin(); std::vector< TaskThread* >::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"); outSupportedConnectionTypes.push_back("btdirect"); } void SocketNetworkSystem::GetAdditionalConnectionInformationFormat(std::vector< std::string >& outAdditionalInformation) { outAdditionalInformation.push_back("port,BROADCAST(optional)"); outAdditionalInformation.push_back("port"); outAdditionalInformation.push_back("port"); outAdditionalInformation.push_back("port"); } bool SocketNetworkSystem::GetInterfaceInformation(std::vector& outInterfaceInformation) { InterfaceInformation interfaceInformation; char ac[80]; if(echo_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) { interfaceInformation.mIPAddress = inet_ntoa(*reinterpret_cast(&phe->h_addr_list[i])); //cout << "Address " << i << ": " << inet_ntoa(addr) << endl; //Determine the subnet mask outInterfaceInformation.push_back(interfaceInformation); } return 0; } bool SocketNetworkSystem::AcceptConnection(Socket s) { 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 false; sockaddr_in sockaddrFrom; socklen_t len = sizeof (sockaddr_in); memset(&sockaddrFrom, 0, len); Socket newSocket = echo_accept(s, (SocketAddress*) & sockaddrFrom, &len); shared_ptr connection(new TCPConnection(*this)); connection->SetIP(sockaddrFrom.sin_addr.s_addr); connection->SetPort_(sockaddrFrom.sin_port); connection->mSocket = newSocket; connection->mSocketAddress = sockaddrFrom; connection->SetState(Connection::States::CONNECTED); shared_ptr connectionptr=shared_ptr(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); return true; } void SocketNetworkSystem::CheckForTimeout(Socket s) { mConnectionsMutex.Lock(); std::map< Socket, shared_ptr >::iterator it = mConnections.find(s); if(it == mConnections.end()) { //This is not an error because the connection may have disconnected between read or write processing and checking for a timeout. mConnectionsMutex.Unlock(); return; } shared_ptr connection = it->second; mConnectionsMutex.Unlock(); if(connection->GetConnecting()) { connection->_Disconnect(); } } bool SocketNetworkSystem::IsSocketConnected(Socket s) { mConnectionsMutex.Lock(); std::map< Socket, shared_ptr >::iterator it = mConnections.find(s); if(it != mConnections.end()) { return it->second->IsConnected(); } mConnectionsMutex.Unlock(); return false; } void SocketNetworkSystem::ReadNotify(Socket s) { mConnectionsMutex.Lock(); std::map< Socket, shared_ptr >::iterator it = mConnections.find(s); if(it == mConnections.end()) { mConnectionsMutex.Unlock(); return; } shared_ptr connection = it->second; mConnectionsMutex.Unlock(); if(!connection->IsConnected()) { //Attempt to accept a new incoming connection if(AcceptConnection(s)) { return; } // Must be a new connection in the other direction. We'll set to connected // and UpdateReceive() will disconnect on error. connection->SetState(Connection::States::CONNECTED); } UpdateReceive(connection); } void SocketNetworkSystem::WriteNotify(Socket s) { mConnectionsMutex.Lock(); std::map< Socket, shared_ptr >::iterator it = mConnections.find(s); if(it == mConnections.end()) { //This is not an error because the connection may have disconnected between read processing and write processing. mConnectionsMutex.Unlock(); return; } shared_ptr connection = it->second; mConnectionsMutex.Unlock(); if(connection->GetConnecting()) { connection->SetState(Connection::States::CONNECTED); UpdateConnect(connection); } UpdateWrite(connection); } void SocketNetworkSystem::ExceptNotify(Socket s) { mConnectionsMutex.Lock(); std::map< Socket, shared_ptr >::iterator it = mConnections.find(s); if(it == mConnections.end()) { std::cout << "SocketNetworkSystem::ExceptNotify(): Socket not associated with a connection." << std::endl; mConnectionsMutex.Unlock(); return; } // Exception can occur on TCP streams when out of band data is available for reading. This is // apparently very rare and often not used. Based on that, we'll disconnect the connection in // case of an attempt to find an exploit. it->second->Disconnect(); 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 (echo_net_ioctl(fd, FIONBIO, &mode) == 0) ? true : false; #elif defined (ECHO_PLATFORM_NINTENDO_WII) //This is adapted from the net_ioctl() implementation. The network_wii code includes the following define: // #define IOS_O_NONBLOCK 0x04 //(O_NONBLOCK >> 16) - it's in octal representation, so this shift // leads to 0 and hence nonblocking sockets didn't work. changed it to the right value. // So I've hard coded this value in here. u32 flags = net_fcntl(fd, F_GETFL, 0); const u32 IOS_O_NONBLOCK=0x4; flags &= ~IOS_O_NONBLOCK; if (!blocking) { flags |= IOS_O_NONBLOCK; } return (net_fcntl(fd, F_SETFL, flags)==0); #else int flags = echo_net_fcntl(fd, F_GETFL, 0); if(flags < 0) { return false; } flags = blocking ? (flags&~O_NONBLOCK) : (flags | O_NONBLOCK); return (echo_net_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; } return true; #elif defined (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; } #else //ECHO_PLATFORM_LINUX and all others (assuming nix) if(code >= 0) 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 false; break; } #endif return false; } 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() { TaskThread* t = new TaskThread("SocketNetworkSystem worker"); SocketThreadTask* task = new SocketThreadTask(this); t->AddTask(task); 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(options[0]); std::string connectionType; if(connectionDetails.HasType()) { connectionType = connectionDetails.GetType(); } else { connectionType = "direct"; } //TODO: Move these implementation details into the corresponding connection classes. if(connectionType == "passive") { //Setup the UDP Socket shared_ptr 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] = 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(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; // Enable address reuse int on = 1; if(!HandleError(echo_setsockopt( s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ))) { std::cout << "Unable to flag the socket for resuse, re-binding later may fail." << std::endl; } if(!HandleError(echo_bind(s, (SocketAddress*)&tcpConnection->mSocketAddress, sizeof (SocketAddressIn)))) { 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] = tcpConnection; mIncomingConnectionListeners[s] = listener; mConnectionsMutex.Unlock(); } else if(connectionType == "btdirect") { s = echo_socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); if(!HandleError(s)) { std::cout << "ERROR: Unable to create bluetooth socket" << std::endl; return false; } shared_ptr bluConnection(new BluetoothConnection(*this)); bluConnection->SetAddress(connectionDetails.GetAddress()); bluConnection->SetPort(htons(port)); if(bluConnection->GetAddress() == "ANY") { // BDADDR_ANY is an address of all zeros, but using the macro for assignment causes compile errors. bluConnection->mSocketAddress.rc_bdaddr = (bdaddr_t) {{0, 0, 0, 0, 0, 0}}; }else { if(str2ba( bluConnection->GetAddress().c_str(), &bluConnection->mSocketAddress.rc_bdaddr )) { std::cout << "Error: cannot convert address " << std::endl; return false; } } bluConnection->mSocketAddress.rc_family = AF_BLUETOOTH; bluConnection->mSocketAddress.rc_channel = bluConnection->GetPort(); bluConnection->mSocket = s; // Enable address reuse int on = 1; if(!HandleError(echo_setsockopt( s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ))) { std::cout << "Unable to flag the socket for resuse, re-binding later may fail." << std::endl; } if(!HandleError(echo_bind(s, (SocketAddress*)&bluConnection->mSocketAddress, sizeof(sockaddr_rc)))) { 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 Bluetooth port: " << port << std::endl; if(mConnections.find(s) != mConnections.end()) { std::cout << "ERROR: !!!!!!!!!!!!!Socket Collision!!!!!!!!!" << std::endl; } mConnectionsMutex.Lock(); mConnections[s] = bluConnection; mIncomingConnectionListeners[s] = listener; mConnectionsMutex.Unlock(); } else { std::cout << "Error: SocketNetworkSystem::Listen(): Unsupported connection type. '" << connectionDetails.GetType() << "'" << std::endl; return false; } if(s == -1) { return false; } 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 SocketNetworkSystem::Connect(const ConnectionDetails& connectionDetails) { if(!connectionDetails.HasAddress() || !connectionDetails.HasAdditionalInfo()) { return shared_ptr(); } //Type defaults to Direct //Type shared_ptr connection; std::vector< std::string > options; if(!connectionDetails.HasAdditionalInfo()) return shared_ptr(); Utils::String::Split(connectionDetails.GetAdditionalInfo(), ",", options); if(options.empty()) return shared_ptr(); u16 port = boost::lexical_cast(options[0]); std::string connectionType; if(connectionDetails.HasType()) { connectionType = connectionDetails.GetType(); } else { connectionType = "direct"; } if(connectionType == "passive") { if(port == 0) return shared_ptr(); shared_ptr udpConnection(new UDPConnection(*this)); udpConnection->SetConnectionDetails(connectionDetails); udpConnection->Connect(); connection = udpConnection; } else if(connectionType == "direct") { shared_ptr tcpConnection(new TCPConnection(*this)); tcpConnection->SetConnectionDetails(connectionDetails); tcpConnection->Connect(); connection = tcpConnection; } else if(connectionType == "btdirect") { shared_ptr bluetoothConnection(new BluetoothConnection(*this)); bluetoothConnection->SetConnectionDetails(connectionDetails); bluetoothConnection->Connect(); connection = bluetoothConnection; } else { std::cout << "Error: SocketNetworkSystem::Listen(): Unsupported connection type. '" << connectionDetails.GetType() << "'" << std::endl; return shared_ptr(); } return connection; } void SocketNetworkSystem::UpdateSocket(Socket s, shared_ptr connection) { Socket originalSocket = -1; mConnectionsMutex.Lock(); //Update the connection lookup and find the original socket std::map< Socket, shared_ptr >::iterator it = mConnections.begin(); std::map< Socket, shared_ptr >::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; } } } bool SocketNetworkSystem::GetHostByName(const std::string& hostnameOrIP, u32& output) { #if defined(ECHO_WINSOCKS_NETWORKING) || defined(ECHO_POSIX_NETWORKING) struct addrinfo* dnsResult; int e = getaddrinfo(hostnameOrIP.c_str(),NULL,NULL,&dnsResult); if(e != 0) { std::cout << "Error SocketNetworkSystem::GetHostByName(): getaddrinfo returned: " << e << std::endl; + return false; }else { if(dnsResult) { //Is it an IPv4? if((dnsResult->ai_protocol==IPPROTO_TCP || dnsResult->ai_protocol==IPPROTO_UDP) && dnsResult->ai_addrlen==sizeof(SocketAddressIn)) { struct sockaddr_in* inSockAddr = reinterpret_cast(dnsResult->ai_addr); output = inSockAddr->sin_addr.s_addr; freeaddrinfo(dnsResult); return true; }else { if(dnsResult->ai_protocol!=IPPROTO_TCP || dnsResult->ai_protocol!=IPPROTO_UDP) { std::cout << "Error SocketNetworkSystem::GetHostByName(): ai_protocol!=IPPROTO_TCP || ai_protocol!=IPPROTO_UDP: " << dnsResult->ai_protocol << std::endl; } if(dnsResult->ai_addrlen!=sizeof(SocketAddressIn)) { std::cout << "Error SocketNetworkSystem::GetHostByName(): ai_addrlen!=sizeof(SocketAddressIn): " << sizeof(SocketAddressIn) << std::endl; } } }else { std::cout << "Error SocketNetworkSystem::GetHostByName(): getaddrinfo: dnsResult is null " << std::endl; + return false; } } freeaddrinfo(dnsResult); #elif defined(ECHO_WII_NETWORKING) // There is a function net_gethostbyname() but when I tested it the system froze. // This will do for IP addresses. output = inet_addr(hostnameOrIP.c_str()); return output!=0; #endif return false; } }