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

KDECore

  • 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
34static 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
43static 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
52static 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
61static 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
70static 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
112class KSockaddrUn
113{
114 int datalen;
115 QVarLengthArray<char, 128> data;
116public:
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
124KSockaddrUn::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
158static 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
171void 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
238bool 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
318void 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
337bool 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
374bool 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
399void KLocalSocketServerPrivate::_k_newConnectionActivity()
400{
401 if (descriptor == -1)
402 return;
403
404 processSocketActivity();
405}
KLocalSocketPrivate::connectToPath
void connectToPath(const QString &path, KLocalSocket::LocalSocketType type, QAbstractSocket::OpenMode openMode)
Definition: klocalsocket_unix.cpp:171
KLocalSocketPrivate::type
KLocalSocket::LocalSocketType type
Definition: klocalsocket_p.h:40
KLocalSocketPrivate::emitError
void emitError(QAbstractSocket::SocketError, const QString &errorString)
Definition: klocalsocket.cpp:29
KLocalSocketPrivate::q
KLocalSocket *const q
Definition: klocalsocket_p.h:33
KLocalSocketPrivate::peerPath
QString peerPath
Definition: klocalsocket_p.h:39
KLocalSocketServerPrivate::pendingConnections
QQueue< KLocalSocket * > pendingConnections
Definition: klocalsocket_p.h:66
KLocalSocketServerPrivate::maxPendingConnections
int maxPendingConnections
Definition: klocalsocket_p.h:58
KLocalSocketServerPrivate::errorString
QString errorString
Definition: klocalsocket_p.h:63
KLocalSocketServerPrivate::emitError
void emitError(QAbstractSocket::SocketError, const QString &errorString)
Definition: klocalsocket.cpp:38
KLocalSocketServerPrivate::close
void close()
Definition: klocalsocket_unix.cpp:318
KLocalSocketServerPrivate::type
KLocalSocket::LocalSocketType type
Definition: klocalsocket_p.h:61
KLocalSocketServerPrivate::localPath
QString localPath
Definition: klocalsocket_p.h:62
KLocalSocketServerPrivate::waitForNewConnection
bool waitForNewConnection(int msec, bool *timedOut)
Definition: klocalsocket_unix.cpp:337
KLocalSocketServerPrivate::error
QAbstractSocket::SocketError error
Definition: klocalsocket_p.h:60
KLocalSocketServerPrivate::state
QAbstractSocket::SocketState state
Definition: klocalsocket_p.h:59
KLocalSocketServerPrivate::descriptor
int descriptor
Definition: klocalsocket_p.h:57
KLocalSocketServerPrivate::_k_newConnectionActivity
void _k_newConnectionActivity()
Definition: klocalsocket_unix.cpp:399
KLocalSocketServerPrivate::readNotifier
QSocketNotifier * readNotifier
Definition: klocalsocket_p.h:65
KLocalSocketServerPrivate::listen
bool listen(const QString &path, KLocalSocket::LocalSocketType type)
Definition: klocalsocket_unix.cpp:238
KLocalSocketServerPrivate::processSocketActivity
bool processSocketActivity()
Definition: klocalsocket_unix.cpp:374
KLocalSocketServerPrivate::q
KLocalSocketServer *const q
Definition: klocalsocket_p.h:54
KLocalSocketServer::incomingConnection
virtual void incomingConnection(int handle)
Definition: klocalsocket.cpp:202
KLocalSocket::LocalSocketType
LocalSocketType
Defines the local socket type.
Definition: klocalsocket.h:59
KLocalSocket::UnknownLocalSocketType
@ UnknownLocalSocketType
Definition: klocalsocket.h:62
KLocalSocket::AbstractUnixSocket
@ AbstractUnixSocket
Abstract Unix sockets.
Definition: klocalsocket.h:61
KLocalSocket::UnixSocket
@ UnixSocket
Unix sockets.
Definition: klocalsocket.h:60
QString
MIN_SOCKADDR_UN_LEN
#define MIN_SOCKADDR_UN_LEN
Definition: k3socketaddress.cpp:236
klocale.h
i18n
QString i18n(const char *text)
Returns a localized version of a string.
Definition: klocalizedstring.h:630
klocalsocket.h
klocalsocket_p.h
kConnect
static int kConnect(int fd, const sockaddr *sa, int len)
Definition: klocalsocket_unix.cpp:52
kBind
static int kBind(int fd, const sockaddr *sa, int len)
Definition: klocalsocket_unix.cpp:43
setNonBlocking
static bool setNonBlocking(int fd)
Definition: klocalsocket_unix.cpp:158
kListen
static int kListen(int fd, int backlog)
Definition: klocalsocket_unix.cpp:61
kAccept
static int kAccept(int fd)
Definition: klocalsocket_unix.cpp:70
kSocket
static int kSocket(int af, int socketype, int proto)
Definition: klocalsocket_unix.cpp:34
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 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-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 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
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