(file) Return to Socket.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

File: [Pegasus] / pegasus / src / Pegasus / Common / Socket.cpp (download)
Revision: 1.9.4.6, Thu Jul 17 14:59:27 2003 UTC (20 years, 11 months ago) by mday
Branch: pep_88
Changes since 1.9.4.5: +12 -38 lines
finished bsd_socket and socket test program

//%/////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2000, 2001, 2002 BMC Software, Hewlett-Packard Company, IBM,
// The Open Group, Tivoli Systems
//
// 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.
//
//==============================================================================
//
// Author: Mike Brasher (mbrasher@bmc.com)
//
// Modified By:
//
//%/////////////////////////////////////////////////////////////////////////////

#include "Socket.h"

#ifdef PEGASUS_OS_TYPE_WINDOWS
#include <windows.h>
# ifndef _WINSOCKAPI_
#   include <winsock2.h>
# endif
#else
# include <cctype>
#ifndef PEGASUS_OS_OS400
#   include <unistd.h>
#else
#   include <Pegasus/Common/OS400ConvertChar.h>
#   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>
PEGASUS_NAMESPACE_BEGIN

static Uint32 _socketInterfaceRefCount = 0;

Sint32 Socket::read(Sint32 socket, void* ptr, Uint32 size)
{
#ifdef PEGASUS_OS_TYPE_WINDOWS
    return ::recv(socket, (char*)ptr, size, 0);
#elif defined(PEGASUS_OS_ZOS)
    int i=::read(socket, (char*)ptr, size);
#ifdef PEGASUS_HAVE_EBCDIC
    __atoe_l((char *)ptr,size);
#endif
    return i;
#elif defined(PEGASUS_OS_OS400)
    int i=::read(socket, (char*)ptr, size);
    AtoE((char *)ptr, size);
    return i;
#else

#if defined (__GNUC__)
    int ccode = TEMP_FAILURE_RETRY(::read(socket, (char*)ptr, size));
    return ccode;
#else 
    return ::read(socket, (char*)ptr, size);
#endif
#endif
}

Sint32 Socket::write(Sint32 socket, const void* ptr, Uint32 size)
{
#ifdef PEGASUS_OS_TYPE_WINDOWS
    return ::send(socket, (const char*)ptr, size, 0);
#elif defined(PEGASUS_OS_ZOS)
    char * ptr2 = (char *)malloc(size);
    int i;
    memcpy(ptr2,ptr,size);
#ifdef PEGASUS_HAVE_EBCDIC
    __etoa_l(ptr2,size);
#endif
    i = ::write(socket, ptr2, size);
    free(ptr2);
    return i;
#elif defined(PEGASUS_OS_OS400)
    char * ptr2 = (char *)malloc(size);
    int i;
    memcpy(ptr2,ptr,size);
    EtoA(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
    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
}

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
}

int Socket::disableBlocking2(Sint32 socket)
{
#ifdef PEGASUS_OS_TYPE_WINDOWS
    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()
{
#ifdef PEGASUS_OS_TYPE_WINDOWS
    if (_socketInterfaceRefCount == 0)
    {
	WSADATA tmp;

	if (WSAStartup(0x202, &tmp) == SOCKET_ERROR)
	    WSACleanup();
    }

    _socketInterfaceRefCount++;
#endif
}

void Socket::uninitializeInterface()
{
#ifdef PEGASUS_OS_TYPE_WINDOWS
    _socketInterfaceRefCount--;

    if (_socketInterfaceRefCount == 0)
	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

#endif


/** 
 * 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;
   
   shutdown(2);
   ccode = Socket::close2(_socket);
   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);
}

abstract_socket* bsd_socket_rep::accept(struct sockaddr *addr, size_t *length_ptr)
{
   int new_sock = ::accept(_socket, addr, length_ptr);
   if(new_sock == -1)
   {
      _errno = errno;
      return 0;
   }

   bsd_socket_rep *rep = new bsd_socket_rep(new_sock);
   // set the close-on-exec flag 
   rep->set_close_on_exec();
   return rep;
}

int bsd_socket_rep::connect (struct sockaddr *addr, size_t length)
{
   int ccode = ::connect(_socket, addr, length);
   if(ccode == -1)
      _errno = errno;
   return ccode;
}


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)
{
   int ccode = ::send(_socket, buffer, size, flags);
   if(ccode == -1)
      _errno = errno;
   return ccode;
}


int bsd_socket_rep::recv (void *buffer, size_t size, int flags)
{
   int ccode = ::recv(_socket, buffer, size, flags);
   if(ccode == -1)
      _errno = errno;
   return ccode;
}

int bsd_socket_rep::sendto(void *buffer, size_t size, int flags, struct sockaddr *addr, size_t length)
{
   int ccode = ::sendto(_socket, buffer, size, flags, addr, length);
      if(ccode == -1)
      _errno = errno;
   return ccode;
}


int bsd_socket_rep::recvfrom(void *buffer, 
			     size_t size, 
			     int flags, 
			     struct sockaddr *addr, 
			     size_t *length_ptr)
{
   int ccode = ::recvfrom(_socket, buffer, size, flags, addr, length_ptr);
   if(ccode == -1)
      _errno = errno;
   return ccode;
}

int bsd_socket_rep::setsockopt (int level, int optname, void *optval, size_t optlen)
{
   int ccode = ::setsockopt(_socket, level, optname, optval, optlen);
   if(ccode == -1)
      _errno = errno;
   return ccode;
}


int bsd_socket_rep::getsockopt (int level, int optname, void *optval, size_t *optlen_ptr)
{
   int ccode = ::getsockopt(_socket, level, optname, optval, optlen_ptr);
   if(ccode == -1)
      _errno = errno;
   return ccode;
}


Boolean bsd_socket_rep::incompleteReadOccurred(Sint32 retCode)
{
   return false;
}

Boolean bsd_socket_rep::is_secure(void)
{
   return false;
}

void bsd_socket_rep::set_close_on_exec(void)
{
   int sock_flags;
   if( (sock_flags = fcntl(_socket, F_GETFD, 0)) >= 0)
   {
      sock_flags |= FD_CLOEXEC;
      fcntl(_socket, F_SETFD, sock_flags);
   }
}


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)
{
}

abstract_socket* bsd_socket_factory::make_socket(void)
{
   return new bsd_socket_rep();
}




/** 
 * pegasus_socket - the high level socket object in pegasus
 * 
 **/ 

pegasus_socket::pegasus_socket(void)
{
   _rep = new empty_socket_rep();
}


pegasus_socket::pegasus_socket(socket_factory *factory)
{
   _rep = factory->make_socket();
}

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);
}


