Socket::Status UdpSocket::send(const void* data, std::size_t size, const IpAddress& remoteAddress, unsigned short remotePort) { // Create the internal socket if it doesn't exist create(); // Make sure that all the data will fit in one datagram if (size > MaxDatagramSize) { err() << "Cannot send data over the network " << "(the number of bytes to send is greater than sf::UdpSocket::MaxDatagramSize)" << std::endl; return Error; } // Build the target address sockaddr_in address = priv::SocketImpl::createAddress(remoteAddress.toInteger(), remotePort); // Send the data (unlike TCP, all the data is always sent in one call) int sent = sendto(getHandle(), static_cast<const char*>(data), static_cast<int>(size), 0, reinterpret_cast<sockaddr*>(&address), sizeof(address)); // Check for errors if (sent < 0) return priv::SocketImpl::getErrorStatus(); return Done; }
Socket::Status TcpListener::Listen(unsigned short port, const IpAddress& address) { Create(); if ((address == IpAddress::None) || (address == IpAddress::Broadcast)) return Error; sockaddr_in addr = be::SocketBE::createAddress(address.toInteger(), port); if (bind(GetHandle(), reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1) { return Error; } if (::listen(GetHandle(), 0) == -1) { return Error; } return Done; }
Socket::Status UdpSocket::bind(unsigned short port, const IpAddress& address) { // Create the internal socket if it doesn't exist create(); // Check if the address is valid if ((address == IpAddress::None) || (address == IpAddress::Broadcast)) return Error; // Bind the socket sockaddr_in addr = priv::SocketImpl::createAddress(address.toInteger(), port); if (::bind(getHandle(), reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1) { err() << "Failed to bind socket to port " << port << std::endl; return Error; } return Done; }
Socket::Status TcpSocket::connect(const IpAddress& remoteAddress, unsigned short remotePort, Time timeout) { // Disconnect the socket if it is already connected disconnect(); // 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 <= Time::Zero) { // ----- 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...) setBlocking(blocking); return Done; } // Get the error status Status status = priv::SocketImpl::getErrorStatus(); // If we were in non-blocking mode, return immediately 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 = static_cast<long>(timeout.asMicroseconds() / 1000000); time.tv_usec = static_cast<long>(timeout.asMicroseconds() % 1000000); // 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() != 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(); }