Source Code (Use browser search to find items of interest.)

Class Index

kdelibs'KSocket (./kdelibs/kdecore/ksock.h:72)

class KSocket : public QObject
{
    Q_OBJECT
public:
    /** 
     * Create a KSocket with the provided file descriptor.
     * @param _sock	The file descriptor to use.
     */
    KSocket( int _sock );    
    /** 
     * Create a socket and connect to a host.
     * @param _host	The remote host to which to connect.
     * @param _port	The port on the remote host.
     * @param timeOut	The number of seconds waiting for connect (default 30).
     */
    KSocket( const char *_host, unsigned short int _port, int timeOut = 30);
    
    /** 
     * Connects to a UNIX domain socket.
     * @param _path    The filename of the socket.
     */
    KSocket( const char * _path );

    /** 
     * Destructor. Closes the socket if it is still open.
     */
    ~KSocket();

    /**
      *  A small wrapper around @ref gethostbyname() and such.
      */
    static bool initSockaddr(ksockaddr_in *server_name, const char *hostname, unsigned short int port, int domain = PF_INET);
    
    /** 
     * Returns a file descriptor for this socket.
     */
    int socket() const { return sock; }
    
    /** 
     * Enable the socket for reading.
     *
     * If you enable read mode, the socket will emit the signal
     * @ref readEvent() whenever there is something to read out of this
     * socket.
     */
    void enableRead( bool );
    
    /** 
     * Enable the socket for writing.
     *
     * If you enable write mode, the socket will emit the signal
     * @ref writeEvent() whenever the socket is ready for writing.
     */
    void enableWrite( bool );
    
    /**
     * Return address.
     */
    unsigned long ipv4_addr();
    
signals:
    /** 
     * Data has arrived for reading.
     *
     * This signal will only be raised if @ref enableRead( @p true ) was called
     * first.
     */
    void readEvent( KSocket * );
    
    /** 
     * Socket is ready for writing.
     *
     * This signal will only be raised if @ref enableWrite( @p true ) was 
     * called first.
     */
    void writeEvent( KSocket * );
    
    /** 
     * Raised when the connection is broken.
     */
    void closeEvent( KSocket * );
    
public slots:
    /** 
     * Connected to the writeNotifier.
     *
     * Called when
     *  the socket is ready for writing.
     */
    void slotWrite( int );
    
    /** 
     * Connected to the readNotifier.
     *
     * Called when
     *  the socket is ready for reading.
     */
    void slotRead( int );
    
protected:
    bool connect( const QString& _host, unsigned short int _port );
    bool connect( const char *_path );
  
    bool init_sockaddr( const QString& hostname, unsigned short int port );
    
    ksockaddr_in server_name;
    struct sockaddr_un unix_addr;

    /******************************************************
     * The file descriptor for this socket. sock may be -1.
     * This indicates that it is not connected.
     */
    int sock;

    int domain;
  
    QSocketNotifier *readNotifier;
    QSocketNotifier *writeNotifier;

private:
    int timeOut;
    
    KSocket(const KSocket&);
    KSocket& operator=(const KSocket&);

    KSocketPrivate *d;
};


/**
 * Monitor a port for incoming TCP/IP connections.
 *
 * You can use a KServerSocket to listen on a port for incoming
 * connections. When a connection arrived in the port, a KSocket
 * is created and the signal accepted is raised. Make sure you
 * always connect to this signal. If you dont the ServerSocket will
 * create new KSocket's and no one will delete them!
 *
 * If socket() is -1 or less the socket was not created properly.
 *
 * @author Torben Weis <weis@stud.uni-frankfurt.de>
 * @version $Id: ksock.h,v 1.38 2000/03/08 19:46:49 granroth Exp $
 * @short Monitor a port for incoming TCP/IP connections.
*/

kdelibs'KSocket::KSocket() (./kdelibs/kdecore/ksock.cpp:76)

KSocket::KSocket( int _sock)
 : sock(_sock), readNotifier(0), writeNotifier(0)
{
  struct sockaddr_in sin;
  ksize_t len = sizeof(sin);

  memset(&sin, 0, len);

  // getsockname will fill in all the appropiate details, and
  // since sockaddr_in will exist everywhere and is somewhat compatible
  // with sockaddr_in6, we can use it to avoid needless ifdefs.
  getsockname(_sock, (struct sockaddr *)&sin, &len);

  // Now that we've got the domain, remember it
  domain = sin.sin_family;
}


kdelibs'KSocket::KSocket() (./kdelibs/kdecore/ksock.cpp:93)

