Added a thread-safe and robust wrapper for APR pools.
See http://redmine.imprudenceviewer.org/issues/590 and https://jira.secondlife.com/browse/SNOW-596
This commit is contained in:
@@ -41,6 +41,7 @@
|
||||
#include "llhost.h"
|
||||
#include "llmemtype.h"
|
||||
#include "llpumpio.h"
|
||||
#include "llthread.h"
|
||||
|
||||
//
|
||||
// constants
|
||||
@@ -104,51 +105,31 @@ void ll_debug_socket(const char* msg, apr_socket_t* apr_sock)
|
||||
///
|
||||
|
||||
// static
|
||||
LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port)
|
||||
LLSocket::ptr_t LLSocket::create(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;
|
||||
}
|
||||
LLSocket::ptr_t rv(new LLSocket);
|
||||
|
||||
if(STREAM_TCP == type)
|
||||
{
|
||||
status = apr_socket_create(
|
||||
&socket,
|
||||
APR_INET,
|
||||
SOCK_STREAM,
|
||||
APR_PROTO_TCP,
|
||||
new_pool);
|
||||
status = apr_socket_create(&rv->mSocket, APR_INET, SOCK_STREAM, APR_PROTO_TCP, rv->mPool());
|
||||
}
|
||||
else if(DATAGRAM_UDP == type)
|
||||
{
|
||||
status = apr_socket_create(
|
||||
&socket,
|
||||
APR_INET,
|
||||
SOCK_DGRAM,
|
||||
APR_PROTO_UDP,
|
||||
new_pool);
|
||||
status = apr_socket_create(&rv->mSocket, APR_INET, SOCK_DGRAM, APR_PROTO_UDP, rv->mPool());
|
||||
}
|
||||
else
|
||||
{
|
||||
if(new_pool) apr_pool_destroy(new_pool);
|
||||
rv.reset();
|
||||
return rv;
|
||||
}
|
||||
if(ll_apr_warn_status(status))
|
||||
{
|
||||
if(new_pool) apr_pool_destroy(new_pool);
|
||||
rv->mSocket = NULL;
|
||||
rv.reset();
|
||||
return rv;
|
||||
}
|
||||
rv = ptr_t(new LLSocket(socket, new_pool));
|
||||
if(port > 0)
|
||||
{
|
||||
apr_sockaddr_t* sa = NULL;
|
||||
@@ -158,7 +139,7 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port)
|
||||
APR_UNSPEC,
|
||||
port,
|
||||
0,
|
||||
new_pool);
|
||||
rv->mPool());
|
||||
if(ll_apr_warn_status(status))
|
||||
{
|
||||
rv.reset();
|
||||
@@ -166,8 +147,8 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port)
|
||||
}
|
||||
// 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);
|
||||
ll_apr_warn_status(apr_socket_opt_set(rv->mSocket, APR_SO_REUSEADDR, 1));
|
||||
status = apr_socket_bind(rv->mSocket, sa);
|
||||
if(ll_apr_warn_status(status))
|
||||
{
|
||||
rv.reset();
|
||||
@@ -181,7 +162,7 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port)
|
||||
// to keep a queue of incoming connections for ACCEPT.
|
||||
lldebugs << "Setting listen state for socket." << llendl;
|
||||
status = apr_socket_listen(
|
||||
socket,
|
||||
rv->mSocket,
|
||||
LL_DEFAULT_LISTEN_BACKLOG);
|
||||
if(ll_apr_warn_status(status))
|
||||
{
|
||||
@@ -202,21 +183,28 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port)
|
||||
}
|
||||
|
||||
// static
|
||||
LLSocket::ptr_t LLSocket::create(apr_socket_t* socket, apr_pool_t* pool)
|
||||
LLSocket::ptr_t LLSocket::create(apr_status_t& status, LLSocket::ptr_t& listen_socket)
|
||||
{
|
||||
LLMemType m1(LLMemType::MTYPE_IO_TCP);
|
||||
LLSocket::ptr_t rv;
|
||||
if(!socket)
|
||||
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 = ptr_t(new LLSocket(socket, pool));
|
||||
rv->mPort = PORT_EPHEMERAL;
|
||||
rv->setOptions();
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
bool LLSocket::blockingConnect(const LLHost& host)
|
||||
{
|
||||
if(!mSocket) return false;
|
||||
@@ -229,7 +217,7 @@ bool LLSocket::blockingConnect(const LLHost& host)
|
||||
APR_UNSPEC,
|
||||
host.getPort(),
|
||||
0,
|
||||
mPool)))
|
||||
mPool())))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -240,13 +228,11 @@ bool LLSocket::blockingConnect(const LLHost& host)
|
||||
return true;
|
||||
}
|
||||
|
||||
LLSocket::LLSocket(apr_socket_t* socket, apr_pool_t* pool) :
|
||||
mSocket(socket),
|
||||
mPool(pool),
|
||||
LLSocket::LLSocket() :
|
||||
mSocket(NULL),
|
||||
mPool(LLThread::tldata().mRootPool),
|
||||
mPort(PORT_INVALID)
|
||||
{
|
||||
ll_debug_socket("Constructing wholely formed socket", mSocket);
|
||||
LLMemType m1(LLMemType::MTYPE_IO_TCP);
|
||||
}
|
||||
|
||||
LLSocket::~LLSocket()
|
||||
@@ -258,10 +244,6 @@ LLSocket::~LLSocket()
|
||||
ll_debug_socket("Destroying socket", mSocket);
|
||||
apr_socket_close(mSocket);
|
||||
}
|
||||
if(mPool)
|
||||
{
|
||||
apr_pool_destroy(mPool);
|
||||
}
|
||||
}
|
||||
|
||||
void LLSocket::setOptions()
|
||||
@@ -522,10 +504,8 @@ LLIOPipe::EStatus LLIOSocketWriter::process_impl(
|
||||
///
|
||||
|
||||
LLIOServerSocket::LLIOServerSocket(
|
||||
apr_pool_t* pool,
|
||||
LLIOServerSocket::socket_t listener,
|
||||
factory_t factory) :
|
||||
mPool(pool),
|
||||
mListenSocket(listener),
|
||||
mReactor(factory),
|
||||
mInitialized(false),
|
||||
@@ -585,21 +565,15 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(
|
||||
lldebugs << "accepting socket" << llendl;
|
||||
|
||||
PUMP_DEBUG;
|
||||
apr_pool_t* new_pool = NULL;
|
||||
apr_status_t status = apr_pool_create(&new_pool, mPool);
|
||||
apr_socket_t* socket = NULL;
|
||||
status = apr_socket_accept(
|
||||
&socket,
|
||||
mListenSocket->getSocket(),
|
||||
new_pool);
|
||||
LLSocket::ptr_t llsocket(LLSocket::create(socket, new_pool));
|
||||
apr_status_t status;
|
||||
LLSocket::ptr_t llsocket(LLSocket::create(status, mListenSocket));
|
||||
//EStatus rv = STATUS_ERROR;
|
||||
if(llsocket)
|
||||
if(llsocket && status == APR_SUCCESS)
|
||||
{
|
||||
PUMP_DEBUG;
|
||||
|
||||
apr_sockaddr_t* remote_addr;
|
||||
apr_socket_addr_get(&remote_addr, APR_REMOTE, socket);
|
||||
apr_socket_addr_get(&remote_addr, APR_REMOTE, llsocket->getSocket());
|
||||
|
||||
char* remote_host_string;
|
||||
apr_sockaddr_ip_get(&remote_host_string, remote_addr);
|
||||
@@ -614,7 +588,6 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(
|
||||
{
|
||||
chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(llsocket)));
|
||||
pump->addChain(chain, mResponseTimeout);
|
||||
status = STATUS_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -623,7 +596,8 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "Unable to create linden socket." << llendl;
|
||||
char buf[256];
|
||||
llwarns << "Unable to accept linden socket: " << apr_strerror(status, buf, sizeof(buf)) << llendl;
|
||||
}
|
||||
|
||||
PUMP_DEBUG;
|
||||
@@ -636,11 +610,10 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(
|
||||
#if 0
|
||||
LLIODataSocket::LLIODataSocket(
|
||||
U16 suggested_port,
|
||||
U16 start_discovery_port,
|
||||
apr_pool_t* pool) :
|
||||
U16 start_discovery_port) :
|
||||
mSocket(NULL)
|
||||
{
|
||||
if(!pool || (PORT_INVALID == suggested_port)) return;
|
||||
if(PORT_INVALID == suggested_port) return;
|
||||
if(ll_apr_warn_status(apr_socket_create(&mSocket, APR_INET, SOCK_DGRAM, APR_PROTO_UDP, pool))) return;
|
||||
apr_sockaddr_t* sa = NULL;
|
||||
if(ll_apr_warn_status(apr_sockaddr_info_get(&sa, APR_ANYADDR, APR_UNSPEC, suggested_port, 0, pool))) return;
|
||||
|
||||
Reference in New Issue
Block a user