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.89 2003/06/26 21:13:41 tjansen 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 appropriate 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 kdecore Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Sep 29 09:43:11 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003