version 1.26, 2006/11/10 18:14:58
|
version 1.42, 2014/11/10 16:16:47
|
|
|
//%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, |
|
// and/or sell copies of the Software, and to permit persons to whom the |
|
// Software is furnished to do so, subject to the following conditions: |
|
// |
|
// The above copyright notice and this permission notice shall be included |
|
// in all copies or substantial portions of the Software. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
|
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
|
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 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. |
// | // |
// Permission is hereby granted, free of charge, to any person obtaining a copy |
////////////////////////////////////////////////////////////////////////// |
// of this software and associated documentation files (the "Software"), to |
|
// deal in the Software without restriction, including without limitation the |
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
|
// sell copies of the Software, and to permit persons to whom the Software is |
|
// furnished to do so, subject to the following conditions: |
|
// |
|
// THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN |
|
// ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED |
|
// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT |
|
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
|
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
|
// 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. |
|
// |
|
//============================================================================== |
|
// | // |
//%///////////////////////////////////////////////////////////////////////////// | //%///////////////////////////////////////////////////////////////////////////// |
| |
|
|
#include <Pegasus/Common/Sharable.h> | #include <Pegasus/Common/Sharable.h> |
#include <Pegasus/Common/Logger.h> | #include <Pegasus/Common/Logger.h> |
#include <Pegasus/Common/System.h> | #include <Pegasus/Common/System.h> |
|
#include <Pegasus/Common/Tracer.h> |
|
#include <Pegasus/Common/Threads.h> |
|
#include <Pegasus/Common/Mutex.h> |
| |
//------------------------------------------------------------------------------ |
PEGASUS_NAMESPACE_BEGIN |
// |
|
// PEGASUS_RETRY_SYSTEM_CALL() |
#ifdef PEGASUS_OS_TYPE_WINDOWS |
// |
static Uint32 _socketInterfaceRefCount = 0; |
// This macro repeats the given system call until it returns something |
static Mutex _socketInterfaceRefCountLock; |
// other than EINTR. |
#endif |
// |
|
//------------------------------------------------------------------------------ |
|
| |
|
Boolean Socket::timedConnect( |
|
SocketHandle socket, |
|
sockaddr* address, |
|
int addressLength, |
|
Uint32 timeoutMilliseconds) |
|
{ |
|
int connectResult; |
#ifdef PEGASUS_OS_TYPE_WINDOWS | #ifdef PEGASUS_OS_TYPE_WINDOWS |
# define PEGASUS_RETRY_SYSTEM_CALL(EXPR, RESULT) RESULT = EXPR |
connectResult = ::connect(socket, address, addressLength); |
#else | #else |
# define PEGASUS_RETRY_SYSTEM_CALL(EXPR, RESULT) \ |
Uint32 maxConnectAttempts = 100; |
while (((RESULT = (EXPR)) == -1) && (errno == EINTR)) |
// Retry the connect() until it succeeds or it fails with an error other |
|
// than EINTR, EAGAIN (for Linux), or ECONNREFUSED (for HP-UX and z/OS). |
|
while (((connectResult = ::connect(socket, address, addressLength)) == -1) |
|
&& (maxConnectAttempts-- > 0) |
|
&& ((errno == EINTR) || (errno == EAGAIN) || |
|
(errno == ECONNREFUSED))) |
|
{ |
|
Threads::sleep(1); |
|
} |
#endif | #endif |
| |
PEGASUS_NAMESPACE_BEGIN |
if (connectResult == 0) |
|
{ |
|
return true; |
|
} |
| |
static Uint32 _socketInterfaceRefCount = 0; |
if (getSocketError() == PEGASUS_NETWORK_EINPROGRESS) |
|
{ |
|
PEG_TRACE((TRC_HTTP, Tracer::LEVEL4, |
|
"Connection to server in progress. Waiting up to %u milliseconds " |
|
"for the socket to become connected.", |
|
timeoutMilliseconds)); |
|
|
|
fd_set fdwrite; |
|
FD_ZERO(&fdwrite); |
|
FD_SET(socket, &fdwrite); |
|
struct timeval timeoutValue = |
|
{ timeoutMilliseconds/1000, timeoutMilliseconds%1000*1000 }; |
|
int selectResult = -1; |
|
|
|
#ifdef PEGASUS_OS_TYPE_WINDOWS |
|
PEGASUS_RETRY_SYSTEM_CALL( |
|
select(FD_SETSIZE, NULL, &fdwrite, &fdwrite, &timeoutValue), |
|
selectResult); |
|
#else |
|
PEGASUS_RETRY_SYSTEM_CALL( |
|
select(FD_SETSIZE, NULL, &fdwrite, NULL, &timeoutValue), |
|
selectResult); |
|
#endif |
|
if (selectResult == 0) |
|
{ |
|
PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL1, |
|
"select() timed out waiting for the socket connection to be " |
|
"established."); |
|
return false; |
|
} |
|
else if (selectResult > 0) |
|
{ |
|
int optval; |
|
SocketLength optlen = sizeof(int); |
|
getsockopt(socket, SOL_SOCKET, SO_ERROR, (char*)&optval, &optlen); |
|
if (optval == 0) |
|
{ |
|
PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL4, |
|
"Connection with server established."); |
|
return true; |
|
} |
|
else |
|
{ |
|
PEG_TRACE((TRC_HTTP, Tracer::LEVEL1, |
|
"Did not connect, getsockopt() returned optval = %d", |
|
optval)); |
|
return false; |
|
} |
|
} |
|
else |
|
{ |
|
PEG_TRACE((TRC_HTTP, Tracer::LEVEL1, |
|
"select() returned error code %d", |
|
getSocketError())); |
|
return false; |
|
} |
|
} |
|
|
|
PEG_TRACE((TRC_HTTP, Tracer::LEVEL1, |
|
"connect() returned error code %d", |
|
getSocketError())); |
|
return false; |
|
} |
| |
Sint32 Socket::read(SocketHandle socket, void* ptr, Uint32 size) | Sint32 Socket::read(SocketHandle socket, void* ptr, Uint32 size) |
{ | { |
|
|
#endif | #endif |
} | } |
| |
|
Sint32 Socket::peek(SocketHandle socket, void* ptr, Uint32 size) |
|
{ |
|
#ifdef PEGASUS_OS_TYPE_WINDOWS |
|
return ::recv(socket, (char*)ptr, size, MSG_PEEK); |
|
#else |
|
int status; |
|
PEGASUS_RETRY_SYSTEM_CALL(::recv(socket, (char*)ptr, size, MSG_PEEK), |
|
status); |
|
return status; |
|
#endif |
|
} |
|
|
Sint32 Socket::write(SocketHandle socket, const void* ptr, Uint32 size) | Sint32 Socket::write(SocketHandle socket, const void* ptr, Uint32 size) |
{ | { |
#ifdef PEGASUS_OS_TYPE_WINDOWS | #ifdef PEGASUS_OS_TYPE_WINDOWS |
|
|
} | } |
} | } |
| |
void Socket::close(SocketHandle socket) |
void Socket::close(SocketHandle& socket) |
{ | { |
if (socket != -1) |
if (socket != PEGASUS_INVALID_SOCKET) |
{ | { |
#ifdef PEGASUS_OS_TYPE_WINDOWS | #ifdef PEGASUS_OS_TYPE_WINDOWS |
if (!closesocket(socket)) | if (!closesocket(socket)) |
socket = -1; |
{ |
|
socket = PEGASUS_INVALID_SOCKET; |
|
} |
#else | #else |
int status; | int status; |
PEGASUS_RETRY_SYSTEM_CALL(::close(socket), status); | PEGASUS_RETRY_SYSTEM_CALL(::close(socket), status); |
| |
if (status == 0) | if (status == 0) |
socket = -1; |
|
#endif |
|
} |
|
} |
|
|
|
void Socket::enableBlocking(SocketHandle socket) |
|
{ | { |
#ifdef PEGASUS_OS_TYPE_WINDOWS |
socket = PEGASUS_INVALID_SOCKET; |
unsigned long flag = 0; |
} |
ioctlsocket(socket, FIONBIO, &flag); |
|
#else |
|
int flags = fcntl(socket, F_GETFL, 0); |
|
flags &= ~O_NONBLOCK; |
|
fcntl(socket, F_SETFL, flags); |
|
#endif | #endif |
} | } |
|
} |
| |
void Socket::disableBlocking(SocketHandle socket) | void Socket::disableBlocking(SocketHandle socket) |
{ | { |
#ifdef PEGASUS_OS_TYPE_WINDOWS | #ifdef PEGASUS_OS_TYPE_WINDOWS |
unsigned long flag = 1; |
unsigned long flag = 1; // Use "flag = 0" to enable blocking |
ioctlsocket(socket, FIONBIO, &flag); | ioctlsocket(socket, FIONBIO, &flag); |
|
#elif PEGASUS_OS_VMS |
|
int flag=1; // Use "flag = 0" to enable blocking |
|
ioctl(socket, FIONBIO, &flag); |
#else | #else |
int flags = fcntl(socket, F_GETFL, 0); | int flags = fcntl(socket, F_GETFL, 0); |
flags |= O_NONBLOCK; |
flags |= O_NONBLOCK; // Use "flags &= ~O_NONBLOCK" to enable blocking |
fcntl(socket, F_SETFL, flags); | fcntl(socket, F_SETFL, flags); |
#endif | #endif |
} | } |
|
|
void Socket::initializeInterface() | void Socket::initializeInterface() |
{ | { |
#ifdef PEGASUS_OS_TYPE_WINDOWS | #ifdef PEGASUS_OS_TYPE_WINDOWS |
|
AutoMutex mtx(_socketInterfaceRefCountLock); |
if (_socketInterfaceRefCount == 0) | if (_socketInterfaceRefCount == 0) |
{ | { |
WSADATA tmp; | WSADATA tmp; |
| |
if (WSAStartup(0x202, &tmp) == SOCKET_ERROR) |
int err = WSAStartup(0x202, &tmp); |
WSACleanup(); |
if (err != 0) |
|
{ |
|
throw Exception(MessageLoaderParms( |
|
"Common.Socket.WSASTARTUP_FAILED.WINDOWS", |
|
"WSAStartup failed with error $0.", |
|
err)); |
|
} |
} | } |
| |
_socketInterfaceRefCount++; | _socketInterfaceRefCount++; |
|
|
void Socket::uninitializeInterface() | void Socket::uninitializeInterface() |
{ | { |
#ifdef PEGASUS_OS_TYPE_WINDOWS | #ifdef PEGASUS_OS_TYPE_WINDOWS |
|
AutoMutex mtx(_socketInterfaceRefCountLock); |
_socketInterfaceRefCount--; | _socketInterfaceRefCount--; |
| |
if (_socketInterfaceRefCount == 0) | if (_socketInterfaceRefCount == 0) |
|
|
int opt = 1; | int opt = 1; |
setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*)&opt, sizeof(opt)); | setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*)&opt, sizeof(opt)); |
} | } |
//------------------------------------------------------------------------------ |
|
// |
#ifdef PEGASUS_OS_ZOS |
// _setInformIfNewTCPIP() |
|
// |
|
//------------------------------------------------------------------------------ |
|
inline void _setInformIfNewTCPIP(SocketHandle socket) | inline void _setInformIfNewTCPIP(SocketHandle socket) |
{ | { |
#ifdef PEGASUS_OS_ZOS |
|
// This function enables the notification of the CIM Server that a new | // This function enables the notification of the CIM Server that a new |
// TCPIP transport layer is active. This is needed to be aware of a | // TCPIP transport layer is active. This is needed to be aware of a |
// restart of the transport layer. When this option is in effect, | // restart of the transport layer. When this option is in effect, |
|
|
SO_EioIfNewTP, | SO_EioIfNewTP, |
(char*)&NewTcpipOn, | (char*)&NewTcpipOn, |
sizeof(NewTcpipOn)); | sizeof(NewTcpipOn)); |
#endif |
|
} | } |
|
#else |
|
inline void _setInformIfNewTCPIP(SocketHandle) |
|
{ |
|
} |
|
#endif |
| |
| |
SocketHandle Socket::createSocket(int domain, int type, int protocol) | SocketHandle Socket::createSocket(int domain, int type, int protocol) |
|
|
return socket(domain,type,protocol); | return socket(domain,type,protocol); |
} | } |
| |
|
#ifdef PEGASUS_OS_ZOS |
bool sendTcpipMsg = true; | bool sendTcpipMsg = true; |
|
#endif |
| |
while (1) | while (1) |
{ | { |
newSocket = socket(domain,type,protocol); | newSocket = socket(domain,type,protocol); |
| |
|
if ((newSocket != PEGASUS_INVALID_SOCKET) || |
|
(getSocketError() != PEGASUS_NETWORK_TRYAGAIN)) |
|
{ |
|
break; |
|
} |
|
|
|
#ifdef PEGASUS_OS_ZOS |
// The program should wait for transport layer to become ready. | // The program should wait for transport layer to become ready. |
| |
if (newSocket == PEGASUS_INVALID_SOCKET && |
|
getSocketError() == PEGASUS_NETWORK_TCPIP_TRYAGAIN ) |
|
{ |
|
if (sendTcpipMsg) | if (sendTcpipMsg) |
{ | { |
Logger::put_l( | Logger::put_l( |
Logger::STANDARD_LOG, System::CIMSERVER, Logger::INFORMATION, | Logger::STANDARD_LOG, System::CIMSERVER, Logger::INFORMATION, |
|
MessageLoaderParms( |
"Common.Socket.WAIT_FOR_TCPIP", | "Common.Socket.WAIT_FOR_TCPIP", |
"TCP/IP temporary unavailable."); |
"TCP/IP temporary unavailable.")); |
sendTcpipMsg=false; | sendTcpipMsg=false; |
} | } |
| |
System::sleep(30); | System::sleep(30); |
continue; |
#endif |
} |
|
else |
|
{ |
|
break; |
|
} |
|
} // wait for the transport layer become ready. | } // wait for the transport layer become ready. |
| |
// Is the socket in an unrecoverable error ? | // Is the socket in an unrecoverable error ? |