KSocket::KSocket( const char *_host, unsigned short int _port, int _timeout ) :
  sock( -1 ), readNotifier( 0L ), writeNotifier( 0L )
{
    timeOut = _timeout;
#ifdef INET6
    // Setup the resolver to look for IPv6 addresses and then
    // as a fall back, look for IPv4.  This means we don't need further
    // ifdefs to use gethostbyname2. (Taken from rfc2133)
    res_init();
    _res.options |= RES_USE_INET6;

    // Also we do this because gethostbyname will return IPv4 mapped on to
    // IPv6 addresses when set like this and use 16 byte hostents, so we
    // should be safe and use sockaddr_in6, etc, and by setting the domain to
    // PF_INET6, anyone who checks our sockaddr stuff will avoid buffer
    // overflows by seeing that it's new style.
    domain = PF_INET6;
#else
    domain = PF_INET;
#endif
    connect( _host, _port );
}


kdelibs'KSocket::KSocket() (./kdelibs/kdecore/ksock.cpp:116)

KSocket::KSocket( const char *_path ) :
  sock( -1 ), readNotifier( 0L ), writeNotifier( 0L )
{
  timeOut = 0; // Not used
  domain = PF_UNIX;
  connect( _path );
}


kdelibs'KSocket::enableRead() (./kdelibs/kdecore/ksock.cpp:124)

void KSocket::enableRead( bool _state )
{
  if ( _state )
    {
	  if ( !readNotifier  )
		{
		  readNotifier = new QSocketNotifier( sock, QSocketNotifier::Read );
		  QObject::connect( readNotifier, SIGNAL( activated(int) ), this, SLOT( slotRead(int) ) );
		}
	  else
	    readNotifier->setEnabled( true );
    }
  else if ( readNotifier )
	readNotifier->setEnabled( false );
}


kdelibs'KSocket::enableWrite() (./kdelibs/kdecore/ksock.cpp:140)

void KSocket::enableWrite( bool _state )
{
  if ( _state )
    {
	  if ( !writeNotifier )
		{
		  writeNotifier = new QSocketNotifier( sock, QSocketNotifier::Write );
		  QObject::connect( writeNotifier, SIGNAL( activated(int) ), this, 
							SLOT( slotWrite(int) ) );
		}
	  else
	    writeNotifier->setEnabled( true );
    }
  else if ( writeNotifier )
	writeNotifier->setEnabled( false );
}


kdelibs'KSocket::slotRead() (./kdelibs/kdecore/ksock.cpp:157)

void KSocket::slotRead( int )
{
  char buffer[2];
  
  int n = recv( sock, buffer, 1, MSG_PEEK );
  if ( n <= 0 )
	emit closeEvent( this );
  else
	emit readEvent( this );
}


kdelibs'KSocket::slotWrite() (./kdelibs/kdecore/ksock.cpp:168)

void KSocket::slotWrite( int )
{
  emit writeEvent( this );
}

/*
 * Initializes a sockaddr structure. Do this after creating a socket and
 * before connecting to any other socket. Here you must specify the
 * host and port you want to connect to.
 */

kdelibs'KSocket::init_sockaddr() (./kdelibs/kdecore/ksock.cpp:178)

bool KSocket::init_sockaddr( const QString& hostname, unsigned short int port )
{
  if (
#ifdef INET6
     ( domain != PF_INET6 ) &&
#endif
     ( domain != PF_INET ) )
    return false;
  
  struct hostent *hostinfo;
  memset(&server_name, 0, sizeof(server_name));

  hostinfo = gethostbyname( hostname.ascii() );
  if ( !hostinfo ) {
	  warning("Unknown host %s.\n", hostname.ascii());
	  return false;	
    }

  get_sin_family(server_name) = domain;
  get_sin_port(server_name) = htons(port);
  memcpy(&get_sin_addr(server_name), hostinfo->h_addr_list[0], hostinfo->h_length);

  return true;
}

/*
 * Connects the PF_UNIX domain socket to _path.
 */

kdelibs'KSocket::connect() (./kdelibs/kdecore/ksock.cpp:206)

bool KSocket::connect( const char *_path )
{
  if ( domain != PF_UNIX )
    fatal( "Connecting a PF_INET socket to a PF_UNIX domain socket\n");
  
  sock = ::socket(PF_UNIX,SOCK_STREAM,0);
  if (sock < 0)
	return false;
  
  unix_addr.sun_family = AF_UNIX;
  int l = strlen( _path );
  if ( l > UNIX_PATH_MAX - 1 )
  {      
    warning( "Too long PF_UNIX domain name '%s'\n",_path);
    return false;
  }  
  strcpy( unix_addr.sun_path, _path );

  if ( 0 > ::connect( sock, (struct sockaddr*)(&unix_addr), 
					  sizeof( unix_addr ) ) )
  {
      ::close( sock );
      sock = -1;
      return false;
  }

  return true;
}

