diff options
author | Rat <none@none> | 2010-06-07 19:35:24 +0200 |
---|---|---|
committer | Rat <none@none> | 2010-06-07 19:35:24 +0200 |
commit | e4e13c2bb8c691486ac717b206f166f33c8c531a (patch) | |
tree | a0ab601406c1396d41527a49392725c8179a6d8a /dep/src/g3dlite/NetworkDevice.cpp | |
parent | 32546e22828e793e3881e1055acb72b6a044e331 (diff) |
removed 'dep' folder, no more needed
--HG--
branch : trunk
Diffstat (limited to 'dep/src/g3dlite/NetworkDevice.cpp')
-rw-r--r-- | dep/src/g3dlite/NetworkDevice.cpp | 1362 |
1 files changed, 0 insertions, 1362 deletions
diff --git a/dep/src/g3dlite/NetworkDevice.cpp b/dep/src/g3dlite/NetworkDevice.cpp deleted file mode 100644 index 246c97d4dbf..00000000000 --- a/dep/src/g3dlite/NetworkDevice.cpp +++ /dev/null @@ -1,1362 +0,0 @@ -/** - @file NetworkDevice.cpp - - @maintainer Morgan McGuire, morgan@cs.brown.edu - @created 2002-11-22 - @edited 2006-02-24 - */ - -#include <stdlib.h> -#include <time.h> -#include "G3D/platform.h" -#include "G3D/TextOutput.h" -#include "G3D/NetworkDevice.h" -#include "G3D/NetAddress.h" -#include "G3D/BinaryInput.h" -#include "G3D/BinaryOutput.h" -#include "G3D/Log.h" -#include "G3D/G3DGameUnits.h" -#include "G3D/stringutils.h" -#include "G3D/debug.h" - -#include <cstring> - -#if defined(G3D_LINUX) || defined(G3D_OSX) || defined(G3D_FREEBSD) -# include <sys/types.h> -# include <sys/socket.h> -# include <ifaddrs.h> -# include <netinet/in.h> -# include <net/if.h> -# ifdef __linux__ -# include <sys/ioctl.h> -# include <netinet/in.h> -# include <unistd.h> -# include <string.h> -// Match Linux to FreeBSD -# define AF_LINK AF_PACKET -# else -# include <net/if_dl.h> -# include <sys/sockio.h> -# endif - - #include <unistd.h> - #include <errno.h> - #include <sys/socket.h> - #include <netinet/in.h> - #include <arpa/inet.h> - #include <netdb.h> - #include <netinet/tcp.h> - #include <sys/ioctl.h> - #include <netinet/if_ether.h> - #include <net/ethernet.h> - #include <net/if.h> - - #include <sys/types.h> - - #define _alloca alloca - - /** Define an error code for non-windows platforms. */ - int WSAGetLastError() { - return -1; - } - - #define SOCKET_ERROR -1 - - static std::string socketErrorCode(int code) { - return G3D::format("CODE %d: %s\n", code, strerror(code)); - } - - static std::string socketErrorCode() { - return socketErrorCode(errno); - } - - static const int WSAEWOULDBLOCK = -100; - - typedef int SOCKET; - typedef struct sockaddr_in SOCKADDR_IN; - -#else - - // Windows - static std::string socketErrorCode(int code) { - LPTSTR formatMsg = NULL; - - FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_IGNORE_INSERTS | - FORMAT_MESSAGE_FROM_SYSTEM, - NULL, - code, - 0, - (LPTSTR)&formatMsg, - 0, - NULL); - - return G3D::format("CODE %d: %s\n", code, formatMsg); - } - - static std::string socketErrorCode() { - return socketErrorCode(GetLastError()); - } - -#endif - - -#ifndef _SOCKLEN_T -# if defined(G3D_WIN32) || defined(G3D_OSX) - typedef int socklen_t; -# endif -#endif - -namespace G3D { - -NetworkDevice* NetworkDevice::s_instance = NULL; - -std::ostream& operator<<(std::ostream& os, const NetAddress& a) { - return os << a.toString(); -} - - -static void logSocketInfo(const SOCKET& sock) { - uint32 val; - socklen_t sz = 4; - int ret; - - ret = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&val, (socklen_t*)&sz); - logPrintf("SOL_SOCKET/SO_RCVBUF = %d\n", val); - - ret = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&val, (socklen_t*)&sz); - logPrintf("SOL_SOCKET/SO_SNDBUF = %d\n", val); - - // Note: timeout = 0 means no timeout - ret = getsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&val, (socklen_t*)&sz); - logPrintf("SOL_SOCKET/SO_RCVTIMEO = %d\n", val); - - ret = getsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&val, (socklen_t*)&sz); - logPrintf("SOL_SOCKET/SO_SNDTIMEO = %d\n", val); -} - - -///////////////////////////////////////////////////////////////////////////// - -/** Invokes select on one socket. Returns SOCKET_ERROR on error, 0 if - there is no read pending, sock if there a read pending. */ -static int selectOneReadSocket(const SOCKET& sock) { - // 0 time timeout is specified to poll and return immediately - struct timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = 0; - - // Create a set that contains just this one socket - fd_set socketSet; - FD_ZERO(&socketSet); - FD_SET(sock, &socketSet); - - int ret = select(sock + 1, &socketSet, NULL, NULL, &timeout); - - return ret; -} - - -/** Returns true if the socket has a read pending */ -static bool readWaiting(const SOCKET& sock) { - int ret = selectOneReadSocket(sock); - - switch (ret) { - case SOCKET_ERROR: - logPrintf("ERROR: selectOneReadSocket returned " - "SOCKET_ERROR in readWaiting(). %s", socketErrorCode().c_str()); - // Return true so that we'll force an error on read and close - // the socket. - return true; - - case 0: - return false; - - default: - return true; - } -} - - -/** Invokes select on one socket. */ -static int selectOneWriteSocket(const SOCKET& sock) { - // 0 time timeout is specified to poll and return immediately - struct timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = 0; - - // Create a set that contains just this one socket - fd_set socketSet; - FD_ZERO(&socketSet); - FD_SET(sock, &socketSet); - - return select(sock + 1, NULL, &socketSet, NULL, &timeout); -} - -/////////////////////////////////////////////////////////////////////////////// - -NetworkDevice* NetworkDevice::instance() { - if (s_instance == NULL) { - s_instance = new NetworkDevice(); - if (! s_instance->init()) { - delete s_instance; - s_instance = NULL; - } - } - return s_instance; -} - - -void NetworkDevice::cleanup() { - if (s_instance) { - s_instance->_cleanup(); - delete s_instance; - s_instance = NULL; - } -} - - -NetworkDevice::NetworkDevice() { - initialized = false; -} - - -NetworkDevice::~NetworkDevice() { -} - - -std::string NetworkDevice::localHostName() const { - char ac[128]; - if (gethostname(ac, sizeof(ac)) == -1) { - Log::common()->printf("Error while getting local host name\n"); - return "localhost"; - } - return gethostbyname(ac)->h_name; -} - -#ifndef G3D_WIN32 -const char* errnoToString() { - switch (errno) { - case EBADF: - return "file descriptor is invalid."; - - case EINVAL: - return "Request or argp is not valid."; - - case ENOTTY: - return - "file descriptor is not associated with a character special device OR " - "The specified request does not apply to the " - "kind of object that the descriptor fildes references."; - - case EADDRNOTAVAIL: - return "Address not available."; - - default: - { - static char buffer[20]; - sprintf(buffer, "Error %d", errno); - return buffer; - } - } -} -#endif - - -NetworkDevice::EthernetAdapter::EthernetAdapter() { - name = ""; - ip = 0; - hostname = ""; - subnet = 0; - broadcast = 0; - for (int i = 0; i < 6; ++i) { - mac[i] = 0; - } -} - -void NetworkDevice::EthernetAdapter::describe(TextOutput& t) const { - t.writeSymbol("{"); - t.pushIndent(); - t.writeNewline(); - - t.writeSymbols("hostname", "="); - t.writeString(hostname); - t.writeNewline(); - - t.writeSymbols("name", "="); - t.writeString(name); - t.writeNewline(); - - t.writeSymbols("ip", "="); - t.writeSymbol(formatIP(ip)); - t.writeNewline(); - - t.writeSymbols("subnet", "="); - t.writeSymbol(formatIP(subnet)); - t.writeNewline(); - - t.writeSymbols("broadcast", "="); - t.writeSymbol(formatIP(broadcast)); - t.writeNewline(); - - t.writeSymbols("mac", "="); - t.writeSymbol(formatMAC(mac)); - t.writeNewline(); - - t.popIndent(); - t.writeSymbol("}"); - t.writeNewline(); -} - - -void NetworkDevice::addAdapter(const EthernetAdapter& a) { - m_adapterArray.append(a); - if (a.broadcast != 0) { - int i = m_broadcastAddresses.findIndex(a.broadcast); - if (i == -1) { - m_broadcastAddresses.append(a.broadcast); - } - } -} - - -std::string NetworkDevice::formatIP(uint32 addr) { - return format("%3d.%3d.%3d.%3d", (addr >> 24) & 0xFF, (addr >> 16) & 0xFF, - (addr >> 8) & 0xFF, addr & 0xFF); -} - - -std::string NetworkDevice::formatMAC(const uint8 MAC[6]) { - return format("%02x:%02x:%02x:%02x:%02x:%02x", MAC[0], MAC[1], MAC[2], MAC[3], MAC[4], MAC[5]); -} - - -#ifdef G3D_WIN32 - -bool NetworkDevice::init() { - debugAssert(! initialized); - - logPrintf("Network Startup"); - logPrintf("Starting WinSock networking.\n"); - WSADATA wsda; - WSAStartup(MAKEWORD(G3D_WINSOCK_MAJOR_VERSION, G3D_WINSOCK_MINOR_VERSION), &wsda); - - std::string hostname = "localhost"; - { - char ac[128]; - if (gethostname(ac, sizeof(ac)) == -1) { - logPrintf("Warning: Error while getting local host name\n"); - } else { - hostname = gethostbyname(ac)->h_name; - } - } - - EthernetAdapter a; - a.hostname = hostname; - a.name = ""; - a.ip = NetAddress(hostname, 0).ip(); - - // TODO: Find subnet on Win32 - a.subnet = 0x0000FFFF; - - // TODO: Find broadcast on Win32 - a.broadcast = 0xFFFFFFFF; - - // TODO: find MAC on Win32 - - addAdapter(a); - - std::string machine = localHostName(); - std::string addr = NetAddress(machine, 0).ipString(); - logPrintf( - "Network:\n" - " Status: %s\n" - " Loaded winsock specification version %d (%d is " - "the highest available)\n" - " %d sockets available\n" - " Largest UDP datagram packet size is %d bytes\n\n", - wsda.szDescription, - wsda.szSystemStatus, - wsda.wVersion, - wsda.wHighVersion, - wsda.iMaxSockets, - wsda.iMaxUdpDg); - - // TODO: WSAIoctl for subnet and broadcast addresses - // http://msdn.microsoft.com/en-us/library/ms741621(VS.85).aspx - // - // TODO: SIO_GET_INTERFACE_LIST - - initialized = true; - - return true; -} -#endif - - -#if defined(G3D_LINUX) || defined(G3D_OSX) || defined(G3D_FREEBSD) - -const sockaddr_in* castToIP4(const sockaddr* addr) { - if (addr == NULL) { - return NULL; - } else if (addr->sa_family == AF_INET) { - // An IPv4 address - return reinterpret_cast<const sockaddr_in*>(addr); - } else { - // Not an IPv4 address - return NULL; - } -} - -uint32 getIP(const sockaddr_in* addr) { - if (addr != NULL) { - return ntohl(addr->sin_addr.s_addr); - } else { - return 0; - } -} - - -bool NetworkDevice::init() { - debugAssert(! initialized); - - // Used for combining the MAC and ip information - typedef Table<std::string, EthernetAdapter> AdapterTable; - - AdapterTable table; - - // Head of a linked list of network interfaces on this machine - ifaddrs* ifap = NULL; - - int r = getifaddrs(&ifap); - - if (r != 0) { - logPrintf("ERROR: getifaddrs returned %d\n", r); - return false; - } - - ifaddrs* current = ifap; - - if (current == NULL) { - logPrintf("WARNING: No network interfaces found\n"); - EthernetAdapter a; - a.name = "fallback"; - a.hostname = "localhost"; - a.ip = (127 << 24) | 1; - a.broadcast = 0xFFFFFFFF; - a.subnet = 0x000000FF; - addAdapter(a); - - } else { - - while (current != NULL) { - - bool up = (current->ifa_flags & IFF_UP); - bool loopback = (current->ifa_flags & IFF_LOOPBACK); - - if (! up || loopback) { - // Skip this adapter; it is offline or is a loopback - current = current->ifa_next; - continue; - } - - if (! table.containsKey(current->ifa_name)) { - EthernetAdapter a; - a.name = current->ifa_name; - table.set(a.name, a); - } - - // This adapter must exist because it was created above - EthernetAdapter& adapter = table[current->ifa_name]; - - const sockaddr_in* interfaceAddress = castToIP4(current->ifa_addr); - const sockaddr_in* broadcastAddress = castToIP4(current->ifa_dstaddr); - const sockaddr_in* subnetMask = castToIP4(current->ifa_netmask); - - uint32 ip = getIP(interfaceAddress); - uint32 ba = getIP(broadcastAddress); - uint32 sn = getIP(subnetMask); - - if (ip != 0) { - adapter.ip = ip; - } - - if (ba != 0) { - adapter.broadcast = ba; - } - - if (sn != 0) { - adapter.subnet = sn; - } - - uint8_t* MAC = NULL; - // Extract MAC address - if ((current->ifa_addr != NULL) && (current->ifa_addr->sa_family == AF_LINK)) { -# ifdef __linux__ - { - // Linux - struct ifreq ifr; - - int fd = socket(AF_INET, SOCK_DGRAM, 0); - - ifr.ifr_addr.sa_family = AF_INET; - strcpy(ifr.ifr_name, current->ifa_name); - ioctl(fd, SIOCGIFHWADDR, &ifr); - close(fd); - - MAC = reinterpret_cast<uint8_t*>(ifr.ifr_hwaddr.sa_data); - } -# else - { - // The MAC address and the interfaceAddress come in as - // different interfaces with the same name. - - // Posix/FreeBSD/Mac OS - sockaddr_dl* sdl = (struct sockaddr_dl *)current->ifa_addr; - MAC = reinterpret_cast<uint8_t*>(LLADDR(sdl)); - } -# endif - - // See if there was a MAC address - if (MAC != NULL) { - bool anyNonZero = false; - for (int i = 0; i < 6; ++i) { - anyNonZero = anyNonZero || (MAC[i] != 0); - } - if (anyNonZero) { - System::memcpy(adapter.mac, MAC, 6); - } - } - } - - current = current->ifa_next; - } - - freeifaddrs(ifap); - ifap = NULL; - } - - // Extract all interesting adapters from the table - for (AdapterTable::Iterator it = table.begin(); it.hasMore(); ++it) { - const EthernetAdapter& adapter = it->value; - - // Only add adapters that have IP addresses - if (adapter.ip != 0) { - addAdapter(adapter); - } else { - logPrintf("NetworkDevice: Ignored adapter %s because ip = 0\n", adapter.name.c_str()); - } - } - - initialized = true; - - return true; -} - -#endif - - -void NetworkDevice::_cleanup() { - debugAssert(initialized); - - logPrintf("Network Cleanup"); -# ifdef G3D_WIN32 - WSACleanup(); -# endif - logPrintf("Network cleaned up."); -} - -bool NetworkDevice::bind(SOCKET sock, const NetAddress& addr) const { - Log::common()->printf("Binding socket %d on port %d ", - sock, htons(addr.addr.sin_port)); - if (::bind(sock, (struct sockaddr*)&(addr.addr), sizeof(addr.addr)) == - SOCKET_ERROR) { - - Log::common()->println("FAIL"); - Log::common()->println(socketErrorCode()); - closesocket(sock); - return false; - } - - Log::common()->println("Ok"); - return true; -} - - -void NetworkDevice::closesocket(SOCKET& sock) const { - if (sock != 0) { - #ifdef G3D_WIN32 - ::closesocket(sock); - #else - close(sock); - #endif - - Log::common()->printf("Closed socket %d\n", sock); - sock = 0; - } -} - - -void NetworkDevice::localHostAddresses(Array<NetAddress>& array) const { - array.resize(0); - - char ac[128]; - - if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR) { - Log::common()->printf("Error while getting local host name\n"); - return; - } - - struct hostent* phe = gethostbyname(ac); - if (phe == 0) { - Log::common()->printf("Error while getting local host address\n"); - return; - } - - 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)); - array.append(NetAddress(addr)); - } -} - -/////////////////////////////////////////////////////////////////////////////// - -Conduit::Conduit() : binaryOutput("<memory>", G3D_LITTLE_ENDIAN) { - sock = 0; - mSent = 0; - mReceived = 0; - bSent = 0; - bReceived = 0; -} - - -Conduit::~Conduit() { - NetworkDevice::instance()->closesocket(sock); -} - - -uint64 Conduit::bytesSent() const { - return bSent; -} - - -uint64 Conduit::bytesReceived() const { - return bReceived; -} - - -uint64 Conduit::messagesSent() const { - return mSent; -} - - -uint64 Conduit::messagesReceived() const { - return mReceived; -} - - -bool Conduit::ok() const { - return (sock != 0) && (sock != SOCKET_ERROR); -} - - -bool Conduit::messageWaiting() { - return readWaiting(sock); -} - - -/** - Increases the send and receive sizes of a socket to 2 MB from 8k - */ -static void increaseBufferSize(SOCKET sock) { - - // Increase the buffer size; the default (8192) is too easy to - // overflow when the network latency is high. - { - uint32 val = 1024 * 1024 * 2; - if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, - (char*)&val, sizeof(val)) == SOCKET_ERROR) { - Log::common()->printf("WARNING: Increasing socket " - "receive buffer to %d failed.\n", val); - Log::common()->println(socketErrorCode()); - } - - if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, - (char*)&val, sizeof(val)) == SOCKET_ERROR) { - Log::common()->printf("WARNING: Increasing socket " - "send buffer to %d failed.\n", val); - Log::common()->println(socketErrorCode()); - } - } -} - -////////////////////////////////////////////////////////////////////////////// - -ReliableConduitRef ReliableConduit::create(const NetAddress& address) { - return new ReliableConduit(address); -} - - -ReliableConduit::ReliableConduit( - const NetAddress& _addr) : state(NO_MESSAGE), receiveBuffer(NULL), - receiveBufferTotalSize(0), receiveBufferUsedSize(0) { - - NetworkDevice* nd = NetworkDevice::instance(); - - messageType = 0; - - addr = _addr; - Log::common()->print("Creating a TCP socket "); - sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); - - if (sock == SOCKET_ERROR) { - Log::common()->println("FAIL"); - Log::common()->println(socketErrorCode()); - nd->closesocket(sock); - return; - } - - Log::common()->println("Ok"); - - // Setup socket options (both constructors should set the same options) - - // Disable Nagle's algorithm (we send lots of small packets) - const int T = true; - if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, - (const char*)&T, sizeof(T)) == SOCKET_ERROR) { - - Log::common()->println("WARNING: Disabling Nagel's " - "algorithm failed."); - Log::common()->println(socketErrorCode()); - } else { - Log::common()->println("Disabled Nagel's algorithm."); - } - - // Set the NO LINGER option so the socket doesn't hang around if - // there is unsent data in the queue when it closes. - struct linger ling; - ling.l_onoff = 0; - ling.l_linger = 0; - if (setsockopt(sock, SOL_SOCKET, SO_LINGER, - (const char*)&ling, sizeof(ling)) == SOCKET_ERROR) { - - Log::common()->println("WARNING: Setting socket no linger failed."); - Log::common()->println(socketErrorCode()); - } else { - Log::common()->println("Set socket option no_linger."); - } - - // Set reuse address so that a new server can start up soon after - // an old one has closed. - if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, - (const char*)&T, sizeof(T)) == SOCKET_ERROR) { - - Log::common()->println("WARNING: Setting socket reuseaddr failed."); - Log::common()->println(socketErrorCode()); - } else { - Log::common()->println("Set socket option reuseaddr."); - } - - // Ideally, we'd like to specify IPTOS_LOWDELAY as well. - - logSocketInfo(sock); - - increaseBufferSize(sock); - - Log::common()->printf("Created TCP socket %d\n", sock); - - std::string x = addr.toString(); - Log::common()->printf("Connecting to %s on TCP socket %d ", x.c_str(), sock); - - int ret = connect(sock, (struct sockaddr *) &(addr.addr), sizeof(addr.addr)); - - if (ret == WSAEWOULDBLOCK) { - RealTime t = System::time() + 5.0; - // Non-blocking; we must wait until select returns non-zero - while ((selectOneWriteSocket(sock) == 0) && (System::time() < t)) { - System::sleep(0.02); - } - - // TODO: check for failure on the select call - - } else if (ret != 0) { - sock = (SOCKET)SOCKET_ERROR; - Log::common()->println("FAIL"); - Log::common()->println(socketErrorCode()); - return; - } - - Log::common()->println("Ok"); -} - - -ReliableConduit::ReliableConduit( - const SOCKET& _sock, - const NetAddress& _addr) : - state(NO_MESSAGE), - receiveBuffer(NULL), - receiveBufferTotalSize(0), - receiveBufferUsedSize(0) { - sock = _sock; - addr = _addr; - - messageType = 0; - - // Setup socket options (both constructors should set the same options) - - // Disable Nagle's algorithm (we send lots of small packets) - const int T = true; - if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, - (const char*)&T, sizeof(T)) == SOCKET_ERROR) { - - Log::common()->println("WARNING: Disabling Nagel's algorithm failed."); - Log::common()->println(socketErrorCode()); - } else { - Log::common()->println("Disabled Nagel's algorithm."); - } - - // Set the NO LINGER option so the socket doesn't hang around if - // there is unsent data in the queue when it closes. - struct linger ling; - ling.l_onoff = 0; - ling.l_linger = 0; - if (setsockopt(sock, SOL_SOCKET, SO_LINGER, - (const char*)&ling, sizeof(ling)) == SOCKET_ERROR) { - - Log::common()->println("WARNING: Setting socket no linger failed."); - Log::common()->println(socketErrorCode()); - } else { - Log::common()->println("Set socket option no_linger."); - } - - // Set reuse address so that a new server can start up soon after - // an old one has closed. - if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, - (const char*)&T, sizeof(T)) == SOCKET_ERROR) { - - Log::common()->println("WARNING: Setting socket reuseaddr failed."); - Log::common()->println(socketErrorCode()); - } else { - Log::common()->println("Set socket option reuseaddr."); - } - - // Ideally, we'd like to specify IPTOS_LOWDELAY as well. - - logSocketInfo(sock); -} - - -ReliableConduit::~ReliableConduit() { - free(receiveBuffer); - receiveBuffer = NULL; - receiveBufferTotalSize = 0; - receiveBufferUsedSize = 0; -} - - -bool ReliableConduit::messageWaiting() { - switch (state) { - case HOLDING: - // We've already read the message and are waiting - // for a receive call. - return true; - - case RECEIVING: - - if (! ok()) { - return false; - } - // We're currently receiving the message. Read a little more. - receiveIntoBuffer(); - - if (messageSize == receiveBufferUsedSize) { - // We've read the whole mesage. Switch to holding state - // and return true. - state = HOLDING; - return true; - } else { - // There are more bytes left to read. We'll read them on - // the next call. Because the *entire* message is not ready, - // return false. - return false; - } - break; - - case NO_MESSAGE: - if (Conduit::messageWaiting()) { - // Message incoming. Read the header. - - state = RECEIVING; - receiveHeader(); - - // Loop back around now that we're in the receive state; we - // may be able to read the whole message before returning - // to the caller. - return messageWaiting(); - } else { - // No message incoming. - return false; - } - } - - debugAssertM(false, "Should not reach this point"); - return false; -} - - -uint32 ReliableConduit::waitingMessageType() { - // The messageWaiting call is what actually receives the message. - if (messageWaiting()) { - return messageType; - } else { - return 0; - } -} - - -void ReliableConduit::sendBuffer(const BinaryOutput& b) { - NetworkDevice* nd = NetworkDevice::instance(); - int ret = ::send(sock, (const char*)b.getCArray(), b.size(), 0); - - if (ret == SOCKET_ERROR) { - Log::common()->println("Error occured while sending message."); - Log::common()->println(socketErrorCode()); - nd->closesocket(sock); - return; - } - - ++mSent; - bSent += b.size(); - - // Verify the packet was actually sent - // Conversion to unsigned is safe because -1 is caught earlier - debugAssert(ret == b.size()); -} - - -/** Null serializer. Used by reliable conduit::send(type) */ -class Dummy { -public: - void serialize(BinaryOutput& b) const { (void)b; } -}; - - -void ReliableConduit::send(uint32 type) { - static Dummy dummy; - send(type, dummy); -} - - - -NetAddress ReliableConduit::address() const { - return addr; -} - - -void ReliableConduit::receiveHeader() { - NetworkDevice* nd = NetworkDevice::instance(); - debugAssert(state == RECEIVING); - - // Read the type - uint32 tmp; - int ret = recv(sock, (char*)&tmp, sizeof(tmp), 0); - - // The type is the first four bytes. It is little endian. - if (System::machineEndian() == G3D_LITTLE_ENDIAN) { - messageType = tmp; - } else { - // Swap the byte order - for (int i = 0; i < 4; ++i) { - ((char*)&messageType)[i] = ((char*)&tmp)[3 - i]; - } - } - - if ((ret == SOCKET_ERROR) || (ret != sizeof(messageType))) { - Log::common()->printf("Call to recv failed. ret = %d," - " sizeof(messageType) = %d\n", - (int)ret, (int)sizeof(messageType)); - Log::common()->println(socketErrorCode()); - nd->closesocket(sock); - messageType = 0; - return; - } - - // Read the size - ret = recv(sock, (char*)&messageSize, sizeof(messageSize), 0); - - if ((ret == SOCKET_ERROR) || (ret != sizeof(messageSize))) { - Log::common()->printf("Call to recv failed. ret = %d," - " sizeof(len) = %d\n", (int)ret, - (int)sizeof(messageSize)); - Log::common()->println(socketErrorCode()); - nd->closesocket(sock); - messageType = 0; - return; - } - - messageSize = ntohl(messageSize); - debugAssert(messageSize < 6e7); - - debugAssert(receiveBufferUsedSize == 0); - - // Extend the size of the buffer. - if (messageSize > receiveBufferTotalSize) { - receiveBuffer = realloc(receiveBuffer, messageSize); - receiveBufferTotalSize = messageSize; - } - - if (receiveBuffer == NULL) { - Log::common()->println("Could not allocate a memory buffer " - "during receivePacket."); - nd->closesocket(sock); - } - - bReceived += 4; -} - - -void ReliableConduit::receiveIntoBuffer() { - NetworkDevice* nd = NetworkDevice::instance(); - - debugAssert(state == RECEIVING); - debugAssert(messageType != 0); - debugAssertM(receiveBufferUsedSize < messageSize, "Message already received."); - debugAssertM(messageSize >= receiveBufferUsedSize, "Message size overflow."); - - // Read the data itself - int ret = 0; - uint32 left = messageSize - receiveBufferUsedSize; - int count = 0; - while ((ret != SOCKET_ERROR) && (left > 0) && (count < 100)) { - - ret = recv(sock, ((char*)receiveBuffer) + receiveBufferUsedSize, left, 0); - - if (ret > 0) { - left -= ret; - receiveBufferUsedSize += ret; - bReceived += ret; - - if (left > 0) { - // There's still more. Give the machine a chance to read - // more data, but don't wait forever. - - ++count; - System::sleep(0.001); - } - } else { - // Something went wrong; our blocking read returned nothing. - break; - } - } - - if ((ret == 0) || (ret == SOCKET_ERROR)) { - - if (ret == SOCKET_ERROR) { - Log::common()->printf("Call to recv failed. ret = %d," - " sizeof(messageSize) = %d\n", ret, messageSize); - Log::common()->println(socketErrorCode()); - } else { - Log::common()->printf("recv returned 0\n"); - } - nd->closesocket(sock); - return; - } - - ++mReceived; -} - - -/////////////////////////////////////////////////////////////////////////////// -LightweightConduitRef LightweightConduit::create( - uint16 receivePort, - bool enableReceive, - bool enableBroadcast) { - - return new LightweightConduit(receivePort, enableReceive, enableBroadcast); -} - -LightweightConduit::LightweightConduit( - uint16 port, - bool enableReceive, - bool enableBroadcast) { - NetworkDevice* nd = NetworkDevice::instance(); - - Log::common()->print("Creating a UDP socket "); - sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - - if (sock == SOCKET_ERROR) { - sock = 0; - Log::common()->println("FAIL"); - Log::common()->println(socketErrorCode()); - return; - } - Log::common()->println("Ok"); - - if (enableReceive) { - debugAssert(port != 0); - if (! nd->bind(sock, NetAddress(0, port))) { - nd->closesocket(sock); - sock = (SOCKET)SOCKET_ERROR; - } - } - - // Figuring out the MTU seems very complicated, so we just set it to 1000, - // which is likely to be safe. See IP_MTU for more information. - MTU = 1000; - - increaseBufferSize(sock); - - if (enableBroadcast) { - int TR = true; - if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, - (const char*)&TR, sizeof(TR)) != 0) { - Log::common()->println("Call to setsockopt failed"); - Log::common()->println(socketErrorCode()); - nd->closesocket(sock); - sock = 0; - return; - } - } - - Log::common()->printf("Done creating UDP socket %d\n", sock); - - alreadyReadMessage = false; -} - - -LightweightConduit::~LightweightConduit() { -} - - -bool LightweightConduit::receive(NetAddress& sender) { - // This both checks to ensure that a message was waiting and - // actively consumes the message from the network stream if - // it has not been read yet. - uint32 t = waitingMessageType(); - if (t == 0) { - return false; - } - - sender = messageSender; - alreadyReadMessage = false; - - if (messageBuffer.size() < 4) { - // Something went wrong - return false; - } - - return true; -} - - -void LightweightConduit::sendBuffer(const NetAddress& a, BinaryOutput& b) { - NetworkDevice* nd = NetworkDevice::instance(); - if (sendto(sock, (const char*)b.getCArray(), b.size(), 0, - (struct sockaddr *) &(a.addr), sizeof(a.addr)) == SOCKET_ERROR) { - Log::common()->printf("Error occured while sending packet " - "to %s\n", inet_ntoa(a.addr.sin_addr)); - Log::common()->println(socketErrorCode()); - nd->closesocket(sock); - } else { - ++mSent; - bSent += b.size(); - } -} - - -bool LightweightConduit::messageWaiting() { - // We may have already pulled the message off the network stream - return alreadyReadMessage || Conduit::messageWaiting(); -} - - -uint32 LightweightConduit::waitingMessageType() { - NetworkDevice* nd = NetworkDevice::instance(); - if (! messageWaiting()) { - return 0; - } - - if (! alreadyReadMessage) { - messageBuffer.resize(8192); - - SOCKADDR_IN remote_addr; - int iRemoteAddrLen = sizeof(sockaddr); - - int ret = recvfrom(sock, (char*)messageBuffer.getCArray(), - messageBuffer.size(), 0, (struct sockaddr *) &remote_addr, - (socklen_t*)&iRemoteAddrLen); - - if (ret == SOCKET_ERROR) { - Log::common()->println("Error: recvfrom failed in " - "LightweightConduit::waitingMessageType()."); - Log::common()->println(socketErrorCode()); - nd->closesocket(sock); - messageBuffer.resize(0); - messageSender = NetAddress(); - messageType = 0; - return 0; - } - - messageSender = NetAddress(remote_addr); - - ++mReceived; - bReceived += ret; - - messageBuffer.resize(ret, DONT_SHRINK_UNDERLYING_ARRAY); - - // The type is the first four bytes. It is little endian. - if (System::machineEndian() == G3D_LITTLE_ENDIAN) { - messageType = *((uint32*)messageBuffer.getCArray()); - } else { - // Swap the byte order - for (int i = 0; i < 4; ++i) { - ((char*)&messageType)[i] = messageBuffer[3 - i]; - } - } - - alreadyReadMessage = true; - } - - return messageType; -} - - -/////////////////////////////////////////////////////////////////////////////// - -NetListenerRef NetListener::create(const uint16 port) { - return new NetListener(port); -} - - -NetListener::NetListener(uint16 port) { - NetworkDevice* nd = NetworkDevice::instance(); - - // Start the listener socket - Log::common()->print("Creating a listener "); - sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); - - if (sock == SOCKET_ERROR) { - Log::common()->printf("FAIL"); - Log::common()->println(socketErrorCode()); - return; - } - Log::common()->println("Ok"); - - const int T = true; - - // Set reuse address so that a new server can start up soon after - // an old one has closed. - if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, - (const char*)&T, sizeof(T)) == SOCKET_ERROR) { - - Log::common()->println("WARNING: Setting socket reuseaddr failed."); - Log::common()->println(socketErrorCode()); - } else { - Log::common()->println("Set socket option reuseaddr."); - } - - - if (! nd->bind(sock, NetAddress(0, port))) { - Log::common()->printf("Unable to bind!\n"); - nd->closesocket(sock); - sock = (SOCKET)SOCKET_ERROR; - return; - } - - Log::common()->printf("Listening on port %5d ", port); - - // listen is supposed to return 0 when there is no error. - // The 2nd argument is the number of connections to allow pending - // at any time. - int L = listen(sock, 100); - if (L == SOCKET_ERROR) { - Log::common()->println("FAIL"); - Log::common()->println(socketErrorCode()); - nd->closesocket(sock); - sock = (SOCKET)SOCKET_ERROR; - return; - } - Log::common()->println("Ok"); - Log::common()->printf("Now listening on socket %d.\n\n", sock); -} - - -NetListener::~NetListener() { - NetworkDevice* nd = NetworkDevice::instance(); - nd->closesocket(sock); -} - - -ReliableConduitRef NetListener::waitForConnection() { - NetworkDevice* nd = NetworkDevice::instance(); - // The address of the connecting host - SOCKADDR_IN remote_addr; - int iAddrLen = sizeof(remote_addr); - - Log::common()->println("Blocking in NetListener::waitForConnection()."); - - SOCKET sClient = accept(sock, (struct sockaddr*) &remote_addr, - (socklen_t*)&iAddrLen); - - if (sClient == SOCKET_ERROR) { - Log::common()->println("Error in NetListener::acceptConnection."); - Log::common()->println(socketErrorCode()); - nd->closesocket(sock); - return NULL; - } - - Log::common()->printf("%s connected, transferred to socket %d.\n", - inet_ntoa(remote_addr.sin_addr), sClient); - - #ifndef G3D_WIN32 - return new ReliableConduit(sClient, - NetAddress(htonl(remote_addr.sin_addr.s_addr), - ntohs(remote_addr.sin_port))); - #else - return new ReliableConduit(sClient, - NetAddress(ntohl(remote_addr.sin_addr.S_un.S_addr), - ntohs(remote_addr.sin_port))); - #endif -} - - -bool NetListener::ok() const { - return (sock != 0) && (sock != SOCKET_ERROR); -} - - -bool NetListener::clientWaiting() const { - return readWaiting(sock); -} - -//////////////////////////////////////////////////////////////////////////////////////////////// - -void NetworkDevice::describeSystem( - TextOutput& t) { - - t.writeSymbols("Network", "{"); - t.writeNewline(); - t.pushIndent(); - - for (int i = 0; i < m_adapterArray.size(); ++i) { - m_adapterArray[i].describe(t); - } - - - t.popIndent(); - t.writeSymbols("}"); - t.writeNewline(); - t.writeNewline(); -} - - -void NetworkDevice::describeSystem( - std::string& s) { - - TextOutput t; - describeSystem(t); - t.commitString(s); -} - -} // namespace |