version 1.3, 2002/03/07 21:15:57
|
version 1.22.2.2, 2008/01/02 21:07:59
|
|
|
//%///////////////////////////////////////////////////////////////////////////// |
//%2006//////////////////////////////////////////////////////////////////////// |
// | // |
// Copyright (c) 2000, 2001 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) | // Author: Mike Brasher (mbrasher@bmc.com) |
// | // |
// Modified By: |
// Modified By: Josephine Eskaline Joyce, IBM (jojustin@in.ibm.com) for Bug#2513 |
|
// David Dillard, Symantec Corp., (david_dillard@symantec.com) |
// | // |
//%///////////////////////////////////////////////////////////////////////////// | //%///////////////////////////////////////////////////////////////////////////// |
| |
|
// NOCHKSRC |
|
|
#include "Socket.h" | #include "Socket.h" |
| |
#ifdef PEGASUS_OS_TYPE_WINDOWS | #ifdef PEGASUS_OS_TYPE_WINDOWS |
# include <windows.h> | # include <windows.h> |
|
# ifndef _WINSOCKAPI_ |
|
# include <winsock2.h> |
|
# endif |
#else | #else |
# include <cctype> | # include <cctype> |
|
#ifndef PEGASUS_OS_OS400 |
# include <unistd.h> | # include <unistd.h> |
|
#else |
|
# include <unistd.cleinc> |
|
#endif |
|
# include <string.h> // added by rk for memcpy |
# include <cstdlib> | # include <cstdlib> |
# include <errno.h> | # include <errno.h> |
# include <fcntl.h> | # include <fcntl.h> |
|
|
# include <netinet/in.h> | # include <netinet/in.h> |
# include <arpa/inet.h> | # include <arpa/inet.h> |
# include <sys/socket.h> | # include <sys/socket.h> |
|
# include <errno.h> |
|
#endif |
|
|
|
#include <Pegasus/Common/Sharable.h> |
|
#include <Pegasus/Common/Tracer.h> |
|
|
|
//------------------------------------------------------------------------------ |
|
// |
|
// PEGASUS_RETRY_SYSTEM_CALL() |
|
// |
|
// This macro repeats the given system call until it returns something |
|
// other than EINTR. |
|
// |
|
//------------------------------------------------------------------------------ |
|
|
|
#ifdef PEGASUS_OS_TYPE_WINDOWS |
|
# define PEGASUS_RETRY_SYSTEM_CALL(EXPR, RESULT) RESULT = EXPR |
|
#else |
|
# define PEGASUS_RETRY_SYSTEM_CALL(EXPR, RESULT) \ |
|
while (((RESULT = (EXPR)) == -1) && (errno == EINTR)) |
|
#endif |
|
|
|
//------------------------------------------------------------------------------ |
|
// |
|
// PEGASUS_SOCKET_ERROR |
|
// |
|
// This macro defines the error return code of network functions. |
|
// Should be used instead of comparing with -1. |
|
// |
|
//------------------------------------------------------------------------------ |
|
|
|
#ifdef PEGASUS_OS_TYPE_WINDOWS |
|
# define PEGASUS_SOCKET_ERROR SOCKET_ERROR |
|
#else |
|
# define PEGASUS_SOCKET_ERROR (-1) |
#endif | #endif |
| |
|
//------------------------------------------------------------------------------ |
|
// |
|
// getSocketError() |
|
// |
|
//------------------------------------------------------------------------------ |
|
|
|
static inline int getSocketError() |
|
{ |
|
#ifdef PEGASUS_OS_TYPE_WINDOWS |
|
return WSAGetLastError(); |
|
#else |
|
return errno; |
|
#endif |
|
} |
|
|
|
//------------------------------------------------------------------------------ |
|
// |
|
// PEGASUS_NETWORK_EINPROGRESS |
|
// |
|
// This return code indicates that the network function |
|
// is in progress. The application should try select or poll and |
|
// check for successful completion. |
|
// |
|
//------------------------------------------------------------------------------ |
|
|
|
#if !defined(PEGASUS_OS_TYPE_WINDOWS) |
|
# define PEGASUS_NETWORK_EINPROGRESS EINPROGRESS |
|
#else |
|
# define PEGASUS_NETWORK_EINPROGRESS WSAEWOULDBLOCK |
|
#endif |
|
|
|
|
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( |
|
PEGASUS_SOCKET socket, |
|
sockaddr* address, |
|
int addressLength, |
|
Uint32 timeoutMilliseconds) |
|
{ |
|
int connectResult; |
|
PEGASUS_RETRY_SYSTEM_CALL( |
|
::connect(socket, address, addressLength), connectResult); |
|
|
|
if (connectResult == 0) |
|
{ |
|
return true; |
|
} |
|
|
|
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; |
|
|
|
PEGASUS_RETRY_SYSTEM_CALL( |
|
select(FD_SETSIZE, NULL, &fdwrite, NULL, &timeoutValue), |
|
selectResult); |
|
if (selectResult == 0) |
|
{ |
|
PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2, |
|
"select() timed out waiting for the socket connection to be " |
|
"established."); |
|
return false; |
|
} |
|
else if (selectResult > 0) |
|
{ |
|
int optval; |
|
PEGASUS_SOCKLEN_T optlen = sizeof(int); |
|
getsockopt(socket, SOL_SOCKET, SO_ERROR, (char*)&optval, &optlen); |
|
if (optval == 0) |
|
{ |
|
PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL4, |
|
"Connection with server established."); |
|
return true; |
|
} |
|
else |
|
{ |
|
PEG_TRACE((TRC_HTTP, Tracer::LEVEL2, |
|
"Did not connect, getsockopt() returned optval = %d", |
|
optval)); |
|
return false; |
|
} |
|
} |
|
else |
|
{ |
|
PEG_TRACE((TRC_HTTP, Tracer::LEVEL2, |
|
"select() returned error code %d", |
|
getSocketError())); |
|
return false; |
|
} |
|
} |
|
|
|
PEG_TRACE((TRC_HTTP, Tracer::LEVEL2, |
|
"connect() returned error code %d", |
|
getSocketError())); |
|
return false; |
|
} |
|
|
|
Sint32 Socket::read(PEGASUS_SOCKET socket, void* ptr, Uint32 size) |
{ | { |
#ifdef PEGASUS_OS_TYPE_WINDOWS | #ifdef PEGASUS_OS_TYPE_WINDOWS |
return ::recv(socket, (char*)ptr, size, 0); | return ::recv(socket, (char*)ptr, size, 0); |
#elif defined(PEGASUS_OS_ZOS) |
#else |
int i=::read(socket, (char*)ptr, size); |
#if defined (__GNUC__) && !defined(PEGASUS_OS_SOLARIS) && !defined(PEGASUS_OS_DARWIN) && !defined(PEGASUS_OS_LSB) |
__atoe_l((char *)ptr,size); |
int ccode = TEMP_FAILURE_RETRY(::read(socket, (char*)ptr, size)); |
return i; |
return ccode; |
#else | #else |
return ::read(socket, (char*)ptr, size); | return ::read(socket, (char*)ptr, size); |
#endif | #endif |
|
#endif |
} | } |
| |
Sint32 Socket::write(Sint32 socket, const void* ptr, Uint32 size) |
Sint32 Socket::write(PEGASUS_SOCKET socket, const void* ptr, Uint32 size) |
{ | { |
#ifdef PEGASUS_OS_TYPE_WINDOWS | #ifdef PEGASUS_OS_TYPE_WINDOWS |
return ::send(socket, (const char*)ptr, size, 0); | return ::send(socket, (const char*)ptr, size, 0); |
#elif defined(PEGASUS_OS_ZOS) |
#else |
char * ptr2 = (char *)malloc(size); |
#if (__GNUC__) && !defined(PEGASUS_OS_SOLARIS) && !defined(PEGASUS_OS_DARWIN) && !defined(PEGASUS_OS_LSB) |
int i; |
int ccode = TEMP_FAILURE_RETRY(::write(socket, (char*)ptr, size)); |
memcpy(ptr2,ptr,size); |
return ccode; |
__etoa_l(ptr2,size); |
|
i = ::write(socket, ptr2, size); |
|
free(ptr2); |
|
return i; |
|
#else | #else |
return ::write(socket, (char*)ptr, size); | return ::write(socket, (char*)ptr, size); |
#endif | #endif |
|
#endif |
|
} |
|
|
|
Sint32 Socket::timedWrite(PEGASUS_SOCKET socket, |
|
const void* ptr, |
|
Uint32 size, |
|
Uint32 socketWriteTimeout) |
|
{ |
|
Sint32 bytesWritten = 0; |
|
Sint32 totalBytesWritten = 0; |
|
Boolean socketTimedOut = false; |
|
int selreturn = 0; |
|
while (1) |
|
{ |
|
#ifdef PEGASUS_OS_TYPE_WINDOWS |
|
PEGASUS_RETRY_SYSTEM_CALL( |
|
::send(socket, (const char*)ptr, size, 0), bytesWritten); |
|
#else |
|
PEGASUS_RETRY_SYSTEM_CALL( |
|
::write(socket, (char*)ptr, size), bytesWritten); |
|
#endif |
|
// Some data written this cycle ? |
|
// Add it to the total amount of written data. |
|
if (bytesWritten > 0) |
|
{ |
|
totalBytesWritten += bytesWritten; |
|
socketTimedOut = false; |
} | } |
| |
void Socket::close(Sint32 socket) |
// All data written ? return amount of data written |
|
if ((Uint32)bytesWritten == size) |
{ | { |
|
return totalBytesWritten; |
|
} |
|
// If data has been written partially, we resume writing data |
|
// this also accounts for the case of a signal interrupt |
|
// (i.e. errno = EINTR) |
|
if (bytesWritten > 0) |
|
{ |
|
size -= bytesWritten; |
|
ptr = (void *)((char *)ptr + bytesWritten); |
|
continue; |
|
} |
|
// Something went wrong |
|
if (bytesWritten == PEGASUS_SOCKET_ERROR) |
|
{ |
|
// if we already waited for the socket to get ready, bail out |
|
if( socketTimedOut ) return bytesWritten; |
#ifdef PEGASUS_OS_TYPE_WINDOWS | #ifdef PEGASUS_OS_TYPE_WINDOWS |
closesocket(socket); |
if (WSAGetLastError() == WSAEWOULDBLOCK) |
#else | #else |
::close(socket); |
if (errno == EAGAIN || errno == EWOULDBLOCK) |
#endif | #endif |
|
{ |
|
fd_set fdwrite; |
|
// 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; |
|
} |
|
} |
} | } |
| |
void Socket::enableBlocking(Sint32 socket) |
void Socket::close(PEGASUS_SOCKET socket) |
|
{ |
|
if(-1 != socket) |
{ | { |
#ifdef PEGASUS_OS_TYPE_WINDOWS | #ifdef PEGASUS_OS_TYPE_WINDOWS |
unsigned long flag = 0; |
if(!closesocket(socket)) socket=-1; |
ioctlsocket(socket, FIONBIO, &flag); |
|
#else | #else |
int flags = fcntl(socket, F_GETFL, 0); |
#if (__GNUC__) && !defined(PEGASUS_OS_SOLARIS) && !defined(PEGASUS_OS_DARWIN) && !defined(PEGASUS_OS_LSB) |
flags &= ~O_NONBLOCK; |
if(!TEMP_FAILURE_RETRY(::close(socket))) socket = -1; |
fcntl(socket, F_SETFL, flags); |
#else |
|
if(!::close(socket)) socket = -1; |
|
#endif |
#endif | #endif |
} | } |
|
} |
| |
void Socket::disableBlocking(Sint32 socket) |
void Socket::disableBlocking(PEGASUS_SOCKET 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); |
#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 |
} | } |
|
|
#endif | #endif |
} | } |
| |
|
|
PEGASUS_NAMESPACE_END | PEGASUS_NAMESPACE_END |
|
|