/*
 * Connects the socket to _host, _port.
 */

kdelibs'KSocket::connect() (./kdelibs/kdecore/ksock.cpp:238)

bool KSocket::connect( const QString& _host, unsigned short int _port )
{
#ifdef INET6
  if ( (domain != PF_INET6) && (domain != PF_INET) )
#else
  if ( domain != PF_INET )
#endif
    fatal( "Connecting a PF_UNIX domain socket to a PF_INET domain socket\n");

  sock = ::socket(domain, SOCK_STREAM, 0);
  if (sock < 0)
	return false;
  
  if ( !init_sockaddr( _host, _port) ) {
	  ::close( sock );
	  sock = -1;
	  return false;
  }

  fcntl(sock, F_SETFL, ( fcntl(sock,F_GETFL)|O_NDELAY) );

  errno = 0;
  if (::connect(sock, (struct sockaddr*)(&server_name), sizeof(server_name))){
      if(errno != EINPROGRESS && errno != EWOULDBLOCK) {
          ::close( sock );
          sock = -1;
          return false;
      }
  } else
      return true;

  fd_set rd, wr;
  struct timeval timeout;

  int n = timeOut*10; // Timeout in 1/10th's of a second
  while(n--){
      FD_ZERO(&rd);
      FD_ZERO(&wr);
      FD_SET(sock, &rd);
      FD_SET(sock, &wr);

      timeout.tv_usec = 100*1000; // 1/10th sec
      timeout.tv_sec = 0;

      select(sock + 1, &rd, &wr, (fd_set *)0, &timeout);

      if (FD_ISSET(sock, &rd) || FD_ISSET(sock, &wr))
      {
         int errcode;
         ksize_t len = sizeof(errcode);
         int ret = getsockopt(sock, SOL_SOCKET, SO_ERROR, (char*)&errcode, &len);
         if ((ret == -1) || (errcode != 0))
         {
            ::close(sock);
            sock = -1;
            return false;
         }
         return true;
      }
      qApp->processEvents();
      qApp->flushX();
  }
  warning("Timeout connecting socket...\n");
  ::close( sock );
  sock = -1;
  return false;
}


kdelibs'KSocket::ipv4_addr() (./kdelibs/kdecore/ksock.cpp:306)

unsigned long KSocket::ipv4_addr()
{
  if ( domain != PF_INET )
    return 0;
  
  sockaddr_in name; ksize_t len = sizeof(name);
  getsockname(sock, (struct sockaddr *) &name, &len);
  if (name.sin_family == AF_INET) // It's IPv4
    return ntohl(name.sin_addr.s_addr);
#ifdef INET6
  else if (name.sin_family == AF_INET6) // It's IPv6 Ah.
    return 0;
#endif
  else // We dunno what it is
    return 0;
}


kdelibs'KSocket::initSockaddr() (./kdelibs/kdecore/ksock.cpp:323)

bool KSocket::initSockaddr (ksockaddr_in *server_name, const char *hostname, unsigned short int port, int domain)
{
  struct hostent *hostinfo;
#ifdef INET6
  if (domain == PF_INET6) {
    server_name->sin6_family = domain;
    server_name->sin6_port = htons( port );
  } else
#endif
  {
    get_sin_pfamily(server_name) = domain;
    get_sin_pport(server_name) = htons( port );
  }

  hostinfo = gethostbyname( hostname );

  if ( hostinfo == 0L )
    return false;

#ifdef INET6
  if (domain == PF_INET6) {
    server_name->sin6_family = hostinfo->h_addrtype;
    memcpy(&server_name->sin6_addr, hostinfo->h_addr_list[0], hostinfo->h_length);
  } else
#endif
  {
    get_sin_pfamily(server_name) = hostinfo->h_addrtype;
    memcpy(&get_sin_paddr(server_name), hostinfo->h_addr_list[0], hostinfo->h_length);
  }

  return true;
}


kdelibs'KSocket::~KSocket() (./kdelibs/kdecore/ksock.cpp:356)

KSocket::~KSocket()
{
    if ( readNotifier )
    {
	delete readNotifier;
    }
    if ( writeNotifier )
	delete writeNotifier; 
  
    ::close( sock ); 
}