long StreamSocketImpl::send_bytes(const void* buffer, size_t length, int flags) { const char* p = reinterpret_cast<const char*>(buffer); long remaining = length; long sent = 0; const auto blocking = get_blocking(); while (remaining > 0) { auto n = SocketImpl::send_bytes(p, remaining, flags); if (n < 0) { throw NetException("send_bytes error"); } p += n; sent += n; remaining -= n; if (blocking && remaining > 0) { std::this_thread::yield(); } else { break; } } return sent; }
// timeout (in microseconds) Socket::Status Socket::connect(const Address& remote_addr, uint16 remote_port, uint32 timeout) { create(); // create the remote address sockaddr_in address = priv::SocketImpl::create_addr(remote_addr.to_uint32(), remote_port); if (timeout == 0) { // connect the socket if (::connect(get_handle(), reinterpret_cast<struct sockaddr*>(&address), sizeof(address)) == -1) return priv::SocketImpl::get_error(); return STATUS_DONE; } else { bool blocking = get_blocking(); // switch to non-blocking to enable our connection timeout if (blocking) set_blocking(false); // try to connect to the remote address if (::connect(get_handle(), reinterpret_cast<struct sockaddr*>(&address), sizeof(address)) >= 0) { // we got instantly connected return STATUS_DONE; } Status status = priv::SocketImpl::get_error(); // 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 == STATUS_NOTREADY) { fd_set selector; FD_ZERO(&selector); FD_SET(get_handle(), &selector); timeval time; time.tv_sec = static_cast<long>(timeout / 1000000); time.tv_usec = static_cast<long>(timeout % 1000000); // wait for something to write on our socket (which means that the connection request has returned) if (select(static_cast<int>(get_handle() + 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 (get_address_remote() != Address::ADDR_NONE) { status = STATUS_DONE; } else { status = priv::SocketImpl::get_error(); } } else { status = priv::SocketImpl::get_error(); } } // switch back to blocking mode set_blocking(true); return status; } }