• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDECore

klocalsocket_unix.cpp

Go to the documentation of this file.
00001 /*
00002  * This file is part of the KDE libraries
00003  * Copyright (C) 2007 Thiago Macieira <thiago@kde.org>
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU Library General Public
00007  * License as published by the Free Software Foundation; either
00008  * version 2 of the License, or (at your option) any later version.
00009  *
00010  * This library is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Library General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Library General Public License
00016  * along with this library; see the file COPYING.LIB.  If not, write to
00017  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019  */
00020 #include <config-network.h>
00021 
00022 #include <sys/types.h>
00023 #include <sys/time.h>
00024 #include <sys/socket.h>
00025 #include <sys/select.h>
00026 #include <sys/un.h>
00027 #include <errno.h>
00028 #include <fcntl.h>
00029 #include <string.h>
00030 #include <unistd.h>
00031 
00032 #include "klocale.h"
00033 
00034 static inline int kSocket(int af, int socketype, int proto)
00035 {
00036     int ret;
00037     do {
00038         ret = ::socket(af, socketype, proto);
00039     } while (ret == -1 && errno == EINTR);
00040     return ret;
00041 }
00042 
00043 static inline int kBind(int fd, const sockaddr *sa, int len)
00044 {
00045     int ret;
00046     do {
00047         ret = ::bind(fd, sa, len);
00048     } while (ret == -1 && errno == EINTR);
00049     return ret;
00050 }
00051 
00052 static inline int kConnect(int fd, const sockaddr *sa, int len)
00053 {
00054     int ret;
00055     do {
00056         ret = ::connect(fd, sa, len);
00057     } while (ret == -1 && errno == EINTR);
00058     return ret;
00059 }
00060 
00061 static inline int kListen(int fd, int backlog)
00062 {
00063     int ret;
00064     do {
00065         ret = ::listen(fd, backlog);
00066     } while (ret == -1 && errno == EINTR);
00067     return ret;
00068 }
00069 
00070 static inline int kAccept(int fd)
00071 {
00072     int ret;
00073     sockaddr sa;
00074     socklen_t len = sizeof(sa);
00075     do {
00076         ret = ::accept(fd, &sa, &len);
00077     } while (ret == -1 && errno == EINTR);
00078     return ret;
00079 }
00080 
00081 #ifdef socket
00082 #undef socket
00083 #endif
00084 
00085 #ifdef bind
00086 #undef bind
00087 #endif
00088 
00089 #ifdef listen
00090 #undef listen
00091 #endif
00092 
00093 #ifdef connect
00094 #undef connect
00095 #endif
00096 
00097 #ifdef accept
00098 #undef accept
00099 #endif
00100 
00101 #include <QtCore/qfile.h>
00102 #include <QtCore/qsocketnotifier.h>
00103 #include <QtCore/qvarlengtharray.h>
00104 
00105 #include "klocalsocket.h"
00106 #include "klocalsocket_p.h"
00107 
00108 #if !defined(AF_UNIX) && defined(AF_LOCAL)
00109 # define AF_UNIX       AF_LOCAL
00110 #endif
00111 
00112 class KSockaddrUn
00113 {
00114     int datalen;
00115     QVarLengthArray<char, 128> data;
00116 public:
00117     KSockaddrUn(const QString &path, KLocalSocket::LocalSocketType type);
00118     bool ok() const { return datalen; }
00119     int length() const { return datalen; }
00120     const sockaddr* address()
00121         { return reinterpret_cast<sockaddr *>(data.data()); }
00122 };
00123 
00124 KSockaddrUn::KSockaddrUn(const QString &path, KLocalSocket::LocalSocketType type)
00125     : datalen(0)
00126 {
00127     if (path.isEmpty())
00128         return;
00129 
00130     QString path2(path);
00131     if (!path.startsWith(QLatin1Char('/')))
00132         // relative path; put everything in /tmp
00133         path2.prepend(QLatin1String("/tmp/"));
00134 
00135     QByteArray encodedPath = QFile::encodeName(path2);
00136 
00137     datalen = MIN_SOCKADDR_UN_LEN + encodedPath.length();
00138     if (type == KLocalSocket::AbstractUnixSocket)
00139         ++datalen;
00140     data.resize(datalen);
00141 
00142     sockaddr_un *saddr = reinterpret_cast<sockaddr_un *>(data.data());
00143     saddr->sun_family = AF_UNIX;
00144 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
00145     saddr->sun_len = datalen;
00146 #endif
00147 
00148     if (type == KLocalSocket::UnixSocket) {
00149         strcpy(saddr->sun_path, encodedPath.constData());
00150     } else if (type == KLocalSocket::AbstractUnixSocket) {
00151         *saddr->sun_path = '\0';
00152         strcpy(saddr->sun_path + 1, encodedPath.constData());
00153     } else {
00154         datalen = 0;            // error
00155     }
00156 }
00157 
00158 static bool setNonBlocking(int fd)
00159 {
00160     int fdflags = fcntl(fd, F_GETFL, 0);
00161     if (fdflags == -1)
00162         return false;       // error
00163 
00164     fdflags |= O_NONBLOCK;
00165     if (fcntl(fd, F_SETFL, fdflags) == -1)
00166         return false;       // error
00167 
00168     return true;
00169 }
00170 
00171 void KLocalSocketPrivate::connectToPath(const QString &path, KLocalSocket::LocalSocketType aType,
00172                                         QAbstractSocket::OpenMode openMode)
00173 {
00174     if (aType == KLocalSocket::UnixSocket || aType == KLocalSocket::AbstractUnixSocket) {
00175         // connect to Unix socket
00176         KSockaddrUn addr(path, aType);
00177         if (!addr.ok()) {
00178             emitError(QAbstractSocket::NetworkError, i18n("Specified socket path is invalid"));
00179             return;
00180         }
00181 
00182         // create the socket
00183         int fd = kSocket(AF_UNIX, SOCK_STREAM, 0);
00184         if (fd == -1) {
00185             // failed
00186             emitError(QAbstractSocket::UnsupportedSocketOperationError,
00187                       i18n("The socket operation is not supported"));
00188             return;
00189         }
00190 
00191         // try to connect
00192         // ### support non-blocking mode!
00193         if (kConnect(fd, addr.address(), addr.length()) == -1) {
00194             // failed
00195             int error = errno;
00196             ::close(fd);
00197 
00198             switch (error) {
00199             case ECONNREFUSED:
00200                 emitError(QAbstractSocket::ConnectionRefusedError, i18n("Connection refused"));
00201                 return;
00202 
00203             case EACCES:
00204             case EPERM:
00205                 emitError(QAbstractSocket::SocketAccessError, i18n("Permission denied"));
00206                 return;
00207 
00208             case ETIMEDOUT:
00209                 emitError(QAbstractSocket::SocketTimeoutError, i18n("Connection timed out"));
00210                 return;
00211 
00212             default:
00213                 emitError(QAbstractSocket::UnknownSocketError, i18n("Unknown error"));
00214                 return;
00215             }
00216         }
00217 
00218         // if we got here, we succeeded in connecting
00219         if (!setNonBlocking(fd)) {
00220             ::close(fd);
00221             emitError(QAbstractSocket::UnknownSocketError, i18n("Could not set non-blocking mode"));
00222             return;
00223         }
00224 
00225         // all is good
00226         peerPath = path;
00227         type = aType;
00228 
00229         // setSocketDescriptor emits stateChanged
00230         q->setSocketDescriptor(fd, QAbstractSocket::ConnectedState, openMode);
00231         emit q->connected();
00232     } else {
00233         emitError(QAbstractSocket::UnsupportedSocketOperationError,
00234                   i18n("The socket operation is not supported"));
00235     }
00236 }
00237 
00238 bool KLocalSocketServerPrivate::listen(const QString &path, KLocalSocket::LocalSocketType aType)
00239 {
00240     qDeleteAll(pendingConnections);
00241     pendingConnections.clear();
00242 
00243     if (aType == KLocalSocket::UnixSocket || aType == KLocalSocket::AbstractUnixSocket) {
00244         KSockaddrUn addr(path, aType);
00245         if (!addr.ok()) {
00246             emitError(QAbstractSocket::NetworkError, i18n("Specified socket path is invalid"));
00247             return false;
00248         }
00249 
00250         // create the socket
00251         descriptor = kSocket(AF_UNIX, SOCK_STREAM, 0);
00252         if (descriptor == -1) {
00253             // failed
00254             emitError(QAbstractSocket::UnsupportedSocketOperationError,
00255                       i18n("The socket operation is not supported"));
00256             return false;
00257         }
00258 
00259         // try to bind to the address
00260         localPath = path;
00261         if (kBind(descriptor, addr.address(), addr.length()) == -1 ||
00262             kListen(descriptor, 5) == -1) {
00263             int error = errno;
00264             close();
00265 
00266             switch (error) {
00267             case EACCES:
00268                 emitError(QAbstractSocket::SocketAccessError, i18n("Permission denied"));
00269                 return false;
00270 
00271             case EADDRINUSE:
00272                 emitError(QAbstractSocket::AddressInUseError, i18n("Address is already in use"));
00273                 return false;
00274 
00275             case ELOOP:
00276             case ENAMETOOLONG:
00277                 emitError(QAbstractSocket::NetworkError, i18n("Path cannot be used"));
00278                 return false;
00279 
00280             case ENOENT:
00281                 emitError(QAbstractSocket::HostNotFoundError, i18n("No such file or directory"));
00282                 return false;
00283 
00284             case ENOTDIR:
00285                 emitError(QAbstractSocket::HostNotFoundError, i18n("Not a directory"));
00286                 return false;
00287 
00288             case EROFS:
00289                 emitError(QAbstractSocket::SocketResourceError, i18n("Read-only filesystem"));
00290                 return false;
00291 
00292             default:
00293                 emitError(QAbstractSocket::UnknownSocketError, i18n("Unknown error"));
00294                 return false;
00295             }
00296         }
00297 
00298         // if we got here, we succeeded in connecting
00299         if (!setNonBlocking(descriptor)) {
00300             close();
00301             emitError(QAbstractSocket::UnknownSocketError, i18n("Could not set non-blocking mode"));
00302             return false;
00303         }
00304 
00305         // done
00306         state = QAbstractSocket::ListeningState;
00307         type = aType;
00308         readNotifier = new QSocketNotifier(descriptor, QSocketNotifier::Read, q);
00309         readNotifier->setEnabled(maxPendingConnections > 0);
00310         QObject::connect(readNotifier, SIGNAL(activated(int)),
00311                          q, SLOT(_k_newConnectionActivity()));
00312         return true;
00313     }
00314 
00315     return false;
00316 }
00317 
00318 void KLocalSocketServerPrivate::close()
00319 {
00320     if (descriptor != -1)
00321         ::close(descriptor);
00322     descriptor = -1;
00323 
00324     delete readNotifier;
00325     readNotifier = 0;
00326 
00327     if (type == KLocalSocket::UnixSocket)
00328         QFile::remove(localPath);
00329     localPath.clear();
00330     type = KLocalSocket::UnknownLocalSocketType;
00331 
00332     state = QAbstractSocket::UnconnectedState;
00333     error = QAbstractSocket::UnknownSocketError;
00334     errorString.clear();
00335 }
00336 
00337 bool KLocalSocketServerPrivate::waitForNewConnection(int msec, bool *timedOut)
00338 {
00339     timeval tv;
00340     tv.tv_sec = msec / 1000;
00341     tv.tv_usec = (msec % 1000) * 1000;
00342 
00343     fd_set readset;
00344     FD_ZERO(&readset);
00345     FD_SET(descriptor, &readset);
00346 
00347     while (descriptor != -1) {
00348         int code = ::select(descriptor + 1, &readset, 0, 0, &tv);
00349         if (code == -1 && errno == EINTR) {
00350             // interrupted
00351             continue;
00352         } else if (code == -1) {
00353             // error
00354             emitError(QAbstractSocket::UnknownSocketError, i18n("Unknown socket error"));
00355             close();
00356             return false;
00357         } else if (code == 0) {
00358             // timed out
00359             if (timedOut)
00360                 *timedOut = true;
00361             return false;
00362         }
00363 
00364         // we must've got a connection. At least, there's activity.
00365         if (processSocketActivity()) {
00366             if (timedOut)
00367                 *timedOut = false;
00368             return true;
00369         }
00370     }
00371     return false;
00372 }
00373 
00374 bool KLocalSocketServerPrivate::processSocketActivity()
00375 {
00376     // we got a read notification in our socket
00377     // see if we can accept anything
00378     int newDescriptor = kAccept(descriptor);
00379     if (newDescriptor == -1) {
00380         switch (errno) {
00381         case EAGAIN:
00382             // shouldn't have happened, but it's ok
00383             return false;       // no new socket
00384 
00385         default:
00386             emitError(QAbstractSocket::UnknownSocketError, i18n("Unknown socket error"));
00387             // fall through
00388         }
00389 
00390         close();
00391         return false;
00392     }
00393 
00394     q->incomingConnection(newDescriptor);
00395     readNotifier->setEnabled(pendingConnections.size() < maxPendingConnections);
00396     return true;
00397 }
00398 
00399 void KLocalSocketServerPrivate::_k_newConnectionActivity()
00400 {
00401     if (descriptor == -1)
00402         return;
00403 
00404     processSocketActivity();
00405 }

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal