Ejemplo n.º 1
0
/**
 Increases the send and receive sizes of a socket to 2 MB from 8k
 */
static void increaseBufferSize(SOCKET sock, Log* debugLog) {

    // 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) {
            if (debugLog) {
                debugLog->printf("WARNING: Increasing socket "
                                     "receive buffer to %d failed.\n", val);
                debugLog->println(socketErrorCode());
            }
        }

        if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, 
                       (char*)&val, sizeof(val)) == SOCKET_ERROR) {
            if (debugLog) {
                debugLog->printf("WARNING: Increasing socket "
                                     "send buffer to %d failed.\n", val);
                debugLog->println(socketErrorCode());
            }
        }
    }
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
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);
}
Ejemplo n.º 4
0
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);
}
Ejemplo n.º 5
0
LightweightConduit::LightweightConduit(
    NetworkDevice* _nd, 
    uint16 port,
    bool enableReceive, 
    bool enableBroadcast) : Conduit(_nd) {

    if (nd->debugLog) {nd->debugLog->print("Creating a UDP socket        ");}
    sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    
    if (sock == SOCKET_ERROR) {
        sock = 0;
        if (nd->debugLog) {
            nd->debugLog->println("FAIL");
            nd->debugLog->println(socketErrorCode());
        }
        return;
    }
    if (nd->debugLog) {nd->debugLog->println("Ok");}

    if (enableReceive) {
        debugAssert(port != 0);
        nd->bind(sock, NetAddress(0, port));
    }

    // 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, nd->debugLog);

    if (enableBroadcast) {
        int TR = true;
        if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, 
                       (const char*)&TR, sizeof(TR)) != 0) {
            if (nd->debugLog) {
                nd->debugLog->println("Call to setsockopt failed");
                nd->debugLog->println(socketErrorCode());
            }
            nd->closesocket(sock);
            return;
        }
    }

    if (nd->debugLog) {
        nd->debugLog->printf("Done creating UDP socket %d\n", sock);
    }

    alreadyReadMessage = false;
}
Ejemplo n.º 6
0
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 ReliableConduitRef();
    }

    Log::common()->printf("%s connected, transferred to socket %d.\n", 
                         inet_ntoa(remote_addr.sin_addr), sClient);

    #ifndef G3D_WINDOWS
    return ReliableConduitRef(new ReliableConduit(sClient, 
                     NetAddress(htonl(remote_addr.sin_addr.s_addr), 
                                ntohs(remote_addr.sin_port))));
    #else
    return ReliableConduitRef(ReliableConduitRef(new ReliableConduit(sClient, 
                    NetAddress(ntohl(remote_addr.sin_addr.S_un.S_addr), 
                               ntohs(remote_addr.sin_port)))));
    #endif
}
Ejemplo n.º 7
0
void LightweightConduit::sendBuffer(const NetAddress& a, BinaryOutput& b) {
    NetworkDevice* nd = NetworkDevice::instance();
    if (sendto(sock, (const char*)b.getCArray(), (int)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();
    }
}
Ejemplo n.º 8
0
void LightweightConduit::sendBuffer(const NetAddress& a, BinaryOutput& b) {
    if (sendto(sock, (const char*)b.getCArray(), b.size(), 0,
       (struct sockaddr *) &(a.addr), sizeof(a.addr)) == SOCKET_ERROR) {
        if (nd->debugLog) {
            nd->debugLog->printf("Error occured while sending packet "
                                 "to %s\n", inet_ntoa(a.addr.sin_addr));
            nd->debugLog->println(socketErrorCode());
        }
        nd->closesocket(sock);
    } else {
        ++mSent;
        bSent += b.size();
    }
}
Ejemplo n.º 9
0
void ReliableConduit::receiveIntoBuffer() {

    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 < 10)) {

        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
            break;
        }
    }

    if ((ret == 0) || (ret == SOCKET_ERROR)) {

        if (nd->debugLog) {
            if (ret == SOCKET_ERROR) {
                nd->debugLog->printf("Call to recv failed.  ret = %d,"
                     " sizeof(messageSize) = %d\n", ret, messageSize);
                nd->debugLog->println(socketErrorCode());
            } else {
                nd->debugLog->printf("recv returned 0\n");
            }
        }
        nd->closesocket(sock);
        return;
    }

    ++mReceived;
}
Ejemplo n.º 10
0
uint32 LightweightConduit::waitingMessageType() {
    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) {
            if (nd->debugLog) {
                nd->debugLog->println("Error: recvfrom failed in "
                        "LightweightConduit::waitingMessageType().");
                nd->debugLog->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;
}
Ejemplo n.º 11
0
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;
}
Ejemplo n.º 12
0
void ReliableConduit::sendBuffer(const BinaryOutput& b) {
    NetworkDevice* nd = NetworkDevice::instance();
    int ret = ::send(sock, (const char*)b.getCArray(), (int)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());
}
Ejemplo n.º 13
0
/** 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;
    }
}
Ejemplo n.º 14
0
/** Returns true if the socket has a read pending */
static bool readWaiting(Log* debugLog, const SOCKET& sock) {
    int ret = selectOneReadSocket(sock);

    switch (ret) {
    case SOCKET_ERROR:
        if (debugLog) {
            debugLog->println("ERROR: selectOneReadSocket returned "
                              "SOCKET_ERROR in readWaiting().");
            debugLog->println(socketErrorCode());
        }
        // Return true so that we'll force an error on read and close
        // the socket.
        return true;

    case 0:
        return false;

    default:
        return true;
    }
}
Ejemplo n.º 15
0
ReliableConduitRef NetListener::waitForConnection() {

    // The address of the connecting host
    SOCKADDR_IN    remote_addr;
    int iAddrLen = sizeof(remote_addr);

    if (nd->debugLog) {
        nd->debugLog->println("Blocking in NetListener::waitForConnection().");
    }

    SOCKET sClient = accept(sock, (struct sockaddr*) &remote_addr, 
                            (socklen_t*)&iAddrLen);

    if (sClient == SOCKET_ERROR) {
        if (nd->debugLog) {
            nd->debugLog->println("Error in NetListener::acceptConnection.");
            nd->debugLog->println(socketErrorCode());
        }
        nd->closesocket(sock);
        return NULL;
    }

    if (nd->debugLog) {
        nd->debugLog->printf("%s connected, transferred to socket %d.\n", 
                             inet_ntoa(remote_addr.sin_addr), sClient);
    }

    #ifndef G3D_WIN32
        return new ReliableConduit(nd, sClient, 
                     NetAddress(htonl(remote_addr.sin_addr.s_addr), 
                                ntohs(remote_addr.sin_port)));
    #else
        return new ReliableConduit(nd, sClient, 
                    NetAddress(ntohl(remote_addr.sin_addr.S_un.S_addr), 
                               ntohs(remote_addr.sin_port)));
    #endif
}
Ejemplo n.º 16
0
bool NetworkDevice::init(G3D::Log* _log) {
    debugAssert(!initialized);
    debugLog = _log;

    #ifdef G3D_WIN32
        if (debugLog) {
            debugLog->section("Network Startup");
            debugLog->println("Starting WinSock networking.\n");
        }
        WSADATA wsda;		    
        WSAStartup(MAKEWORD(G3D_WINSOCK_MAJOR_VERSION, G3D_WINSOCK_MINOR_VERSION), &wsda);

        if (debugLog) {
            std::string machine = localHostName();
            std::string addr    = NetAddress(machine, 0).ipString();
            debugLog->printf(
                "Network:\n"
                "  localhost = %s (%s)\n"
                "  %s\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",
                machine.c_str(), addr.c_str(),
                wsda.szDescription,
                wsda.szSystemStatus,
                wsda.wVersion,
                wsda.wHighVersion,
                wsda.iMaxSockets,
                wsda.iMaxUdpDg);
        }
    #endif


    if (debugLog) {debugLog->section("Testing Network");}

    SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    
    if (debugLog) {debugLog->print("Open Socket                  ");}
    if (sock == SOCKET_ERROR) {
        if (debugLog) {
            debugLog->println("FAIL");
            debugLog->println(socketErrorCode());
        }
        return false;
    }
    if (debugLog) { debugLog->println("Ok"); }

    int TR = true;
    int ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, 
                         (const char*)&TR, sizeof(TR));

    if (debugLog) {debugLog->print("Enable UDP Broadcast         ");}
    if (ret != 0) {
        if (debugLog) {
            debugLog->println("FAIL");
            debugLog->println(socketErrorCode());
        }
        return false;
    }
    if (debugLog) {debugLog->println("Ok");}

    if (debugLog) {debugLog->print("Testing UDP Broadcast        ");}
    SOCKADDR_IN addr;
    int32 x;
    addr = NetAddress(0xFFFFFFFF, 23).addr;
    ret = sendto(sock, (const char*)&x, sizeof(x), 0, 
                 (struct sockaddr *) &addr, sizeof(addr));
    if (ret == SOCKET_ERROR) {
        if (debugLog) {
            debugLog->println("FAIL");
            debugLog->println(socketErrorCode());
        }
        return false;
    }
    if (debugLog) {debugLog->println("Ok");}

    if (debugLog) {debugLog->section("");}
    initialized = true;

    return true;
}
Ejemplo n.º 17
0
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");
}
Ejemplo n.º 18
0
 static std::string socketErrorCode() {
     return socketErrorCode(errno);
 }
Ejemplo n.º 19
0
 static std::string socketErrorCode() {
     return socketErrorCode(GetLastError());
 }