Example #1
0
    void Socket::_handleSendError(int ret, const char* context) {
#ifdef MONGO_SSL
        if (_ssl) {
            LOG(_logLevel) << "SSL Error ret: " << ret
                           << " err: " << _sslManager->SSL_get_error(_ssl , ret)
                           << " "
                           << _sslManager->ERR_error_string(_sslManager->ERR_get_error(), NULL)
                           << endl;
            throw SocketException(SocketException::SEND_ERROR , remoteString());
        }
#endif

#if defined(_WIN32)
        const int mongo_errno = WSAGetLastError();
        if ( mongo_errno == WSAETIMEDOUT && _timeout != 0 ) {
#else
        const int mongo_errno = errno;
        if ( ( mongo_errno == EAGAIN || mongo_errno == EWOULDBLOCK ) && _timeout != 0 ) {
#endif
            LOG(_logLevel) << "Socket " << context << 
                " send() timed out " << remoteString() << endl;
            throw SocketException(SocketException::SEND_TIMEOUT , remoteString());
        }
        else {
            LOG(_logLevel) << "Socket " << context << " send() "
                           << errnoWithDescription(mongo_errno) << ' ' << remoteString() << endl;
            throw SocketException(SocketException::SEND_ERROR , remoteString());            
        }
    }

    void Socket::_handleRecvError(int ret, int len, int* retries) {
        if (ret == 0) {
            LOG(3) << "Socket recv() conn closed? " << remoteString() << endl;
            throw SocketException(SocketException::CLOSED , remoteString());
        }
     
        // ret < 0
#ifdef MONGO_SSL
        if (_ssl) {
            LOG(_logLevel) << "SSL Error ret: " << ret
                           << " err: " << _sslManager->SSL_get_error(_ssl , ret)
                           << " "
                           << _sslManager->ERR_error_string(_sslManager->ERR_get_error(), NULL)
                           << endl;
            throw SocketException(SocketException::RECV_ERROR, remoteString());
        }
#endif

#if defined(_WIN32)
        int e = WSAGetLastError();
#else
        int e = errno;
# if defined(EINTR)
        if (e == EINTR) {
            LOG(_logLevel) << "EINTR retry " << ++*retries << endl;
            return;
        }
# endif
#endif

#if defined(_WIN32)
        // Windows
        if ((e == EAGAIN || e == WSAETIMEDOUT) && _timeout > 0) { 
#else
        if (e == EAGAIN && _timeout > 0) { 
#endif
            // this is a timeout
            LOG(_logLevel) << "Socket recv() timeout  " << remoteString() <<endl;
            throw SocketException(SocketException::RECV_TIMEOUT, remoteString());
        }

        LOG(_logLevel) << "Socket recv() " << 
            errnoWithDescription(e) << " " << remoteString() <<endl;
        throw SocketException(SocketException::RECV_ERROR , remoteString());
    }

    void Socket::setTimeout( double secs ) {
        setSockTimeouts( _fd, secs );
    }

    // TODO: allow modification?
    //
    // <positive value> : secs to wait between stillConnected checks
    // 0 : always check
    // -1 : never check
    const int Socket::errorPollIntervalSecs( 5 );

#if defined(NTDDI_VERSION) && ( !defined(NTDDI_VISTA) || ( NTDDI_VERSION < NTDDI_VISTA ) )
    // Windows XP

    // pre-Vista windows doesn't have WSAPoll, so don't test connections
    bool Socket::isStillConnected() {
        return true;
    }

#else // Not Windows XP

    // Patch to allow better tolerance of flaky network connections that get broken
    // while we aren't looking.
    // TODO: Remove when better async changes come.
    //
    // isStillConnected() polls the socket at max every Socket::errorPollIntervalSecs to determine
    // if any disconnection-type events have happened on the socket.
    bool Socket::isStillConnected() {

        if ( errorPollIntervalSecs < 0 ) return true;

        time_t now = time( 0 );
        time_t idleTimeSecs = now - _lastValidityCheckAtSecs;

        // Only check once every 5 secs
        if ( idleTimeSecs < errorPollIntervalSecs ) return true;
        // Reset our timer, we're checking the connection
        _lastValidityCheckAtSecs = now;

        // It's been long enough, poll to see if our socket is still connected

        pollfd pollInfo;
        pollInfo.fd = _fd;
        // We only care about reading the EOF message on clean close (and errors)
        pollInfo.events = POLLIN;

        // Poll( info[], size, timeout ) - timeout == 0 => nonblocking
#if defined(_WIN32)
        int nEvents = WSAPoll( &pollInfo, 1, 0 );
#else
        int nEvents = ::poll( &pollInfo, 1, 0 );
#endif

        LOG( 2 ) << "polling for status of connection to " << remoteString()
                 << ", " << ( nEvents == 0 ? "no events" :
                              nEvents == -1 ? "error detected" :
                                               "event detected" ) << endl;

        if ( nEvents == 0 ) {
            // No events incoming, return still connected AFAWK
            return true;
        }
        else if ( nEvents < 0 ) {
            // Poll itself failed, this is weird, warn and log errno
            warning() << "Socket poll() failed during connectivity check"
                      << " (idle " << idleTimeSecs << " secs,"
                      << " remote host " << remoteString() << ")"
                      << causedBy(errnoWithDescription()) << endl;

            // Return true since it's not clear that we're disconnected.
            return true;
        }

        dassert( nEvents == 1 );
        dassert( pollInfo.revents > 0 );

        // Return false at this point, some event happened on the socket, but log what the
        // actual event was.

        if ( pollInfo.revents & POLLIN ) {

            // There shouldn't really be any data to recv here, so make sure this
            // is a clean hangup.

            // Used concurrently, but we never actually read this data
            static char testBuf[1];

            int recvd = ::recv( _fd, testBuf, 1, portRecvFlags );

            if ( recvd < 0 ) {
                // An error occurred during recv, warn and log errno
                warning() << "Socket recv() failed during connectivity check"
                          << " (idle " << idleTimeSecs << " secs,"
                          << " remote host " << remoteString() << ")"
                          << causedBy(errnoWithDescription()) << endl;
            }
            else if ( recvd > 0 ) {
                // We got nonzero data from this socket, very weird?
                // Log and warn at runtime, log and abort at devtime
                // TODO: Dump the data to the log somehow?
                error() << "Socket found pending data during connectivity check"
                        << " (idle " << idleTimeSecs << " secs,"
                        << " remote host " << remoteString() << ")" << endl;
                dassert( false );
            }
            else {
                // recvd == 0, socket closed remotely, just return false
                LOG( 0 ) << "Socket closed remotely, no longer connected"
                         << " (idle " << idleTimeSecs << " secs,"
                         << " remote host " << remoteString() << ")" << endl;
            }
        }
        else if ( pollInfo.revents & POLLHUP ) {
            // A hangup has occurred on this socket
            LOG( 0 ) << "Socket hangup detected, no longer connected" << " (idle "
                         << idleTimeSecs << " secs," << " remote host " << remoteString() << ")"
                         << endl;
        }
        else if ( pollInfo.revents & POLLERR ) {
            // An error has occurred on this socket
            LOG( 0 ) << "Socket error detected, no longer connected" << " (idle "
                         << idleTimeSecs << " secs," << " remote host " << remoteString() << ")"
                         << endl;
        }
        else if ( pollInfo.revents & POLLNVAL ) {
            // Socket descriptor itself is weird
            // Log and warn at runtime, log and abort at devtime
            error() << "Socket descriptor detected as invalid"
                    << " (idle " << idleTimeSecs << " secs,"
                    << " remote host " << remoteString() << ")" << endl;
            dassert( false );
        }
        else {
            // Don't know what poll is saying here
            // Log and warn at runtime, log and abort at devtime
            error() << "Socket had unknown event (" << static_cast<int>(pollInfo.revents) << ")"
                    << " (idle " << idleTimeSecs << " secs,"
                    << " remote host " << remoteString() << ")" << endl;
            dassert( false );
        }

        return false;
    }

#endif // End Not Windows XP

#if defined(_WIN32)
    struct WinsockInit {
        WinsockInit() {
            WSADATA d;
            if ( WSAStartup(MAKEWORD(2,2), &d) != 0 ) {
                out() << "ERROR: wsastartup failed " << errnoWithDescription() << endl;
                problem() << "ERROR: wsastartup failed " << errnoWithDescription() << endl;
                _exit(EXIT_NTSERVICE_ERROR);
            }
        }
    } winsock_init;
#endif

} // namespace mongo
 org::esb::io::OutputStream * TcpSocket::getOutputStream() {
   if(!isConnected())
     throw SocketException("Socket is not connected");
   return _os;
 }
Example #3
0
 void Socket::SetNonBlockingFalg(bool isNonBlocking)
 {
   if (!SetNonBlockingFalgImpl(SockHandle, isNonBlocking))
     throw SocketException("Error set non blocking flag");
 }
Example #4
0
void Web::Request::Connect() {
   
	SOCKET httpSocket;
	int ret;
	struct sockaddr_in httpAddr;
	struct hostent *hostinfo;
	char buffer[REQUESTBUFFERSIZE + 1];
	int bufferSize;
   int timeout = REQUESTTIMEOUT;

   /* Choses settings for the socket to connect to */
   httpAddr.sin_family = AF_INET;

   /* Set the port */
   //httpAddr.sin_port = htons(url->getPort());
   httpAddr.sin_port = htons(80);

   /* Do a hostname lookup on the host */
   //hostinfo = gethostbyname (url->getHost());
   hostinfo = gethostbyname ("localhost");
   if (hostinfo == NULL) {
      throw HostNotFoundException();
   }
   
   /* Fill the httpAddr with IP data */
   httpAddr.sin_addr = *(struct in_addr *) hostinfo->h_addr;
    
	/* Creates the socket */
	httpSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) ;
	
	/* Check for errors */
	if (httpSocket == INVALID_SOCKET)
	    throw SocketException();

   /* Add a timeout on all communiction*/
   ret = setsockopt(httpSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));

   /* Check for errors */
   if (ret == SOCKET_ERROR) {
      closesocket(httpSocket);
      throw SocketException();
   }

   /* Connect to the server */
   ret = connect(httpSocket,(LPSOCKADDR)&httpAddr, sizeof(struct sockaddr));

   /* Check for errors */
   if (ret == SOCKET_ERROR) {
      closesocket(httpSocket);
      throw ConnectionFailedException(WSAGetLastError());
   }

   /* Create a request */
   bufferSize = _snprintf(buffer, REQUESTBUFFERSIZE, "GET %s HTTP/1.0\r\n\r\n", url->getURL());

   if (bufferSize <= 0) {
      closesocket(httpSocket);
      throw Exception("Request Buffer Too Small");
   }
      
   /* Send a HTTP request */
   ret = send(httpSocket, buffer, bufferSize, 0);

   if (ret < bufferSize) {
      closesocket(httpSocket);
      throw TransferException();
   }
   
   reply.assign("");
   ret = REQUESTBUFFERSIZE;
   
   /* Now wait for the return and loop while its coming */
   while (ret > 0) {
      ret = recv(httpSocket, buffer, REQUESTBUFFERSIZE, 0);
      
      /* Append data to the buffer */
      if (ret > 0)
         reply.append(buffer, ret);
   }

   /* Clean up the socket */
   closesocket(httpSocket);

   /* Now if we didn't get any data throw a error */
   if (reply.length()==0) {
      throw TransferException();
   }

   /* Got some data let parse it */
   ret = (int)reply.find("\r\n\r\n");

   if (ret==-1) {
      throw InvalidDataException();
   }
   
   header = reply.substr(0, ret);
   ret += 4;
   body = reply.substr(ret, reply.length() - ret);  

}
Example #5
0
bool SSLSocket::waitWant(int ret, uint64_t millis) {
#ifdef HEADER_OPENSSLV_H
	int err = SSL_get_error(ssl, ret);
	switch(err) {
	case SSL_ERROR_WANT_READ:
		return wait(millis, Socket::WAIT_READ) == WAIT_READ;
	case SSL_ERROR_WANT_WRITE:
		return wait(millis, Socket::WAIT_WRITE) == WAIT_WRITE;
#else
	int err = ssl->last_error;
	switch(err) {
	case GNUTLS_E_INTERRUPTED:
	case GNUTLS_E_AGAIN: 
	{
		int waitFor = wait(millis, Socket::WAIT_READ | Socket::WAIT_WRITE);
		return (waitFor & Socket::WAIT_READ) || (waitFor & Socket::WAIT_WRITE);
	}
#endif
	// Check if this is a fatal error...
	default: checkSSL(ret);
	}
	dcdebug("SSL: Unexpected fallthrough");
	// There was no error?
	return true;
}

int SSLSocket::read(void* aBuffer, int aBufLen) throw(SocketException) {
	if(!ssl) {
		return -1;
	}
	int len = checkSSL(SSL_read(ssl, aBuffer, aBufLen));

	if(len > 0) {
		stats.totalDown += len;
		//dcdebug("In(s): %.*s\n", len, (char*)aBuffer);
	}
	return len;
}

int SSLSocket::write(const void* aBuffer, int aLen) throw(SocketException) {
	if(!ssl) {
		return -1;
	}
	int ret = checkSSL(SSL_write(ssl, aBuffer, aLen));
	if(ret > 0) {
		stats.totalUp += ret;
		//dcdebug("Out(s): %.*s\n", ret, (char*)aBuffer);
	}
	return ret;
}

int SSLSocket::checkSSL(int ret) throw(SocketException) {
	if(!ssl) {
		return -1;
	}
	if(ret <= 0) {
		int err = SSL_get_error(ssl, ret);
		switch(err) {
			case SSL_ERROR_NONE:		// Fallthrough - YaSSL doesn't for example return an openssl compatible error on recv fail
			case SSL_ERROR_WANT_READ:	// Fallthrough
			case SSL_ERROR_WANT_WRITE:
				return -1;
			case SSL_ERROR_ZERO_RETURN:
#ifndef HEADER_OPENSSLV_H
				if(ssl->last_error == GNUTLS_E_INTERRUPTED || ssl->last_error == GNUTLS_E_AGAIN)
					return -1;
#endif				
				throw SocketException(STRING(CONNECTION_CLOSED));
			default:
				{
					ssl.reset();
					// @todo replace 80 with MAX_ERROR_SZ or whatever's appropriate for yaSSL in some nice way...
					char errbuf[80];

					/* TODO: better message for SSL_ERROR_SYSCALL
					 * If the error queue is empty (i.e. ERR_get_error() returns 0), ret can be used to find out more about the error: 
					 * If ret == 0, an EOF was observed that violates the protocol. If ret == -1, the underlying BIO reported an I/O error 
					 * (for socket I/O on Unix systems, consult errno for details).
					 */
					int error = ERR_get_error();
					sprintf(errbuf, "%s %d: %s", CSTRING(SSL_ERROR), err, (error == 0) ? CSTRING(CONNECTION_CLOSED) : ERR_reason_error_string(error));
					throw SSLSocketException(errbuf);
				}
		}
	}
	return ret;
}

int SSLSocket::wait(uint64_t millis, int waitFor) throw(SocketException) {
#ifdef HEADER_OPENSSLV_H
	if(ssl && (waitFor & Socket::WAIT_READ)) {
		/** @todo Take writing into account as well if reading is possible? */
		char c;
		if(SSL_peek(ssl, &c, 1) > 0)
			return WAIT_READ;
	}
#endif
	return Socket::wait(millis, waitFor);
}

bool SSLSocket::isTrusted() throw() {
	if(!ssl) {
		return false;
	}

#ifdef HEADER_OPENSSLV_H
	if(SSL_get_verify_result(ssl) != X509_V_OK) {
		return false;
	}
#else
	if(gnutls_certificate_verify_peers(((SSL*)ssl)->gnutls_state) != 0) {
		return false;
	}
#endif

	X509* cert = SSL_get_peer_certificate(ssl);
	if(!cert) {
		return false;
	}

	X509_free(cert);

	return true;
}

std::string SSLSocket::getCipherName() throw() {
	if(!ssl)
		return Util::emptyString;
	
	return SSL_get_cipher_name(ssl);
}

std::string SSLSocket::getDigest() const throw() {
#ifdef HEADER_OPENSSLV_H

	if(!ssl)
		return Util::emptyString;
	X509* x509 = SSL_get_peer_certificate(ssl);
	if(!x509)
		return Util::emptyString;
	
	return ssl::X509_digest(x509, EVP_sha1());
#else
	return Util::emptyString;
#endif
}

void SSLSocket::shutdown() throw() {
	if(ssl)
		SSL_shutdown(ssl);
}

void SSLSocket::close() throw() {
	if(ssl) {
		ssl.reset();
	}
	Socket::shutdown();
	Socket::close();
}

} // namespace dcpp
Example #6
0
    /** sends all data or throws an exception
     * @param context descriptive for logging
     */
    void Socket::send( const vector< pair< char *, int > > &data, const char *context ) {

#ifdef MONGO_SSL
        if ( _sslConnection.get() ) {
            _send( data , context );
            return;
        }
#endif

#if defined(_WIN32)
        // TODO use scatter/gather api
        _send( data , context );
#else
        vector<struct iovec> d( data.size() );
        int i = 0;
        for (vector< pair<char *, int> >::const_iterator j = data.begin(); 
             j != data.end(); 
             ++j) {
            if ( j->second > 0 ) {
                d[ i ].iov_base = j->first;
                d[ i ].iov_len = j->second;
                ++i;
                _bytesOut += j->second;
            }
        }
        struct msghdr meta;
        memset( &meta, 0, sizeof( meta ) );
        meta.msg_iov = &d[ 0 ];
        meta.msg_iovlen = d.size();

        while( meta.msg_iovlen > 0 ) {
            int ret = -1;
            if (MONGO_FAIL_POINT(throwSockExcep)) {
#if defined(_WIN32)
                WSASetLastError(WSAENETUNREACH);
#else
                errno = ENETUNREACH;
#endif
            }
            else {
                ret = ::sendmsg(_fd, &meta, portSendFlags);
            }

            if (ret == -1) {
                if ( errno != EAGAIN || _timeout == 0 ) {
                    LOG(_logLevel) << "Socket " << context << 
                        " send() " << errnoWithDescription() << ' ' << remoteString() << endl;
                    throw SocketException( SocketException::SEND_ERROR , remoteString() );
                }
                else {
                    LOG(_logLevel) << "Socket " << context << 
                        " send() remote timeout " << remoteString() << endl;
                    throw SocketException( SocketException::SEND_TIMEOUT , remoteString() );
                }
            }
            else {
                struct iovec *& i = meta.msg_iov;
                while( ret > 0 ) {
                    if ( i->iov_len > unsigned( ret ) ) {
                        i->iov_len -= ret;
                        i->iov_base = (char*)(i->iov_base) + ret;
                        ret = 0;
                    }
                    else {
                        ret -= i->iov_len;
                        ++i;
                        --(meta.msg_iovlen);
                    }
                }
            }
        }
#endif
    }
