ksock.cpp
00001 /* 00002 * This file is part of the KDE libraries 00003 * Copyright (C) 1997 Torben Weis (weis@kde.org) 00004 * 00005 * $Id$ 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 // FIXME 00044 // FOR BINARY COMPATIBILITY ONLY 00045 // REMOVE WHEN PRACTICAL! 00046 #define TDESOCKET_BINARY_COMPAT_HACK 1 00047 #include "ksock.h" 00048 #undef TDESOCKET_BINARY_COMPAT_HACK 00049 #include "kextsock.h" 00050 #include "ksockaddr.h" 00051 00052 #include "ksocks.h" 00053 00054 extern "C" { 00055 #include <errno.h> 00056 #include <fcntl.h> 00057 00058 #ifdef HAVE_GETADDRINFO 00059 #include <netdb.h> 00060 #endif 00061 00062 // defines MAXDNAME under Solaris 00063 #include <arpa/nameser.h> 00064 #include <resolv.h> 00065 } 00066 #include <stdio.h> 00067 #include <stdlib.h> 00068 #include <string.h> 00069 #include <signal.h> 00070 #include <unistd.h> 00071 #include <assert.h> 00072 00073 #ifdef HAVE_SYSENT_H 00074 #include <sysent.h> 00075 #endif 00076 00077 #if TIME_WITH_SYS_TIME 00078 #include <time.h> 00079 #endif 00080 00081 00082 // Play it safe, use a reasonable default, if SOMAXCONN was nowhere defined. 00083 #ifndef SOMAXCONN 00084 #warning Your header files do not seem to support SOMAXCONN 00085 #define SOMAXCONN 5 00086 #endif 00087 00088 #include <tqapplication.h> 00089 #include <tqsocketnotifier.h> 00090 00091 #include "netsupp.h" // leave this last 00092 00093 #ifdef __CYGWIN__ 00094 #include "tqwindowdefs.h" 00095 #endif 00096 00097 class TDESocketPrivate 00098 { 00099 public: 00100 TQSocketNotifier *readNotifier; 00101 TQSocketNotifier *writeNotifier; 00102 00103 TDESocketPrivate() : 00104 readNotifier(0), writeNotifier(0) 00105 { } 00106 }; 00107 00108 // I moved this into here so we could accurately detect the domain, for 00109 // posterity. Really. 00110 TDESocket::TDESocket( int _sock) 00111 : sock(_sock), d(new TDESocketPrivate) 00112 { 00113 struct sockaddr_in sin; 00114 ksocklen_t len = sizeof(sin); 00115 00116 memset(&sin, 0, len); 00117 00118 // getsockname will fill in all the appropriate details, and 00119 // since sockaddr_in will exist everywhere and is somewhat compatible 00120 // with sockaddr_in6, we can use it to avoid needless ifdefs. 00121 KSocks::self()->getsockname(_sock, (struct sockaddr *)&sin, &len); 00122 } 00123 00124 TDESocket::TDESocket( const char *_host, unsigned short int _port, int _timeout ) : 00125 sock( -1 ), d(new TDESocketPrivate) 00126 { 00127 connect( _host, _port, _timeout ); 00128 } 00129 00130 TDESocket::TDESocket( const char *_path ) : 00131 sock( -1 ), d(new TDESocketPrivate) 00132 { 00133 connect( _path ); 00134 } 00135 00136 void TDESocket::enableRead( bool _state ) 00137 { 00138 if ( _state ) 00139 { 00140 if ( !d->readNotifier ) 00141 { 00142 d->readNotifier = new TQSocketNotifier( sock, TQSocketNotifier::Read ); 00143 TQObject::connect( d->readNotifier, TQT_SIGNAL( activated(int) ), this, TQT_SLOT( slotRead(int) ) ); 00144 } 00145 else 00146 d->readNotifier->setEnabled( true ); 00147 } 00148 else if ( d->readNotifier ) 00149 d->readNotifier->setEnabled( false ); 00150 } 00151 00152 void TDESocket::enableWrite( bool _state ) 00153 { 00154 if ( _state ) 00155 { 00156 if ( !d->writeNotifier ) 00157 { 00158 d->writeNotifier = new TQSocketNotifier( sock, TQSocketNotifier::Write ); 00159 TQObject::connect( d->writeNotifier, TQT_SIGNAL( activated(int) ), this, 00160 TQT_SLOT( slotWrite(int) ) ); 00161 } 00162 else 00163 d->writeNotifier->setEnabled( true ); 00164 } 00165 else if ( d->writeNotifier ) 00166 d->writeNotifier->setEnabled( false ); 00167 } 00168 00169 void TDESocket::slotRead( int ) 00170 { 00171 char buffer[2]; 00172 00173 int n = recv( sock, buffer, 1, MSG_PEEK ); 00174 if ( n <= 0 ) 00175 emit closeEvent( this ); 00176 else 00177 emit readEvent( this ); 00178 } 00179 00180 void TDESocket::slotWrite( int ) 00181 { 00182 emit writeEvent( this ); 00183 } 00184 00185 /* 00186 * Connects the PF_UNIX domain socket to _path. 00187 */ 00188 bool TDESocket::connect( const char *_path ) 00189 { 00190 KExtendedSocket ks(TQString::null, _path, KExtendedSocket::unixSocket); 00191 00192 ks.connect(); 00193 sock = ks.fd(); 00194 ks.release(); 00195 00196 return sock >= 0; 00197 } 00198 00199 /* 00200 * Connects the socket to _host, _port. 00201 */ 00202 bool TDESocket::connect( const TQString& _host, unsigned short int _port, int _timeout ) 00203 { 00204 KExtendedSocket ks(_host, _port, KExtendedSocket::inetSocket); 00205 ks.setTimeout(_timeout, 0); 00206 00207 ks.connect(); 00208 sock = ks.fd(); 00209 ks.release(); 00210 00211 return sock >= 0; 00212 } 00213 00214 // only for doxygen - the define is always true as defined above 00215 #ifdef KSOCK_NO_BROKEN 00216 unsigned long TDESocket::ipv4_addr() 00217 { 00218 unsigned long retval = 0; 00219 TDESocketAddress *sa = KExtendedSocket::peerAddress(sock); 00220 if (sa == NULL) 00221 return 0; 00222 00223 if (sa->address() != NULL && (sa->address()->sa_family == PF_INET 00224 #ifdef PF_INET6 00225 || sa->address()->sa_family == PF_INET6 00226 #endif 00227 )) 00228 { 00229 KInetSocketAddress *ksin = (KInetSocketAddress*)sa; 00230 const sockaddr_in *sin = ksin->addressV4(); 00231 if (sin != NULL) 00232 retval = sin->sin_addr.s_addr; 00233 } 00234 delete sa; 00235 return retval; 00236 } 00237 00238 bool TDESocket::initSockaddr (ksockaddr_in *server_name, const char *hostname, unsigned short int port, int domain) 00239 { 00240 // This function is now IPv4 only 00241 // if you want something better, you should use KExtendedSocket::lookup yourself 00242 00243 kdWarning(170) << "deprecated TDESocket::initSockaddr called" << endl; 00244 00245 if (domain != PF_INET) 00246 return false; 00247 00248 TQPtrList<KAddressInfo> list = KExtendedSocket::lookup(hostname, TQString::number(port), 00249 KExtendedSocket::ipv4Socket); 00250 list.setAutoDelete(true); 00251 00252 if (list.isEmpty()) 00253 return false; 00254 00255 memset(server_name, 0, sizeof(*server_name)); 00256 00257 // We are sure that only KInetSocketAddress objects are in the list 00258 KInetSocketAddress *sin = (KInetSocketAddress*)list.getFirst()->address(); 00259 if (sin == NULL) 00260 return false; 00261 00262 memcpy(server_name, sin->addressV4(), sizeof(*server_name)); 00263 kdDebug(170) << "TDESocket::initSockaddr: returning " << sin->pretty() << endl; 00264 return true; 00265 } 00266 00267 #endif 00268 00269 TDESocket::~TDESocket() 00270 { 00271 // Coolo says delete 0 is ok :) -thiago 00272 delete d->readNotifier; 00273 delete d->writeNotifier; 00274 00275 delete d; 00276 00277 if (sock != -1) { 00278 ::close( sock ); 00279 } 00280 } 00281 00282 class TDEServerSocketPrivate 00283 { 00284 public: 00285 bool bind; 00286 TQCString path; 00287 unsigned short int port; 00288 KExtendedSocket *ks; 00289 }; 00290 00291 00292 TDEServerSocket::TDEServerSocket( const char *_path, bool _bind ) : 00293 sock( -1 ) 00294 { 00295 d = new TDEServerSocketPrivate(); 00296 d->bind = _bind; 00297 00298 init ( _path ); 00299 } 00300 00301 TDEServerSocket::TDEServerSocket( unsigned short int _port, bool _bind ) : 00302 sock( -1 ) 00303 { 00304 d = new TDEServerSocketPrivate(); 00305 d->bind = _bind; 00306 00307 init ( _port ); 00308 } 00309 00310 bool TDEServerSocket::init( const char *_path ) 00311 { 00312 unlink(_path ); 00313 d->path = _path; 00314 00315 KExtendedSocket *ks = new KExtendedSocket(TQString::null, _path, KExtendedSocket::passiveSocket | 00316 KExtendedSocket::unixSocket); 00317 d->ks = ks; 00318 00319 if (d->bind) 00320 return bindAndListen(false); 00321 return true; 00322 } 00323 00324 00325 bool TDEServerSocket::init( unsigned short int _port ) 00326 { 00327 d->port = _port; 00328 KExtendedSocket *ks; 00329 ks = new KExtendedSocket(TQString::null, _port, KExtendedSocket::passiveSocket | 00330 KExtendedSocket::inetSocket); 00331 d->ks = ks; 00332 00333 if (d->bind) 00334 return bindAndListen(false); 00335 return true; 00336 } 00337 00338 bool TDEServerSocket::bindAndListen(bool suppressFailureMessages) 00339 { 00340 if (d == NULL || d->ks == NULL) 00341 return false; 00342 00343 00344 int ret = d->ks->listen( SOMAXCONN ); 00345 if (ret < 0) 00346 { 00347 if (!suppressFailureMessages) 00348 { 00349 kdWarning(170) << "Error listening on socket for port " << d->ks->port() << ": " << ret << "\n"; 00350 } 00351 delete d->ks; 00352 d->ks = NULL; 00353 sock = -1; 00354 return false; 00355 } 00356 00357 00358 sock = d->ks->fd(); 00359 00360 connect( d->ks->readNotifier(), TQT_SIGNAL( activated(int) ), this, TQT_SLOT( slotAccept(int) ) ); 00361 return true; 00362 } 00363 00364 00365 unsigned short int TDEServerSocket::port() 00366 { 00367 if (d == NULL || d->ks == NULL || sock == -1) 00368 return 0; 00369 const TDESocketAddress *sa = d->ks->localAddress(); 00370 if (sa == NULL) 00371 return 0; 00372 00373 // we can use sockaddr_in here even if it isn't IPv4 00374 sockaddr_in *sin = (sockaddr_in*)sa->address(); 00375 00376 if (sin->sin_family == PF_INET) 00377 // correct family 00378 return sin->sin_port; 00379 #ifdef PF_INET6 00380 else if (sin->sin_family == PF_INET6) 00381 { 00382 kde_sockaddr_in6 *sin6 = (kde_sockaddr_in6*)sin; 00383 return sin6->sin6_port; 00384 } 00385 #endif 00386 return 0; // not a port we know 00387 } 00388 00389 unsigned long TDEServerSocket::ipv4_addr() 00390 { 00391 if (d == NULL || d->ks == NULL || sock == -1) 00392 return 0; 00393 const TDESocketAddress *sa = d->ks->localAddress(); 00394 00395 const sockaddr_in *sin = (sockaddr_in*)sa->address(); 00396 00397 if (sin->sin_family == PF_INET) 00398 // correct family 00399 return ntohl(sin->sin_addr.s_addr); 00400 #ifdef PF_INET6 00401 else if (sin->sin_family == PF_INET6) 00402 { 00403 KInetSocketAddress *ksin = (KInetSocketAddress*)sa; 00404 sin = ksin->addressV4(); 00405 if (sin != NULL) 00406 return sin->sin_addr.s_addr; 00407 } 00408 #endif 00409 return 0; // this is dumb, isn't it? 00410 } 00411 00412 void TDEServerSocket::slotAccept( int ) 00413 { 00414 if (d == NULL || d->ks == NULL || sock == -1) 00415 return; // nothing! 00416 00417 KExtendedSocket *s; 00418 if (d->ks->accept(s) < 0) 00419 { 00420 kdWarning(170) << "Error accepting\n"; 00421 return; 00422 } 00423 00424 int new_sock = s->fd(); 00425 s->release(); // we're getting rid of the KExtendedSocket 00426 delete s; 00427 00428 emit accepted( new TDESocket( new_sock ) ); 00429 } 00430 00431 TDEServerSocket::~TDEServerSocket() 00432 { 00433 if (d != NULL) 00434 { 00435 if (d->ks != NULL) 00436 delete d->ks; 00437 delete d; 00438 } 00439 // deleting d->ks closes the socket 00440 // ::close( sock ); 00441 } 00442 00443 // DEPRECATED 00444 bool TDEServerSocket::bindAndListen() 00445 { 00446 return bindAndListen(false); 00447 } 00448 00449 #include "ksock.moc"