00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
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;
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;
00163
00164 fdflags |= O_NONBLOCK;
00165 if (fcntl(fd, F_SETFL, fdflags) == -1)
00166 return false;
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
00176 KSockaddrUn addr(path, aType);
00177 if (!addr.ok()) {
00178 emitError(QAbstractSocket::NetworkError, i18n("Specified socket path is invalid"));
00179 return;
00180 }
00181
00182
00183 int fd = kSocket(AF_UNIX, SOCK_STREAM, 0);
00184 if (fd == -1) {
00185
00186 emitError(QAbstractSocket::UnsupportedSocketOperationError,
00187 i18n("The socket operation is not supported"));
00188 return;
00189 }
00190
00191
00192
00193 if (kConnect(fd, addr.address(), addr.length()) == -1) {
00194
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
00219 if (!setNonBlocking(fd)) {
00220 ::close(fd);
00221 emitError(QAbstractSocket::UnknownSocketError, i18n("Could not set non-blocking mode"));
00222 return;
00223 }
00224
00225
00226 peerPath = path;
00227 type = aType;
00228
00229
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
00251 descriptor = kSocket(AF_UNIX, SOCK_STREAM, 0);
00252 if (descriptor == -1) {
00253
00254 emitError(QAbstractSocket::UnsupportedSocketOperationError,
00255 i18n("The socket operation is not supported"));
00256 return false;
00257 }
00258
00259
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
00299 if (!setNonBlocking(descriptor)) {
00300 close();
00301 emitError(QAbstractSocket::UnknownSocketError, i18n("Could not set non-blocking mode"));
00302 return false;
00303 }
00304
00305
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
00351 continue;
00352 } else if (code == -1) {
00353
00354 emitError(QAbstractSocket::UnknownSocketError, i18n("Unknown socket error"));
00355 close();
00356 return false;
00357 } else if (code == 0) {
00358
00359 if (timedOut)
00360 *timedOut = true;
00361 return false;
00362 }
00363
00364
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
00377
00378 int newDescriptor = kAccept(descriptor);
00379 if (newDescriptor == -1) {
00380 switch (errno) {
00381 case EAGAIN:
00382
00383 return false;
00384
00385 default:
00386 emitError(QAbstractSocket::UnknownSocketError, i18n("Unknown socket error"));
00387
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 }