pegasus_socket::~pegasus_socket(void)
{
   Dec(_rep);
}

pegasus_socket& pegasus_socket::operator =(const pegasus_socket& s)
{
   if(this != &s)
   {
      Dec(_rep);
      Inc(this->_rep = s._rep);
   }
   return *this;
}

pegasus_socket::operator Sint32() const
{
   return _rep->operator Sint32();
}

int pegasus_socket::socket(int type, int style, int protocol, void *ssl_context)
{
   return _rep->socket(type, style, protocol, ssl_context);
}


Sint32 pegasus_socket::read(void* ptr, Uint32 size)
{
   return _rep->read(ptr, size);
}

Sint32 pegasus_socket::write(const void* ptr, Uint32 size)
{
   return _rep->write(ptr, size);
}

int pegasus_socket::close(void)
{
   return _rep->close();
}

int pegasus_socket::enableBlocking(void)
{
   return _rep->enableBlocking();
}

int pegasus_socket::disableBlocking(void)
{
   return _rep->disableBlocking();
}

int pegasus_socket::getsockname (struct sockaddr *addr, size_t *length_ptr)
{
   return _rep->getsockname(addr, length_ptr);
}

int pegasus_socket::bind (struct sockaddr *addr, size_t length)
{
   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)
{
   return pegasus_socket(_rep->accept(addr, length_ptr));
}

int pegasus_socket::connect (struct sockaddr *addr, size_t length)
{
   return _rep->connect(addr, length);
}

int pegasus_socket::shutdown(int how)
{
   return _rep->shutdown(how);
}

int pegasus_socket::listen(int q)
{
   return _rep->listen(q);
}

int pegasus_socket::getpeername (struct sockaddr *addr, size_t *length_ptr)
{
   return _rep->getpeername(addr, length_ptr);
}

int pegasus_socket::send(void *buffer, size_t size, int flags)
{
   return _rep->send(buffer, size, flags);
}

int pegasus_socket::recv(void *buffer, size_t size, int flags)
{
   return _rep->recv(buffer, size, flags);
}

int pegasus_socket::sendto(void *buffer, size_t size, int flags, struct sockaddr *addr, size_t length)
{
   return _rep->sendto(buffer, size, flags, addr, length);
}

int pegasus_socket::recvfrom(void *buffer, size_t size, int flags, struct sockaddr *addr, size_t *length_ptr)
{
   return _rep->recvfrom(buffer, size, flags, addr, length_ptr);
}

int pegasus_socket::setsockopt (int level, int optname, void *optval, size_t optlen)
{
   return _rep->setsockopt(level, optname, optval, optlen);
}

int pegasus_socket::getsockopt (int level, int optname, void *optval, size_t *optlen_ptr)
{
   return _rep->getsockopt(level, optname, optval, optlen_ptr);
}

Boolean pegasus_socket::incompleteReadOccurred(Sint32 retCode)
{
   return _rep->incompleteReadOccurred(retCode);
}

Boolean pegasus_socket::is_secure(void)
{
   return _rep->is_secure();
}

void pegasus_socket::set_close_on_exec(void)
{
   return _rep->set_close_on_exec();
}


const char* pegasus_socket::get_err_string(void)
{
   return _rep->get_err_string();
}



PEGASUS_NAMESPACE_END


No CVS admin address has been configured
Powered by
ViewCVS 0.9.2