/** * @brief Open a LLSocket and do a blocking connect to the chosen host. * * Checks for a successful connection, and makes sure the connection is closed if it fails. * * @param host The host to open the connection to. * @return The created socket. Will evaluate as NULL if the connection is unsuccessful. */ static LLSocket::ptr_t tcp_open_channel(LLHost host) { LLSocket::ptr_t socket = LLSocket::create(NULL, LLSocket::STREAM_TCP); bool connected = socket->blockingConnect(host); if (!connected) { tcp_close_channel(&socket); } return socket; }
// static LLSocket::ptr_t LLSocket::create(apr_socket_t* socket, apr_pool_t* pool) { LLSocket::ptr_t rv; if(!socket) { return rv; } rv = ptr_t(new LLSocket(socket, pool)); rv->mPort = PORT_EPHEMERAL; rv->setNonBlocking(); return rv; }
// static LLSocket::ptr_t LLSocket::create(apr_socket_t* socket, apr_pool_t* pool) { LLMemType m1(LLMemType::MTYPE_IO_TCP); LLSocket::ptr_t rv; if(!socket) { return rv; } rv = ptr_t(new LLSocket(socket, pool)); rv->mPort = PORT_EPHEMERAL; rv->setOptions(); return rv; }
/** * @brief Send one TCP packet and receive one in return. * * This operation is done synchronously with a 1000ms timeout. Therefore, it should not be used when a blocking * operation would impact the operation of the viewer. * * @param handle_ptr Pointer to a connected LLSocket of type STREAM_TCP. * @param dataout Data to send. * @param outlen Length of dataout. * @param datain Buffer for received data. Undefined if return value is not APR_SUCCESS. * @param maxinlen Maximum possible length of received data. Short reads are allowed. * @return Indicates APR status code of exchange. APR_SUCCESS if exchange was successful, -1 if invalid data length was received. */ static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen) { apr_socket_t* apr_socket = handle->getSocket(); apr_status_t rv = APR_SUCCESS; apr_size_t expected_len = outlen; handle->setBlocking(1000); rv = apr_socket_send(apr_socket, dataout, &outlen); if (APR_SUCCESS != rv) { LL_WARNS("Proxy") << "Error sending data to proxy control channel, status: " << rv << LL_ENDL; ll_apr_warn_status(rv); } else if (expected_len != outlen) { LL_WARNS("Proxy") << "Incorrect data length sent. Expected: " << expected_len << " Sent: " << outlen << LL_ENDL; rv = -1; } if (APR_SUCCESS == rv) { expected_len = maxinlen; rv = apr_socket_recv(apr_socket, datain, &maxinlen); if (rv != APR_SUCCESS) { LL_WARNS("Proxy") << "Error receiving data from proxy control channel, status: " << rv << LL_ENDL; ll_apr_warn_status(rv); } else if (expected_len < maxinlen) { LL_WARNS("Proxy") << "Incorrect data length received. Expected: " << expected_len << " Received: " << maxinlen << LL_ENDL; rv = -1; } } handle->setNonBlocking(); return rv; }
// static LLSocket::ptr_t LLSocket::create(apr_status_t& status, LLSocket::ptr_t& listen_socket) { if (!listen_socket->getSocket()) { status = APR_ENOSOCKET; return LLSocket::ptr_t(); } LLSocket::ptr_t rv(new LLSocket); LL_DEBUGS() << "accepting socket" << LL_ENDL; status = apr_socket_accept(&rv->mSocket, listen_socket->getSocket(), rv->mPool()); if (status != APR_SUCCESS) { rv->mSocket = NULL; rv.reset(); return rv; } rv->mPort = PORT_EPHEMERAL; rv->setNonBlocking(); return rv; }
// static LLSocket::ptr_t LLSocket::create(apr_status_t& status, LLSocket::ptr_t& listen_socket) { LLMemType m1(LLMemType::MTYPE_IO_TCP); if (!listen_socket->getSocket()) { status = APR_ENOSOCKET; return LLSocket::ptr_t(); } LLSocket::ptr_t rv(new LLSocket); lldebugs << "accepting socket" << llendl; status = apr_socket_accept(&rv->mSocket, listen_socket->getSocket(), rv->mPool()); if (status != APR_SUCCESS) { rv->mSocket = NULL; rv.reset(); return rv; } rv->mPort = PORT_EPHEMERAL; rv->setNonBlocking(); return rv; }
// static LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port) { LLMemType m1(LLMemType::MTYPE_IO_TCP); LLSocket::ptr_t rv; apr_socket_t* socket = NULL; apr_pool_t* new_pool = NULL; apr_status_t status = APR_EGENERAL; // create a pool for the socket status = apr_pool_create(&new_pool, pool); if(ll_apr_warn_status(status)) { if(new_pool) apr_pool_destroy(new_pool); return rv; } if(STREAM_TCP == type) { status = apr_socket_create( &socket, APR_INET, SOCK_STREAM, APR_PROTO_TCP, new_pool); } else if(DATAGRAM_UDP == type) { status = apr_socket_create( &socket, APR_INET, SOCK_DGRAM, APR_PROTO_UDP, new_pool); } else { if(new_pool) apr_pool_destroy(new_pool); return rv; } if(ll_apr_warn_status(status)) { if(new_pool) apr_pool_destroy(new_pool); return rv; } rv = ptr_t(new LLSocket(socket, new_pool)); if(port > 0) { apr_sockaddr_t* sa = NULL; status = apr_sockaddr_info_get( &sa, APR_ANYADDR, APR_UNSPEC, port, 0, new_pool); if(ll_apr_warn_status(status)) { rv.reset(); return rv; } // This allows us to reuse the address on quick down/up. This // is unlikely to create problems. ll_apr_warn_status(apr_socket_opt_set(socket, APR_SO_REUSEADDR, 1)); status = apr_socket_bind(socket, sa); if(ll_apr_warn_status(status)) { rv.reset(); return rv; } lldebugs << "Bound " << ((DATAGRAM_UDP == type) ? "udp" : "tcp") << " socket to port: " << sa->port << llendl; if(STREAM_TCP == type) { // If it's a stream based socket, we need to tell the OS // to keep a queue of incoming connections for ACCEPT. lldebugs << "Setting listen state for socket." << llendl; status = apr_socket_listen( socket, LL_DEFAULT_LISTEN_BACKLOG); if(ll_apr_warn_status(status)) { rv.reset(); return rv; } } } else { // we need to indicate that we have an ephemeral port if the // previous calls were successful. It will port = PORT_EPHEMERAL; } rv->mPort = port; rv->setOptions(); return rv; }