version 1.105, 2007/09/07 20:08:37
|
version 1.133, 2012/07/16 11:27:16
|
|
|
//%2006//////////////////////////////////////////////////////////////////////// |
//%LICENSE//////////////////////////////////////////////////////////////// |
// | // |
// Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development |
// Licensed to The Open Group (TOG) under one or more contributor license |
// Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems. |
// agreements. Refer to the OpenPegasusNOTICE.txt file distributed with |
// Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.; |
// this work for additional information regarding copyright ownership. |
// IBM Corp.; EMC Corporation, The Open Group. |
// Each contributor licenses this file to you under the OpenPegasus Open |
// Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.; |
// Source License; you may not use this file except in compliance with the |
// IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group. |
// License. |
// Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.; |
// |
// EMC Corporation; VERITAS Software Corporation; The Open Group. |
// Permission is hereby granted, free of charge, to any person obtaining a |
// Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.; |
// copy of this software and associated documentation files (the "Software"), |
// EMC Corporation; Symantec Corporation; The Open Group. |
// to deal in the Software without restriction, including without limitation |
// |
// the rights to use, copy, modify, merge, publish, distribute, sublicense, |
// Permission is hereby granted, free of charge, to any person obtaining a copy |
// and/or sell copies of the Software, and to permit persons to whom the |
// of this software and associated documentation files (the "Software"), to |
// Software is furnished to do so, subject to the following conditions: |
// deal in the Software without restriction, including without limitation the |
// |
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
// The above copyright notice and this permission notice shall be included |
// sell copies of the Software, and to permit persons to whom the Software is |
// in all copies or substantial portions of the Software. |
// furnished to do so, subject to the following conditions: |
// |
// |
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
// THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN |
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
// ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED |
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT |
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
// | // |
//============================================================================== |
////////////////////////////////////////////////////////////////////////// |
// | // |
//%///////////////////////////////////////////////////////////////////////////// | //%///////////////////////////////////////////////////////////////////////////// |
| |
|
|
| |
static int _maxConnectionQueueLength = -1; | static int _maxConnectionQueueLength = -1; |
| |
|
Uint32 HTTPAcceptor::_socketWriteTimeout = |
|
PEGASUS_DEFAULT_SOCKETWRITE_TIMEOUT_SECONDS; |
|
|
|
#ifndef PEGASUS_INTEGERS_BOUNDARY_ALIGNED |
|
Mutex HTTPAcceptor::_socketWriteTimeoutMutex; |
|
#endif |
|
|
//////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// |
// | // |
// HTTPAcceptorRep | // HTTPAcceptorRep |
|
|
| |
~HTTPAcceptorRep() | ~HTTPAcceptorRep() |
{ | { |
|
closeSocket(); |
delete address; | delete address; |
} | } |
|
|
|
void closeSocket() |
|
{ |
|
Socket::close(socket); |
|
} |
|
|
struct sockaddr* address; | struct sockaddr* address; |
| |
SocketLength address_size; | SocketLength address_size; |
|
|
Uint16 connectionType, | Uint16 connectionType, |
Uint32 portNumber, | Uint32 portNumber, |
SSLContext * sslcontext, | SSLContext * sslcontext, |
ReadWriteSem* sslContextObjectLock) |
ReadWriteSem* sslContextObjectLock, |
|
HostAddress *listenOn) |
: Base(PEGASUS_QUEUENAME_HTTPACCEPTOR), // ATTN: Need unique names? | : Base(PEGASUS_QUEUENAME_HTTPACCEPTOR), // ATTN: Need unique names? |
_monitor(monitor), | _monitor(monitor), |
_outputMessageQueue(outputMessageQueue), | _outputMessageQueue(outputMessageQueue), |
|
|
_connectionType(connectionType), | _connectionType(connectionType), |
_portNumber(portNumber), | _portNumber(portNumber), |
_sslcontext(sslcontext), | _sslcontext(sslcontext), |
_sslContextObjectLock(sslContextObjectLock) |
_sslContextObjectLock(sslContextObjectLock), |
|
_listenAddress(listenOn) |
{ | { |
|
PEGASUS_ASSERT(!_sslcontext == !_sslContextObjectLock); |
Socket::initializeInterface(); | Socket::initializeInterface(); |
| |
/* | /* |
|
|
SocketMessage* socketMessage = (SocketMessage*)message; | SocketMessage* socketMessage = (SocketMessage*)message; |
| |
// If this is a connection request: | // If this is a connection request: |
|
PEGASUS_ASSERT(socketMessage->socket == _rep->socket); |
|
|
|
PEGASUS_ASSERT(socketMessage->events & SocketMessage::READ); |
| |
if (socketMessage->socket == _rep->socket && |
|
socketMessage->events & SocketMessage::READ) |
|
{ |
|
_acceptConnection(); | _acceptConnection(); |
} |
|
else |
|
{ |
|
// ATTN! this can't happen! |
|
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"HTTPAcceptor::handleEnqueue: Invalid SOCKET_MESSAGE " |
|
"received."); |
|
} |
|
| |
break; | break; |
} | } |
|
|
} | } |
| |
default: | default: |
// ATTN: need unexpected message error! |
PEGASUS_ASSERT(false); |
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"HTTPAcceptor::handleEnqueue: Invalid MESSAGE received."); |
|
break; | break; |
} | } |
| |
|
|
void HTTPAcceptor::handleEnqueue() | void HTTPAcceptor::handleEnqueue() |
{ | { |
Message* message = dequeue(); | Message* message = dequeue(); |
|
|
if (!message) |
|
{ |
|
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"HTTPAcceptor::handleEnqueue(): No message on queue."); |
|
return; |
|
} |
|
|
|
handleEnqueue(message); | handleEnqueue(message); |
} | } |
| |
|
|
{ | { |
MessageLoaderParms parms("Common.HTTPAcceptor.ALREADY_BOUND", | MessageLoaderParms parms("Common.HTTPAcceptor.ALREADY_BOUND", |
"HTTPAcceptor already bound"); | "HTTPAcceptor already bound"); |
|
|
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"HTTPAcceptor::bind: HTTPAcceptor already bound."); |
|
throw BindFailedException(parms); | throw BindFailedException(parms); |
} | } |
| |
|
|
_bind(); | _bind(); |
} | } |
| |
|
|
/** | /** |
_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_DISABLE_LOCAL_DOMAIN_SOCKET is not defined, the port number is | If PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET is not defined, the port number is |
|
|
void HTTPAcceptor::_bind() | void HTTPAcceptor::_bind() |
{ | { |
#ifdef PEGASUS_OS_PASE | #ifdef PEGASUS_OS_PASE |
// bind need ccsid is 819 |
AutoPtr<PaseCcsid> ccsid; |
int orig_ccsid; |
|
orig_ccsid = _SETCCSID(-1); |
|
if (orig_ccsid == -1) |
|
{ |
|
PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
String("HTTPAcceptor::_bind: Can not get current PASE CCSID.")); |
|
orig_ccsid = 1208; |
|
} |
|
PaseCcsid ccsid(819, orig_ccsid); |
|
#endif | #endif |
| |
PEGASUS_ASSERT(_rep != 0); | PEGASUS_ASSERT(_rep != 0); |
|
|
// user. Otherwise, the bind may fail with a vague "bind failed" | // user. Otherwise, the bind may fail with a vague "bind failed" |
// error. | // error. |
// | // |
|
#ifdef PEGASUS_OS_PASE |
|
// PASE domain socket needs ccsid 819 |
|
int orig_ccsid; |
|
orig_ccsid = _SETCCSID(-1); |
|
if (orig_ccsid == -1) |
|
{ |
|
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1, |
|
"HTTPAcceptor::_bind: Can not get current PASE CCSID."); |
|
orig_ccsid = 1208; |
|
} |
|
ccsid.reset(new PaseCcsid(819, orig_ccsid)); |
|
#endif |
if (System::exists(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH)) | if (System::exists(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH)) |
{ | { |
if (!System::removeFile(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH)) | if (!System::removeFile(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH)) |
|
|
#ifdef PEGASUS_ENABLE_IPV6 | #ifdef PEGASUS_ENABLE_IPV6 |
else if (_connectionType == IPV6_CONNECTION) | else if (_connectionType == IPV6_CONNECTION) |
{ | { |
|
if(_listenAddress) |
|
{ |
|
String hostAdd = _listenAddress->getHost(); |
|
CString ip = hostAdd.getCString(); |
|
|
|
struct sockaddr_in6 in6addr; |
|
memset(&in6addr, 0, sizeof(sockaddr_in6)); |
|
if(_listenAddress ->isHostAddLinkLocal()) |
|
{ |
|
HostAddress::convertTextToBinary(AF_INET6, |
|
(const char*)ip, |
|
&in6addr.sin6_addr); |
|
reinterpret_cast<struct sockaddr_in6*>( |
|
_rep->address)->sin6_addr = in6addr.sin6_addr; |
|
reinterpret_cast<struct sockaddr_in6*>( |
|
_rep->address)->sin6_scope_id = |
|
_listenAddress->getScopeID(); |
|
} |
|
else |
|
{ |
|
HostAddress::convertTextToBinary(AF_INET6, |
|
(const char*)ip, |
|
&in6addr.sin6_addr); |
|
reinterpret_cast<struct sockaddr_in6*>( |
|
_rep->address)->sin6_addr = in6addr.sin6_addr; |
|
} |
|
} |
|
else |
|
{ |
reinterpret_cast<struct sockaddr_in6*>(_rep->address)->sin6_addr = | reinterpret_cast<struct sockaddr_in6*>(_rep->address)->sin6_addr = |
in6addr_any; | in6addr_any; |
|
} |
reinterpret_cast<struct sockaddr_in6*>(_rep->address)->sin6_family = | reinterpret_cast<struct sockaddr_in6*>(_rep->address)->sin6_family = |
AF_INET6; | AF_INET6; |
reinterpret_cast<struct sockaddr_in6*>(_rep->address)->sin6_port = | reinterpret_cast<struct sockaddr_in6*>(_rep->address)->sin6_port = |
|
|
#endif | #endif |
else if(_connectionType == IPV4_CONNECTION) | else if(_connectionType == IPV4_CONNECTION) |
{ | { |
reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_addr.s_addr = |
if(_listenAddress) |
INADDR_ANY; |
{ |
|
String hostAdd = _listenAddress->getHost(); |
|
CString ip = hostAdd.getCString(); |
|
struct sockaddr_in addrs; |
|
HostAddress::convertTextToBinary( |
|
AF_INET, |
|
(const char*)ip, |
|
&addrs.sin_addr); |
|
reinterpret_cast<struct sockaddr_in*>( |
|
_rep->address)->sin_addr.s_addr = addrs.sin_addr.s_addr; |
|
} |
|
else |
|
{ |
|
reinterpret_cast<struct sockaddr_in*>( |
|
_rep->address)->sin_addr.s_addr = INADDR_ANY; |
|
} |
reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_family = | reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_family = |
AF_INET; | AF_INET; |
reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_port = | reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_port = |
|
|
_rep = 0; | _rep = 0; |
MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_CREATE_SOCKET", | MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_CREATE_SOCKET", |
"Failed to create socket"); | "Failed to create socket"); |
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"HTTPAcceptor::_bind _rep->socket < 0"); |
|
throw BindFailedException(parms); | throw BindFailedException(parms); |
} | } |
| |
|
Socket::disableBlocking(_rep->socket); |
| |
// set the close-on-exec bit for this file handle. | // set the close-on-exec bit for this file handle. |
// any unix that forks needs this bit set. | // any unix that forks needs this bit set. |
|
|
int sock_flags; | int sock_flags; |
if ((sock_flags = fcntl(_rep->socket, F_GETFD, 0)) < 0) | if ((sock_flags = fcntl(_rep->socket, F_GETFD, 0)) < 0) |
{ | { |
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1, |
"HTTPAcceptor::_bind: fcntl(F_GETFD) failed"); | "HTTPAcceptor::_bind: fcntl(F_GETFD) failed"); |
} | } |
else | else |
|
|
sock_flags |= FD_CLOEXEC; | sock_flags |= FD_CLOEXEC; |
if (fcntl(_rep->socket, F_SETFD, sock_flags) < 0) | if (fcntl(_rep->socket, F_SETFD, sock_flags) < 0) |
{ | { |
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1, |
"HTTPAcceptor::_bind: fcntl(F_SETFD) failed"); | "HTTPAcceptor::_bind: fcntl(F_SETFD) failed"); |
} | } |
} | } |
|
|
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; |
MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_SET_SOCKET_OPTION", | MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_SET_SOCKET_OPTION", |
"Failed to 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); | throw BindFailedException(parms); |
} | } |
| |
|
|
// | // |
if (::bind(_rep->socket, _rep->address, _rep->address_size) < 0) | if (::bind(_rep->socket, _rep->address, _rep->address_size) < 0) |
{ | { |
Socket::close(_rep->socket); |
MessageLoaderParms parms( |
|
"Common.HTTPAcceptor.FAILED_BIND_SOCKET_DETAIL", |
|
"Failed to bind socket on port $0: $1.", |
|
_portNumber, PEGASUS_SYSTEM_NETWORK_ERRORMSG_NLS); |
|
|
delete _rep; | delete _rep; |
_rep = 0; | _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); | throw BindFailedException(parms); |
} | } |
| |
|
|
// | // |
#if !defined(PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET) && \ | #if !defined(PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET) && \ |
(defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) || \ | (defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) || \ |
defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM)) |
defined(PEGASUS_OS_ZOS) || \ |
|
defined(PEGASUS_OS_PASE)) |
if (_connectionType == LOCAL_CONNECTION) | if (_connectionType == LOCAL_CONNECTION) |
{ | { |
if (::chmod(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH, | if (::chmod(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH, |
|
|
S_IRGRP | S_IWGRP | S_IXGRP | | S_IRGRP | S_IWGRP | S_IXGRP | |
S_IROTH | S_IWOTH | S_IXOTH ) < 0 ) | S_IROTH | S_IWOTH | S_IXOTH ) < 0 ) |
{ | { |
Socket::close(_rep->socket); |
MessageLoaderParms parms( |
|
"Common.HTTPAcceptor.FAILED_SET_LDS_FILE_OPTION", |
|
"Failed to set permission on local domain socket $0: $1.", |
|
PEGASUS_LOCAL_DOMAIN_SOCKET_PATH, |
|
PEGASUS_SYSTEM_ERRORMSG_NLS ); |
|
|
delete _rep; | delete _rep; |
_rep = 0; | _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 set domain socket " |
|
"permissions."); |
|
throw BindFailedException(parms); | throw BindFailedException(parms); |
} | } |
} | } |
|
|
| |
//int const _maxConnectionQueueLength = 15; | //int const _maxConnectionQueueLength = 15; |
| |
if (listen(_rep->socket, _maxConnectionQueueLength) < 0) |
if (::listen(_rep->socket, _maxConnectionQueueLength) < 0) |
{ | { |
Socket::close(_rep->socket); |
MessageLoaderParms parms( |
|
"Common.HTTPAcceptor.FAILED_LISTEN_SOCKET", |
|
"Failed to listen on socket $0: $1.", |
|
(int)_rep->socket,PEGASUS_SYSTEM_NETWORK_ERRORMSG_NLS ); |
|
|
delete _rep; | delete _rep; |
_rep = 0; | _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(1)."); |
|
throw BindFailedException(parms); | throw BindFailedException(parms); |
} | } |
| |
|
|
_rep->socket, | _rep->socket, |
SocketMessage::READ | SocketMessage::EXCEPTION, | SocketMessage::READ | SocketMessage::EXCEPTION, |
getQueueId(), | getQueueId(), |
Monitor::ACCEPTOR))) |
MonitorEntry::TYPE_ACCEPTOR))) |
{ | { |
Socket::close(_rep->socket); |
|
delete _rep; | delete _rep; |
_rep = 0; | _rep = 0; |
MessageLoaderParms parms( | MessageLoaderParms parms( |
"Common.HTTPAcceptor.FAILED_SOLICIT_SOCKET_MESSAGES", | "Common.HTTPAcceptor.FAILED_SOLICIT_SOCKET_MESSAGES", |
"Failed to solicit socket messaeges"); | "Failed to solicit socket messaeges"); |
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"HTTPAcceptor::_bind: Failed to solicit socket messages(2)."); |
|
throw BindFailedException(parms); | throw BindFailedException(parms); |
} | } |
} | } |
|
|
//_monitor->unsolicitSocketMessages(_rep->socket); | //_monitor->unsolicitSocketMessages(_rep->socket); |
| |
// close the socket | // close the socket |
Socket::close(_rep->socket); |
_rep->closeSocket(); |
// Unlink Local Domain Socket Bug# 3312 | // Unlink Local Domain Socket Bug# 3312 |
if (_connectionType == LOCAL_CONNECTION) | if (_connectionType == LOCAL_CONNECTION) |
{ | { |
#ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET | #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET |
PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2, |
PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL3, |
"HTTPAcceptor::closeConnectionSocket Unlinking local " | "HTTPAcceptor::closeConnectionSocket Unlinking local " |
"connection."); | "connection."); |
::unlink( | ::unlink( |
reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path); |
reinterpret_cast<struct sockaddr_un*> |
|
(_rep->address)->sun_path); |
#else | #else |
PEGASUS_ASSERT(false); | PEGASUS_ASSERT(false); |
#endif | #endif |
|
|
} | } |
else | else |
{ | { |
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2, |
"HTTPAcceptor::closeConnectionSocket failure _rep is null."); | "HTTPAcceptor::closeConnectionSocket failure _rep is null."); |
} | } |
} | } |
|
|
} | } |
else | else |
{ | { |
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1, |
"HTTPAcceptor::reopenConnectionSocket failure _rep is null."); | "HTTPAcceptor::reopenConnectionSocket failure _rep is null."); |
} | } |
} | } |
|
|
// unregister the socket | // unregister the socket |
_monitor->unsolicitSocketMessages(_rep->socket); | _monitor->unsolicitSocketMessages(_rep->socket); |
// close the socket | // close the socket |
Socket::close(_rep->socket); |
_rep->closeSocket(); |
// Unlink Local Domain Socket Bug# 3312 |
// Unlink Local Domain Socket |
if (_connectionType == LOCAL_CONNECTION) | if (_connectionType == LOCAL_CONNECTION) |
{ | { |
#ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET | #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET |
PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2, |
PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL3, |
"HTTPAcceptor::reconnectConnectionSocket Unlinking local " | "HTTPAcceptor::reconnectConnectionSocket Unlinking local " |
"connection." ); | "connection." ); |
::unlink( | ::unlink( |
reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path); |
reinterpret_cast<struct sockaddr_un*>( |
|
_rep->address)->sun_path); |
#else | #else |
PEGASUS_ASSERT(false); | PEGASUS_ASSERT(false); |
#endif | #endif |
|
|
} | } |
else | else |
{ | { |
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1, |
"HTTPAcceptor::reconnectConnectionSocket failure _rep is null."); | "HTTPAcceptor::reconnectConnectionSocket failure _rep is null."); |
} | } |
} | } |
|
|
if (_rep) | if (_rep) |
{ | { |
AutoMutex autoMut(_rep->_connection_mut); | AutoMutex autoMut(_rep->_connection_mut); |
if (_rep->connections.size() > 0) |
for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++) |
|
{ |
|
HTTPConnection* connection = _rep->connections[i]; |
|
if (connection->isResponsePending()) |
{ | { |
HTTPConnection* connection = _rep->connections[0]; |
count++; |
count = connection->getRequestCount(); |
} |
} | } |
} | } |
return count; | return count; |
|
|
| |
void HTTPAcceptor::setSocketWriteTimeout(Uint32 socketWriteTimeout) | void HTTPAcceptor::setSocketWriteTimeout(Uint32 socketWriteTimeout) |
{ | { |
|
#ifndef PEGASUS_INTEGERS_BOUNDARY_ALIGNED |
|
AutoMutex lock(_socketWriteTimeoutMutex); |
|
#endif |
_socketWriteTimeout = socketWriteTimeout; | _socketWriteTimeout = socketWriteTimeout; |
} | } |
| |
|
|
if (_rep) | if (_rep) |
{ | { |
_portNumber = 0; | _portNumber = 0; |
Socket::close(_rep->socket); |
_rep->closeSocket(); |
| |
if (_connectionType == LOCAL_CONNECTION) | if (_connectionType == LOCAL_CONNECTION) |
{ | { |
#ifndef PEGASUS_DISABLE_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 |
PEGASUS_ASSERT(false); | PEGASUS_ASSERT(false); |
#endif | #endif |
|
|
} | } |
else | else |
{ | { |
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL1, |
"HTTPAcceptor::unbind failure _rep is null." ); | "HTTPAcceptor::unbind failure _rep is null." ); |
} | } |
} | } |
|
|
#endif | #endif |
} | } |
| |
SocketHandle socket; |
// It is not necessary to handle EINTR errors from this accept() call. |
#ifdef PEGASUS_OS_TYPE_WINDOWS |
// An EINTR error should not occur on a non-blocking socket. If the |
socket = accept(_rep->socket, accept_address, &address_size); |
// listen socket is blocking and EINTR occurs, the new socket connection |
#else |
// is not accepted here. |
while ( |
|
((socket = accept(_rep->socket, accept_address, &address_size)) == -1) |
// EAGAIN errors are also not handled here. An EAGAIN error should not |
&& (errno == EINTR)) |
// occur after select() indicates that the listen socket is available for |
; |
// reading. If the accept() fails with an EAGAIN error code, a new |
#endif |
// connection is not accepted here. |
|
|
|
SocketHandle socket = accept(_rep->socket, accept_address, &address_size); |
| |
if (socket == PEGASUS_SOCKET_ERROR) | if (socket == PEGASUS_SOCKET_ERROR) |
{ | { |
|
|
// TCPIP is down reconnect this acceptor | // TCPIP is down reconnect this acceptor |
if (getSocketError() == PEGASUS_NETWORK_TCPIP_STOPPED) | if (getSocketError() == PEGASUS_NETWORK_TCPIP_STOPPED) |
{ | { |
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1, |
"Socket has an IO error. TCP/IP down. Try to reconnect."); | "Socket has an IO error. TCP/IP down. Try to reconnect."); |
| |
reconnectConnectionSocket(); | reconnectConnectionSocket(); |
| |
return; | return; |
} | } |
|
PEG_TRACE(( |
|
TRC_DISCARDED_DATA, |
|
Tracer::LEVEL1, |
|
"HTTPAcceptor: accept() failed. errno: %u", |
|
errno)); |
|
return; |
|
} |
|
|
|
// Use an AutoPtr to ensure the socket handle is closed on exception |
|
AutoPtr<SocketHandle, CloseSocketHandle> socketPtr(&socket); |
|
|
|
#ifndef PEGASUS_OS_TYPE_WINDOWS |
|
// We need to ensure that the socket number is not higher than |
|
// what fits into FD_SETSIZE, because we else won't be able to select on it |
|
// and won't ever communicate correct on that socket. |
|
if (socket >= FD_SETSIZE) |
|
{ |
|
// the remote connection is invalid, destroy client address. |
|
delete accept_address; |
| |
Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE, |
PEG_TRACE( |
"HTTPAcceptor - accept() failure. errno: $0", errno); |
(TRC_DISCARDED_DATA, |
|
Tracer::LEVEL1, |
|
"HTTPAcceptor out of available sockets." |
|
"accept() returned too large socket number %u." |
|
"Closing connection to the new client.", |
|
socket)); |
| |
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"HTTPAcceptor: accept() failed"); |
|
return; | return; |
} | } |
|
#endif |
| |
String ipAddress; | String ipAddress; |
| |
|
|
#ifdef PEGASUS_ENABLE_IPV6 | #ifdef PEGASUS_ENABLE_IPV6 |
char ipBuffer[PEGASUS_INET6_ADDRSTR_LEN]; | char ipBuffer[PEGASUS_INET6_ADDRSTR_LEN]; |
int rc; | int rc; |
while ((rc = getnameinfo(accept_address, address_size, ipBuffer, |
if ((rc = System::getNameInfo(accept_address, |
PEGASUS_INET6_ADDRSTR_LEN, 0, 0, NI_NUMERICHOST)) == EAI_AGAIN) |
address_size, |
; |
ipBuffer, |
if (rc) |
PEGASUS_INET6_ADDRSTR_LEN, |
{ |
0, |
Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE, |
0, |
"HTTPAcceptor - getnameinfo() failure. rc: $0", rc); |
NI_NUMERICHOST))) |
|
{ |
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
PEG_TRACE(( |
"HTTPAcceptor: getnameinfo() failed"); |
TRC_DISCARDED_DATA, |
|
Tracer::LEVEL1, |
|
"HTTPAcceptor: getnameinfo() failed. rc: %d", |
|
rc)); |
delete accept_address; | delete accept_address; |
Socket::close(socket); |
|
return; | return; |
} | } |
ipAddress = ipBuffer; | ipAddress = ipBuffer; |
|
|
int sock_flags; | int sock_flags; |
if ((sock_flags = fcntl(socket, F_GETFD, 0)) < 0) | if ((sock_flags = fcntl(socket, F_GETFD, 0)) < 0) |
{ | { |
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1, |
"HTTPAcceptor: fcntl(F_GETFD) failed"); | "HTTPAcceptor: fcntl(F_GETFD) failed"); |
} | } |
else | else |
|
|
sock_flags |= FD_CLOEXEC; | sock_flags |= FD_CLOEXEC; |
if (fcntl(socket, F_SETFD, sock_flags) < 0) | if (fcntl(socket, F_SETFD, sock_flags) < 0) |
{ | { |
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1, |
"HTTPAcceptor: fcntl(F_SETFD) failed"); | "HTTPAcceptor: fcntl(F_SETFD) failed"); |
} | } |
} | } |
#endif | #endif |
| |
| |
PEG_LOGGER_TRACE((Logger::STANDARD_LOG, System::CIMSERVER, 0, |
PEG_TRACE(( |
"HTTPAcceptor - accept() success. Socket: $1" ,socket)); |
TRC_HTTP, |
|
Tracer::LEVEL3, |
|
"HTTPAcceptor - accept() success. Socket: %u", |
|
socket)); |
| |
SharedPtr<MP_Socket> mp_socket(new MP_Socket( | SharedPtr<MP_Socket> mp_socket(new MP_Socket( |
socket, _sslcontext, _sslContextObjectLock, ipAddress)); | socket, _sslcontext, _sslContextObjectLock, ipAddress)); |
|
// mp_socket now has responsibility for closing the socket handle |
|
socketPtr.release(); |
| |
|
mp_socket->disableBlocking(); |
|
|
|
{ |
|
#ifndef PEGASUS_INTEGERS_BOUNDARY_ALIGNED |
|
AutoMutex lock(_socketWriteTimeoutMutex); |
|
#endif |
mp_socket->setSocketWriteTimeout(_socketWriteTimeout); | mp_socket->setSocketWriteTimeout(_socketWriteTimeout); |
|
} |
| |
// Perform the SSL handshake, if applicable. Make the socket non-blocking |
// Perform the SSL handshake, if applicable. |
// 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(); | Sint32 socketAcceptStatus = mp_socket->accept(); |
mp_socket->enableBlocking(); |
|
| |
if (socketAcceptStatus < 0) | if (socketAcceptStatus < 0) |
{ | { |
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1, |
"HTTPAcceptor: SSL_accept() failed"); | "HTTPAcceptor: SSL_accept() failed"); |
mp_socket->close(); |
|
return; | return; |
} | } |
| |
// Create a new connection and add it to the connection list: | // Create a new connection and add it to the connection list: |
| |
HTTPConnection* connection = new HTTPConnection(_monitor, mp_socket, |
AutoPtr<HTTPConnection> connection(new HTTPConnection( |
ipAddress, this, static_cast<MessageQueue *>(_outputMessageQueue)); |
_monitor, |
|
mp_socket, |
|
ipAddress, |
|
this, |
|
_outputMessageQueue)); |
|
|
|
if (HTTPConnection::getIdleConnectionTimeout()) |
|
{ |
|
Time::gettimeofday(&connection->_idleStartTime); |
|
} |
| |
if (socketAcceptStatus == 0) | if (socketAcceptStatus == 0) |
{ | { |
PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2, |
PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL1, |
"HTTPAcceptor: SSL_accept() pending"); | "HTTPAcceptor: SSL_accept() pending"); |
connection->_acceptPending = true; | connection->_acceptPending = true; |
|
Time::gettimeofday(&connection->_acceptPendingStartTime); |
} | } |
| |
// Solicit events on this new connection's socket: | // Solicit events on this new connection's socket: |
|
|
if (-1 == (index = _monitor->solicitSocketMessages( | if (-1 == (index = _monitor->solicitSocketMessages( |
connection->getSocket(), | connection->getSocket(), |
SocketMessage::READ | SocketMessage::EXCEPTION, | SocketMessage::READ | SocketMessage::EXCEPTION, |
connection->getQueueId(), Monitor::CONNECTION)) ) |
connection->getQueueId(), MonitorEntry::TYPE_CONNECTION)) ) |
{ | { |
// ATTN-DE-P2-2003100503::TODO::Need to enhance code to return |
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1, |
// an error message to Client application. |
|
PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"HTTPAcceptor::_acceptConnection: Attempt to allocate entry in " | "HTTPAcceptor::_acceptConnection: Attempt to allocate entry in " |
"_entries table failed."); | "_entries table failed."); |
delete connection; |
|
Socket::close(socket); |
|
return; | return; |
} | } |
| |
// Save the socket for cleanup later: |
|
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.get()); |
|
connection.release(); |
} | } |
| |
PEGASUS_NAMESPACE_END | PEGASUS_NAMESPACE_END |