version 1.22, 2002/06/20 22:05:18
|
version 1.31, 2003/08/06 13:49:25
|
|
|
// Modified By: | // Modified By: |
// Jenny Yu, Hewlett-Packard Company (jenny_yu@hp.com) | // Jenny Yu, Hewlett-Packard Company (jenny_yu@hp.com) |
// Nag Boranna, Hewlett-Packard Company (nagaraja_boranna@hp.com) | // Nag Boranna, Hewlett-Packard Company (nagaraja_boranna@hp.com) |
|
// Dave Rosckes (rosckes@us.ibm.com) |
// | // |
//%///////////////////////////////////////////////////////////////////////////// | //%///////////////////////////////////////////////////////////////////////////// |
| |
|
|
#include <windows.h> | #include <windows.h> |
#else | #else |
# include <cctype> | # include <cctype> |
# include <unistd.h> |
|
# include <cstdlib> | # include <cstdlib> |
# include <errno.h> | # include <errno.h> |
# include <fcntl.h> | # include <fcntl.h> |
|
|
# include <arpa/inet.h> | # include <arpa/inet.h> |
# include <sys/socket.h> | # include <sys/socket.h> |
# ifdef PEGASUS_LOCAL_DOMAIN_SOCKET | # ifdef PEGASUS_LOCAL_DOMAIN_SOCKET |
|
# include <unistd.h> |
# include <sys/un.h> | # include <sys/un.h> |
# endif | # endif |
#endif | #endif |
|
|
#include "HTTPAcceptor.h" | #include "HTTPAcceptor.h" |
#include "HTTPConnection.h" | #include "HTTPConnection.h" |
#include "Tracer.h" | #include "Tracer.h" |
|
#include <Pegasus/Common/MessageLoader.h> //l10n |
| |
PEGASUS_USING_STD; | PEGASUS_USING_STD; |
| |
|
|
// | // |
//////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// |
| |
struct HTTPAcceptorRep |
class HTTPAcceptorRep |
|
{ |
|
public: |
|
HTTPAcceptorRep(Boolean local) |
|
{ |
|
if (local) |
{ | { |
#ifdef PEGASUS_LOCAL_DOMAIN_SOCKET | #ifdef PEGASUS_LOCAL_DOMAIN_SOCKET |
struct sockaddr_un address; |
address = reinterpret_cast<struct sockaddr*>(new struct sockaddr_un); |
|
address_size = sizeof(struct sockaddr_un); |
|
#else |
|
PEGASUS_ASSERT(false); |
|
#endif |
|
} |
|
else |
|
{ |
|
address = reinterpret_cast<struct sockaddr*>(new struct sockaddr_in); |
|
address_size = sizeof(struct sockaddr_in); |
|
} |
|
} |
|
|
|
struct sockaddr* address; |
|
|
|
#if defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM) |
|
size_t address_size; |
|
#elif defined(PEGASUS_PLATFORM_AIX_RS_IBMCXX) || defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) || (defined(PEGASUS_PLATFORM_SOLARIS_SPARC_CC) && !defined(SUNOS_5_6)) |
|
socklen_t address_size; |
#else | #else |
struct sockaddr_in address; |
int address_size; |
#endif | #endif |
|
Mutex _connection_mut; |
|
|
Sint32 socket; | Sint32 socket; |
Array<HTTPConnection*> connections; | Array<HTTPConnection*> connections; |
}; | }; |
|
|
// | // |
//////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// |
| |
HTTPAcceptor::HTTPAcceptor(Monitor* monitor, MessageQueue* outputMessageQueue) |
HTTPAcceptor::HTTPAcceptor(Monitor* monitor, |
: Base(PEGASUS_QUEUENAME_HTTPACCEPTOR), |
MessageQueue* outputMessageQueue, |
_monitor(monitor), _outputMessageQueue(outputMessageQueue), |
Boolean localConnection, |
_rep(0), _sslcontext(NULL), _entry_index(-1) |
Uint32 portNumber, |
{ |
|
|
|
Socket::initializeInterface(); |
|
} |
|
|
|
HTTPAcceptor::HTTPAcceptor(Monitor* monitor, MessageQueue* outputMessageQueue, |
|
SSLContext * sslcontext) | SSLContext * sslcontext) |
: Base(PEGASUS_QUEUENAME_HTTPACCEPTOR), |
: Base(PEGASUS_QUEUENAME_HTTPACCEPTOR), // ATTN: Need unique names? |
_monitor(monitor), _outputMessageQueue(outputMessageQueue), |
_monitor(monitor), |
|
_outputMessageQueue(outputMessageQueue), |
_rep(0), | _rep(0), |
_sslcontext(sslcontext), |
_entry_index(-1), |
_entry_index(-1) |
_localConnection(localConnection), |
|
_portNumber(portNumber), |
|
_sslcontext(sslcontext) |
{ | { |
Socket::initializeInterface(); | Socket::initializeInterface(); |
} | } |
|
|
HTTPAcceptor::~HTTPAcceptor() | HTTPAcceptor::~HTTPAcceptor() |
{ | { |
unbind(); | unbind(); |
|
// ATTN: Is this correct in a multi-HTTPAcceptor server? |
Socket::uninitializeInterface(); | Socket::uninitializeInterface(); |
} | } |
| |
|
|
CloseConnectionMessage* closeConnectionMessage | CloseConnectionMessage* closeConnectionMessage |
= (CloseConnectionMessage*)message; | = (CloseConnectionMessage*)message; |
| |
|
_rep->_connection_mut.lock(pegasus_thread_self()); |
|
|
for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++) | for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++) |
{ | { |
HTTPConnection* connection = _rep->connections[i]; | HTTPConnection* connection = _rep->connections[i]; |
|
|
break; | break; |
} | } |
} | } |
|
_rep->_connection_mut.unlock(); |
} | } |
| |
default: | default: |
|
|
| |
} | } |
| |
void HTTPAcceptor::bind(Uint32 portNumber) |
void HTTPAcceptor::bind() |
{ | { |
if (_rep) |
if (_rep){ |
throw BindFailed("HTTPAcceptor already bound"); |
//l10n |
|
//throw BindFailedException("HTTPAcceptor already bound"); |
_rep = new HTTPAcceptorRep; |
String s0 = "HTTPAcceptor"; |
|
MessageLoaderParms parms("Common.HTTPAcceptor.ALREADY_BOUND", |
|
"$0 already bound", |
|
s0); |
|
throw BindFailedException(parms); |
|
} |
| |
_portNumber = portNumber; |
_rep = new HTTPAcceptorRep(_localConnection); |
| |
// bind address | // bind address |
_bind(); | _bind(); |
|
|
| |
// Create address: | // Create address: |
| |
memset(&_rep->address, 0, sizeof(_rep->address)); |
memset(_rep->address, 0, sizeof(*_rep->address)); |
| |
|
if (_localConnection) |
|
{ |
#ifdef PEGASUS_LOCAL_DOMAIN_SOCKET | #ifdef PEGASUS_LOCAL_DOMAIN_SOCKET |
_rep->address.sun_family = AF_UNIX; |
reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_family = |
strcpy(_rep->address.sun_path, "/var/opt/wbem/cimxml.socket"); |
AF_UNIX; |
::unlink(_rep->address.sun_path); |
strcpy(reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path, |
|
PEGASUS_LOCAL_DOMAIN_SOCKET_PATH); |
|
::unlink(reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path); |
#else | #else |
_rep->address.sin_addr.s_addr = INADDR_ANY; |
PEGASUS_ASSERT(false); |
_rep->address.sin_family = AF_INET; |
|
_rep->address.sin_port = htons(_portNumber); |
|
#endif | #endif |
|
} |
|
else |
|
{ |
|
reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_addr.s_addr = |
|
INADDR_ANY; |
|
reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_family = |
|
AF_INET; |
|
reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_port = |
|
htons(_portNumber); |
|
} |
| |
// Create socket: | // Create socket: |
| |
#ifdef PEGASUS_LOCAL_DOMAIN_SOCKET |
if (_localConnection) |
|
{ |
_rep->socket = socket(AF_UNIX, SOCK_STREAM, 0); | _rep->socket = socket(AF_UNIX, SOCK_STREAM, 0); |
#else |
} |
|
else |
|
{ |
_rep->socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); | _rep->socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); |
#endif |
} |
| |
if (_rep->socket < 0) | if (_rep->socket < 0) |
{ | { |
delete _rep; | delete _rep; |
_rep = 0; | _rep = 0; |
throw BindFailed("Failed to create socket"); |
//l10n |
|
//throw BindFailedException("Failed to create socket"); |
|
MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_CREATE_SOCKET", |
|
"Failed to create socket"); |
|
throw BindFailedException(parms); |
} | } |
| |
|
|
|
// set the close-on-exec bit for this file handle. |
|
// any unix that forks needs this bit set. |
|
#ifndef PEGASUS_PLATFORM_WIN32_IX86_MSVC |
|
int sock_flags; |
|
if( (sock_flags = fcntl(_rep->socket, F_GETFD, 0)) < 0) |
|
{ |
|
PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2, |
|
"HTTPAcceptor: fcntl(F_GETFD) failed"); |
|
} |
|
else |
|
{ |
|
sock_flags |= FD_CLOEXEC; |
|
if (fcntl(_rep->socket, F_SETFD, sock_flags) < 0) |
|
{ |
|
PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2, |
|
"HTTPAcceptor: fcntl(F_SETFD) failed"); |
|
} |
|
} |
|
#endif |
|
|
|
|
// | // |
// Set the socket option SO_REUSEADDR to reuse the socket address so | // Set the socket option SO_REUSEADDR to reuse the socket address so |
// that we can rebind to a new socket using the same address when we | // that we can rebind to a new socket using the same address when we |
|
|
if (setsockopt(_rep->socket, SOL_SOCKET, SO_REUSEADDR, | if (setsockopt(_rep->socket, SOL_SOCKET, SO_REUSEADDR, |
(char *)&opt, sizeof(opt)) < 0) | (char *)&opt, sizeof(opt)) < 0) |
{ | { |
|
Socket::close(_rep->socket); |
delete _rep; | delete _rep; |
_rep = 0; | _rep = 0; |
throw BindFailed("Failed to set socket option"); |
//l10n |
|
//throw BindFailedException("Failed to set socket option"); |
|
MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_SET_SOCKET_OPTION", |
|
"Failed to set socket option"); |
|
throw BindFailedException(parms); |
} | } |
| |
// Bind socket to port: | // Bind socket to port: |
| |
if (::bind(_rep->socket, |
if (::bind(_rep->socket, _rep->address, _rep->address_size) < 0) |
reinterpret_cast<struct sockaddr*>(&_rep->address), |
|
sizeof(_rep->address)) < 0) |
|
{ | { |
Socket::close(_rep->socket); | Socket::close(_rep->socket); |
delete _rep; | delete _rep; |
_rep = 0; | _rep = 0; |
throw BindFailed("Failed to bind socket"); |
//l10n |
|
//throw BindFailedException("Failed to bind socket"); |
|
MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_BIND_SOCKET", |
|
"Failed to bind socket"); |
|
throw BindFailedException(parms); |
} | } |
| |
// Set up listening on the given socket: | // Set up listening on the given socket: |
|
|
Socket::close(_rep->socket); | Socket::close(_rep->socket); |
delete _rep; | delete _rep; |
_rep = 0; | _rep = 0; |
throw BindFailed("Failed to bind socket"); |
//l10n |
|
//throw BindFailedException("Failed to bind socket"); |
|
MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_BIND_SOCKET", |
|
"Failed to bind socket"); |
|
throw BindFailedException(parms); |
} | } |
| |
// Register to receive SocketMessages on this socket: | // Register to receive SocketMessages on this socket: |
|
|
Socket::close(_rep->socket); | Socket::close(_rep->socket); |
delete _rep; | delete _rep; |
_rep = 0; | _rep = 0; |
throw BindFailed("Failed to solicit socket messaeges"); |
//l10n |
|
//throw BindFailedException("Failed to solicit socket messaeges"); |
|
MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_SOLICIT_SOCKET_MESSAGES", |
|
"Failed to solicit socket messaeges"); |
|
throw BindFailedException(parms); |
} | } |
} | } |
| |
|
|
*/ | */ |
Uint32 HTTPAcceptor::getOutstandingRequestCount() | Uint32 HTTPAcceptor::getOutstandingRequestCount() |
{ | { |
|
Uint32 count = 0; |
|
|
|
_rep->_connection_mut.lock(pegasus_thread_self()); |
if (_rep->connections.size() > 0) | if (_rep->connections.size() > 0) |
{ | { |
HTTPConnection* connection = _rep->connections[0]; | HTTPConnection* connection = _rep->connections[0]; |
return(connection->getRequestCount()); |
count = connection->getRequestCount(); |
} |
|
else |
|
{ |
|
return(0); |
|
} | } |
|
_rep->_connection_mut.unlock(); |
|
return count; |
} | } |
| |
void HTTPAcceptor::unbind() | void HTTPAcceptor::unbind() |
|
|
if (_rep) | if (_rep) |
{ | { |
Socket::close(_rep->socket); | Socket::close(_rep->socket); |
|
|
|
if (_localConnection) |
|
{ |
|
#ifdef PEGASUS_LOCAL_DOMAIN_SOCKET |
|
::unlink( |
|
reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path); |
|
#else |
|
PEGASUS_ASSERT(false); |
|
#endif |
|
} |
|
|
delete _rep; | delete _rep; |
_rep = 0; | _rep = 0; |
} | } |
|
|
| |
void HTTPAcceptor::destroyConnections() | void HTTPAcceptor::destroyConnections() |
{ | { |
|
|
|
|
// For each connection created by this object: | // For each connection created by this object: |
| |
|
_rep->_connection_mut.lock(pegasus_thread_self()); |
for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++) | for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++) |
{ | { |
HTTPConnection* connection = _rep->connections[i]; | HTTPConnection* connection = _rep->connections[i]; |
|
|
} | } |
| |
_rep->connections.clear(); | _rep->connections.clear(); |
|
_rep->_connection_mut.unlock(); |
} | } |
| |
void HTTPAcceptor::_acceptConnection() | void HTTPAcceptor::_acceptConnection() |
|
|
| |
// Accept the connection (populate the address): | // Accept the connection (populate the address): |
| |
sockaddr_in address; |
struct sockaddr* accept_address; |
|
#if defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM) |
#if defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM) || defined(PEGASUS_PLATFORM_AIX_RS_IBMCXX) |
size_t address_size; |
size_t n = sizeof(address); |
#elif defined(PEGASUS_PLATFORM_AIX_RS_IBMCXX) || defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) || (defined(PEGASUS_PLATFORM_SOLARIS_SPARC_CC) && !defined(SUNOS_5_6)) |
|
socklen_t address_size; |
#else | #else |
int n = sizeof(address); |
int address_size; |
#endif | #endif |
| |
#if defined(PEGASUS_PLATFORM_LINUX_IX86_GNU) || defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) |
if (_localConnection) |
Sint32 socket = accept( |
{ |
_rep->socket, (struct sockaddr*)&address, (socklen_t *)&n); |
#ifdef PEGASUS_LOCAL_DOMAIN_SOCKET |
|
accept_address = reinterpret_cast<struct sockaddr*>(new struct sockaddr_un); |
|
address_size = sizeof(struct sockaddr_un); |
#else | #else |
Sint32 socket = accept(_rep->socket, reinterpret_cast<struct sockaddr*>(&address), &n); |
PEGASUS_ASSERT(false); |
#endif | #endif |
|
} |
|
else |
|
{ |
|
accept_address = reinterpret_cast<struct sockaddr*>(new struct sockaddr_in); |
|
address_size = sizeof(struct sockaddr_in); |
|
} |
|
|
|
Sint32 socket = accept(_rep->socket, accept_address, &address_size); |
|
|
|
delete accept_address; |
| |
if (socket < 0) | if (socket < 0) |
{ | { |
|
Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE, |
|
"HTTPAcceptor - accept() failure. errno: $0" |
|
,errno); |
|
|
PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2, | PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2, |
"HTTPAcceptor: accept() failed"); | "HTTPAcceptor: accept() failed"); |
return; | return; |
} | } |
| |
|
// set the close on exec flag |
|
#ifndef PEGASUS_PLATFORM_WIN32_IX86_MSVC |
|
int sock_flags; |
|
if( (sock_flags = fcntl(socket, F_GETFD, 0)) < 0) |
|
{ |
|
PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2, |
|
"HTTPAcceptor: fcntl(F_GETFD) failed"); |
|
} |
|
else |
|
{ |
|
sock_flags |= FD_CLOEXEC; |
|
if (fcntl(socket, F_SETFD, sock_flags) < 0) |
|
{ |
|
PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2, |
|
"HTTPAcceptor: fcntl(F_SETFD) failed"); |
|
} |
|
} |
|
#endif |
|
|
|
|
|
Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE, |
|
"HTTPAcceptor - accept() success. Socket: $1" |
|
,socket); |
|
|
// Create a new conection and add it to the connection list: | // Create a new conection and add it to the connection list: |
| |
MP_Socket * mp_socket = new MP_Socket(socket, _sslcontext); | MP_Socket * mp_socket = new MP_Socket(socket, _sslcontext); |
|
|
| |
// Save the socket for cleanup later: | // Save the socket for cleanup later: |
connection->_entry_index = index; | connection->_entry_index = index; |
|
_rep->_connection_mut.lock(pegasus_thread_self()); |
_rep->connections.append(connection); | _rep->connections.append(connection); |
|
_rep->_connection_mut.unlock(); |
} | } |
| |
PEGASUS_NAMESPACE_END | PEGASUS_NAMESPACE_END |