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 482738 2005-11-24 00:21:15Z mueller $ 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., 51 Franklin Street, Fifth Floor, 00020 * Boston, MA 02110-1301, 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 #ifdef __CYGWIN__ 00089 #include "qwindowdefs.h" 00090 #endif 00091 00092 class KSocketPrivate 00093 { 00094 public: 00095 QSocketNotifier *readNotifier; 00096 QSocketNotifier *writeNotifier; 00097 00098 KSocketPrivate() : 00099 readNotifier(0), writeNotifier(0) 00100 { } 00101 }; 00102 00103 // I moved this into here so we could accurately detect the domain, for 00104 // posterity. Really. 00105 KSocket::KSocket( int _sock) 00106 : sock(_sock), d(new KSocketPrivate) 00107 { 00108 struct sockaddr_in sin; 00109 ksocklen_t len = sizeof(sin); 00110 00111 memset(&sin, 0, len); 00112 00113 // getsockname will fill in all the appropriate details, and 00114 // since sockaddr_in will exist everywhere and is somewhat compatible 00115 // with sockaddr_in6, we can use it to avoid needless ifdefs. 00116 KSocks::self()->getsockname(_sock, (struct sockaddr *)&sin, &len); 00117 } 00118 00119 KSocket::KSocket( const char *_host, unsigned short int _port, int _timeout ) : 00120 sock( -1 ), d(new KSocketPrivate) 00121 { 00122 connect( _host, _port, _timeout ); 00123 } 00124 00125 KSocket::KSocket( const char *_path ) : 00126 sock( -1 ), d(new KSocketPrivate) 00127 { 00128 connect( _path ); 00129 } 00130 00131 void KSocket::enableRead( bool _state ) 00132 { 00133 if ( _state ) 00134 { 00135 if ( !d->readNotifier ) 00136 { 00137 d->readNotifier = new QSocketNotifier( sock, QSocketNotifier::Read ); 00138 QObject::connect( d->readNotifier, SIGNAL( activated(int) ), this, SLOT( slotRead(int) ) ); 00139 } 00140 else 00141 d->readNotifier->setEnabled( true ); 00142 } 00143 else if ( d->readNotifier ) 00144 d->readNotifier->setEnabled( false ); 00145 } 00146 00147 void KSocket::enableWrite( bool _state ) 00148 { 00149 if ( _state ) 00150 { 00151 if ( !d->writeNotifier ) 00152 { 00153 d->writeNotifier = new QSocketNotifier( sock, QSocketNotifier::Write ); 00154 QObject::connect( d->writeNotifier, SIGNAL( activated(int) ), this, 00155 SLOT( slotWrite(int) ) ); 00156 } 00157 else 00158 d->writeNotifier->setEnabled( true ); 00159 } 00160 else if ( d->writeNotifier ) 00161 d->writeNotifier->setEnabled( false ); 00162 } 00163 00164 void KSocket::slotRead( int ) 00165 { 00166 char buffer[2]; 00167 00168 int n = recv( sock, buffer, 1, MSG_PEEK ); 00169 if ( n <= 0 ) 00170 emit closeEvent( this ); 00171 else 00172 emit readEvent( this ); 00173 } 00174 00175 void KSocket::slotWrite( int ) 00176 { 00177 emit writeEvent( this ); 00178 } 00179 00180 /* 00181 * Connects the PF_UNIX domain socket to _path. 00182 */ 00183 bool KSocket::connect( const char *_path ) 00184 { 00185 KExtendedSocket ks(QString::null, _path, KExtendedSocket::unixSocket); 00186 00187 ks.connect(); 00188 sock = ks.fd(); 00189 ks.release(); 00190 00191 return sock >= 0; 00192 } 00193 00194 /* 00195 * Connects the socket to _host, _port. 00196 */ 00197 bool KSocket::connect( const QString& _host, unsigned short int _port, int _timeout ) 00198 { 00199 KExtendedSocket ks(_host, _port, KExtendedSocket::inetSocket); 00200 ks.setTimeout(_timeout, 0); 00201 00202 ks.connect(); 00203 sock = ks.fd(); 00204 ks.release(); 00205 00206 return sock >= 0; 00207 } 00208 00209 // only for doxygen - the define is always true as defined above 00210 #ifdef KSOCK_NO_BROKEN 00211 unsigned long KSocket::ipv4_addr() 00212 { 00213 unsigned long retval = 0; 00214 KSocketAddress *sa = KExtendedSocket::peerAddress(sock); 00215 if (sa == NULL) 00216 return 0; 00217 00218 if (sa->address() != NULL && (sa->address()->sa_family == PF_INET 00219 #ifdef PF_INET6 00220 || sa->address()->sa_family == PF_INET6 00221 #endif 00222 )) 00223 { 00224 KInetSocketAddress *ksin = (KInetSocketAddress*)sa; 00225 const sockaddr_in *sin = ksin->addressV4(); 00226 if (sin != NULL) 00227 retval = sin->sin_addr.s_addr; 00228 } 00229 delete sa; 00230 return retval; 00231 } 00232 00233 bool KSocket::initSockaddr (ksockaddr_in *server_name, const char *hostname, unsigned short int port, int domain) 00234 { 00235 // This function is now IPv4 only 00236 // if you want something better, you should use KExtendedSocket::lookup yourself 00237 00238 kdWarning(170) << "deprecated KSocket::initSockaddr called" << endl; 00239 00240 if (domain != PF_INET) 00241 return false; 00242 00243 QPtrList<KAddressInfo> list = KExtendedSocket::lookup(hostname, QString::number(port), 00244 KExtendedSocket::ipv4Socket); 00245 list.setAutoDelete(true); 00246 00247 if (list.isEmpty()) 00248 return false; 00249 00250 memset(server_name, 0, sizeof(*server_name)); 00251 00252 // We are sure that only KInetSocketAddress objects are in the list 00253 KInetSocketAddress *sin = (KInetSocketAddress*)list.getFirst()->address(); 00254 if (sin == NULL) 00255 return false; 00256 00257 memcpy(server_name, sin->addressV4(), sizeof(*server_name)); 00258 kdDebug(170) << "KSocket::initSockaddr: returning " << sin->pretty() << endl; 00259 return true; 00260 } 00261 00262 #endif 00263 00264 KSocket::~KSocket() 00265 { 00266 // Coolo says delete 0 is ok :) -thiago 00267 delete d->readNotifier; 00268 delete d->writeNotifier; 00269 00270 delete d; 00271 00272 if (sock != -1) { 00273 ::close( sock ); 00274 } 00275 } 00276 00277 class KServerSocketPrivate 00278 { 00279 public: 00280 bool bind; 00281 QCString path; 00282 unsigned short int port; 00283 KExtendedSocket *ks; 00284 }; 00285 00286 00287 KServerSocket::KServerSocket( const char *_path, bool _bind ) : 00288 sock( -1 ) 00289 { 00290 d = new KServerSocketPrivate(); 00291 d->bind = _bind; 00292 00293 init ( _path ); 00294 } 00295 00296 KServerSocket::KServerSocket( unsigned short int _port, bool _bind ) : 00297 sock( -1 ) 00298 { 00299 d = new KServerSocketPrivate(); 00300 d->bind = _bind; 00301 00302 init ( _port ); 00303 } 00304 00305 bool KServerSocket::init( const char *_path ) 00306 { 00307 unlink(_path ); 00308 d->path = _path; 00309 00310 KExtendedSocket *ks = new KExtendedSocket(QString::null, _path, KExtendedSocket::passiveSocket | 00311 KExtendedSocket::unixSocket); 00312 d->ks = ks; 00313 00314 if (d->bind) 00315 return bindAndListen(); 00316 return true; 00317 } 00318 00319 00320 bool KServerSocket::init( unsigned short int _port ) 00321 { 00322 d->port = _port; 00323 KExtendedSocket *ks; 00324 ks = new KExtendedSocket(QString::null, _port, KExtendedSocket::passiveSocket | 00325 KExtendedSocket::inetSocket); 00326 d->ks = ks; 00327 00328 if (d->bind) 00329 return bindAndListen(); 00330 return true; 00331 } 00332 00333 bool KServerSocket::bindAndListen() 00334 { 00335 if (d == NULL || d->ks == NULL) 00336 return false; 00337 00338 00339 int ret = d->ks->listen( SOMAXCONN ); 00340 if (ret < 0) 00341 { 00342 kdWarning(170) << "Error listening on socket: " << ret << "\n"; 00343 delete d->ks; 00344 d->ks = NULL; 00345 sock = -1; 00346 return false; 00347 } 00348 00349 00350 sock = d->ks->fd(); 00351 00352 connect( d->ks->readNotifier(), SIGNAL( activated(int) ), this, SLOT( slotAccept(int) ) ); 00353 return true; 00354 } 00355 00356 00357 unsigned short int KServerSocket::port() 00358 { 00359 if (d == NULL || d->ks == NULL || sock == -1) 00360 return 0; 00361 const KSocketAddress *sa = d->ks->localAddress(); 00362 if (sa == NULL) 00363 return 0; 00364 00365 // we can use sockaddr_in here even if it isn't IPv4 00366 sockaddr_in *sin = (sockaddr_in*)sa->address(); 00367 00368 if (sin->sin_family == PF_INET) 00369 // correct family 00370 return sin->sin_port; 00371 #ifdef PF_INET6 00372 else if (sin->sin_family == PF_INET6) 00373 { 00374 kde_sockaddr_in6 *sin6 = (kde_sockaddr_in6*)sin; 00375 return sin6->sin6_port; 00376 } 00377 #endif 00378 return 0; // not a port we know 00379 } 00380 00381 unsigned long KServerSocket::ipv4_addr() 00382 { 00383 if (d == NULL || d->ks == NULL || sock == -1) 00384 return 0; 00385 const KSocketAddress *sa = d->ks->localAddress(); 00386 00387 const sockaddr_in *sin = (sockaddr_in*)sa->address(); 00388 00389 if (sin->sin_family == PF_INET) 00390 // correct family 00391 return ntohl(sin->sin_addr.s_addr); 00392 #ifdef PF_INET6 00393 else if (sin->sin_family == PF_INET6) 00394 { 00395 KInetSocketAddress *ksin = (KInetSocketAddress*)sa; 00396 sin = ksin->addressV4(); 00397 if (sin != NULL) 00398 return sin->sin_addr.s_addr; 00399 } 00400 #endif 00401 return 0; // this is dumb, isn't it? 00402 } 00403 00404 void KServerSocket::slotAccept( int ) 00405 { 00406 if (d == NULL || d->ks == NULL || sock == -1) 00407 return; // nothing! 00408 00409 KExtendedSocket *s; 00410 if (d->ks->accept(s) < 0) 00411 { 00412 kdWarning(170) << "Error accepting\n"; 00413 return; 00414 } 00415 00416 int new_sock = s->fd(); 00417 s->release(); // we're getting rid of the KExtendedSocket 00418 delete s; 00419 00420 emit accepted( new KSocket( new_sock ) ); 00421 } 00422 00423 KServerSocket::~KServerSocket() 00424 { 00425 if (d != NULL) 00426 { 00427 if (d->ks != NULL) 00428 delete d->ks; 00429 delete d; 00430 } 00431 // deleting d->ks closes the socket 00432 // ::close( sock ); 00433 } 00434 00435 #include "ksock.moc"