Socket::Status TcpSocket::Connect(const IpAddress& remoteAddress, unsigned short remotePort, Uint32 timeout) { // Create the internal socket if it doesn't exist Create(); // Create the remote address sockaddr_in address = priv::SocketImpl::CreateAddress(remoteAddress.ToInteger(), remotePort); if (timeout == 0) { // ----- We're not using a timeout: just try to connect ----- // Connect the socket if (connect(GetHandle(), reinterpret_cast<sockaddr*>(&address), sizeof(address)) == -1) return priv::SocketImpl::GetErrorStatus(); // Connection succeeded return Done; } else { // ----- We're using a timeout: we'll need a few tricks to make it work ----- // Save the previous blocking state bool blocking = IsBlocking(); // Switch to non-blocking to enable our connection timeout if (blocking) SetBlocking(false); // Try to connect to the remote address if (connect(GetHandle(), reinterpret_cast<sockaddr*>(&address), sizeof(address)) >= 0) { // We got instantly connected! (it may no happen a lot...) return Done; } // Get the error status Status status = priv::SocketImpl::GetErrorStatus(); // If we were in non-blocking mode, return immediatly if (!blocking) return status; // Otherwise, wait until something happens to our socket (success, timeout or error) if (status == Socket::NotReady) { // Setup the selector fd_set selector; FD_ZERO(&selector); FD_SET(GetHandle(), &selector); // Setup the timeout timeval time; time.tv_sec = timeout / 1000; time.tv_usec = (timeout - time.tv_sec * 1000) * 1000; // Wait for something to write on our socket (which means that the connection request has returned) if (select(static_cast<int>(GetHandle() + 1), NULL, &selector, NULL, &time) > 0) { // At this point the connection may have been either accepted or refused. // To know whether it's a success or a failure, we must check the address of the connected peer if (GetRemoteAddress() != sf::IpAddress::None) { // Connection accepted status = Done; } else { // Connection refused status = priv::SocketImpl::GetErrorStatus(); } } else { // Failed to connect before timeout is over status = priv::SocketImpl::GetErrorStatus(); } } // Switch back to blocking mode SetBlocking(true); return status; } }
bool operator <(const IpAddress& left, const IpAddress& right) { return left.ToInteger() < right.ToInteger(); }