version 1.58, 2005/02/06 21:13:14
|
version 1.72, 2005/08/19 00:24:32
|
|
|
// Amit Arora, IBM (amita@in.ibm.com) for Bug#2541 | // Amit Arora, IBM (amita@in.ibm.com) for Bug#2541 |
// Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com) | // Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com) |
// Sean Keenan, Hewlett-Packard Company (sean.keenan@hp.com) | // Sean Keenan, Hewlett-Packard Company (sean.keenan@hp.com) |
|
// Josephine Eskaline Joyce, IBM (jojustin@in.ibm.com) for Bug#2065 |
|
// David Dillard, VERITAS Software Corp. |
|
// (david.dillard@veritas.com) |
|
// John Alex, IBM (johnalex@us.ibm.com) for Bug#3312 |
// | // |
//%///////////////////////////////////////////////////////////////////////////// | //%///////////////////////////////////////////////////////////////////////////// |
| |
|
|
# include <netinet/in.h> | # include <netinet/in.h> |
# include <arpa/inet.h> | # include <arpa/inet.h> |
# include <sys/socket.h> | # include <sys/socket.h> |
# ifdef PEGASUS_LOCAL_DOMAIN_SOCKET |
# ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET |
# include <unistd.h> | # include <unistd.h> |
# include <sys/un.h> | # include <sys/un.h> |
# endif | # endif |
|
|
| |
PEGASUS_NAMESPACE_BEGIN | PEGASUS_NAMESPACE_BEGIN |
| |
|
|
|
// |
|
// Determine the correct type to use for the length passed to getsockname(). |
|
// The default is to use the 'socklen_t'. |
|
// |
|
|
|
#if defined(PEGASUS_OS_TYPE_WINDOWS) || defined(PEGASUS_OS_OS400) |
|
#define PEGASUS_SOCKLEN_T int |
|
#endif |
|
|
|
#if defined(PEGASUS_OS_HPUX) && !defined(_XOPEN_SOURCE_EXTENDED) |
|
#define PEGASUS_SOCKLEN_T int |
|
#endif |
|
|
|
|
|
#if defined(PEGASUS_OS_VMS) || defined(PEGASUS_OS_ZOS) |
|
#define PEGASUS_SOCKLEN_T unsigned |
|
#endif |
|
|
|
#ifndef PEGASUS_SOCKLEN_T |
|
#define PEGASUS_SOCKLEN_T socklen_t |
|
#endif |
|
|
static int MAX_CONNECTION_QUEUE_LENGTH = -1; | static int MAX_CONNECTION_QUEUE_LENGTH = -1; |
| |
| |
|
|
{ | { |
if (local) | if (local) |
{ | { |
#ifdef PEGASUS_LOCAL_DOMAIN_SOCKET |
#ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET |
address = reinterpret_cast<struct sockaddr*>(new struct sockaddr_un); | address = reinterpret_cast<struct sockaddr*>(new struct sockaddr_un); |
address_size = sizeof(struct sockaddr_un); | address_size = sizeof(struct sockaddr_un); |
#else | #else |
|
|
address_size = sizeof(struct sockaddr_in); | address_size = sizeof(struct sockaddr_in); |
} | } |
} | } |
|
~HTTPAcceptorRep() |
|
{ |
|
delete address; |
|
} |
struct sockaddr* address; | struct sockaddr* address; |
| |
#if defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM) || defined(PEGASUS_OS_VMS) | #if defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM) || defined(PEGASUS_OS_VMS) |
|
|
Boolean localConnection, | Boolean localConnection, |
Uint32 portNumber, | Uint32 portNumber, |
SSLContext * sslcontext, | SSLContext * sslcontext, |
Boolean exportConnection) |
Boolean exportConnection, |
|
ReadWriteSem* sslContextObjectLock) |
: Base(PEGASUS_QUEUENAME_HTTPACCEPTOR), // ATTN: Need unique names? | : Base(PEGASUS_QUEUENAME_HTTPACCEPTOR), // ATTN: Need unique names? |
_monitor(monitor), | _monitor(monitor), |
_outputMessageQueue(outputMessageQueue), | _outputMessageQueue(outputMessageQueue), |
|
|
_localConnection(localConnection), | _localConnection(localConnection), |
_portNumber(portNumber), | _portNumber(portNumber), |
_sslcontext(sslcontext), | _sslcontext(sslcontext), |
_exportConnection(exportConnection) |
_exportConnection(exportConnection), |
|
_sslContextObjectLock(sslContextObjectLock) |
{ | { |
Socket::initializeInterface(); | Socket::initializeInterface(); |
| |
|
|
| |
HTTPAcceptor::~HTTPAcceptor() | HTTPAcceptor::~HTTPAcceptor() |
{ | { |
|
destroyConnections(); |
unbind(); | unbind(); |
// ATTN: Is this correct in a multi-HTTPAcceptor server? | // ATTN: Is this correct in a multi-HTTPAcceptor server? |
Socket::uninitializeInterface(); | Socket::uninitializeInterface(); |
|
|
if (! message) | if (! message) |
return; | return; |
| |
|
PEGASUS_ASSERT(_rep != 0); |
switch (message->getType()) | switch (message->getType()) |
{ | { |
case SOCKET_MESSAGE: | case SOCKET_MESSAGE: |
|
|
// If this is a connection request: | // If this is a connection request: |
| |
if (socketMessage->socket == _rep->socket && | if (socketMessage->socket == _rep->socket && |
socketMessage->events | SocketMessage::READ) |
socketMessage->events & SocketMessage::READ) |
{ | { |
_acceptConnection(); | _acceptConnection(); |
} | } |
|
|
| |
/** | /** |
_bind - creates a new server socket and bind socket to the port address. | _bind - creates a new server socket and bind socket to the port address. |
If PEGASUS_LOCAL_DOMAIN_SOCKET is defined, the port number is ignored and |
If PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET is not defined, the port number is ignored and |
a domain socket is bound. | a domain socket is bound. |
*/ | */ |
void HTTPAcceptor::_bind() | void HTTPAcceptor::_bind() |
{ | { |
| |
|
PEGASUS_ASSERT(_rep != 0); |
// Create address: | // Create address: |
| |
memset(_rep->address, 0, sizeof(*_rep->address)); | memset(_rep->address, 0, sizeof(*_rep->address)); |
| |
if (_localConnection) | if (_localConnection) |
{ | { |
#ifdef PEGASUS_LOCAL_DOMAIN_SOCKET |
#ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET |
reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_family = | reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_family = |
AF_UNIX; | AF_UNIX; |
strcpy(reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path, | strcpy(reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path, |
|
|
throw BindFailedException(parms); | throw BindFailedException(parms); |
} | } |
| |
// Bind socket to port: |
|
| |
|
// |
|
// Bind socket to port: |
|
// |
if (::bind(_rep->socket, _rep->address, _rep->address_size) < 0) | if (::bind(_rep->socket, _rep->address, _rep->address_size) < 0) |
{ | { |
Socket::close(_rep->socket); | Socket::close(_rep->socket); |
|
|
throw BindFailedException(parms); | throw BindFailedException(parms); |
} | } |
| |
|
|
|
// |
|
// Get the actual port value used if the caller specified a port value of 0. |
|
// |
|
if ( _portNumber == 0 ) |
|
{ |
|
sockaddr_in buf; |
|
PEGASUS_SOCKLEN_T bufSize = sizeof(buf); |
|
if ( getsockname(_rep->socket, reinterpret_cast<sockaddr *>(&buf), &bufSize) == 0 ) |
|
{ |
|
_portNumber = ntohs(buf.sin_port); |
|
} |
|
} |
|
|
|
|
// | // |
// Change permissions on Linux local domain socket to allow writes by others. | // Change permissions on Linux local domain socket to allow writes by others. |
// | // |
#if defined(PEGASUS_LOCAL_DOMAIN_SOCKET) && defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) |
#if !defined(PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET) && defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) |
if (_localConnection) | if (_localConnection) |
{ | { |
if (::chmod( PEGASUS_LOCAL_DOMAIN_SOCKET_PATH, | if (::chmod( PEGASUS_LOCAL_DOMAIN_SOCKET_PATH, |
|
|
| |
// close the socket | // close the socket |
Socket::close(_rep->socket); | Socket::close(_rep->socket); |
|
// Unlink Local Domain Socket Bug# 3312 |
|
if (_localConnection) |
|
{ |
|
#ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET |
|
PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2, |
|
"HTTPAcceptor::closeConnectionSocket Unlinking local connection." ); |
|
::unlink( |
|
reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path); |
|
#else |
|
PEGASUS_ASSERT(false); |
|
#endif |
|
} |
|
|
} | } |
else | else |
{ | { |
|
|
/** | /** |
getOutstandingRequestCount - returns the number of outstanding requests. | getOutstandingRequestCount - returns the number of outstanding requests. |
*/ | */ |
Uint32 HTTPAcceptor::getOutstandingRequestCount() |
Uint32 HTTPAcceptor::getOutstandingRequestCount() const |
{ | { |
Uint32 count = 0; | Uint32 count = 0; |
|
if (_rep) |
|
{ |
AutoMutex autoMut(_rep->_connection_mut); | AutoMutex autoMut(_rep->_connection_mut); |
if (_rep->connections.size() > 0) | if (_rep->connections.size() > 0) |
{ | { |
HTTPConnection* connection = _rep->connections[0]; | HTTPConnection* connection = _rep->connections[0]; |
count = connection->getRequestCount(); | count = connection->getRequestCount(); |
} | } |
|
} |
return count; | return count; |
} | } |
| |
|
|
|
/** |
|
getPortNumber - returns the port number used for the connection |
|
*/ |
|
Uint32 HTTPAcceptor::getPortNumber() const |
|
{ |
|
return _portNumber; |
|
} |
|
|
void HTTPAcceptor::unbind() | void HTTPAcceptor::unbind() |
{ | { |
if (_rep) | if (_rep) |
{ | { |
|
_portNumber = 0; |
Socket::close(_rep->socket); | Socket::close(_rep->socket); |
| |
if (_localConnection) | if (_localConnection) |
{ | { |
#ifdef PEGASUS_LOCAL_DOMAIN_SOCKET |
#ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET |
::unlink( | ::unlink( |
reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path); | reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path); |
#else | #else |
|
|
| |
void HTTPAcceptor::destroyConnections() | void HTTPAcceptor::destroyConnections() |
{ | { |
|
if (_rep) |
|
{ |
// For each connection created by this object: | // For each connection created by this object: |
| |
AutoMutex autoMut(_rep->_connection_mut); | AutoMutex autoMut(_rep->_connection_mut); |
|
|
} | } |
| |
_rep->connections.clear(); | _rep->connections.clear(); |
|
} |
} | } |
| |
void HTTPAcceptor::_acceptConnection() | void HTTPAcceptor::_acceptConnection() |
|
|
| |
if (_localConnection) | if (_localConnection) |
{ | { |
#ifdef PEGASUS_LOCAL_DOMAIN_SOCKET |
#ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET |
accept_address = reinterpret_cast<struct sockaddr*>(new struct sockaddr_un); | accept_address = reinterpret_cast<struct sockaddr*>(new struct sockaddr_un); |
address_size = sizeof(struct sockaddr_un); | address_size = sizeof(struct sockaddr_un); |
#else | #else |
|
|
"HTTPAcceptor - accept() success. Socket: $1" | "HTTPAcceptor - accept() success. Socket: $1" |
,socket); | ,socket); |
| |
// Create a new conection and add it to the connection list: |
AutoPtr<MP_Socket> mp_socket(new MP_Socket( |
|
socket, _sslcontext, _sslContextObjectLock, _exportConnection)); |
|
|
|
// Perform the SSL handshake, if applicable. Make the socket non-blocking |
|
// for this operation so we can send it back to the Monitor's select() loop |
|
// if it takes a while. |
|
|
|
mp_socket->disableBlocking(); |
|
Sint32 socketAcceptStatus = mp_socket->accept(); |
|
mp_socket->enableBlocking(); |
| |
AutoPtr<MP_Socket> mp_socket(new MP_Socket(socket, _sslcontext, _exportConnection)); |
if (socketAcceptStatus < 0) |
if (mp_socket->accept() < 0) |
|
{ | { |
PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, | PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
"HTTPAcceptor: SSL_accept() failed"); | "HTTPAcceptor: SSL_accept() failed"); |
|
|
return; | return; |
} | } |
| |
|
// Create a new connection and add it to the connection list: |
|
|
HTTPConnection* connection = new HTTPConnection(_monitor, mp_socket, | HTTPConnection* connection = new HTTPConnection(_monitor, mp_socket, |
this, static_cast<MessageQueue *>(_outputMessageQueue), _exportConnection); | this, static_cast<MessageQueue *>(_outputMessageQueue), _exportConnection); |
| |
|
if (socketAcceptStatus == 0) |
|
{ |
|
PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2, |
|
"HTTPAcceptor: SSL_accept() pending"); |
|
connection->_acceptPending = true; |
|
} |
|
|
// Solicit events on this new connection's socket: | // Solicit events on this new connection's socket: |
int index; | int index; |
| |
|
|
connection->_entry_index = index; | connection->_entry_index = index; |
AutoMutex autoMut(_rep->_connection_mut); | AutoMutex autoMut(_rep->_connection_mut); |
_rep->connections.append(connection); | _rep->connections.append(connection); |
|
|
} | } |
| |
PEGASUS_NAMESPACE_END | PEGASUS_NAMESPACE_END |