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

KDECore

  • sources
  • kde-4.14
  • kdelibs
  • kdecore
  • network
klocalsocket_unix.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the KDE libraries
3  * Copyright (C) 2007 Thiago Macieira <thiago@kde.org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB. If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 #include <config-network.h>
21 
22 #include <sys/types.h>
23 #include <sys/time.h>
24 #include <sys/socket.h>
25 #include <sys/select.h>
26 #include <sys/un.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <string.h>
30 #include <unistd.h>
31 
32 #include "klocale.h"
33 
34 static inline int kSocket(int af, int socketype, int proto)
35 {
36  int ret;
37  do {
38  ret = ::socket(af, socketype, proto);
39  } while (ret == -1 && errno == EINTR);
40  return ret;
41 }
42 
43 static inline int kBind(int fd, const sockaddr *sa, int len)
44 {
45  int ret;
46  do {
47  ret = ::bind(fd, sa, len);
48  } while (ret == -1 && errno == EINTR);
49  return ret;
50 }
51 
52 static inline int kConnect(int fd, const sockaddr *sa, int len)
53 {
54  int ret;
55  do {
56  ret = ::connect(fd, sa, len);
57  } while (ret == -1 && errno == EINTR);
58  return ret;
59 }
60 
61 static inline int kListen(int fd, int backlog)
62 {
63  int ret;
64  do {
65  ret = ::listen(fd, backlog);
66  } while (ret == -1 && errno == EINTR);
67  return ret;
68 }
69 
70 static inline int kAccept(int fd)
71 {
72  int ret;
73  sockaddr sa;
74  socklen_t len = sizeof(sa);
75  do {
76  ret = ::accept(fd, &sa, &len);
77  } while (ret == -1 && errno == EINTR);
78  return ret;
79 }
80 
81 #ifdef socket
82 #undef socket
83 #endif
84 
85 #ifdef bind
86 #undef bind
87 #endif
88 
89 #ifdef listen
90 #undef listen
91 #endif
92 
93 #ifdef connect
94 #undef connect
95 #endif
96 
97 #ifdef accept
98 #undef accept
99 #endif
100 
101 #include <QtCore/qfile.h>
102 #include <QtCore/qsocketnotifier.h>
103 #include <QtCore/qvarlengtharray.h>
104 
105 #include "klocalsocket.h"
106 #include "klocalsocket_p.h"
107 
108 #if !defined(AF_UNIX) && defined(AF_LOCAL)
109 # define AF_UNIX AF_LOCAL
110 #endif
111 
112 class KSockaddrUn
113 {
114  int datalen;
115  QVarLengthArray<char, 128> data;
116 public:
117  KSockaddrUn(const QString &path, KLocalSocket::LocalSocketType type);
118  bool ok() const { return datalen; }
119  int length() const { return datalen; }
120  const sockaddr* address()
121  { return reinterpret_cast<sockaddr *>(data.data()); }
122 };
123 
124 KSockaddrUn::KSockaddrUn(const QString &path, KLocalSocket::LocalSocketType type)
125  : datalen(0)
126 {
127  if (path.isEmpty())
128  return;
129 
130  QString path2(path);
131  if (!path.startsWith(QLatin1Char('/')))
132  // relative path; put everything in /tmp
133  path2.prepend(QLatin1String("/tmp/"));
134 
135  QByteArray encodedPath = QFile::encodeName(path2);
136 
137  datalen = MIN_SOCKADDR_UN_LEN + encodedPath.length();
138  if (type == KLocalSocket::AbstractUnixSocket)
139  ++datalen;
140  data.resize(datalen);
141 
142  sockaddr_un *saddr = reinterpret_cast<sockaddr_un *>(data.data());
143  saddr->sun_family = AF_UNIX;
144 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
145  saddr->sun_len = datalen;
146 #endif
147 
148  if (type == KLocalSocket::UnixSocket) {
149  strcpy(saddr->sun_path, encodedPath.constData());
150  } else if (type == KLocalSocket::AbstractUnixSocket) {
151  *saddr->sun_path = '\0';
152  strcpy(saddr->sun_path + 1, encodedPath.constData());
153  } else {
154  datalen = 0; // error
155  }
156 }
157 
158 static bool setNonBlocking(int fd)
159 {
160  int fdflags = fcntl(fd, F_GETFL, 0);
161  if (fdflags == -1)
162  return false; // error
163 
164  fdflags |= O_NONBLOCK;
165  if (fcntl(fd, F_SETFL, fdflags) == -1)
166  return false; // error
167 
168  return true;
169 }
170 
171 void KLocalSocketPrivate::connectToPath(const QString &path, KLocalSocket::LocalSocketType aType,
172  QAbstractSocket::OpenMode openMode)
173 {
174  if (aType == KLocalSocket::UnixSocket || aType == KLocalSocket::AbstractUnixSocket) {
175  // connect to Unix socket
176  KSockaddrUn addr(path, aType);
177  if (!addr.ok()) {
178  emitError(QAbstractSocket::NetworkError, i18n("Specified socket path is invalid"));
179  return;
180  }
181 
182  // create the socket
183  int fd = kSocket(AF_UNIX, SOCK_STREAM, 0);
184  if (fd == -1) {
185  // failed
186  emitError(QAbstractSocket::UnsupportedSocketOperationError,
187  i18n("The socket operation is not supported"));
188  return;
189  }
190 
191  // try to connect
192  // ### support non-blocking mode!
193  if (kConnect(fd, addr.address(), addr.length()) == -1) {
194  // failed
195  int error = errno;
196  ::close(fd);
197 
198  switch (error) {
199  case ECONNREFUSED:
200  emitError(QAbstractSocket::ConnectionRefusedError, i18n("Connection refused"));
201  return;
202 
203  case EACCES:
204  case EPERM:
205  emitError(QAbstractSocket::SocketAccessError, i18n("Permission denied"));
206  return;
207 
208  case ETIMEDOUT:
209  emitError(QAbstractSocket::SocketTimeoutError, i18n("Connection timed out"));
210  return;
211 
212  default:
213  emitError(QAbstractSocket::UnknownSocketError, i18n("Unknown error"));
214  return;
215  }
216  }
217 
218  // if we got here, we succeeded in connecting
219  if (!setNonBlocking(fd)) {
220  ::close(fd);
221  emitError(QAbstractSocket::UnknownSocketError, i18n("Could not set non-blocking mode"));
222  return;
223  }
224 
225  // all is good
226  peerPath = path;
227  type = aType;
228 
229  // setSocketDescriptor emits stateChanged
230  q->setSocketDescriptor(fd, QAbstractSocket::ConnectedState, openMode);
231  emit q->connected();
232  } else {
233  emitError(QAbstractSocket::UnsupportedSocketOperationError,
234  i18n("The socket operation is not supported"));
235  }
236 }
237 
238 bool KLocalSocketServerPrivate::listen(const QString &path, KLocalSocket::LocalSocketType aType)
239 {
240  qDeleteAll(pendingConnections);
241  pendingConnections.clear();
242 
243  if (aType == KLocalSocket::UnixSocket || aType == KLocalSocket::AbstractUnixSocket) {
244  KSockaddrUn addr(path, aType);
245  if (!addr.ok()) {
246  emitError(QAbstractSocket::NetworkError, i18n("Specified socket path is invalid"));
247  return false;
248  }
249 
250  // create the socket
251  descriptor = kSocket(AF_UNIX, SOCK_STREAM, 0);
252  if (descriptor == -1) {
253  // failed
254  emitError(QAbstractSocket::UnsupportedSocketOperationError,
255  i18n("The socket operation is not supported"));
256  return false;
257  }
258 
259  // try to bind to the address
260  localPath = path;
261  if (kBind(descriptor, addr.address(), addr.length()) == -1 ||
262  kListen(descriptor, 5) == -1) {
263  int error = errno;
264  close();
265 
266  switch (error) {
267  case EACCES:
268  emitError(QAbstractSocket::SocketAccessError, i18n("Permission denied"));
269  return false;
270 
271  case EADDRINUSE:
272  emitError(QAbstractSocket::AddressInUseError, i18n("Address is already in use"));
273  return false;
274 
275  case ELOOP:
276  case ENAMETOOLONG:
277  emitError(QAbstractSocket::NetworkError, i18n("Path cannot be used"));
278  return false;
279 
280  case ENOENT:
281  emitError(QAbstractSocket::HostNotFoundError, i18n("No such file or directory"));
282  return false;
283 
284  case ENOTDIR:
285  emitError(QAbstractSocket::HostNotFoundError, i18n("Not a directory"));
286  return false;
287 
288  case EROFS:
289  emitError(QAbstractSocket::SocketResourceError, i18n("Read-only filesystem"));
290  return false;
291 
292  default:
293  emitError(QAbstractSocket::UnknownSocketError, i18n("Unknown error"));
294  return false;
295  }
296  }
297 
298  // if we got here, we succeeded in connecting
299  if (!setNonBlocking(descriptor)) {
300  close();
301  emitError(QAbstractSocket::UnknownSocketError, i18n("Could not set non-blocking mode"));
302  return false;
303  }
304 
305  // done
306  state = QAbstractSocket::ListeningState;
307  type = aType;
308  readNotifier = new QSocketNotifier(descriptor, QSocketNotifier::Read, q);
309  readNotifier->setEnabled(maxPendingConnections > 0);
310  QObject::connect(readNotifier, SIGNAL(activated(int)),
311  q, SLOT(_k_newConnectionActivity()));
312  return true;
313  }
314 
315  return false;
316 }
317 
318 void KLocalSocketServerPrivate::close()
319 {
320  if (descriptor != -1)
321  ::close(descriptor);
322  descriptor = -1;
323 
324  delete readNotifier;
325  readNotifier = 0;
326 
327  if (type == KLocalSocket::UnixSocket)
328  QFile::remove(localPath);
329  localPath.clear();
330  type = KLocalSocket::UnknownLocalSocketType;
331 
332  state = QAbstractSocket::UnconnectedState;
333  error = QAbstractSocket::UnknownSocketError;
334  errorString.clear();
335 }
336 
337 bool KLocalSocketServerPrivate::waitForNewConnection(int msec, bool *timedOut)
338 {
339  timeval tv;
340  tv.tv_sec = msec / 1000;
341  tv.tv_usec = (msec % 1000) * 1000;
342 
343  fd_set readset;
344  FD_ZERO(&readset);
345  FD_SET(descriptor, &readset);
346 
347  while (descriptor != -1) {
348  int code = ::select(descriptor + 1, &readset, 0, 0, &tv);
349  if (code == -1 && errno == EINTR) {
350  // interrupted
351  continue;
352  } else if (code == -1) {
353  // error
354  emitError(QAbstractSocket::UnknownSocketError, i18n("Unknown socket error"));
355  close();
356  return false;
357  } else if (code == 0) {
358  // timed out
359  if (timedOut)
360  *timedOut = true;
361  return false;
362  }
363 
364  // we must've got a connection. At least, there's activity.
365  if (processSocketActivity()) {
366  if (timedOut)
367  *timedOut = false;
368  return true;
369  }
370  }
371  return false;
372 }
373 
374 bool KLocalSocketServerPrivate::processSocketActivity()
375 {
376  // we got a read notification in our socket
377  // see if we can accept anything
378  int newDescriptor = kAccept(descriptor);
379  if (newDescriptor == -1) {
380  switch (errno) {
381  case EAGAIN:
382  // shouldn't have happened, but it's ok
383  return false; // no new socket
384 
385  default:
386  emitError(QAbstractSocket::UnknownSocketError, i18n("Unknown socket error"));
387  // fall through
388  }
389 
390  close();
391  return false;
392  }
393 
394  q->incomingConnection(newDescriptor);
395  readNotifier->setEnabled(pendingConnections.size() < maxPendingConnections);
396  return true;
397 }
398 
399 void KLocalSocketServerPrivate::_k_newConnectionActivity()
400 {
401  if (descriptor == -1)
402  return;
403 
404  processSocketActivity();
405 }
QIODevice::OpenMode
typedef OpenMode
i18n
QString i18n(const char *text)
Returns a localized version of a string.
Definition: klocalizedstring.h:630
QSocketNotifier
QByteArray
QFile::remove
bool remove()
KLocalSocketServerPrivate::state
QAbstractSocket::SocketState state
Definition: klocalsocket_p.h:59
KLocalSocketServerPrivate::processSocketActivity
bool processSocketActivity()
Definition: klocalsocket_unix.cpp:374
KLocalSocket::AbstractUnixSocket
Abstract Unix sockets.
Definition: klocalsocket.h:61
KLocalSocketPrivate::q
KLocalSocket *const q
Definition: klocalsocket_p.h:33
KLocalSocketServerPrivate::readNotifier
QSocketNotifier * readNotifier
Definition: klocalsocket_p.h:65
KLocalSocketServerPrivate::_k_newConnectionActivity
void _k_newConnectionActivity()
Definition: klocalsocket_unix.cpp:399
QVarLengthArray< char, 128 >
KSocketFactory::listen
QTcpServer * listen(const QString &protocol, const QHostAddress &address=QHostAddress::Any, quint16 port=0, QObject *parent=0)
Opens a TCP/IP socket for listening protocol protocol, binding only at address address.
Definition: ksocketfactory.cpp:115
KLocalSocketServerPrivate::errorString
QString errorString
Definition: klocalsocket_p.h:63
QByteArray::length
int length() const
KLocalSocket::UnknownLocalSocketType
Definition: klocalsocket.h:62
QAbstractSocket::setSocketDescriptor
bool setSocketDescriptor(int socketDescriptor, SocketState socketState, QFlags< QIODevice::OpenModeFlag > openMode)
kBind
static int kBind(int fd, const sockaddr *sa, int len)
Definition: klocalsocket_unix.cpp:43
klocale.h
KLocalSocketServerPrivate::localPath
QString localPath
Definition: klocalsocket_p.h:62
kAccept
static int kAccept(int fd)
Definition: klocalsocket_unix.cpp:70
KLocalSocketServerPrivate::pendingConnections
QQueue< KLocalSocket * > pendingConnections
Definition: klocalsocket_p.h:66
KLocalSocketServerPrivate::descriptor
int descriptor
Definition: klocalsocket_p.h:57
QAbstractSocket::connected
void connected()
KLocalSocketServerPrivate::listen
bool listen(const QString &path, KLocalSocket::LocalSocketType type)
Definition: klocalsocket_unix.cpp:238
QString::clear
void clear()
KLocalSocketServerPrivate::error
QAbstractSocket::SocketError error
Definition: klocalsocket_p.h:60
KLocalSocketPrivate::connectToPath
void connectToPath(const QString &path, KLocalSocket::LocalSocketType type, QAbstractSocket::OpenMode openMode)
Definition: klocalsocket_unix.cpp:171
klocalsocket_p.h
QString::isEmpty
bool isEmpty() const
QByteArray::constData
const char * constData() const
QString::startsWith
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
KLocalSocketServerPrivate::q
KLocalSocketServer *const q
Definition: klocalsocket_p.h:54
KLocalSocketPrivate::emitError
void emitError(QAbstractSocket::SocketError, const QString &errorString)
Definition: klocalsocket.cpp:29
QString
kListen
static int kListen(int fd, int backlog)
Definition: klocalsocket_unix.cpp:61
MIN_SOCKADDR_UN_LEN
#define MIN_SOCKADDR_UN_LEN
Definition: k3socketaddress.cpp:236
QLatin1Char
KLocalSocketServerPrivate::maxPendingConnections
int maxPendingConnections
Definition: klocalsocket_p.h:58
KLocalSocketServerPrivate::close
void close()
Definition: klocalsocket_unix.cpp:318
kConnect
static int kConnect(int fd, const sockaddr *sa, int len)
Definition: klocalsocket_unix.cpp:52
QSocketNotifier::setEnabled
void setEnabled(bool enable)
kSocket
static int kSocket(int af, int socketype, int proto)
Definition: klocalsocket_unix.cpp:34
QLatin1String
KLocalSocket::UnixSocket
Unix sockets.
Definition: klocalsocket.h:60
KLocalSocketPrivate::peerPath
QString peerPath
Definition: klocalsocket_p.h:39
KLocalSocketServer::incomingConnection
virtual void incomingConnection(int handle)
Definition: klocalsocket.cpp:202
setNonBlocking
static bool setNonBlocking(int fd)
Definition: klocalsocket_unix.cpp:158
KLocalSocketServerPrivate::emitError
void emitError(QAbstractSocket::SocketError, const QString &errorString)
Definition: klocalsocket.cpp:38
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
KLocalSocket::LocalSocketType
LocalSocketType
Defines the local socket type.
Definition: klocalsocket.h:59
klocalsocket.h
QFile::encodeName
QByteArray encodeName(const QString &fileName)
KLocalSocketServerPrivate::waitForNewConnection
bool waitForNewConnection(int msec, bool *timedOut)
Definition: klocalsocket_unix.cpp:337
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:22:11 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDECore

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

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal