version 1.21, 2002/06/19 22:06:32
|
version 1.101, 2007/06/26 20:26:13
|
|
|
//%///////////////////////////////////////////////////////////////////////////// |
//%2006//////////////////////////////////////////////////////////////////////// |
// | // |
// Copyright (c) 2000, 2001, 2002 BMC Software, Hewlett-Packard Company, IBM, |
// Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development |
// The Open Group, Tivoli Systems |
// Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems. |
|
// Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.; |
|
// IBM Corp.; EMC Corporation, The Open Group. |
|
// Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.; |
|
// IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group. |
|
// Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.; |
|
// EMC Corporation; VERITAS Software Corporation; The Open Group. |
|
// Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.; |
|
// EMC Corporation; Symantec Corporation; The Open Group. |
// | // |
// Permission is hereby granted, free of charge, to any person obtaining a copy | // Permission is hereby granted, free of charge, to any person obtaining a copy |
// of this software and associated documentation files (the "Software"), to | // of this software and associated documentation files (the "Software"), to |
|
|
// | // |
//============================================================================== | //============================================================================== |
// | // |
// Author: Mike Brasher (mbrasher@bmc.com) |
|
// |
|
// Modified By: |
|
// Jenny Yu, Hewlett-Packard Company (jenny_yu@hp.com) |
|
// Nag Boranna, Hewlett-Packard Company (nagaraja_boranna@hp.com) |
|
// |
|
//%///////////////////////////////////////////////////////////////////////////// | //%///////////////////////////////////////////////////////////////////////////// |
| |
#include "Config.h" | #include "Config.h" |
#include "Constants.h" | #include "Constants.h" |
#include <iostream> | #include <iostream> |
#include "Socket.h" |
|
|
|
#ifdef PEGASUS_PLATFORM_WIN32_IX86_MSVC |
|
#include <windows.h> |
|
#else |
|
# include <cctype> |
|
# include <unistd.h> |
|
# include <cstdlib> |
|
# include <errno.h> |
|
# include <fcntl.h> |
|
# include <netdb.h> |
|
# include <netinet/in.h> |
|
# include <arpa/inet.h> |
|
# include <sys/socket.h> |
|
# ifdef PEGASUS_LOCAL_DOMAIN_SOCKET |
|
# include <sys/un.h> |
|
# endif |
|
#endif |
|
| |
|
#include "Network.h" |
#include "Socket.h" | #include "Socket.h" |
#include "TLS.h" | #include "TLS.h" |
#include "HTTPAcceptor.h" | #include "HTTPAcceptor.h" |
#include "HTTPConnection.h" | #include "HTTPConnection.h" |
|
#include "HostAddress.h" |
#include "Tracer.h" | #include "Tracer.h" |
|
#include <Pegasus/Common/MessageLoader.h> |
| |
PEGASUS_USING_STD; | PEGASUS_USING_STD; |
| |
PEGASUS_NAMESPACE_BEGIN | PEGASUS_NAMESPACE_BEGIN |
| |
|
|
|
static int MAX_CONNECTION_QUEUE_LENGTH = -1; |
|
|
//////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// |
// | // |
// HTTPAcceptorRep | // HTTPAcceptorRep |
// | // |
//////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// |
| |
struct HTTPAcceptorRep |
class HTTPAcceptorRep |
|
{ |
|
public: |
|
HTTPAcceptorRep(Uint16 connectionType) |
|
{ |
|
if (connectionType == HTTPAcceptor::LOCAL_CONNECTION) |
{ | { |
#ifdef PEGASUS_LOCAL_DOMAIN_SOCKET |
#ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET |
struct sockaddr_un address; |
address = |
|
reinterpret_cast<struct sockaddr*>(new struct sockaddr_un); |
|
address_size = sizeof(struct sockaddr_un); |
#else | #else |
struct sockaddr_in address; |
PEGASUS_ASSERT(false); |
#endif | #endif |
Sint32 socket; |
} |
|
#ifdef PEGASUS_ENABLE_IPV6 |
|
else if (connectionType == HTTPAcceptor::IPV6_CONNECTION) |
|
{ |
|
address = |
|
reinterpret_cast<struct sockaddr*>(new struct sockaddr_in6); |
|
address_size = sizeof(struct sockaddr_in6); |
|
} |
|
#endif |
|
else if (connectionType == HTTPAcceptor::IPV4_CONNECTION) |
|
{ |
|
address = |
|
reinterpret_cast<struct sockaddr*>(new struct sockaddr_in); |
|
address_size = sizeof(struct sockaddr_in); |
|
} |
|
else |
|
{ |
|
PEGASUS_ASSERT(false); |
|
} |
|
} |
|
|
|
~HTTPAcceptorRep() |
|
{ |
|
delete address; |
|
} |
|
struct sockaddr* address; |
|
|
|
SocketLength address_size; |
|
Mutex _connection_mut; |
|
|
|
SocketHandle socket; |
Array<HTTPConnection*> connections; | Array<HTTPConnection*> connections; |
}; | }; |
| |
|
|
//////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// |
// | // |
// HTTPAcceptor | // HTTPAcceptor |
// | // |
//////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// |
| |
HTTPAcceptor::HTTPAcceptor(Monitor* monitor, MessageQueue* outputMessageQueue) |
HTTPAcceptor::HTTPAcceptor(Monitor* monitor, |
: Base(PEGASUS_QUEUENAME_HTTPACCEPTOR), |
MessageQueue* outputMessageQueue, |
_monitor(monitor), _outputMessageQueue(outputMessageQueue), |
Uint16 connectionType, |
_rep(0), _sslcontext(NULL), _entry_index(-1) |
Uint32 portNumber, |
{ |
SSLContext * sslcontext, |
|
ReadWriteSem* sslContextObjectLock) |
Socket::initializeInterface(); |
: Base(PEGASUS_QUEUENAME_HTTPACCEPTOR), // ATTN: Need unique names? |
} |
_monitor(monitor), |
|
_outputMessageQueue(outputMessageQueue), |
HTTPAcceptor::HTTPAcceptor(Monitor* monitor, MessageQueue* outputMessageQueue, |
|
SSLContext * sslcontext) |
|
: Base(PEGASUS_QUEUENAME_HTTPACCEPTOR), |
|
_monitor(monitor), _outputMessageQueue(outputMessageQueue), |
|
_rep(0), | _rep(0), |
|
_entry_index(-1), |
|
_connectionType(connectionType), |
|
_portNumber(portNumber), |
_sslcontext(sslcontext), | _sslcontext(sslcontext), |
_entry_index(-1) |
_sslContextObjectLock(sslContextObjectLock) |
{ | { |
Socket::initializeInterface(); | Socket::initializeInterface(); |
|
|
|
/* |
|
Platforms interpret the value of MAX_CONNECTION_QUEUE_LENGTH |
|
differently. Some platforms interpret the value literally, while |
|
others multiply a fudge factor. When the server is under stress from |
|
multiple clients with multiple requests, toggling this number may |
|
prevent clients from being dropped. Instead of hard coding the |
|
value, we allow an environment variable to be set which specifies a |
|
number greater than the maximum concurrent client connections |
|
possible. If this environment var is not specified, then |
|
MAX_CONNECTION_QUEUE_LENGTH = 15. |
|
*/ |
|
|
|
//To engage runtime backlog queue length: uncomment the following block AND |
|
//comment out the line MAX_CONNECTION_QUEUE_LENGTH = 15 |
|
|
|
/* |
|
if (MAX_CONNECTION_QUEUE_LENGTH == -1) |
|
{ |
|
const char* env = getenv("PEGASUS_MAX_BACKLOG_CONNECTION_QUEUE"); |
|
if (!env) |
|
{ |
|
MAX_CONNECTION_QUEUE_LENGTH = 15; |
|
} |
|
else |
|
{ |
|
char* end = NULL; |
|
MAX_CONNECTION_QUEUE_LENGTH = strtol(env, &end, 10); |
|
if (*end) |
|
MAX_CONNECTION_QUEUE_LENGTH = 15; |
|
cout << " MAX_CONNECTION_QUEUE_LENGTH = " << |
|
MAX_CONNECTION_QUEUE_LENGTH << endl; |
|
} |
|
} |
|
*/ |
|
MAX_CONNECTION_QUEUE_LENGTH = 15; |
} | } |
| |
HTTPAcceptor::~HTTPAcceptor() | HTTPAcceptor::~HTTPAcceptor() |
{ | { |
|
destroyConnections(); |
unbind(); | unbind(); |
|
// 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(); |
} | } |
else | else |
{ | { |
// ATTN! this can't happen! | // ATTN! this can't happen! |
|
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"HTTPAcceptor::handleEnqueue: Invalid SOCKET_MESSAGE " |
|
"received."); |
} | } |
| |
break; | break; |
|
|
| |
case CLOSE_CONNECTION_MESSAGE: | case CLOSE_CONNECTION_MESSAGE: |
{ | { |
CloseConnectionMessage* closeConnectionMessage |
CloseConnectionMessage* closeConnectionMessage = |
= (CloseConnectionMessage*)message; |
(CloseConnectionMessage*)message; |
|
|
|
AutoMutex autoMut(_rep->_connection_mut); |
| |
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]; |
Sint32 socket = connection->getSocket(); |
SocketHandle socket = connection->getSocket(); |
| |
if (socket == closeConnectionMessage->socket) | if (socket == closeConnectionMessage->socket) |
{ | { |
|
|
break; | break; |
} | } |
} | } |
|
|
|
break; |
} | } |
| |
default: | default: |
// ATTN: need unexpected message error! | // ATTN: need unexpected message error! |
|
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"HTTPAcceptor::handleEnqueue: Invalid MESSAGE received."); |
break; | break; |
}; |
} |
| |
delete message; | delete message; |
} | } |
|
|
Message* message = dequeue(); | Message* message = dequeue(); |
| |
if (!message) | if (!message) |
|
{ |
|
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"HTTPAcceptor::handleEnqueue(): No message on queue."); |
return; | return; |
|
} |
| |
handleEnqueue(message); | handleEnqueue(message); |
|
|
} | } |
| |
void HTTPAcceptor::bind(Uint32 portNumber) |
void HTTPAcceptor::bind() |
{ | { |
if (_rep) | if (_rep) |
throw BindFailed("HTTPAcceptor already bound"); |
{ |
|
MessageLoaderParms parms("Common.HTTPAcceptor.ALREADY_BOUND", |
|
"HTTPAcceptor already bound"); |
| |
_rep = new HTTPAcceptorRep; |
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"HTTPAcceptor::bind: HTTPAcceptor already bound."); |
|
throw BindFailedException(parms); |
|
} |
| |
_portNumber = portNumber; |
_rep = new HTTPAcceptorRep(_connectionType); |
| |
// bind address | // bind address |
_bind(); | _bind(); |
|
|
return; |
|
} | } |
| |
/** | /** |
_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 |
a domain socket is bound. |
ignored and a domain socket is bound. |
*/ | */ |
void HTTPAcceptor::_bind() | void HTTPAcceptor::_bind() |
{ | { |
|
PEGASUS_ASSERT(_rep != 0); |
// Create address: | // Create address: |
|
memset(_rep->address, 0, _rep->address_size); |
| |
memset(&_rep->address, 0, sizeof(_rep->address)); |
if (_connectionType == LOCAL_CONNECTION) |
|
{ |
|
#ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET |
|
// |
|
// Make sure the local domain socket can be owned by the cimserver |
|
// user. Otherwise, the bind may fail with a vague "bind failed" |
|
// error. |
|
// |
|
if (System::exists(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH)) |
|
{ |
|
if (!System::removeFile(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH)) |
|
{ |
|
throw CannotRemoveFile(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH); |
|
} |
|
} |
| |
#ifdef PEGASUS_LOCAL_DOMAIN_SOCKET |
reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_family = |
_rep->address.sun_family = AF_UNIX; |
AF_UNIX; |
strcpy(_rep->address.sun_path, "/var/opt/wbem/cimxml.socket"); |
strcpy(reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path, |
::unlink(_rep->address.sun_path); |
PEGASUS_LOCAL_DOMAIN_SOCKET_PATH); |
#else | #else |
_rep->address.sin_addr.s_addr = INADDR_ANY; |
PEGASUS_ASSERT(false); |
_rep->address.sin_family = AF_INET; |
#endif |
_rep->address.sin_port = htons(_portNumber); |
} |
|
#ifdef PEGASUS_ENABLE_IPV6 |
|
else if (_connectionType == IPV6_CONNECTION) |
|
{ |
|
reinterpret_cast<struct sockaddr_in6*>(_rep->address)->sin6_addr = |
|
in6addr_any; |
|
reinterpret_cast<struct sockaddr_in6*>(_rep->address)->sin6_family = |
|
AF_INET6; |
|
reinterpret_cast<struct sockaddr_in6*>(_rep->address)->sin6_port = |
|
htons(_portNumber); |
|
} |
#endif | #endif |
|
else if(_connectionType == IPV4_CONNECTION) |
|
{ |
|
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); |
|
} |
|
else |
|
{ |
|
PEGASUS_ASSERT(false); |
|
} |
| |
// Create socket: | // Create socket: |
| |
#ifdef PEGASUS_LOCAL_DOMAIN_SOCKET |
if (_connectionType == LOCAL_CONNECTION) |
_rep->socket = socket(AF_UNIX, SOCK_STREAM, 0); |
{ |
#else |
_rep->socket = Socket::createSocket(AF_UNIX, SOCK_STREAM, 0); |
_rep->socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); |
} |
|
#ifdef PEGASUS_ENABLE_IPV6 |
|
else if (_connectionType == IPV6_CONNECTION) |
|
{ |
|
_rep->socket = Socket::createSocket(PF_INET6, SOCK_STREAM, IPPROTO_TCP); |
|
} |
#endif | #endif |
|
else if (_connectionType == IPV4_CONNECTION) |
|
{ |
|
_rep->socket = Socket::createSocket(PF_INET, SOCK_STREAM, IPPROTO_TCP); |
|
} |
|
else |
|
{ |
|
PEGASUS_ASSERT(false); |
|
} |
| |
if (_rep->socket < 0) | if (_rep->socket < 0) |
{ | { |
delete _rep; | delete _rep; |
_rep = 0; | _rep = 0; |
throw BindFailed("Failed to create socket"); |
MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_CREATE_SOCKET", |
|
"Failed to create socket"); |
|
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"HTTPAcceptor::_bind _rep->socket < 0"); |
|
throw BindFailedException(parms); |
|
} |
|
|
|
|
|
// set the close-on-exec bit for this file handle. |
|
// any unix that forks needs this bit set. |
|
#if !defined PEGASUS_OS_TYPE_WINDOWS && !defined(PEGASUS_OS_VMS) |
|
int sock_flags; |
|
if ((sock_flags = fcntl(_rep->socket, F_GETFD, 0)) < 0) |
|
{ |
|
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"HTTPAcceptor::_bind: fcntl(F_GETFD) failed"); |
|
} |
|
else |
|
{ |
|
sock_flags |= FD_CLOEXEC; |
|
if (fcntl(_rep->socket, F_SETFD, sock_flags) < 0) |
|
{ |
|
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"HTTPAcceptor::_bind: 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 |
|
|
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"); |
MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_SET_SOCKET_OPTION", |
|
"Failed to set socket option"); |
|
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"HTTPAcceptor::_bind: Failed to set socket option."); |
|
throw BindFailedException(parms); |
} | } |
| |
|
|
|
// |
// Bind socket to port: | // Bind socket to port: |
|
// |
|
if (::bind(_rep->socket, _rep->address, _rep->address_size) < 0) |
|
{ |
|
Socket::close(_rep->socket); |
|
delete _rep; |
|
_rep = 0; |
|
MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_BIND_SOCKET", |
|
"Failed to bind socket"); |
|
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"HTTPAcceptor::_bind: Failed to bind socket."); |
|
throw BindFailedException(parms); |
|
} |
|
|
|
|
|
// |
|
// Get the actual port value used if the caller specified a port value of 0. |
|
// |
|
if (_portNumber == 0) |
|
{ |
|
sockaddr_in buf; |
|
SocketLength bufSize = sizeof(buf); |
|
if (getsockname(_rep->socket, reinterpret_cast<sockaddr *>(&buf), |
|
&bufSize) == 0 ) |
|
{ |
|
_portNumber = ntohs(buf.sin_port); |
|
} |
|
} |
|
|
| |
if (::bind(_rep->socket, |
// |
reinterpret_cast<struct sockaddr*>(&_rep->address), |
// Change permissions on Linux local domain socket to allow writes by |
sizeof(_rep->address)) < 0) |
// others. |
|
// |
|
#if !defined(PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET) && \ |
|
(defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) || \ |
|
defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM)) |
|
if (_connectionType == LOCAL_CONNECTION) |
|
{ |
|
if (::chmod(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH, |
|
S_IRUSR | S_IWUSR | S_IXUSR | |
|
S_IRGRP | S_IWGRP | S_IXGRP | |
|
S_IROTH | S_IWOTH | S_IXOTH ) < 0 ) |
{ | { |
Socket::close(_rep->socket); | Socket::close(_rep->socket); |
delete _rep; | delete _rep; |
_rep = 0; | _rep = 0; |
throw BindFailed("Failed to bind socket"); |
MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_BIND_SOCKET", |
|
"Failed to bind socket"); |
|
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"HTTPAcceptor::_bind: Failed to set domain socket " |
|
"permissions."); |
|
throw BindFailedException(parms); |
|
} |
} | } |
|
#endif |
| |
// Set up listening on the given socket: | // Set up listening on the given socket: |
| |
int const MAX_CONNECTION_QUEUE_LENGTH = 5; |
//int const MAX_CONNECTION_QUEUE_LENGTH = 15; |
| |
if (listen(_rep->socket, MAX_CONNECTION_QUEUE_LENGTH) < 0) | if (listen(_rep->socket, MAX_CONNECTION_QUEUE_LENGTH) < 0) |
{ | { |
Socket::close(_rep->socket); | Socket::close(_rep->socket); |
delete _rep; | delete _rep; |
_rep = 0; | _rep = 0; |
throw BindFailed("Failed to bind socket"); |
MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_BIND_SOCKET", |
|
"Failed to bind socket"); |
|
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"HTTPAcceptor::_bind: Failed to bind socket(1)."); |
|
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"); |
MessageLoaderParms parms( |
|
"Common.HTTPAcceptor.FAILED_SOLICIT_SOCKET_MESSAGES", |
|
"Failed to solicit socket messaeges"); |
|
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"HTTPAcceptor::_bind: Failed to solicit socket messages(2)."); |
|
throw BindFailedException(parms); |
} | } |
} | } |
| |
|
|
if (_rep) | if (_rep) |
{ | { |
// unregister the socket | // unregister the socket |
_monitor->unsolicitSocketMessages(_rep->socket); |
|
|
// ATTN - comment out - see CIMServer::stopClientConnection() |
|
//_monitor->unsolicitSocketMessages(_rep->socket); |
| |
// close the socket | // close the socket |
Socket::close(_rep->socket); | Socket::close(_rep->socket); |
|
// Unlink Local Domain Socket Bug# 3312 |
|
if (_connectionType == LOCAL_CONNECTION) |
|
{ |
|
#ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET |
|
PEG_TRACE_CSTRING(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 |
|
{ |
|
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"HTTPAcceptor::closeConnectionSocket failure _rep is null."); |
} | } |
} | } |
| |
|
|
{ | { |
_bind(); | _bind(); |
} | } |
|
else |
|
{ |
|
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"HTTPAcceptor::reopenConnectionSocket failure _rep is null."); |
|
} |
|
} |
|
|
|
|
|
/** |
|
reconnectConnectionSocket - creates a new server socket. |
|
*/ |
|
void HTTPAcceptor::reconnectConnectionSocket() |
|
{ |
|
if (_rep) |
|
{ |
|
// unregister the socket |
|
_monitor->unsolicitSocketMessages(_rep->socket); |
|
// close the socket |
|
Socket::close(_rep->socket); |
|
// Unlink Local Domain Socket Bug# 3312 |
|
if (_connectionType == LOCAL_CONNECTION) |
|
{ |
|
#ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET |
|
PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2, |
|
"HTTPAcceptor::reconnectConnectionSocket Unlinking local " |
|
"connection." ); |
|
::unlink( |
|
reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path); |
|
#else |
|
PEGASUS_ASSERT(false); |
|
#endif |
|
} |
|
// open the socket |
|
_bind(); |
|
} |
|
else |
|
{ |
|
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"HTTPAcceptor::reconnectConnectionSocket failure _rep is null."); |
|
} |
} | } |
| |
/** | /** |
getOutstandingRequestCount - returns the number of outstanding requests. | getOutstandingRequestCount - returns the number of outstanding requests. |
*/ | */ |
Uint32 HTTPAcceptor::getOutstandingRequestCount() |
Uint32 HTTPAcceptor::getOutstandingRequestCount() const |
{ | { |
|
Uint32 count = 0; |
|
if (_rep) |
|
{ |
|
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]; |
return(connection->getRequestCount()); |
count = connection->getRequestCount(); |
} | } |
else |
} |
|
return count; |
|
} |
|
|
|
|
|
/** |
|
getPortNumber - returns the port number used for the connection |
|
*/ |
|
Uint32 HTTPAcceptor::getPortNumber() const |
{ | { |
return(0); |
return _portNumber; |
} | } |
|
|
|
void HTTPAcceptor::setSocketWriteTimeout(Uint32 socketWriteTimeout) |
|
{ |
|
_socketWriteTimeout = socketWriteTimeout; |
} | } |
| |
void HTTPAcceptor::unbind() | void HTTPAcceptor::unbind() |
{ | { |
if (_rep) | if (_rep) |
{ | { |
|
_portNumber = 0; |
Socket::close(_rep->socket); | Socket::close(_rep->socket); |
|
|
|
if (_connectionType == LOCAL_CONNECTION) |
|
{ |
|
#ifndef PEGASUS_DISABLE_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; |
} | } |
|
else |
|
{ |
|
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"HTTPAcceptor::unbind failure _rep is null." ); |
|
} |
} | } |
| |
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); |
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]; |
Sint32 socket = connection->getSocket(); |
SocketHandle socket = connection->getSocket(); |
| |
// Unsolicit SocketMessages: | // Unsolicit SocketMessages: |
| |
|
|
| |
// Destroy the connection (causing it to close): | // Destroy the connection (causing it to close): |
| |
while (connection->refcount.value()) { } |
while (connection->refcount.get()) { } |
delete connection; | delete connection; |
} | } |
| |
_rep->connections.clear(); | _rep->connections.clear(); |
} | } |
|
} |
| |
void HTTPAcceptor::_acceptConnection() | void HTTPAcceptor::_acceptConnection() |
{ | { |
|
|
| |
PEGASUS_ASSERT(_rep != 0); | PEGASUS_ASSERT(_rep != 0); |
| |
if (!_rep) |
|
return; |
|
|
|
// Accept the connection (populate the address): | // Accept the connection (populate the address): |
| |
sockaddr_in address; |
struct sockaddr* accept_address; |
|
SocketLength address_size; |
| |
#if defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM) || defined(PEGASUS_PLATFORM_AIX_RS_IBMCXX) |
if (_connectionType == LOCAL_CONNECTION) |
size_t n = sizeof(address); |
{ |
|
#ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET |
|
accept_address = |
|
reinterpret_cast<struct sockaddr*>(new struct sockaddr_un); |
|
address_size = sizeof(struct sockaddr_un); |
|
#else |
|
PEGASUS_ASSERT(false); |
|
#endif |
|
} |
|
else |
|
{ |
|
#ifdef PEGASUS_ENABLE_IPV6 |
|
accept_address = |
|
reinterpret_cast<struct sockaddr*> |
|
(new struct sockaddr_storage); |
|
address_size = sizeof(struct sockaddr_storage); |
#else | #else |
int n = sizeof(address); |
accept_address = |
|
reinterpret_cast<struct sockaddr*>(new struct sockaddr_in); |
|
address_size = sizeof(struct sockaddr_in); |
#endif | #endif |
|
} |
| |
#if defined(PEGASUS_PLATFORM_LINUX_IX86_GNU) || defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) |
SocketHandle socket; |
Sint32 socket = accept( |
#ifdef PEGASUS_OS_TYPE_WINDOWS |
_rep->socket, (struct sockaddr*)&address, (socklen_t *)&n); |
socket = accept(_rep->socket, accept_address, &address_size); |
#else | #else |
Sint32 socket = accept(_rep->socket, reinterpret_cast<struct sockaddr*>(&address), &n); |
while ( |
|
((socket = accept(_rep->socket, accept_address, &address_size)) == -1) |
|
&& (errno == EINTR)) |
|
; |
#endif | #endif |
| |
if (socket < 0) |
if (socket == PEGASUS_SOCKET_ERROR) |
|
{ |
|
// the remote connection is invalid, destroy client address. |
|
delete accept_address; |
|
|
|
// TCPIP is down reconnect this acceptor |
|
if (getSocketError() == PEGASUS_NETWORK_TCPIP_STOPPED) |
{ | { |
PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2, |
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"Socket has an IO error. TCP/IP down. Try to reconnect."); |
|
|
|
reconnectConnectionSocket(); |
|
|
|
return; |
|
} |
|
|
|
Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE, |
|
"HTTPAcceptor - accept() failure. errno: $0", errno); |
|
|
|
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
"HTTPAcceptor: accept() failed"); | "HTTPAcceptor: accept() failed"); |
return; | return; |
} | } |
| |
// Create a new conection and add it to the connection list: |
String ipAddress; |
|
|
|
if (_connectionType == LOCAL_CONNECTION) |
|
{ |
|
ipAddress = "localhost"; |
|
} |
|
else |
|
{ |
|
#ifdef PEGASUS_ENABLE_IPV6 |
|
char ipBuffer[PEGASUS_INET6_ADDRSTR_LEN]; |
|
int rc; |
|
while ((rc = getnameinfo(accept_address, address_size, ipBuffer, |
|
PEGASUS_INET6_ADDRSTR_LEN, 0, 0, NI_NUMERICHOST)) == EAI_AGAIN) |
|
; |
|
if (rc) |
|
{ |
|
Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE, |
|
"HTTPAcceptor - getnameinfo() failure. rc: $0", rc); |
|
|
|
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"HTTPAcceptor: getnameinfo() failed"); |
|
delete accept_address; |
|
Socket::close(socket); |
|
return; |
|
} |
|
ipAddress = ipBuffer; |
|
#else |
|
unsigned char* sa = reinterpret_cast<unsigned char*>( |
|
&reinterpret_cast<struct sockaddr_in*>( |
|
accept_address)->sin_addr.s_addr); |
|
char ipBuffer[32]; |
|
sprintf(ipBuffer, "%u.%u.%u.%u", sa[0], sa[1], sa[2], sa[3]); |
|
ipAddress = ipBuffer; |
|
#endif |
|
} |
|
|
|
delete accept_address; |
|
|
|
// set the close on exec flag |
|
#if !defined(PEGASUS_OS_TYPE_WINDOWS) && !defined(PEGASUS_OS_VMS) |
|
int sock_flags; |
|
if ((sock_flags = fcntl(socket, F_GETFD, 0)) < 0) |
|
{ |
|
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"HTTPAcceptor: fcntl(F_GETFD) failed"); |
|
} |
|
else |
|
{ |
|
sock_flags |= FD_CLOEXEC; |
|
if (fcntl(socket, F_SETFD, sock_flags) < 0) |
|
{ |
|
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"HTTPAcceptor: fcntl(F_SETFD) failed"); |
|
} |
|
} |
|
#endif |
|
|
|
|
|
PEG_LOGGER_TRACE((Logger::STANDARD_LOG, System::CIMSERVER, 0, |
|
"HTTPAcceptor - accept() success. Socket: $1" ,socket)); |
|
|
|
SharedPtr<MP_Socket> mp_socket(new MP_Socket( |
|
socket, _sslcontext, _sslContextObjectLock, ipAddress)); |
|
|
|
mp_socket->setSocketWriteTimeout(_socketWriteTimeout); |
|
|
|
// 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 * mp_socket = new MP_Socket(socket, _sslcontext); |
mp_socket->disableBlocking(); |
if (mp_socket->accept() < 0) |
Sint32 socketAcceptStatus = mp_socket->accept(); |
|
mp_socket->enableBlocking(); |
|
|
|
if (socketAcceptStatus < 0) |
{ | { |
PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2, |
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
"HTTPAcceptor: SSL_accept() failed"); | "HTTPAcceptor: SSL_accept() failed"); |
|
mp_socket->close(); |
return; | return; |
} | } |
| |
HTTPConnection* connection = new HTTPConnection( |
// Create a new connection and add it to the connection list: |
_monitor, mp_socket, this, static_cast<MessageQueue *>(_outputMessageQueue)); |
|
|
HTTPConnection* connection = new HTTPConnection(_monitor, mp_socket, |
|
ipAddress, this, static_cast<MessageQueue *>(_outputMessageQueue)); |
|
|
|
if (socketAcceptStatus == 0) |
|
{ |
|
PEG_TRACE_CSTRING(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; |
| |
if (! (index = _monitor->solicitSocketMessages( |
if (-1 == (index = _monitor->solicitSocketMessages( |
socket, |
connection->getSocket(), |
SocketMessage::READ | SocketMessage::EXCEPTION, | SocketMessage::READ | SocketMessage::EXCEPTION, |
connection->getQueueId(), Monitor::CONNECTION)) ) | connection->getQueueId(), Monitor::CONNECTION)) ) |
{ | { |
|
// ATTN-DE-P2-2003100503::TODO::Need to enhance code to return |
|
// an error message to Client application. |
|
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"HTTPAcceptor::_acceptConnection: Attempt to allocate entry in " |
|
"_entries table failed."); |
delete connection; | delete connection; |
Socket::close(socket); | Socket::close(socket); |
|
return; |
} | } |
| |
// Save the socket for cleanup later: | // Save the socket for cleanup later: |
connection->_entry_index = index; | connection->_entry_index = index; |
|
AutoMutex autoMut(_rep->_connection_mut); |
_rep->connections.append(connection); | _rep->connections.append(connection); |
} | } |
| |