version 1.1.2.2, 2001/08/01 21:56:24
|
version 1.19, 2002/05/30 00:12:38
|
|
|
// Author: Mike Brasher (mbrasher@bmc.com) | // Author: Mike Brasher (mbrasher@bmc.com) |
// | // |
// Modified By: | // Modified By: |
|
// Jenny Yu, Hewlett-Packard Company (jenny_yu@hp.com) |
|
// Nag Boranna, Hewlett-Packard Company (nagaraja_boranna@hp.com) |
// | // |
//%///////////////////////////////////////////////////////////////////////////// | //%///////////////////////////////////////////////////////////////////////////// |
| |
#include <iostream> |
|
#include "Config.h" | #include "Config.h" |
|
#include "Constants.h" |
|
#include <iostream> |
#include "Socket.h" | #include "Socket.h" |
| |
#ifdef PEGASUS_OS_TYPE_WINDOWS |
#ifdef PEGASUS_PLATFORM_WIN32_IX86_MSVC |
# include <winsock.h> |
#include <windows.h> |
#else | #else |
# include <cctype> | # include <cctype> |
# include <unistd.h> | # include <unistd.h> |
|
|
# 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 |
|
# include <sys/un.h> |
|
# endif |
#endif | #endif |
| |
#include "Socket.h" | #include "Socket.h" |
|
#include "TLS.h" |
#include "HTTPAcceptor.h" | #include "HTTPAcceptor.h" |
#include "HTTPConnection.h" | #include "HTTPConnection.h" |
|
#include "Tracer.h" |
| |
PEGASUS_USING_STD; | PEGASUS_USING_STD; |
| |
|
|
| |
struct HTTPAcceptorRep | struct HTTPAcceptorRep |
{ | { |
|
#ifdef PEGASUS_LOCAL_DOMAIN_SOCKET |
|
struct sockaddr_un address; |
|
#else |
struct sockaddr_in address; | struct sockaddr_in address; |
|
#endif |
Sint32 socket; | Sint32 socket; |
Array<HTTPConnection*> connections; | Array<HTTPConnection*> connections; |
}; | }; |
|
|
// | // |
//////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// |
| |
HTTPAcceptor::HTTPAcceptor(Monitor* monitor) : _monitor(monitor), _rep(0) |
HTTPAcceptor::HTTPAcceptor(Monitor* monitor, MessageQueue* outputMessageQueue) |
|
: Base(PEGASUS_QUEUENAME_HTTPACCEPTOR), |
|
_monitor(monitor), _outputMessageQueue(outputMessageQueue), |
|
_rep(0), _sslcontext(NULL) |
{ | { |
// Note: we are counting on the monitor to initialize the socket |
|
// interface (in Windows you have to call WSAInitialize() and |
Socket::initializeInterface(); |
// WSAShutDown()). |
} |
|
|
|
HTTPAcceptor::HTTPAcceptor(Monitor* monitor, MessageQueue* outputMessageQueue, |
|
SSLContext * sslcontext) |
|
: Base(PEGASUS_QUEUENAME_HTTPACCEPTOR), |
|
_monitor(monitor), _outputMessageQueue(outputMessageQueue), |
|
_rep(0), |
|
_sslcontext(sslcontext) |
|
{ |
|
Socket::initializeInterface(); |
} | } |
| |
HTTPAcceptor::~HTTPAcceptor() | HTTPAcceptor::~HTTPAcceptor() |
{ | { |
unbind(); | unbind(); |
|
Socket::uninitializeInterface(); |
} | } |
| |
void HTTPAcceptor::handleEnqueue() |
void HTTPAcceptor::handleEnqueue(Message *message) |
{ | { |
cout << "HTTPAcceptor::handleEnqueue()" << endl; |
|
|
|
Message* message = dequeue(); |
|
|
|
if (!message) | if (!message) |
return; | return; |
| |
if (getenv("PEGASUS_TRACE")) |
|
message->print(cout); |
|
|
|
switch (message->getType()) | switch (message->getType()) |
{ | { |
case SOCKET_MESSAGE: | case SOCKET_MESSAGE: |
|
|
{ | { |
_monitor->unsolicitSocketMessages(socket); | _monitor->unsolicitSocketMessages(socket); |
_rep->connections.remove(i); | _rep->connections.remove(i); |
|
while (connection->refcount.value()) { } |
delete connection; | delete connection; |
break; | break; |
} | } |
|
|
delete message; | delete message; |
} | } |
| |
|
|
|
void HTTPAcceptor::handleEnqueue() |
|
{ |
|
Message* message = dequeue(); |
|
|
|
if (!message) |
|
return; |
|
|
|
handleEnqueue(message); |
|
|
|
} |
|
|
void HTTPAcceptor::bind(Uint32 portNumber) | void HTTPAcceptor::bind(Uint32 portNumber) |
{ | { |
if (_rep) | if (_rep) |
|
|
| |
_rep = new HTTPAcceptorRep; | _rep = new HTTPAcceptorRep; |
| |
|
_portNumber = portNumber; |
|
|
|
// bind address |
|
_bind(); |
|
|
|
return; |
|
} |
|
|
|
/** |
|
_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 |
|
a domain socket is bound. |
|
*/ |
|
void HTTPAcceptor::_bind() |
|
{ |
|
|
// Create address: | // Create address: |
| |
memset(&_rep->address, 0, sizeof(_rep->address)); | memset(&_rep->address, 0, sizeof(_rep->address)); |
|
|
|
#ifdef PEGASUS_LOCAL_DOMAIN_SOCKET |
|
_rep->address.sun_family = AF_UNIX; |
|
strcpy(_rep->address.sun_path, "/var/opt/wbem/cimxml.socket"); |
|
::unlink(_rep->address.sun_path); |
|
#else |
_rep->address.sin_addr.s_addr = INADDR_ANY; | _rep->address.sin_addr.s_addr = INADDR_ANY; |
_rep->address.sin_family = AF_INET; | _rep->address.sin_family = AF_INET; |
_rep->address.sin_port = htons(portNumber); |
_rep->address.sin_port = htons(_portNumber); |
|
#endif |
| |
// Create socket: | // Create socket: |
| |
|
#ifdef PEGASUS_LOCAL_DOMAIN_SOCKET |
|
_rep->socket = socket(AF_UNIX, SOCK_STREAM, 0); |
|
#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) |
{ | { |
|
|
throw BindFailed("Failed to create socket"); | throw BindFailed("Failed to create socket"); |
} | } |
| |
|
// |
|
// 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 |
|
// need to resume the cimom as a result of a timeout during a Shutdown |
|
// operation. |
|
// |
|
int opt=1; |
|
if (setsockopt(_rep->socket, SOL_SOCKET, SO_REUSEADDR, |
|
(char *)&opt, sizeof(opt)) < 0) |
|
{ |
|
delete _rep; |
|
_rep = 0; |
|
throw BindFailed("Failed to set socket option"); |
|
} |
|
|
// Bind socket to port: | // Bind socket to port: |
| |
if (::bind(_rep->socket, | if (::bind(_rep->socket, |
(struct sockaddr*)(void*)&_rep->address, |
reinterpret_cast<struct sockaddr*>(&_rep->address), |
sizeof(_rep->address)) < 0) | 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 to port"); |
throw BindFailed("Failed to bind socket"); |
} | } |
| |
// Set up listening on the given port: |
// Set up listening on the given socket: |
| |
int const MAX_CONNECTION_QUEUE_LENGTH = 5; | int const MAX_CONNECTION_QUEUE_LENGTH = 5; |
| |
|
|
Socket::close(_rep->socket); | Socket::close(_rep->socket); |
delete _rep; | delete _rep; |
_rep = 0; | _rep = 0; |
throw BindFailed("Failed to bind socket to port"); |
throw BindFailed("Failed to bind socket"); |
} | } |
| |
// Register to receive SocketMessages on this socket: | // Register to receive SocketMessages on this socket: |
|
|
if (!_monitor->solicitSocketMessages( | if (!_monitor->solicitSocketMessages( |
_rep->socket, | _rep->socket, |
SocketMessage::READ | SocketMessage::EXCEPTION, | SocketMessage::READ | SocketMessage::EXCEPTION, |
getQueueId())) |
getQueueId(), |
|
Monitor::ACCEPTOR)) |
{ | { |
Socket::close(_rep->socket); | Socket::close(_rep->socket); |
delete _rep; | delete _rep; |
|
|
} | } |
} | } |
| |
|
/** |
|
closeConnectionSocket - close the server listening socket to disallow |
|
new client connections. |
|
*/ |
|
void HTTPAcceptor::closeConnectionSocket() |
|
{ |
|
if (_rep) |
|
{ |
|
// unregister the socket |
|
_monitor->unsolicitSocketMessages(_rep->socket); |
|
|
|
// close the socket |
|
Socket::close(_rep->socket); |
|
} |
|
} |
|
|
|
/** |
|
reopenConnectionSocket - creates a new server socket. |
|
*/ |
|
void HTTPAcceptor::reopenConnectionSocket() |
|
{ |
|
if (_rep) |
|
{ |
|
_bind(); |
|
} |
|
} |
|
|
|
/** |
|
getOutstandingRequestCount - returns the number of outstanding requests. |
|
*/ |
|
Uint32 HTTPAcceptor::getOutstandingRequestCount() |
|
{ |
|
if (_rep->connections.size() > 0) |
|
{ |
|
HTTPConnection* connection = _rep->connections[0]; |
|
return(connection->getRequestCount()); |
|
} |
|
else |
|
{ |
|
return(0); |
|
} |
|
} |
|
|
void HTTPAcceptor::unbind() | void HTTPAcceptor::unbind() |
{ | { |
if (_rep) | if (_rep) |
|
|
| |
// Destroy the connection (causing it to close): | // Destroy the connection (causing it to close): |
| |
|
while (connection->refcount.value()) { } |
delete connection; | delete connection; |
} | } |
| |
|
|
// Accept the connection (populate the address): | // Accept the connection (populate the address): |
| |
sockaddr_in address; | sockaddr_in address; |
|
|
|
#if defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM) || defined(PEGASUS_PLATFORM_AIX_RS_IBMCXX) |
|
size_t n = sizeof(address); |
|
#else |
int n = sizeof(address); | int n = sizeof(address); |
#if defined(PEGASUS_PLATFORM_LINUX_IX86_GNU) |
#endif |
Sint32 socket = accept(_rep->socket, (struct sockaddr*)&address, (socklen_t *)&n); |
|
|
#if defined(PEGASUS_PLATFORM_LINUX_IX86_GNU) || defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) |
|
Sint32 socket = accept( |
|
_rep->socket, (struct sockaddr*)&address, (socklen_t *)&n); |
#else | #else |
Sint32 socket = accept(_rep->socket, (struct sockaddr*)&address, &n); |
Sint32 socket = accept(_rep->socket, reinterpret_cast<struct sockaddr*>(&address), &n); |
#endif | #endif |
| |
if (socket < 0) | if (socket < 0) |
{ | { |
if (getenv("PEGASUS_TRACE")) |
PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2, |
cerr <<"HTTPAcceptor: accept() failed" << endl; |
"HTTPAcceptor: accept() failed"); |
|
|
return; | return; |
} | } |
| |
// Create a new conection and add it to the connection list: | // Create a new conection and add it to the connection list: |
| |
HTTPConnection* connection = new HTTPConnection(socket, this); |
MP_Socket * mp_socket = new MP_Socket(socket, _sslcontext); |
|
if (mp_socket->accept() < 0) |
|
{ |
|
PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2, |
|
"HTTPAcceptor: SSL_accept() failed"); |
|
return; |
|
} |
|
|
|
HTTPConnection* connection = new HTTPConnection( |
|
_monitor, mp_socket, this, static_cast<MessageQueue *>(_outputMessageQueue)); |
| |
// Solicit events on this new connection socket: |
// Solicit events on this new connection's socket: |
| |
if (!_monitor->solicitSocketMessages( | if (!_monitor->solicitSocketMessages( |
socket, | socket, |
SocketMessage::READ | SocketMessage::EXCEPTION, | SocketMessage::READ | SocketMessage::EXCEPTION, |
connection->getQueueId())) |
connection->getQueueId(), Monitor::CONNECTION)) |
{ | { |
delete connection; | delete connection; |
Socket::close(socket); | Socket::close(socket); |