Example #7
0
size_t TCPClient::write(const char *msg) throw(SocketException)
{
    if ( ::write(m_sockfd, msg, strlen(msg)) == -1 )
        throw SocketException("tcp client write error");
    return strlen(msg);
}
Example #8
0
void SocketIPv4::shutdown(int how)
{
  if (::shutdown(m_socket, how) == SOCKET_ERROR) {
    throw SocketException();
  }
}
Example #9
0
void SocketIO::Bind(Socket *s, const Anope::string &ip, int port)
{
	s->bindaddr.pton(s->IsIPv6() ? AF_INET6 : AF_INET, ip, port);
	if (bind(s->GetFD(), &s->bindaddr.sa, s->bindaddr.size()) == -1)
		throw SocketException("Unable to bind to address: " + Anope::LastError());
}
Example #10
0
void TCPClient::write(const void *buf, size_t count) throw(SocketException)
{
    if ( ::write(m_sockfd, buf, count) == -1 )
        throw SocketException("tcp client write error");
}
Example #11
0
int Socket::connect(const char *hostName, in_port_t port)
{
    int rc = -1;
    int sockfd, nodelay;
    char service[NI_MAXSERV] = {0};
    struct addrinfo *host = NULL, *ressave;
    int count = 0;
	bool connected = false;

    while (count < connTimes) {
        struct addrinfo hints = {0};
        ::sprintf(service, "%d", port);
        hints.ai_family = AF_UNSPEC;
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;

        rc = ::getaddrinfo(hostName, service, &hints, &host);
        if (rc == EAI_NONAME) {
            hints.ai_flags = 0;
            rc = ::getaddrinfo(hostName, service, &hints, &host);
        }
        if (!host) {
            throw SocketException(SocketException::NET_ERR_GETADDRINFO, errno);
        }

		ressave = host;
        while (host) {
            if ((host->ai_family == AF_INET6) && (getDisableIPv6() == 1)) {
                host = host->ai_next;
                continue;
            }

			sockfd = ::socket(host->ai_family, host->ai_socktype, host->ai_protocol);
			if (sockfd < 0) {
				::freeaddrinfo(host);
				throw SocketException(SocketException::NET_ERR_SOCKET, errno);
			}
			nodelay = 1;
			rc = ::setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char*)&nodelay, sizeof(nodelay));

			rc = ::connect(sockfd, host->ai_addr, host->ai_addrlen);
			if (rc == 0) {
				connected = true;
				break;
			}
			host = host->ai_next;
		}
        count++;
        ::freeaddrinfo(ressave);
		if (connected)
			break;

        ::close(sockfd);
        ::sleep(1);
    }
    if (rc < 0) {
        throw SocketException(SocketException::NET_ERR_CONNECT, errno);
    }
    socket = sockfd;

    return sockfd;
}
Example #12
0
int Socket::listen(int &port, char *hname)
{
    int sockfd;
    int yes, rc;
	int accCount = 0;
    struct addrinfo hints, *host, *ressave;
    char service[NI_MAXSERV] = {0};

    ::memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_flags = (hname == NULL) ? AI_PASSIVE : 0;
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    ::sprintf(service, "%d", port);
    ::getaddrinfo(hname, service, &hints, &host);
    ressave = host;

    while (host && (accCount < NELEMS(accSockets))) {
		if ((host->ai_family != AF_INET) && (host->ai_family != AF_INET6)) {
            host = host->ai_next;
            continue;
        }

        if ((host->ai_family == AF_INET6) && (getDisableIPv6() == 1)) {
            host = host->ai_next;
            continue;
        }

        sockfd = ::socket(host->ai_family, host->ai_socktype, host->ai_protocol);
        if (sockfd >= 0) {
			yes = 1;
			rc = ::setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
			if (host->ai_family == AF_INET6) {
				setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes));
				sockaddr_in6 *addr6 = (sockaddr_in6 *)host->ai_addr;
				if (port != 0)
					addr6->sin6_port = htons(port);
			} else {
				sockaddr_in *addr4 = (sockaddr_in *)host->ai_addr;
				if (port != 0)
					addr4->sin_port = htons(port);
			}
			setMode(sockfd, false);
            rc = ::bind(sockfd, host->ai_addr, host->ai_addrlen);
            if (rc == 0) {
                struct sockaddr_storage sockaddr;
                socklen_t len = sizeof(sockaddr);

                ::getsockname(sockfd, (struct sockaddr *)&sockaddr, &len);
                ::getnameinfo((struct sockaddr *)&sockaddr, len, NULL, 0,
                        service, sizeof(service), NI_NUMERICSERV);
                port = ::atoi(service);
				rc = ::listen(sockfd, SOMAXCONN);
                accSockets[accCount] = sockfd;
				accCount++;
            } else {
				::close(sockfd);
			}
        }
        host = host->ai_next;
    }

    if (accCount <= 0) {
        throw SocketException(SocketException::NET_ERR_BIND, errno);
    }
    ::freeaddrinfo(ressave);

    numListenfds = accCount;
    return accCount;
}
Example #13
0
/** Bind a socket
 * @param s The socket
 * @param ip The IP to bind to
 * @param port The optional port to bind to
 */
