kdecore Library API Documentation

ksock.cpp

00001 /*
00002  *  This file is part of the KDE libraries
00003  *  Copyright (C) 1997 Torben Weis (weis@kde.org)
00004  *
00005  *  $Id: ksock.cpp,v 1.86 2002/07/31 20:57:27 coolo Exp $
00006  *
00007  *  This library is free software; you can redistribute it and/or
00008  *  modify it under the terms of the GNU Library General Public
00009  *  License as published by the Free Software Foundation; either
00010  *  version 2 of the License, or (at your option) any later version.
00011  *
00012  *  This library is distributed in the hope that it will be useful,
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  *  Library General Public License for more details.
00016  *
00017  *  You should have received a copy of the GNU Library General Public License
00018  *  along with this library; see the file COPYING.LIB.  If not, write to
00019  *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00020  *  Boston, MA 02111-1307, USA.
00021  **/
00022 
00023 #include <config.h>
00024 
00025 #include <sys/types.h>
00026 #include <sys/stat.h>
00027 // on Linux/libc5, this includes linux/socket.h where SOMAXCONN is defined
00028 #include <sys/socket.h>
00029 #include <sys/resource.h>
00030 #include <sys/time.h>
00031 #include <sys/un.h>
00032 #ifdef HAVE_SYS_SELECT_H
00033 #include <sys/select.h>
00034 #endif
00035 extern "C" {
00036 #include <netinet/in.h>
00037 
00038 #include <arpa/inet.h>
00039 }
00040 
00041 #define KSOCK_NO_BROKEN
00042 #include "kdebug.h"
00043 #include "ksock.h"
00044 #include "kextsock.h"
00045 #include "ksockaddr.h"
00046 
00047 #include "ksocks.h"
00048 
00049 extern "C" {
00050 #include <errno.h>
00051 #include <fcntl.h>
00052 
00053 #ifdef HAVE_GETADDRINFO
00054 #include <netdb.h>
00055 #endif
00056 
00057 // defines MAXDNAME under Solaris
00058 #include <arpa/nameser.h>
00059 #include <resolv.h>
00060 }
00061 #include <stdio.h>
00062 #include <stdlib.h>
00063 #include <string.h>
00064 #include <signal.h>
00065 #include <unistd.h>
00066 #include <assert.h>
00067 
00068 #ifdef HAVE_SYSENT_H
00069 #include <sysent.h>
00070 #endif
00071 
00072 #if TIME_WITH_SYS_TIME
00073 #include <time.h>
00074 #endif
00075 
00076 
00077 // Play it safe, use a reasonable default, if SOMAXCONN was nowhere defined.
00078 #ifndef SOMAXCONN
00079 #warning Your header files do not seem to support SOMAXCONN
00080 #define SOMAXCONN 5
00081 #endif
00082 
00083 #include <qapplication.h>
00084 #include <qsocketnotifier.h>
00085 
00086 #include "netsupp.h"            // leave this last
00087 
00088 class KSocketPrivate
00089 {
00090 public:
00091   QSocketNotifier *readNotifier;
00092   QSocketNotifier *writeNotifier;
00093 
00094   KSocketPrivate() :
00095     readNotifier(0), writeNotifier(0)
00096   { }
00097 };
00098 
00099 // I moved this into here so we could accurately detect the domain, for
00100 // posterity.  Really.
00101 KSocket::KSocket( int _sock)
00102   : sock(_sock), d(new KSocketPrivate)
00103 {
00104   struct sockaddr_in sin;
00105   ksocklen_t len = sizeof(sin);
00106 
00107   memset(&sin, 0, len);
00108 
00109   // getsockname will fill in all the appropiate details, and
00110   // since sockaddr_in will exist everywhere and is somewhat compatible
00111   // with sockaddr_in6, we can use it to avoid needless ifdefs.
00112   KSocks::self()->getsockname(_sock, (struct sockaddr *)&sin, &len);
00113 }
00114 
00115 KSocket::KSocket( const char *_host, unsigned short int _port, int _timeout ) :
00116   sock( -1 ), d(new KSocketPrivate)
00117 {
00118     connect( _host, _port, _timeout );
00119 }
00120 
00121 KSocket::KSocket( const char *_path ) :
00122   sock( -1 ), d(new KSocketPrivate)
00123 {
00124   connect( _path );
00125 }
00126 
00127 void KSocket::enableRead( bool _state )
00128 {
00129   if ( _state )
00130     {
00131           if ( !d->readNotifier  )
00132                 {
00133                   d->readNotifier = new QSocketNotifier( sock, QSocketNotifier::Read );
00134                   QObject::connect( d->readNotifier, SIGNAL( activated(int) ), this, SLOT( slotRead(int) ) );
00135                 }
00136           else
00137             d->readNotifier->setEnabled( true );
00138     }
00139   else if ( d->readNotifier )
00140         d->readNotifier->setEnabled( false );
00141 }
00142 
00143 void KSocket::enableWrite( bool _state )
00144 {
00145   if ( _state )
00146     {
00147           if ( !d->writeNotifier )
00148                 {
00149                   d->writeNotifier = new QSocketNotifier( sock, QSocketNotifier::Write );
00150                   QObject::connect( d->writeNotifier, SIGNAL( activated(int) ), this,
00151                                                         SLOT( slotWrite(int) ) );
00152                 }
00153           else
00154             d->writeNotifier->setEnabled( true );
00155     }
00156   else if ( d->writeNotifier )
00157         d->writeNotifier->setEnabled( false );
00158 }
00159 
00160 void KSocket::slotRead( int )
00161 {
00162   char buffer[2];
00163 
00164   int n = recv( sock, buffer, 1, MSG_PEEK );
00165   if ( n <= 0 )
00166         emit closeEvent( this );
00167   else
00168         emit readEvent( this );
00169 }
00170 
00171 void KSocket::slotWrite( int )
00172 {
00173   emit writeEvent( this );
00174 }
00175 
00176 /*
00177  * Connects the PF_UNIX domain socket to _path.
00178  */
00179 bool KSocket::connect( const char *_path )
00180 {
00181   KExtendedSocket ks(QString::null, _path, KExtendedSocket::unixSocket);
00182 
00183   ks.connect();
00184   sock = ks.fd();
00185   ks.release();
00186 
00187   return sock >= 0;
00188 }
00189 
00190 /*
00191  * Connects the socket to _host, _port.
00192  */
00193 bool KSocket::connect( const QString& _host, unsigned short int _port, int _timeout )
00194 {
00195   KExtendedSocket ks(_host, _port, KExtendedSocket::inetSocket);
00196   ks.setTimeout(_timeout, 0);
00197 
00198   ks.connect();
00199   sock = ks.fd();
00200   ks.release();
00201 
00202   return sock >= 0;
00203 }
00204 
00205 // only for doxygen - the define is always true as defined above
00206 #ifdef KSOCK_NO_BROKEN
00207 unsigned long KSocket::ipv4_addr()
00208 {
00209   unsigned long retval = 0;
00210   KSocketAddress *sa = KExtendedSocket::peerAddress(sock);
00211   if (sa == NULL)
00212     return 0;
00213 
00214   if (sa->address() != NULL && (sa->address()->sa_family == PF_INET
00215 #ifdef PF_INET6
00216                                 || sa->address()->sa_family == PF_INET6
00217 #endif
00218       ))
00219     {
00220       KInetSocketAddress *ksin = (KInetSocketAddress*)sa;
00221       const sockaddr_in *sin = ksin->addressV4();
00222       if (sin != NULL)
00223         retval = *(unsigned long*)&sin->sin_addr; // I told you this was dumb
00224     }
00225   delete sa;
00226   return retval;
00227 }
00228 
00229 bool KSocket::initSockaddr (ksockaddr_in *server_name, const char *hostname, unsigned short int port, int domain)
00230 {
00231   // This function is now IPv4 only
00232   // if you want something better, you should use KExtendedSocket::lookup yourself
00233 
00234   kdWarning(170) << "deprecated KSocket::initSockaddr called" << endl;
00235 
00236   if (domain != PF_INET)
00237     return false;
00238 
00239   QPtrList<KAddressInfo> list = KExtendedSocket::lookup(hostname, QString::number(port),
00240                                                         KExtendedSocket::ipv4Socket);
00241   list.setAutoDelete(true);
00242 
00243   if (list.isEmpty())
00244     return false;
00245 
00246   memset(server_name, 0, sizeof(*server_name));
00247 
00248   // We are sure that only KInetSocketAddress objects are in the list
00249   KInetSocketAddress *sin = (KInetSocketAddress*)list.getFirst()->address();
00250   if (sin == NULL)
00251     return false;
00252 
00253   memcpy(server_name, sin->addressV4(), sizeof(*server_name));
00254   kdDebug(170) << "KSocket::initSockaddr: returning " << sin->pretty() << endl;
00255   return true;
00256 }
00257 
00258 #endif
00259 
00260 KSocket::~KSocket()
00261 {
00262   // Coolo says delete 0 is ok :) -thiago
00263   delete d->readNotifier;
00264   delete d->writeNotifier;
00265 
00266   delete d;
00267 
00268   if (sock != -1) {
00269     ::close( sock );
00270   }
00271 }
00272 
00273 class KServerSocketPrivate
00274 {
00275 public:
00276    bool bind;
00277    QCString path;
00278    unsigned short int port;
00279    KExtendedSocket *ks;
00280 };
00281 
00282 
00283 KServerSocket::KServerSocket( const char *_path, bool _bind ) :
00284   sock( -1 )
00285 {
00286   d = new KServerSocketPrivate();
00287   d->bind = _bind;
00288 
00289   init ( _path );
00290 }
00291 
00292 KServerSocket::KServerSocket( unsigned short int _port, bool _bind ) :
00293   sock( -1 )
00294 {
00295   d = new KServerSocketPrivate();
00296   d->bind = _bind;
00297 
00298   init ( _port );
00299 }
00300 
00301 bool KServerSocket::init( const char *_path )
00302 {
00303   unlink(_path );
00304   d->path = _path;
00305 
00306   KExtendedSocket *ks = new KExtendedSocket(QString::null, _path, KExtendedSocket::passiveSocket |
00307                                             KExtendedSocket::unixSocket);
00308   d->ks = ks;
00309 
00310   if (d->bind)
00311     return bindAndListen();
00312   return true;
00313 }
00314 
00315 
00316 bool KServerSocket::init( unsigned short int _port )
00317 {
00318   d->port = _port;
00319   KExtendedSocket *ks;
00320   ks = new KExtendedSocket(QString::null, _port, KExtendedSocket::passiveSocket |
00321                            KExtendedSocket::inetSocket);
00322   d->ks = ks;
00323 
00324   if (d->bind)
00325     return bindAndListen();
00326   return true;
00327 }
00328 
00329 bool KServerSocket::bindAndListen()
00330 {
00331   if (d == NULL || d->ks == NULL)
00332     return false;
00333 
00334 
00335   int ret = d->ks->listen( SOMAXCONN );
00336   if (ret < 0)
00337     {
00338         kdWarning(170) << "Error listening on socket: " << ret << "\n";
00339         delete d->ks;
00340         d->ks = NULL;
00341         sock = -1;
00342         return false;
00343     }
00344 
00345 
00346   sock = d->ks->fd();
00347 
00348   connect( d->ks->readNotifier(), SIGNAL( activated(int) ), this, SLOT( slotAccept(int) ) );
00349   return true;
00350 }
00351 
00352 
00353 unsigned short int KServerSocket::port()
00354 {
00355   if (d == NULL || d->ks == NULL || sock == -1)
00356     return 0;
00357   const KSocketAddress *sa = d->ks->localAddress();
00358   if (sa == NULL)
00359     return 0;
00360 
00361   // we can use sockaddr_in here even if it isn't IPv4
00362   sockaddr_in *sin = (sockaddr_in*)sa->address();
00363 
00364   if (sin->sin_family == PF_INET)
00365     // correct family
00366     return sin->sin_port;
00367 #ifdef PF_INET6
00368   else if (sin->sin_family == PF_INET6)
00369     {
00370       kde_sockaddr_in6 *sin6 = (kde_sockaddr_in6*)sin;
00371       return sin6->sin6_port;
00372     }
00373 #endif
00374   return 0;                     // not a port we know
00375 }
00376 
00377 unsigned long KServerSocket::ipv4_addr()
00378 {
00379   if (d == NULL || d->ks == NULL || sock == -1)
00380     return 0;
00381   const KSocketAddress *sa = d->ks->localAddress();
00382 
00383   const sockaddr_in *sin = (sockaddr_in*)sa->address();
00384 
00385   if (sin->sin_family == PF_INET)
00386     // correct family
00387     return ntohl(*(unsigned long*)&sin->sin_addr);
00388 #ifdef PF_INET6
00389   else if (sin->sin_family == PF_INET6)
00390     {
00391       KInetSocketAddress *ksin = (KInetSocketAddress*)sa;
00392       sin = ksin->addressV4();
00393       if (sin != NULL)
00394         return *(unsigned long*)&sin->sin_addr;
00395     }
00396 #endif
00397   return 0;                     // this is dumb, isn't it?
00398 }
00399 
00400 void KServerSocket::slotAccept( int )
00401 {
00402   if (d == NULL || d->ks == NULL || sock == -1)
00403     return;                     // nothing!
00404 
00405   KExtendedSocket *s;
00406   if (d->ks->accept(s) < 0)
00407     {
00408         kdWarning(170) << "Error accepting\n";
00409         return;
00410     }
00411 
00412   int new_sock = s->fd();
00413   s->release();                 // we're getting rid of the KExtendedSocket
00414   delete s;
00415 
00416   emit accepted( new KSocket( new_sock ) );
00417 }
00418 
00419 KServerSocket::~KServerSocket()
00420 {
00421   if (d != NULL)
00422     {
00423       if (d->ks != NULL)
00424         delete d->ks;
00425       delete d;
00426     }
00427   // deleting d->ks closes the socket
00428   //  ::close( sock );
00429 }
00430 
00431 #include "ksock.moc"
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 12:46:55 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001