version 1.9.4.7, 2003/08/13 19:39:50
|
version 1.35, 2008/09/30 18:21:35
|
|
|
//%///////////////////////////////////////////////////////////////////////////// |
//%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: |
|
// |
|
//%///////////////////////////////////////////////////////////////////////////// | //%///////////////////////////////////////////////////////////////////////////// |
| |
#include "Socket.h" | #include "Socket.h" |
|
#include "Network.h" |
#ifdef PEGASUS_OS_TYPE_WINDOWS |
|
#include <windows.h> |
|
# ifndef _WINSOCKAPI_ |
|
# include <winsock2.h> |
|
# endif |
|
#else |
|
# include <cctype> | # include <cctype> |
#ifndef PEGASUS_OS_OS400 |
#include <cstring> |
# include <unistd.h> |
|
#else |
|
# include <unistd.cleinc> |
|
#endif |
|
# include <string.h> // added by rk for memcpy |
|
# include <cstdlib> |
|
# include <errno.h> |
|
# include <fcntl.h> |
|
# include <netdb.h> |
|
# include <netinet/in.h> |
|
# include <arpa/inet.h> |
|
# include <sys/socket.h> |
|
# include <errno.h> |
|
#endif |
|
|
|
#include <Pegasus/Common/Sharable.h> | #include <Pegasus/Common/Sharable.h> |
|
#include <Pegasus/Common/Logger.h> |
|
#include <Pegasus/Common/System.h> |
|
#include <Pegasus/Common/Tracer.h> |
|
#include <Pegasus/Common/Threads.h> |
|
|
PEGASUS_NAMESPACE_BEGIN | PEGASUS_NAMESPACE_BEGIN |
| |
static Uint32 _socketInterfaceRefCount = 0; | static Uint32 _socketInterfaceRefCount = 0; |
| |
Sint32 Socket::read(Sint32 socket, void* ptr, Uint32 size) |
Boolean Socket::timedConnect( |
|
SocketHandle socket, |
|
sockaddr* address, |
|
int addressLength, |
|
Uint32 timeoutMilliseconds) |
{ | { |
|
int connectResult; |
#ifdef PEGASUS_OS_TYPE_WINDOWS | #ifdef PEGASUS_OS_TYPE_WINDOWS |
return ::recv(socket, (char*)ptr, size, 0); |
connectResult = ::connect(socket, address, addressLength); |
#elif defined(PEGASUS_OS_ZOS) |
|
int i=::read(socket, (char*)ptr, size); |
|
__atoe_l((char *)ptr,size); |
|
return i; |
|
#else |
|
|
|
#if defined (__GNUC__) |
|
int ccode = TEMP_FAILURE_RETRY(::read(socket, (char*)ptr, size)); |
|
return ccode; |
|
#else | #else |
return ::read(socket, (char*)ptr, size); |
Boolean connectionAlreadyRefused = false; |
#endif |
Uint32 maxConnectAttempts = 100; |
#endif |
// Retry the connect() until it succeeds or it fails with an error other |
} |
// than EINTR, EAGAIN (for Linux), or the first ECONNREFUSED (for HP-UX). |
|
while (((connectResult = ::connect(socket, address, addressLength)) == -1) |
Sint32 Socket::write(Sint32 socket, const void* ptr, Uint32 size) |
&& (maxConnectAttempts-- > 0) |
|
&& ((errno == EINTR) || (errno == EAGAIN) || |
|
((errno == ECONNREFUSED) && !connectionAlreadyRefused))) |
{ | { |
#ifdef PEGASUS_OS_TYPE_WINDOWS |
if (errno == ECONNREFUSED) |
return ::send(socket, (const char*)ptr, size, 0); |
|
#elif defined(PEGASUS_OS_ZOS) |
|
char * ptr2 = (char *)malloc(size); |
|
int i; |
|
memcpy(ptr2,ptr,size); |
|
__etoa_l(ptr2,size); |
|
i = ::write(socket, ptr2, size); |
|
free(ptr2); |
|
return i; |
|
#else |
|
#if (__GNUC__) |
|
int ccode = TEMP_FAILURE_RETRY(::write(socket, (char*)ptr, size)); |
|
return ccode; |
|
#else |
|
return ::write(socket, (char*)ptr, size); |
|
#endif |
|
#endif |
|
} |
|
|
|
void Socket::close(Sint32 socket) |
|
{ |
|
#ifdef PEGASUS_OS_TYPE_WINDOWS |
|
closesocket(socket); |
|
#else |
|
#if (__GNUC__) |
|
TEMP_FAILURE_RETRY(::close(socket)); |
|
#else |
|
::close(socket); |
|
#endif |
|
#endif |
|
} |
|
|
|
int Socket::close2(Sint32 socket) |
|
{ |
|
#ifdef PEGASUS_OS_TYPE_WINDOWS |
|
return closesocket(socket); |
|
#else |
|
#if (__GNUC__) |
|
int ccode = TEMP_FAILURE_RETRY(::close(socket)); |
|
return ccode; |
|
#else |
|
return ::close(socket); |
|
#endif |
|
#endif |
|
} |
|
|
|
|
|
void Socket::enableBlocking(Sint32 socket) |
|
{ | { |
#ifdef PEGASUS_OS_TYPE_WINDOWS |
connectionAlreadyRefused = true; |
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 |
|
} | } |
|
Threads::sleep(1); |
int Socket::enableBlocking2(Sint32 socket) |
|
{ |
|
#ifdef PEGASUS_OS_TYPE_WINDOWS |
|
unsigned long flag = 0; |
|
return ioctlsocket(socket, FIONBIO, &flag); |
|
#else |
|
int flags = fcntl(socket, F_GETFL, 0); |
|
flags &= ~O_NONBLOCK; |
|
return fcntl(socket, F_SETFL, flags); |
|
#endif |
|
} | } |
|
|
void Socket::disableBlocking(Sint32 socket) |
|
{ |
|
#ifdef PEGASUS_OS_TYPE_WINDOWS |
|
unsigned long flag = 1; |
|
ioctlsocket(socket, FIONBIO, &flag); |
|
#else |
|
int flags = fcntl(socket, F_GETFL, 0); |
|
flags |= O_NONBLOCK; |
|
fcntl(socket, F_SETFL, flags); |
|
#endif | #endif |
} |
|
| |
int Socket::disableBlocking2(Sint32 socket) |
if (connectResult == 0) |
{ | { |
#ifdef PEGASUS_OS_TYPE_WINDOWS |
return true; |
unsigned long flag = 1; |
|
return ioctlsocket(socket, FIONBIO, &flag); |
|
#else |
|
int flags = fcntl(socket, F_GETFL, 0); |
|
flags |= O_NONBLOCK; |
|
return fcntl(socket, F_SETFL, flags); |
|
#endif |
|
} | } |
| |
void Socket::initializeInterface() |
if (getSocketError() == PEGASUS_NETWORK_EINPROGRESS) |
{ | { |
#ifdef PEGASUS_OS_TYPE_WINDOWS |
PEG_TRACE((TRC_HTTP, Tracer::LEVEL4, |
if (_socketInterfaceRefCount == 0) |
"Connection to server in progress. Waiting up to %u milliseconds " |
{ |
"for the socket to become connected.", |
WSADATA tmp; |
timeoutMilliseconds)); |
| |
if (WSAStartup(0x202, &tmp) == SOCKET_ERROR) |
fd_set fdwrite; |
WSACleanup(); |
FD_ZERO(&fdwrite); |
} |
FD_SET(socket, &fdwrite); |
|
struct timeval timeoutValue = |
_socketInterfaceRefCount++; |
{ timeoutMilliseconds/1000, timeoutMilliseconds%1000*1000 }; |
#endif |
int selectResult = -1; |
} |
|
| |
void Socket::uninitializeInterface() |
|
{ |
|
#ifdef PEGASUS_OS_TYPE_WINDOWS | #ifdef PEGASUS_OS_TYPE_WINDOWS |
_socketInterfaceRefCount--; |
PEGASUS_RETRY_SYSTEM_CALL( |
|
select(FD_SETSIZE, NULL, &fdwrite, &fdwrite, &timeoutValue), |
if (_socketInterfaceRefCount == 0) |
selectResult); |
WSACleanup(); |
|
#endif |
|
} |
|
|
|
|
|
class PEGASUS_COMMON_LINKAGE abstract_socket : public Sharable |
|
{ |
|
public: |
|
abstract_socket(void) { } |
|
virtual ~abstract_socket(void){ } |
|
|
|
virtual operator Sint32() const = 0; |
|
virtual int socket(int sock_type, int sock_style, int sock_protocol, void *ssl_context = 0) = 0; |
|
|
|
virtual Sint32 read(void* ptr, Uint32 size) = 0; |
|
virtual Sint32 write(const void* ptr, Uint32 size) = 0; |
|
virtual int close(void) = 0; |
|
virtual int enableBlocking(void) = 0; |
|
virtual int disableBlocking(void) = 0; |
|
|
|
virtual int getsockname (struct sockaddr *addr, size_t *length_ptr) = 0; |
|
virtual int bind (struct sockaddr *addr, size_t length) = 0; |
|
|
|
// change size_t to size_t for ZOS and windows |
|
virtual abstract_socket* accept(struct sockaddr *addr, size_t *length_ptr) = 0; |
|
virtual int connect (struct sockaddr *addr, size_t length) = 0; |
|
virtual int shutdown(int how) = 0; |
|
virtual int listen(int q) = 0; |
|
virtual int getpeername (struct sockaddr *addr, size_t *length_ptr) = 0; |
|
virtual int send (void *buffer, size_t size, int flags) = 0; |
|
virtual int recv (void *buffer, size_t size, int flags) = 0; |
|
virtual int sendto(void *buffer, size_t size, int flags, struct sockaddr *addr, size_t length) = 0; |
|
virtual int recvfrom(void *buffer, size_t size, int flags, struct sockaddr *addr, size_t *length_ptr) = 0; |
|
virtual int setsockopt (int level, int optname, void *optval, size_t optlen) = 0; |
|
virtual int getsockopt (int level, int optname, void *optval, size_t *optlen_ptr) = 0; |
|
|
|
virtual Boolean incompleteReadOccurred(Sint32 retCode) = 0; |
|
virtual Boolean is_secure(void) = 0; |
|
virtual void set_close_on_exec(void) = 0; |
|
virtual const char* get_err_string(void) = 0; |
|
|
|
private: |
|
|
|
abstract_socket(const abstract_socket& ); |
|
abstract_socket& operator=(const abstract_socket& ); |
|
}; |
|
|
|
|
|
|
|
/** |
|
* null socket class - |
|
* error handling rep for empty pegasus_sockets - |
|
* |
|
*/ |
|
class empty_socket_rep : public abstract_socket |
|
{ |
|
public: |
|
empty_socket_rep(void){ } |
|
~empty_socket_rep(void){ } |
|
operator Sint32() const { return -1 ;} |
|
|
|
int socket(int sock_type, int sock_style, |
|
int sock_protocol, void *ssl_context = 0) { return -1 ;} |
|
|
|
Sint32 read(void* ptr, Uint32 size) { return -1 ;} |
|
Sint32 write(const void* ptr, Uint32 size){ return -1 ;} |
|
int close(void){ return -1 ;} |
|
int enableBlocking(void){ return -1 ;} |
|
int disableBlocking(void){ return -1 ;} |
|
|
|
int getsockname (struct sockaddr *addr, size_t *length_ptr){ return -1 ;} |
|
int bind (struct sockaddr *addr, size_t length) { return -1;} |
|
|
|
// change size_t to size_t for ZOS and windows |
|
abstract_socket* accept(struct sockaddr *addr, size_t *length_ptr) { return 0;} |
|
int connect (struct sockaddr *addr, size_t length) { return -1;} |
|
int shutdown(int how) { return -1;} |
|
int listen(int queue_len ) { return -1;} |
|
int getpeername (struct sockaddr *addr, size_t *length_ptr) { return -1;} |
|
int send (void *buffer, size_t size, int flags) { return -1;} |
|
int recv (void *buffer, size_t size, int flags) { return -1;} |
|
int sendto(void *buffer, size_t size, int flags, struct sockaddr *addr, size_t length) { return -1;} |
|
int recvfrom(void *buffer, size_t size, int flags, struct sockaddr *addr, size_t *length_ptr) { return -1;} |
|
int setsockopt (int level, int optname, void *optval, size_t optlen) { return -1;} |
|
int getsockopt (int level, int optname, void *optval, size_t *optlen_ptr) { return -1;} |
|
|
|
Boolean incompleteReadOccurred(Sint32 retCode) { return false;} |
|
Boolean is_secure(void) { return false;} |
|
void set_close_on_exec(void) { } |
|
const char* get_err_string(void) |
|
{ |
|
static const char* msg = "Unsupported."; |
|
return msg; |
|
} |
|
private: |
|
empty_socket_rep(int); |
|
}; |
|
|
|
|
|
/** |
|
* internet socket class |
|
* designed to be overriden by ssl_socket_rep and file_socket_rep |
|
* |
|
*/ |
|
class bsd_socket_rep : public abstract_socket |
|
{ |
|
public: |
|
|
|
/** |
|
* map to pegasus_socket::sock_err |
|
*/ |
|
|
|
bsd_socket_rep(void); |
|
virtual ~bsd_socket_rep(void); |
|
// used to allow the accept method to work |
|
bsd_socket_rep(int sock); |
|
|
|
operator Sint32() const; |
|
int socket(int sock_type, int sock_style, int sock_protocol, void *ssl_context = 0); |
|
|
|
virtual Sint32 read(void* ptr, Uint32 size); |
|
virtual Sint32 write(const void* ptr, Uint32 size); |
|
virtual int close(void); |
|
int enableBlocking(void); |
|
int disableBlocking(void); |
|
|
|
virtual int getsockname (struct sockaddr *addr, size_t *length_ptr); |
|
virtual int bind (struct sockaddr *addr, size_t length); |
|
|
|
// change size_t to size_t for ZOS and windows |
|
virtual abstract_socket* accept(struct sockaddr *addr, size_t *length_ptr); |
|
virtual int connect (struct sockaddr *addr, size_t length); |
|
virtual int shutdown(int how); |
|
virtual int listen(int queue_len ); |
|
int getpeername (struct sockaddr *addr, size_t *length_ptr); |
|
virtual int send (void *buffer, size_t size, int flags); |
|
virtual int recv (void *buffer, size_t size, int flags); |
|
virtual int sendto(void *buffer, size_t size, int flags, struct sockaddr *addr, size_t length); |
|
virtual int recvfrom(void *buffer, size_t size, int flags, struct sockaddr *addr, size_t *length_ptr); |
|
int setsockopt (int level, int optname, void *optval, size_t optlen); |
|
int getsockopt (int level, int optname, void *optval, size_t *optlen_ptr); |
|
|
|
virtual Boolean incompleteReadOccurred(Sint32 retCode); |
|
virtual Boolean is_secure(void); |
|
void set_close_on_exec(void); |
|
virtual const char* get_err_string(void); |
|
|
|
private: |
|
|
|
|
|
bsd_socket_rep& operator=(const bsd_socket_rep& ); |
|
// use to perform one-time initializion and destruction |
|
struct _library_init |
|
{ |
|
_library_init(void) |
|
{ |
|
} |
|
~_library_init(void) |
|
{ |
|
} |
|
}; |
|
|
|
static struct _library_init _lib_init; |
|
|
|
int _socket; |
|
void *_ssl_context; |
|
int _errno; |
|
char _strerr[256]; |
|
}; |
|
|
|
|
|
|
|
|
|
#if defined(__GNUC__) && GCC_VERSION >= 30200 |
|
// TEMP_FAILURE_RETRY (expression) |
|
#else | #else |
|
PEGASUS_RETRY_SYSTEM_CALL( |
|
select(FD_SETSIZE, NULL, &fdwrite, NULL, &timeoutValue), |
|
selectResult); |
#endif | #endif |
|
if (selectResult == 0) |
|
|
/** |
|
* default constructor for an (uninitialized) bsd socket |
|
*/ |
|
bsd_socket_rep::bsd_socket_rep(void) |
|
:_errno(0) |
|
{ |
|
} |
|
|
|
bsd_socket_rep::bsd_socket_rep(int sock) |
|
: _socket(sock) |
|
{ |
|
} |
|
|
|
|
|
/** |
|
* default destructor for bsd_socket_rep |
|
* |
|
*/ |
|
bsd_socket_rep::~bsd_socket_rep(void) |
|
{ |
|
|
|
} |
|
|
|
int bsd_socket_rep::shutdown(int how) |
|
{ |
|
int ccode = ::shutdown(_socket, how); |
|
if(ccode == -1) |
|
_errno = errno; |
|
return ccode; |
|
} |
|
|
|
bsd_socket_rep::operator Sint32() const |
|
{ |
|
return (Sint32)_socket; |
|
} |
|
|
|
int bsd_socket_rep::socket(int sock_type, int sock_style, int sock_protocol, void *ssl_context) |
|
{ |
|
_socket = ::socket(sock_type, sock_style, sock_protocol); |
|
if(-1 == _socket ) |
|
{ |
|
_errno = errno; |
|
} |
|
return _socket; |
|
} |
|
|
|
|
|
Sint32 bsd_socket_rep::read(void* ptr, Uint32 size) |
|
{ |
|
int ccode = Socket::read(_socket, ptr, size); |
|
if(ccode == -1) |
|
_errno = errno; |
|
return ccode; |
|
} |
|
|
|
|
|
Sint32 bsd_socket_rep::write(const void* ptr, Uint32 size) |
|
{ |
|
int ccode = Socket::write(_socket, ptr, size); |
|
if(ccode == -1) |
|
errno = _errno; |
|
return ccode; |
|
} |
|
|
|
|
|
int bsd_socket_rep::close(void) |
|
{ | { |
int ccode; |
PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL1, |
|
"select() timed out waiting for the socket connection to be " |
shutdown(2); |
"established."); |
ccode = Socket::close2(_socket); |
return false; |
if(ccode == -1) |
|
_errno = errno; |
|
return ccode; |
|
} |
|
|
|
|
|
|
|
int bsd_socket_rep::enableBlocking(void) |
|
{ |
|
return Socket::enableBlocking2(_socket); |
|
} |
|
|
|
int bsd_socket_rep::disableBlocking(void) |
|
{ |
|
return Socket::disableBlocking2(_socket); |
|
} |
|
|
|
int bsd_socket_rep::getsockname (struct sockaddr *addr, size_t *length_ptr) |
|
{ |
|
int ccode = ::getsockname(_socket, addr, length_ptr); |
|
if(ccode == -1) |
|
_errno = errno; |
|
return ccode; |
|
} |
|
|
|
/** |
|
* default implementation allows reuseof address |
|
* sockaddr structure needs to be fully initialized or call will fail |
|
*/ |
|
int bsd_socket_rep::bind (struct sockaddr *addr, size_t length) |
|
{ |
|
int opt = 1; |
|
int ccode = setsockopt(SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)); |
|
if(ccode < 0) |
|
{ |
|
_errno = errno; |
|
return ccode; |
|
} |
|
return ::bind(_socket, addr, length); |
|
} | } |
|
else if (selectResult > 0) |
abstract_socket* bsd_socket_rep::accept(struct sockaddr *addr, size_t *length_ptr) |
|
{ | { |
int new_sock = ::accept(_socket, addr, length_ptr); |
int optval; |
if(new_sock == -1) |
SocketLength optlen = sizeof(int); |
{ |
getsockopt(socket, SOL_SOCKET, SO_ERROR, (char*)&optval, &optlen); |
_errno = errno; |
if (optval == 0) |
return 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; |
} | } |
|
|
bsd_socket_rep *rep = new bsd_socket_rep(new_sock); |
|
// set the close-on-exec flag |
|
rep->set_close_on_exec(); |
|
return rep; |
|
} | } |
|
else |
int bsd_socket_rep::connect (struct sockaddr *addr, size_t length) |
|
{ | { |
int ccode = ::connect(_socket, addr, length); |
PEG_TRACE((TRC_HTTP, Tracer::LEVEL1, |
if(ccode == -1) |
"select() returned error code %d", |
_errno = errno; |
getSocketError())); |
return ccode; |
return false; |
} |
|
|
|
|
|
int bsd_socket_rep::listen(int queue_len) |
|
{ |
|
int ccode = ::listen(_socket, queue_len); |
|
if(ccode == -1) |
|
_errno = errno; |
|
return ccode; |
|
} | } |
|
|
|
|
int bsd_socket_rep::getpeername (struct sockaddr *addr, size_t *length_ptr) |
|
{ |
|
int ccode = ::getpeername(_socket, addr, length_ptr); |
|
if(ccode == -1 ) |
|
_errno = errno; |
|
return ccode; |
|
} | } |
| |
int bsd_socket_rep::send (void *buffer, size_t size, int flags) |
PEG_TRACE((TRC_HTTP, Tracer::LEVEL1, |
{ |
"connect() returned error code %d", |
int ccode = ::send(_socket, buffer, size, flags); |
getSocketError())); |
if(ccode == -1) |
return false; |
_errno = errno; |
|
return ccode; |
|
} | } |
| |
|
Sint32 Socket::read(SocketHandle socket, void* ptr, Uint32 size) |
int bsd_socket_rep::recv (void *buffer, size_t size, int flags) |
|
{ | { |
int ccode = ::recv(_socket, buffer, size, flags); |
#ifdef PEGASUS_OS_TYPE_WINDOWS |
if(ccode == -1) |
return ::recv(socket, (char*)ptr, size, 0); |
_errno = errno; |
#else |
return ccode; |
int status; |
|
PEGASUS_RETRY_SYSTEM_CALL(::read(socket, (char*)ptr, size), status); |
|
return status; |
|
#endif |
} | } |
| |
int bsd_socket_rep::sendto(void *buffer, size_t size, int flags, struct sockaddr *addr, size_t length) |
Sint32 Socket::write(SocketHandle socket, const void* ptr, Uint32 size) |
{ | { |
int ccode = ::sendto(_socket, buffer, size, flags, addr, length); |
#ifdef PEGASUS_OS_TYPE_WINDOWS |
if(ccode == -1) |
return ::send(socket, (const char*)ptr, size, 0); |
_errno = errno; |
#else |
return ccode; |
int status; |
|
PEGASUS_RETRY_SYSTEM_CALL(::write(socket, (char*)ptr, size), status); |
|
return status; |
|
#endif |
} | } |
| |
|
Sint32 Socket::timedWrite( |
int bsd_socket_rep::recvfrom(void *buffer, |
SocketHandle socket, |
size_t size, |
const void* ptr, |
int flags, |
Uint32 size, |
struct sockaddr *addr, |
Uint32 socketWriteTimeout) |
size_t *length_ptr) |
|
{ | { |
int ccode = ::recvfrom(_socket, buffer, size, flags, addr, length_ptr); |
Sint32 bytesWritten = 0; |
if(ccode == -1) |
Sint32 totalBytesWritten = 0; |
_errno = errno; |
Boolean socketTimedOut = false; |
return ccode; |
int selreturn = 0; |
} |
while (1) |
|
|
int bsd_socket_rep::setsockopt (int level, int optname, void *optval, size_t optlen) |
|
{ | { |
int ccode = ::setsockopt(_socket, level, optname, optval, optlen); |
#ifdef PEGASUS_OS_TYPE_WINDOWS |
if(ccode == -1) |
PEGASUS_RETRY_SYSTEM_CALL( |
_errno = errno; |
::send(socket, (const char*)ptr, size, 0), bytesWritten); |
return ccode; |
#else |
} |
PEGASUS_RETRY_SYSTEM_CALL( |
|
::write(socket, (char*)ptr, size), bytesWritten); |
|
#endif |
int bsd_socket_rep::getsockopt (int level, int optname, void *optval, size_t *optlen_ptr) |
// Some data written this cycle ? |
|
// Add it to the total amount of written data. |
|
if (bytesWritten > 0) |
{ | { |
int ccode = ::getsockopt(_socket, level, optname, optval, optlen_ptr); |
totalBytesWritten += bytesWritten; |
if(ccode == -1) |
socketTimedOut = false; |
_errno = errno; |
|
return ccode; |
|
} | } |
| |
|
// All data written ? return amount of data written |
Boolean bsd_socket_rep::incompleteReadOccurred(Sint32 retCode) |
if ((Uint32)bytesWritten == size) |
{ | { |
return false; |
return totalBytesWritten; |
} | } |
|
// If data has been written partially, we resume writing data |
Boolean bsd_socket_rep::is_secure(void) |
// this also accounts for the case of a signal interrupt |
|
// (i.e. errno = EINTR) |
|
if (bytesWritten > 0) |
{ | { |
return false; |
size -= bytesWritten; |
|
ptr = (void *)((char *)ptr + bytesWritten); |
|
continue; |
} | } |
|
// Something went wrong |
void bsd_socket_rep::set_close_on_exec(void) |
if (bytesWritten == PEGASUS_SOCKET_ERROR) |
{ | { |
int sock_flags; |
// if we already waited for the socket to get ready, bail out |
if( (sock_flags = fcntl(_socket, F_GETFD, 0)) >= 0) |
if (socketTimedOut) return bytesWritten; |
|
#ifdef PEGASUS_OS_TYPE_WINDOWS |
|
if (WSAGetLastError() == WSAEWOULDBLOCK) |
|
#else |
|
if (errno == EAGAIN || errno == EWOULDBLOCK) |
|
#endif |
{ | { |
sock_flags |= FD_CLOEXEC; |
fd_set fdwrite; |
fcntl(_socket, F_SETFD, sock_flags); |
// max. timeout seconds waiting for the socket to get ready |
|
struct timeval tv = { socketWriteTimeout, 0 }; |
|
FD_ZERO(&fdwrite); |
|
FD_SET(socket, &fdwrite); |
|
selreturn = select(FD_SETSIZE, NULL, &fdwrite, NULL, &tv); |
|
if (selreturn == 0) socketTimedOut = true; // ran out of time |
|
continue; |
} | } |
|
return bytesWritten; |
} | } |
|
|
|
|
const char* bsd_socket_rep::get_err_string(void) |
|
{ |
|
strncpy(_strerr, strerror(_errno), 255); |
|
return _strerr; |
|
} | } |
|
|
|
|
bsd_socket_factory::bsd_socket_factory(void) |
|
{ |
|
} | } |
| |
bsd_socket_factory::~bsd_socket_factory(void) |
void Socket::close(SocketHandle& socket) |
{ | { |
} |
if (socket != PEGASUS_INVALID_SOCKET) |
|
|
abstract_socket* bsd_socket_factory::make_socket(void) |
|
{ | { |
return new bsd_socket_rep(); |
#ifdef PEGASUS_OS_TYPE_WINDOWS |
} |
if (!closesocket(socket)) |
|
|
|
|
|
|
|
|
/** |
|
* pegasus_socket - the high level socket object in pegasus |
|
* |
|
**/ |
|
|
|
pegasus_socket::pegasus_socket(void) |
|
{ | { |
_rep = new empty_socket_rep(); |
socket = PEGASUS_INVALID_SOCKET; |
} | } |
|
#else |
|
int status; |
|
PEGASUS_RETRY_SYSTEM_CALL(::close(socket), status); |
| |
|
if (status == 0) |
pegasus_socket::pegasus_socket(socket_factory *factory) |
|
{ | { |
_rep = factory->make_socket(); |
socket = PEGASUS_INVALID_SOCKET; |
} | } |
|
#endif |
pegasus_socket::pegasus_socket(const pegasus_socket& s) |
|
{ |
|
if(this != &s) |
|
{ |
|
Inc(this->_rep = s._rep); |
|
} | } |
}; |
|
|
|
pegasus_socket::pegasus_socket(abstract_socket* s) |
|
{ |
|
Inc(this->_rep = s); |
|
} | } |
| |
|
void Socket::disableBlocking(SocketHandle socket) |
pegasus_socket::~pegasus_socket(void) |
|
{ | { |
Dec(_rep); |
#ifdef PEGASUS_OS_TYPE_WINDOWS |
|
unsigned long flag = 1; // Use "flag = 0" to enable blocking |
|
ioctlsocket(socket, FIONBIO, &flag); |
|
#elif PEGASUS_OS_VMS |
|
int flag=1; // Use "flag = 0" to enable blocking |
|
ioctl(socket, FIONBIO, &flag); |
|
#else |
|
int flags = fcntl(socket, F_GETFL, 0); |
|
flags |= O_NONBLOCK; // Use "flags &= ~O_NONBLOCK" to enable blocking |
|
fcntl(socket, F_SETFL, flags); |
|
#endif |
} | } |
| |
pegasus_socket& pegasus_socket::operator =(const pegasus_socket& s) |
void Socket::initializeInterface() |
{ |
|
if(this != &s) |
|
{ | { |
Dec(_rep); |
#ifdef PEGASUS_OS_TYPE_WINDOWS |
Inc(this->_rep = s._rep); |
if (_socketInterfaceRefCount == 0) |
} |
|
return *this; |
|
} |
|
|
|
pegasus_socket::operator Sint32() const |
|
{ | { |
return _rep->operator Sint32(); |
WSADATA tmp; |
} |
|
| |
int pegasus_socket::socket(int type, int style, int protocol, void *ssl_context) |
int err = WSAStartup(0x202, &tmp); |
|
if (err != 0) |
{ | { |
return _rep->socket(type, style, protocol, ssl_context); |
throw Exception(MessageLoaderParms( |
|
"Common.Socket.WSASTARTUP_FAILED.WINDOWS", |
|
"WSAStartup failed with error $0.", |
|
err)); |
} | } |
|
|
|
|
Sint32 pegasus_socket::read(void* ptr, Uint32 size) |
|
{ |
|
return _rep->read(ptr, size); |
|
} | } |
| |
Sint32 pegasus_socket::write(const void* ptr, Uint32 size) |
_socketInterfaceRefCount++; |
{ |
#endif |
return _rep->write(ptr, size); |
|
} | } |
| |
int pegasus_socket::close(void) |
void Socket::uninitializeInterface() |
{ | { |
return _rep->close(); |
#ifdef PEGASUS_OS_TYPE_WINDOWS |
} |
_socketInterfaceRefCount--; |
| |
int pegasus_socket::enableBlocking(void) |
if (_socketInterfaceRefCount == 0) |
{ |
WSACleanup(); |
return _rep->enableBlocking(); |
#endif |
} | } |
| |
int pegasus_socket::disableBlocking(void) |
//------------------------------------------------------------------------------ |
{ |
// |
return _rep->disableBlocking(); |
// _setTCPNoDelay() |
} |
// |
|
//------------------------------------------------------------------------------ |
| |
int pegasus_socket::getsockname (struct sockaddr *addr, size_t *length_ptr) |
inline void _setTCPNoDelay(SocketHandle socket) |
{ | { |
return _rep->getsockname(addr, length_ptr); |
// This function disables "Nagle's Algorithm" also known as "the TCP delay |
} |
// algorithm", which causes read operations to obtain whatever data is |
|
// already in the input queue and then wait a little longer to see if |
|
// more data arrives. This algorithm optimizes the case in which data is |
|
// sent in only one direction but severely impairs performance of round |
|
// trip servers. Disabling TCP delay is a standard technique for round |
|
// trip servers. |
| |
int pegasus_socket::bind (struct sockaddr *addr, size_t length) |
int opt = 1; |
{ |
setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*)&opt, sizeof(opt)); |
return _rep->bind(addr, length); |
|
} | } |
|
//------------------------------------------------------------------------------ |
// change socklen_t to size_t for ZOS and windows |
// |
pegasus_socket pegasus_socket::accept(struct sockaddr *addr, size_t *length_ptr) |
// _setInformIfNewTCPIP() |
|
// |
|
//------------------------------------------------------------------------------ |
|
inline void _setInformIfNewTCPIP(SocketHandle socket) |
{ | { |
return pegasus_socket(_rep->accept(addr, length_ptr)); |
#ifdef PEGASUS_OS_ZOS |
} |
// 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 |
|
// restart of the transport layer. When this option is in effect, |
|
// the accetp(), select(), and read() request will receive an errno=EIO. |
|
// Once this happens, the socket should be closed and create a new. |
| |
int pegasus_socket::connect (struct sockaddr *addr, size_t length) |
int NewTcpipOn = 1; |
{ |
setibmsockopt( |
return _rep->connect(addr, length); |
socket, |
|
SOL_SOCKET, |
|
SO_EioIfNewTP, |
|
(char*)&NewTcpipOn, |
|
sizeof(NewTcpipOn)); |
|
#endif |
} | } |
| |
int pegasus_socket::shutdown(int how) |
|
{ |
|
return _rep->shutdown(how); |
|
} |
|
| |
int pegasus_socket::listen(int q) |
SocketHandle Socket::createSocket(int domain, int type, int protocol) |
{ | { |
return _rep->listen(q); |
SocketHandle newSocket; |
} |
|
| |
int pegasus_socket::getpeername (struct sockaddr *addr, size_t *length_ptr) |
if (domain == AF_UNIX) |
{ | { |
return _rep->getpeername(addr, length_ptr); |
return socket(domain,type,protocol); |
} | } |
| |
int pegasus_socket::send(void *buffer, size_t size, int flags) |
bool sendTcpipMsg = true; |
{ |
|
return _rep->send(buffer, size, flags); |
|
} |
|
| |
int pegasus_socket::recv(void *buffer, size_t size, int flags) |
while (1) |
{ | { |
return _rep->recv(buffer, size, flags); |
newSocket = socket(domain,type,protocol); |
} |
|
| |
int pegasus_socket::sendto(void *buffer, size_t size, int flags, struct sockaddr *addr, size_t length) |
if ((newSocket != PEGASUS_INVALID_SOCKET) || |
|
(getSocketError() != PEGASUS_NETWORK_TRYAGAIN)) |
{ | { |
return _rep->sendto(buffer, size, flags, addr, length); |
break; |
} | } |
| |
int pegasus_socket::recvfrom(void *buffer, size_t size, int flags, struct sockaddr *addr, size_t *length_ptr) |
#ifdef PEGASUS_OS_ZOS |
{ |
// The program should wait for transport layer to become ready. |
return _rep->recvfrom(buffer, size, flags, addr, length_ptr); |
|
} |
|
| |
int pegasus_socket::setsockopt (int level, int optname, void *optval, size_t optlen) |
if (sendTcpipMsg) |
{ | { |
return _rep->setsockopt(level, optname, optval, optlen); |
Logger::put_l( |
|
Logger::STANDARD_LOG, System::CIMSERVER, Logger::INFORMATION, |
|
MessageLoaderParms( |
|
"Common.Socket.WAIT_FOR_TCPIP", |
|
"TCP/IP temporary unavailable.")); |
|
sendTcpipMsg = false; |
} | } |
| |
int pegasus_socket::getsockopt (int level, int optname, void *optval, size_t *optlen_ptr) |
System::sleep(30); |
{ |
#endif |
return _rep->getsockopt(level, optname, optval, optlen_ptr); |
} // wait for the transport layer become ready. |
} |
|
| |
Boolean pegasus_socket::incompleteReadOccurred(Sint32 retCode) |
// Is the socket in an unrecoverable error ? |
|
if (newSocket == PEGASUS_INVALID_SOCKET) |
{ | { |
return _rep->incompleteReadOccurred(retCode); |
// return immediate |
|
return PEGASUS_INVALID_SOCKET; |
} | } |
|
else |
Boolean pegasus_socket::is_secure(void) |
|
{ | { |
return _rep->is_secure(); |
// set aditional socket options |
} |
_setTCPNoDelay(newSocket); |
|
_setInformIfNewTCPIP(newSocket); |
| |
void pegasus_socket::set_close_on_exec(void) |
return newSocket; |
{ |
|
return _rep->set_close_on_exec(); |
|
} | } |
|
|
|
|
const char* pegasus_socket::get_err_string(void) |
|
{ |
|
return _rep->get_err_string(); |
|
} | } |
| |
|
|
|
|
PEGASUS_NAMESPACE_END | PEGASUS_NAMESPACE_END |
|
|