summaryrefslogtreecommitdiffstats
path: root/tdecore/ksock.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tdecore/ksock.cpp')
-rw-r--r--tdecore/ksock.cpp435
1 files changed, 435 insertions, 0 deletions
diff --git a/tdecore/ksock.cpp b/tdecore/ksock.cpp
new file mode 100644
index 000000000..10c694512
--- /dev/null
+++ b/tdecore/ksock.cpp
@@ -0,0 +1,435 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 1997 Torben Weis (weis@kde.org)
+ *
+ * $Id$
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+// on Linux/libc5, this includes linux/socket.h where SOMAXCONN is defined
+#include <sys/socket.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+extern "C" {
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+}
+
+#define KSOCK_NO_BROKEN
+#include "kdebug.h"
+#include "ksock.h"
+#include "kextsock.h"
+#include "ksockaddr.h"
+
+#include "ksocks.h"
+
+extern "C" {
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef HAVE_GETADDRINFO
+#include <netdb.h>
+#endif
+
+// defines MAXDNAME under Solaris
+#include <arpa/nameser.h>
+#include <resolv.h>
+}
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <assert.h>
+
+#ifdef HAVE_SYSENT_H
+#include <sysent.h>
+#endif
+
+#if TIME_WITH_SYS_TIME
+#include <time.h>
+#endif
+
+
+// Play it safe, use a reasonable default, if SOMAXCONN was nowhere defined.
+#ifndef SOMAXCONN
+#warning Your header files do not seem to support SOMAXCONN
+#define SOMAXCONN 5
+#endif
+
+#include <tqapplication.h>
+#include <tqsocketnotifier.h>
+
+#include "netsupp.h" // leave this last
+
+#ifdef __CYGWIN__
+#include "tqwindowdefs.h"
+#endif
+
+class KSocketPrivate
+{
+public:
+ TQSocketNotifier *readNotifier;
+ TQSocketNotifier *writeNotifier;
+
+ KSocketPrivate() :
+ readNotifier(0), writeNotifier(0)
+ { }
+};
+
+// I moved this into here so we could accurately detect the domain, for
+// posterity. Really.
+KSocket::KSocket( int _sock)
+ : sock(_sock), d(new KSocketPrivate)
+{
+ struct sockaddr_in sin;
+ ksocklen_t len = sizeof(sin);
+
+ memset(&sin, 0, len);
+
+ // getsockname will fill in all the appropriate details, and
+ // since sockaddr_in will exist everywhere and is somewhat compatible
+ // with sockaddr_in6, we can use it to avoid needless ifdefs.
+ KSocks::self()->getsockname(_sock, (struct sockaddr *)&sin, &len);
+}
+
+KSocket::KSocket( const char *_host, unsigned short int _port, int _timeout ) :
+ sock( -1 ), d(new KSocketPrivate)
+{
+ connect( _host, _port, _timeout );
+}
+
+KSocket::KSocket( const char *_path ) :
+ sock( -1 ), d(new KSocketPrivate)
+{
+ connect( _path );
+}
+
+void KSocket::enableRead( bool _state )
+{
+ if ( _state )
+ {
+ if ( !d->readNotifier )
+ {
+ d->readNotifier = new TQSocketNotifier( sock, TQSocketNotifier::Read );
+ TQObject::connect( d->readNotifier, TQT_SIGNAL( activated(int) ), this, TQT_SLOT( slotRead(int) ) );
+ }
+ else
+ d->readNotifier->setEnabled( true );
+ }
+ else if ( d->readNotifier )
+ d->readNotifier->setEnabled( false );
+}
+
+void KSocket::enableWrite( bool _state )
+{
+ if ( _state )
+ {
+ if ( !d->writeNotifier )
+ {
+ d->writeNotifier = new TQSocketNotifier( sock, TQSocketNotifier::Write );
+ TQObject::connect( d->writeNotifier, TQT_SIGNAL( activated(int) ), this,
+ TQT_SLOT( slotWrite(int) ) );
+ }
+ else
+ d->writeNotifier->setEnabled( true );
+ }
+ else if ( d->writeNotifier )
+ d->writeNotifier->setEnabled( false );
+}
+
+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 );
+}
+
+void KSocket::slotWrite( int )
+{
+ emit writeEvent( this );
+}
+
+/*
+ * Connects the PF_UNIX domain socket to _path.
+ */
+bool KSocket::connect( const char *_path )
+{
+ KExtendedSocket ks(TQString::null, _path, KExtendedSocket::unixSocket);
+
+ ks.connect();
+ sock = ks.fd();
+ ks.release();
+
+ return sock >= 0;
+}
+
+/*
+ * Connects the socket to _host, _port.
+ */
+bool KSocket::connect( const TQString& _host, unsigned short int _port, int _timeout )
+{
+ KExtendedSocket ks(_host, _port, KExtendedSocket::inetSocket);
+ ks.setTimeout(_timeout, 0);
+
+ ks.connect();
+ sock = ks.fd();
+ ks.release();
+
+ return sock >= 0;
+}
+
+// only for doxygen - the define is always true as defined above
+#ifdef KSOCK_NO_BROKEN
+unsigned long KSocket::ipv4_addr()
+{
+ unsigned long retval = 0;
+ KSocketAddress *sa = KExtendedSocket::peerAddress(sock);
+ if (sa == NULL)
+ return 0;
+
+ if (sa->address() != NULL && (sa->address()->sa_family == PF_INET
+#ifdef PF_INET6
+ || sa->address()->sa_family == PF_INET6
+#endif
+ ))
+ {
+ KInetSocketAddress *ksin = (KInetSocketAddress*)sa;
+ const sockaddr_in *sin = ksin->addressV4();
+ if (sin != NULL)
+ retval = sin->sin_addr.s_addr;
+ }
+ delete sa;
+ return retval;
+}
+
+bool KSocket::initSockaddr (ksockaddr_in *server_name, const char *hostname, unsigned short int port, int domain)
+{
+ // This function is now IPv4 only
+ // if you want something better, you should use KExtendedSocket::lookup yourself
+
+ kdWarning(170) << "deprecated KSocket::initSockaddr called" << endl;
+
+ if (domain != PF_INET)
+ return false;
+
+ TQPtrList<KAddressInfo> list = KExtendedSocket::lookup(hostname, TQString::number(port),
+ KExtendedSocket::ipv4Socket);
+ list.setAutoDelete(true);
+
+ if (list.isEmpty())
+ return false;
+
+ memset(server_name, 0, sizeof(*server_name));
+
+ // We are sure that only KInetSocketAddress objects are in the list
+ KInetSocketAddress *sin = (KInetSocketAddress*)list.getFirst()->address();
+ if (sin == NULL)
+ return false;
+
+ memcpy(server_name, sin->addressV4(), sizeof(*server_name));
+ kdDebug(170) << "KSocket::initSockaddr: returning " << sin->pretty() << endl;
+ return true;
+}
+
+#endif
+
+KSocket::~KSocket()
+{
+ // Coolo says delete 0 is ok :) -thiago
+ delete d->readNotifier;
+ delete d->writeNotifier;
+
+ delete d;
+
+ if (sock != -1) {
+ ::close( sock );
+ }
+}
+
+class KServerSocketPrivate
+{
+public:
+ bool bind;
+ TQCString path;
+ unsigned short int port;
+ KExtendedSocket *ks;
+};
+
+
+KServerSocket::KServerSocket( const char *_path, bool _bind ) :
+ sock( -1 )
+{
+ d = new KServerSocketPrivate();
+ d->bind = _bind;
+
+ init ( _path );
+}
+
+KServerSocket::KServerSocket( unsigned short int _port, bool _bind ) :
+ sock( -1 )
+{
+ d = new KServerSocketPrivate();
+ d->bind = _bind;
+
+ init ( _port );
+}
+
+bool KServerSocket::init( const char *_path )
+{
+ unlink(_path );
+ d->path = _path;
+
+ KExtendedSocket *ks = new KExtendedSocket(TQString::null, _path, KExtendedSocket::passiveSocket |
+ KExtendedSocket::unixSocket);
+ d->ks = ks;
+
+ if (d->bind)
+ return bindAndListen();
+ return true;
+}
+
+
+bool KServerSocket::init( unsigned short int _port )
+{
+ d->port = _port;
+ KExtendedSocket *ks;
+ ks = new KExtendedSocket(TQString::null, _port, KExtendedSocket::passiveSocket |
+ KExtendedSocket::inetSocket);
+ d->ks = ks;
+
+ if (d->bind)
+ return bindAndListen();
+ return true;
+}
+
+bool KServerSocket::bindAndListen()
+{
+ if (d == NULL || d->ks == NULL)
+ return false;
+
+
+ int ret = d->ks->listen( SOMAXCONN );
+ if (ret < 0)
+ {
+ kdWarning(170) << "Error listening on socket: " << ret << "\n";
+ delete d->ks;
+ d->ks = NULL;
+ sock = -1;
+ return false;
+ }
+
+
+ sock = d->ks->fd();
+
+ connect( d->ks->readNotifier(), TQT_SIGNAL( activated(int) ), this, TQT_SLOT( slotAccept(int) ) );
+ return true;
+}
+
+
+unsigned short int KServerSocket::port()
+{
+ if (d == NULL || d->ks == NULL || sock == -1)
+ return 0;
+ const KSocketAddress *sa = d->ks->localAddress();
+ if (sa == NULL)
+ return 0;
+
+ // we can use sockaddr_in here even if it isn't IPv4
+ sockaddr_in *sin = (sockaddr_in*)sa->address();
+
+ if (sin->sin_family == PF_INET)
+ // correct family
+ return sin->sin_port;
+#ifdef PF_INET6
+ else if (sin->sin_family == PF_INET6)
+ {
+ kde_sockaddr_in6 *sin6 = (kde_sockaddr_in6*)sin;
+ return sin6->sin6_port;
+ }
+#endif
+ return 0; // not a port we know
+}
+
+unsigned long KServerSocket::ipv4_addr()
+{
+ if (d == NULL || d->ks == NULL || sock == -1)
+ return 0;
+ const KSocketAddress *sa = d->ks->localAddress();
+
+ const sockaddr_in *sin = (sockaddr_in*)sa->address();
+
+ if (sin->sin_family == PF_INET)
+ // correct family
+ return ntohl(sin->sin_addr.s_addr);
+#ifdef PF_INET6
+ else if (sin->sin_family == PF_INET6)
+ {
+ KInetSocketAddress *ksin = (KInetSocketAddress*)sa;
+ sin = ksin->addressV4();
+ if (sin != NULL)
+ return sin->sin_addr.s_addr;
+ }
+#endif
+ return 0; // this is dumb, isn't it?
+}
+
+void KServerSocket::slotAccept( int )
+{
+ if (d == NULL || d->ks == NULL || sock == -1)
+ return; // nothing!
+
+ KExtendedSocket *s;
+ if (d->ks->accept(s) < 0)
+ {
+ kdWarning(170) << "Error accepting\n";
+ return;
+ }
+
+ int new_sock = s->fd();
+ s->release(); // we're getting rid of the KExtendedSocket
+ delete s;
+
+ emit accepted( new KSocket( new_sock ) );
+}
+
+KServerSocket::~KServerSocket()
+{
+ if (d != NULL)
+ {
+ if (d->ks != NULL)
+ delete d->ks;
+ delete d;
+ }
+ // deleting d->ks closes the socket
+ // ::close( sock );
+}
+
+#include "ksock.moc"