void SocketIO::Bind(Socket *s, const Flux::string &ip, int port)
{
	s->bindaddr.pton(s->IsIPv6() ? AF_INET6 : AF_INET, ip, port);
	if (bind(s->GetFD(), &s->bindaddr.sa, s->bindaddr.size()) == -1)
		throw SocketException(printfify("Unable to bind to address: %s", strerror(errno)));
}
Example #14
0
void SocketIPv4::listen(int backlog)
{
  if (::listen(m_socket, backlog) == SOCKET_ERROR) {
    throw SocketException();
  }
}
SocketEnvironment::SocketEnvironment() {
  WSADATA data;
  if (::WSAStartup(MAKEWORD(2, 0), &data)) {
    throw SocketException(__FILE__, __LINE__);
  }
}
Example #16
0
void SocketIPv4::getSocketOptions(int level, int name, void *value, socklen_t *len)
{
  if (getsockopt(m_socket, level, name, (char*)value, len) == SOCKET_ERROR) {
    throw SocketException();
  }
}
void BufferedSocket::threadRead() throw(SocketException) {
	if(state != RUNNING)
		return;

	DownloadManager *dm = DownloadManager::getInstance();
	size_t readsize = inbuf.size();
	bool throttling = false;
	if(mode == MODE_DATA)
	{
		uint32_t getMaximum;
		throttling = dm->throttle();
		if (throttling)
		{
			getMaximum = dm->throttleGetSlice();
			readsize = (uint32_t)min((int64_t)inbuf.size(), (int64_t)getMaximum);
			if (readsize <= 0  || readsize > inbuf.size()) { // FIX
				sleep(dm->throttleCycleTime());
				return;
			}
		}
	}
	int left = sock->read(&inbuf[0], (int)readsize);
	if(left == -1) {
		// EWOULDBLOCK, no data received...
		return;
	} else if(left == 0) {
		// This socket has been closed...
		throw SocketException(_("Connection closed"));
	}
	string::size_type pos = 0;
	// always uncompressed data
	string l;
	int bufpos = 0, total = left;

	while (left > 0) {
		switch (mode) {
			case MODE_ZPIPE: {
					const int BUF_SIZE = 1024;
					// Special to autodetect nmdc connections...
					string::size_type pos = 0;
					boost::scoped_array<char> buffer(new char[BUF_SIZE]);
					l = line;
					// decompress all input data and store in l.
					while (left) {
						size_t in = BUF_SIZE;
						size_t used = left;
						bool ret = (*filterIn) (&inbuf[0] + total - left, used, &buffer[0], in);
						left -= used;
						l.append (&buffer[0], in);
						// if the stream ends before the data runs out, keep remainder of data in inbuf
						if (!ret) {
							bufpos = total-left;
							setMode (MODE_LINE, rollback);
							break;
						}
					}
					// process all lines
					while ((pos = l.find(separator)) != string::npos) {
						fire(BufferedSocketListener::Line(), l.substr(0, pos));
						l.erase (0, pos + 1 /* separator char */);
					}
					// store remainder
					line = l;

					break;
				}
			case MODE_LINE:
				// Special to autodetect nmdc connections...
				if(separator == 0) {
					if(inbuf[0] == '$') {
						separator = '|';
					} else {
						separator = '\n';
					}
				}
				l = line + string ((char*)&inbuf[bufpos], left);
				while ((pos = l.find(separator)) != string::npos) {
					fire(BufferedSocketListener::Line(), l.substr(0, pos));
					l.erase (0, pos + 1 /* separator char */);
					if (l.length() < (size_t)left) left = l.length();
					if (mode != MODE_LINE) {
						// we changed mode; remainder of l is invalid.
						l.clear();
						bufpos = total - left;
						break;
					}
				}
				if (pos == string::npos)
					left = 0;
				line = l;
				break;
			case MODE_DATA:
				while(left > 0) {
					if(dataBytes == -1) {
						fire(BufferedSocketListener::Data(), &inbuf[bufpos], left);
						bufpos += (left - rollback);
						left = rollback;
						rollback = 0;
					} else {
						int high = (int)min(dataBytes, (int64_t)left);
						fire(BufferedSocketListener::Data(), &inbuf[bufpos], high);
						bufpos += high;
						left -= high;

						dataBytes -= high;
						if(dataBytes == 0) {
							mode = MODE_LINE;
							fire(BufferedSocketListener::ModeChange());
						}
					}
					if (throttling) {
						if (left > 0 && left < (int)readsize) {
							dm->throttleReturnBytes(left - readsize);
						}
						uint32_t sleep_interval =  dm->throttleCycleTime();
						Thread::sleep(sleep_interval);
					}
				}
				break;
		}
	}

	if(mode == MODE_LINE && line.size() > static_cast<size_t>(SETTING(MAX_COMMAND_LENGTH))) {
		throw SocketException(_("Maximum command length exceeded"));
	}
}
vpr::Uint32 SocketDatagramImplBSD::sendto(const void* msg,
                                          const vpr::Uint32 length,
                                          const vpr::InetAddr& to,
                                          const vpr::Interval timeout)
{
   vpr::Uint32 bytes_sent(0);

   // If not writable within timeout interval throw exception.
   if ( ! mHandle->isWriteable(timeout) )
   {
      std::ostringstream msg_stream;
      msg_stream << "Timeout occured while trying to write to "
                 << mHandle->getName();
      throw TimeoutException(msg_stream.str(), VPR_LOCATION);
   }

   ssize_t bytes;

   mBlockingFixed = true;

   bytes = ::sendto(mHandle->mFdesc, msg, length, 0,
                    (struct sockaddr*) &to.mAddr, to.size());

   if ( bytes == -1 )
   {
      if ( errno == EAGAIN && ! isBlocking() )
      {
         throw WouldBlockException("Would block while reading.", VPR_LOCATION);
      }
      else
      {
         std::stringstream ss;
         ss << "[vpr::SocketDatagramImplBSD::sendto()] ERROR: Could not send "
            << " to " << to << " on socket (" << mRemoteAddr << "): "
            << strerror(errno);

         throw SocketException(ss.str(), VPR_LOCATION);
      }
   }

   if ( ECONNRESET == errno)
   {
      throw ConnectionResetException("Connection reset.", VPR_LOCATION);
   }
   else if (EHOSTUNREACH == errno)
   {
      throw NoRouteToHostException("No route to host.", VPR_LOCATION);
   }
   else if (EHOSTDOWN == errno)
   {
      throw UnknownHostException("Unknown host.", VPR_LOCATION);
   }
   else if (ENETDOWN == errno)
   {
      throw IOException("Network is down.", VPR_LOCATION);
   }
   else
   {
      bytes_sent = bytes;
   }

   return bytes_sent;
}
//==============================================================================
// PlainDatagramSocketImpl::send
//
//==============================================================================
void PlainDatagramSocketImpl::send(const DatagramPacket& p)
{
	testSocketIsValid();

	int flags = 0;
	struct sockaddr* to=0;
	struct sockaddr_in sa;

	if(isConnected())
	{
		if(p.getAddress() && !(m_rpRemoteAddr->equals(*(p.getAddress()))))
		{
			throw IllegalArgumentException(QC_T("Address in datagram packet does not match connected address"));
		}
		if(p.getPort()!= -1 && p.getPort()!=m_remotePort)
		{
			throw IllegalArgumentException(QC_T("Port in datagram packet does not match connected port"));
		}
	}
	else
	{
		//
		// If the socket is not connected, then the passed datagram packet must contain
		// valid information.
		//
		if(!p.getAddress() || p.getPort()==-1)
		{
			throw IllegalArgumentException(QC_T("datagram packet does not contain required address/port information"));
		}
		//
		// Use the InetAddress and port contained in the packet to 
		// create and initialize a sockaddr_in structure.
		//
		::memset(&sa, 0, sizeof(sa));
		sa.sin_family = AF_INET;
		sa.sin_port = htons(p.getPort()); // convert port to network byte order 
		::memcpy(&sa.sin_addr, p.getAddress()->getAddress(), p.getAddress()->getAddressLength());
		to = reinterpret_cast<struct sockaddr*>(&sa);
	}

	if(Tracer::IsEnabled())
	{
		Tracer::TraceBytes(Tracer::Net, Tracer::Low, QC_T("Datagram send:"), p.getData(), p.getLength());
	}

	int rc = ::sendto(m_rpSocketDescriptor->getFD(),
	                  (const char*) p.getData(),
	                  p.getLength(),
	                  flags,
	                  to,
	                  to ? sizeof(struct sockaddr_in) : 0);

	if(rc<0)
	{
		static const String err(QC_T("error calling sendto "));
		String errMsg = err + NetUtils::GetSocketErrorString();
		throw SocketException(errMsg);
	}

	//
	// When an unbound datagram socket is used to send data, the system will allocate
	// it an address and ephemeral port.  Let's see what weve been given!
	//
	if(!isBound())
	{
	}
}
Example #20
0
void SocketIO::Process()
{
  SET_SEGV_LOCATION();
  timeval timeout;
  timeout.tv_sec = Config->SockWait;
  timeout.tv_usec = 0; //this timeout keeps the bot from being a CPU hog for no reason :)
  fd_set read = ReadFD, write = WriteFD, except = ExceptFD;

  FD_ZERO(&read);
  FD_SET(this->GetFD(), &read);

  int sres = select(this->GetFD() + 1, &read, &write, &except, &timeout);
  if(sres == -1 && errno != EINTR)
  {
    Log(LOG_DEBUG) << "Select() error: " << strerror(errno);
    return;
  }

  if(throwex) //throw a socket exception if we want to. mainly used for ping timeouts.
    throw SocketException(throwmsg);

  bool has_read = FD_ISSET(this->GetFD(), &read);
  bool has_write = FD_ISSET(this->GetFD(), &write);
  bool has_error = FD_ISSET(this->GetFD(), &except);

  if(has_error)
  {
    int optval = 0;
    socklen_t optlen = sizeof(optval);
    getsockopt(this->GetFD(), SOL_SOCKET, SO_ERROR, reinterpret_cast<char *>(&optval), &optlen);
    errno = optval;
    FOREACH_MOD(I_OnSocketError, OnSocketError(optval ? strerror(errno) : "Unknown socket error"));
    throw SocketException("Socket error");
  }
  
  if(has_read)
  {
    char tbuf[BUFSIZE + 1] = "\0";
    size_t i = recv(this->GetFD(), tbuf, BUFSIZE, 0);
    
    if(i <= 0)
      throw SocketException(printfify("Socket Error: %s", strerror(errno)));
    
    sepstream sep(tbuf, '\n');
    Flux::string buf;
    while(sep.GetToken(buf))
    {
      this->LastBuf.clear();
      this->LastBuf = buf;
      if(!this->Read(buf))
	throw SocketException("Error reading socket");
    }

    FD_CLR(this->GetFD(), &ReadFD);
  }

  if(has_write)
  {
    Flux::string buf;
    while(!this->WriteBuffer.empty())
    {
      buf = this->WriteBuffer.front();
      this->WriteBuffer.pop();

      int i = ::send(this->GetFD(), buf.c_str(), buf.size(), MSG_NOSIGNAL);

      if(i <= -1 && !quitting)
	throw SocketException(printfify("Error writing \"%s\" to socket: %s", buf.c_str(), strerror(errno)));

      Log(LOG_RAWIO) << "Sent: " << buf << " | " << buf.size() << " bytes";
      
      this->LastBuf.clear();
      this->LastBuf = buf;

      buf.clear();
    }

    FD_CLR(this->GetFD(), &WriteFD);
  }
}
//==============================================================================
// PlainDatagramSocketImpl::receive
//
//==============================================================================
void PlainDatagramSocketImpl::receive(DatagramPacket& p)
{
	testSocketIsValid();

	sockaddr_in remoteAddr;
	cel_socklen_t addrLen;
	sockaddr* pRemoteAddr = reinterpret_cast<struct sockaddr*>(&remoteAddr);
	int recvLength;

	//
	// The following code is placed within a while() block to attempt to unify
	// the behaviour on multiple platforms.  If this datagram socket has been
	// used to send a dataram packet, an ICMP response may be received to
	// indicate that the send request was unsuccessful.  This behaviour is not
	// always helpful and is not guaranteed to occur (but seems to on Windows).
	// There is a far greater liklihood of this behaviour occurring on all platforms
	// when the socket has been connected to a particular host.  For this reason,
	// connect errors are ignored unless the socket has been connected.
	//
	while(true)
	{
		// simulate SO_TIMEOUT
		if(m_nTimeoutMS && !NetUtils::SelectSocket(m_rpSocketDescriptor.get(), m_nTimeoutMS,true,false))
		{
			static const String err(QC_T("receive timed out"));
			throw SocketTimeoutException(err);
		}

		int flags = 0;
		addrLen = sizeof(remoteAddr);
		recvLength = recvfrom(m_rpSocketDescriptor->getFD(),
		                      (char*) p.getData(),
		                      p.getLength(),
		                      flags,
		                      pRemoteAddr,
		                      &addrLen);

		if(recvLength < 0)
		{
			const int errorNum = NetUtils::GetLastSocketError();

			// Failure of recvfrom may be cause by the buffer length being smaller
			// than the message (in which case we silently ignore it, and set the
			// received length equal to the buffer length supplied), or due to
			// some other serious problem which will result in a SocketException
			//
			if(errorNum == QC_EMSGSIZE)
			{
				recvLength = p.getLength();
				break;
			}
			else if(!isConnected() && (errorNum == QC_ECONNRESET || errorNum == QC_ECONNABORTED || errorNum == QC_EHOSTUNREACH))
			{
				// See detailed comment above
				continue;
			}
			else
			{
				static const String err(QC_T("error calling recvfrom "));
				String errMsg = err + NetUtils::GetSocketErrorString(errorNum);
				throw SocketException(errMsg);
			}
		}
		else
		{
			break;
		}
	}
	
	//
	// Note: this test should migrate to the InetAddress class
	//
	if(addrLen != sizeof(sockaddr_in))
	{
		static const String err(QC_T("recvfrom() returned invalid address size"));
		throw SocketException(err);
	}

	//
	// Update the DatagramPacket with the address/length info
	//
	p.setPort(ntohs(remoteAddr.sin_port));
	p.setAddress(InetAddress::FromNetworkAddress(pRemoteAddr, addrLen).get());
	p.setLength(recvLength);

	if(Tracer::IsEnabled())
	{
		Tracer::TraceBytes(Tracer::Net, Tracer::Low, QC_T("Datagram rcvd:"), p.getData(), recvLength);
	}
}
Example #22
0
    void Socket::handleSendError(int ret, const char* context) {

#if defined(_WIN32)
        const int mongo_errno = WSAGetLastError();
        if ( mongo_errno == WSAETIMEDOUT && _timeout != 0 ) {
#else
        const int mongo_errno = errno;
        if ( ( mongo_errno == EAGAIN || mongo_errno == EWOULDBLOCK ) && _timeout != 0 ) {
#endif
            LOG(_logLevel) << "Socket " << context << 
                " send() timed out " << remoteString() << endl;
            throw SocketException(SocketException::SEND_TIMEOUT , remoteString());
        }
        else {
            LOG(_logLevel) << "Socket " << context << " send() "
                           << errnoWithDescription(mongo_errno) << ' ' << remoteString() << endl;
            throw SocketException(SocketException::SEND_ERROR , remoteString());            
        }
    }

    void Socket::handleRecvError(int ret, int len) {
        if (ret == 0) {
            LOG(3) << "Socket recv() conn closed? " << remoteString() << endl;
            throw SocketException(SocketException::CLOSED , remoteString());
        }
     
        // ret < 0
#if defined(_WIN32)
        int e = WSAGetLastError();
#else
        int e = errno;
# if defined(EINTR)
        if (e == EINTR) {
            LOG(_logLevel) << "EINTR returned from recv(), retrying";
            return;
        }
# endif
#endif

#if defined(_WIN32)
        // Windows
        if ((e == EAGAIN || e == WSAETIMEDOUT) && _timeout > 0) { 
#else
        if (e == EAGAIN && _timeout > 0) { 
#endif
            // this is a timeout
            LOG(_logLevel) << "Socket recv() timeout  " << remoteString() <<endl;
            throw SocketException(SocketException::RECV_TIMEOUT, remoteString());
        }

        LOG(_logLevel) << "Socket recv() " << 
            errnoWithDescription(e) << " " << remoteString() <<endl;
        throw SocketException(SocketException::RECV_ERROR , remoteString());
    }

    void Socket::setTimeout( double secs ) {
        setSockTimeouts( _fd, secs );
    }

    // TODO: allow modification?
    //
    // <positive value> : secs to wait between stillConnected checks
    // 0 : always check
    // -1 : never check
    const int Socket::errorPollIntervalSecs( 5 );

    // Patch to allow better tolerance of flaky network connections that get broken
    // while we aren't looking.
    // TODO: Remove when better async changes come.
    //
    // isStillConnected() polls the socket at max every Socket::errorPollIntervalSecs to determine
    // if any disconnection-type events have happened on the socket.
    bool Socket::isStillConnected() {

        if (MONGO_FAIL_POINT(notStillConnected)) { return false; }

        if (_fd == -1) {
            // According to the man page, poll will respond with POLLVNAL for invalid or
            // unopened descriptors, but it doesn't seem to be properly implemented in
            // some platforms - it can return 0 events and 0 for revent. Hence this workaround.
            return false;
        }

        if ( errorPollIntervalSecs < 0 ) return true;
        if ( ! isPollSupported() ) return true; // nothing we can do

        time_t now = time( 0 );
        time_t idleTimeSecs = now - _lastValidityCheckAtSecs;

        // Only check once every 5 secs
        if ( idleTimeSecs < errorPollIntervalSecs ) return true;
        // Reset our timer, we're checking the connection
        _lastValidityCheckAtSecs = now;

        // It's been long enough, poll to see if our socket is still connected

        pollfd pollInfo;
        pollInfo.fd = _fd;
        // We only care about reading the EOF message on clean close (and errors)
        pollInfo.events = POLLIN;

        // Poll( info[], size, timeout ) - timeout == 0 => nonblocking
        int nEvents = socketPoll( &pollInfo, 1, 0 );

        LOG( 2 ) << "polling for status of connection to " << remoteString()
                 << ", " << ( nEvents == 0 ? "no events" :
                              nEvents == -1 ? "error detected" :
                                               "event detected" ) << endl;

        if ( nEvents == 0 ) {
            // No events incoming, return still connected AFAWK
            return true;
        }
        else if ( nEvents < 0 ) {
            // Poll itself failed, this is weird, warn and log errno
            warning() << "Socket poll() failed during connectivity check"
                      << " (idle " << idleTimeSecs << " secs,"
                      << " remote host " << remoteString() << ")"
                      << causedBy(errnoWithDescription()) << endl;

            // Return true since it's not clear that we're disconnected.
            return true;
        }

        dassert( nEvents == 1 );
        dassert( pollInfo.revents > 0 );

        // Return false at this point, some event happened on the socket, but log what the
        // actual event was.

        if ( pollInfo.revents & POLLIN ) {

            // There shouldn't really be any data to recv here, so make sure this
            // is a clean hangup.

            const int testBufLength = 1024;
            char testBuf[testBufLength];

            int recvd = ::recv( _fd, testBuf, testBufLength, portRecvFlags );

            if ( recvd < 0 ) {
                // An error occurred during recv, warn and log errno
                warning() << "Socket recv() failed during connectivity check"
                          << " (idle " << idleTimeSecs << " secs,"
                          << " remote host " << remoteString() << ")"
                          << causedBy(errnoWithDescription()) << endl;
            }
            else if ( recvd > 0 ) {
                // We got nonzero data from this socket, very weird?
                // Log and warn at runtime, log and abort at devtime
                // TODO: Dump the data to the log somehow?
                error() << "Socket found pending " << recvd
                        << " bytes of data during connectivity check"
                        << " (idle " << idleTimeSecs << " secs,"
                        << " remote host " << remoteString() << ")" << endl;
                dassert( false );
            }
            else {
                // recvd == 0, socket closed remotely, just return false
                LOG( 0 ) << "Socket closed remotely, no longer connected"
                         << " (idle " << idleTimeSecs << " secs,"
                         << " remote host " << remoteString() << ")" << endl;
            }
        }
        else if ( pollInfo.revents & POLLHUP ) {
            // A hangup has occurred on this socket
            LOG( 0 ) << "Socket hangup detected, no longer connected" << " (idle "
                         << idleTimeSecs << " secs," << " remote host " << remoteString() << ")"
                         << endl;
        }
        else if ( pollInfo.revents & POLLERR ) {
            // An error has occurred on this socket
            LOG( 0 ) << "Socket error detected, no longer connected" << " (idle "
                         << idleTimeSecs << " secs," << " remote host " << remoteString() << ")"
                         << endl;
        }
        else if ( pollInfo.revents & POLLNVAL ) {
            // Socket descriptor itself is weird
            // Log and warn at runtime, log and abort at devtime
            error() << "Socket descriptor detected as invalid"
                    << " (idle " << idleTimeSecs << " secs,"
                    << " remote host " << remoteString() << ")" << endl;
            dassert( false );
        }
        else {
            // Don't know what poll is saying here
            // Log and warn at runtime, log and abort at devtime
            error() << "Socket had unknown event (" << static_cast<int>(pollInfo.revents) << ")"
                    << " (idle " << idleTimeSecs << " secs,"
                    << " remote host " << remoteString() << ")" << endl;
            dassert( false );
        }

        return false;
    }

#if defined(_WIN32)
    MONGO_INITIALIZER(SockWSAStartup)(InitializerContext * context) {
        WSADATA d;
        if ( WSAStartup(MAKEWORD(2,2), &d) != 0 ) {
            log() << "ERROR: wsastartup failed " << errnoWithDescription() << endl;
            abort();
        }

        return Status::OK();
    }
Example #23
0
SocketIPv4 *SocketIPv4::accept()
{
  SOCKET result;

  struct sockaddr_in addr;
  socklen_t addrlen = sizeof(struct sockaddr_in);

  SocketIPv4 *accepted;

  fd_set afd;

  timeval timeout;
  timeout.tv_sec = 0;
  timeout.tv_usec = 200;

  while (true) {
    FD_ZERO(&afd);
    FD_SET(m_socket, &afd);

    int ret = select(m_socket + 1, &afd, NULL, NULL, &timeout);

    if (ret == SOCKET_ERROR) {
      throw SocketException();
    } else if (ret == 0) {
      continue;
    } else if (ret > 0) {
      if (FD_ISSET(m_socket, &afd)) {
        result = ::accept(m_socket, (struct sockaddr*)&addr, &addrlen);
        if (result == INVALID_SOCKET) {
          throw SocketException();
        }
        break;
      } 
    } 
  } 

  try {
    accepted = new SocketIPv4(); 
    accepted->close();
  } catch(...) {
#ifdef _WIN32
    ::closesocket(result);
#else
    ::close(result);
#endif
    throw SocketException();
  }

  AutoLock l(&accepted->m_mutex);

  accepted->m_socket = result;

  accepted->m_peerAddr = new SocketAddressIPv4(*(struct sockaddr_in *)&addr);

  AutoLock l2(&m_mutex);

  if (m_localAddr) {
    sockaddr_in tsa = m_localAddr->getSockAddr();

    accepted->m_localAddr = new SocketAddressIPv4(*(struct sockaddr_in*)&tsa);
  }

  return accepted; 
}
Example #24
0
 void Socket::Listen(int maxQueueLen)
 {
   if (::listen(SockHandle, maxQueueLen) == -1)
     throw SocketException("Error listen socket");
 }
Example #25
0
void ServerSocket::bind(uint16_t port, int32_t backlog, const sp<InetAddress>& localAddress) {
    if (mIsBound) {
        throw SocketException("Socket is already bound");
    }
    if (mIsClosed) {
        throw SocketException("Socket is already closed");
    }

    if (localAddress == nullptr) {
        mLocalAddress = Inet6Address::ANY;
    } else {
        mLocalAddress = localAddress;
    }

    sockaddr_storage ss;
    socklen_t saSize = 0;
    std::memset(&ss, 0, sizeof(ss));
    if (Class<Inet6Address>::isInstance(mLocalAddress)) {
        mFd = ::socket(AF_INET6, SOCK_STREAM, 0);
        int32_t value = 0;
        ::setsockopt(mFd, SOL_SOCKET, IPV6_V6ONLY, &value, sizeof(value));
        value = mReuseAddress;
        ::setsockopt(mFd, SOL_SOCKET, SO_REUSEADDR, (char*) &value, sizeof(value));

        sockaddr_in6& sin6 = reinterpret_cast<sockaddr_in6&>(ss);
        sin6.sin6_family = AF_INET6;
        std::memcpy(&sin6.sin6_addr.s6_addr, mLocalAddress->getAddress()->c_arr(), 16);
        sin6.sin6_port = htons(port);
        saSize = sizeof(sockaddr_in6);
    } else {
        mFd = ::socket(AF_INET, SOCK_STREAM, 0);
        int32_t value = mReuseAddress;
        ::setsockopt(mFd, SOL_SOCKET, SO_REUSEADDR, (char*) &value, sizeof(value));

        sockaddr_in& sin = reinterpret_cast<sockaddr_in&>(ss);
        sin.sin_family = AF_INET;
        std::memcpy(&sin.sin_addr.s_addr, mLocalAddress->getAddress()->c_arr(), 4);
        sin.sin_port = htons(port);
        saSize = sizeof(sockaddr_in);
    }
    if (::bind(mFd, (struct sockaddr*) &ss, saSize) != 0) {
        close();
    }
    if (mFd != -1 && ::listen(mFd, backlog) == 0) {
        if (port != 0) {
            mLocalPort = port;
        } else {
            sockaddr_storage ss;
            sockaddr* sa = reinterpret_cast<sockaddr*>(&ss);
            socklen_t saSize = sizeof(ss);
            std::memset(&ss, 0, saSize);
            int32_t rc = ::getsockname(mFd, sa, &saSize);
            if (rc == 0) {
                switch (ss.ss_family) {
                case AF_INET6: {
                    const sockaddr_in6& sin6 = *reinterpret_cast<const sockaddr_in6*>(&ss);
                    mLocalPort = sin6.sin6_port;
                    break;
                }
                case AF_INET: {
                    const sockaddr_in& sin = *reinterpret_cast<const sockaddr_in*>(&ss);
                    mLocalPort = sin.sin_port;
                    break;
                }
                default:
                    break;
                }
            }
        }
        mIsBound = true;
    } else {
        close();
        throw SocketException(String::format("Failed to bind to port %u (errno=%d)", port, errno));
    }
}