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 static inline int kSocket(int af, int socketype, int proto)
00033 {
00034 int ret;
00035 do {
00036 ret = ::socket(af, socketype, proto);
00037 } while (ret == -1 && errno == EINTR);
00038 return ret;
00039 }
00040
00041 static inline int kBind(int fd, const sockaddr *sa, int len)
00042 {
00043 int ret;
00044 do {
00045 ret = ::bind(fd, sa, len);
00046 } while (ret == -1 && errno == EINTR);
00047 return ret;
00048 }
00049
00050 static inline int kConnect(int fd, const sockaddr *sa, int len)
00051 {
00052 int ret;
00053 do {
00054 ret = ::connect(fd, sa, len);
00055 } while (ret == -1 && errno == EINTR);
00056 return ret;
00057 }
00058
00059 static inline int kListen(int fd, int backlog)
00060 {
00061 int ret;
00062 do {
00063 ret = ::listen(fd, backlog);
00064 } while (ret == -1 && errno == EINTR);
00065 return ret;
00066 }
00067
00068 static inline int kAccept(int fd)
00069 {
00070 int ret;
00071 sockaddr sa;
00072 socklen_t len = sizeof(sa);
00073 do {
00074 ret = ::accept(fd, &sa, &len);
00075 } while (ret == -1 && errno == EINTR);
00076 return ret;
00077 }
00078
00079 #ifdef socket
00080 #undef socket
00081 #endif
00082
00083 #ifdef bind
00084 #undef bind
00085 #endif
00086
00087 #ifdef listen
00088 #undef listen
00089 #endif
00090
00091 #ifdef connect
00092 #undef connect
00093 #endif
00094
00095 #ifdef accept
00096 #undef accept
00097 #endif
00098
00099 #include <QtCore/qfile.h>
00100 #include <QtCore/qsocketnotifier.h>
00101 #include <QtCore/qvarlengtharray.h>
00102
00103 #include "klocalsocket.h"
00104 #include "klocalsocket_p.h"
00105
00106 #if !defined(AF_UNIX) && defined(AF_LOCAL)
00107 # define AF_UNIX AF_LOCAL
00108 #endif
00109
00110 class KSockaddrUn
00111 {
00112 int datalen;
00113 QVarLengthArray<char, 128> data;
00114 public:
00115 KSockaddrUn(const QString &path, KLocalSocket::LocalSocketType type);
00116 bool ok() const { return datalen; }
00117 int length() const { return datalen; }
00118 const sockaddr* address()
00119 { return reinterpret_cast<sockaddr *>(data.data()); }
00120 };
00121
00122 KSockaddrUn::KSockaddrUn(const QString &path, KLocalSocket::LocalSocketType type)
00123 : datalen(0)
00124 {
00125 if (path.isEmpty())
00126 return;
00127
00128 QString path2(path);
00129 if (!path.startsWith(QLatin1Char('/')))
00130
00131 path2.prepend(QLatin1String("/tmp/"));
00132
00133 QByteArray encodedPath = QFile::encodeName(path2);
00134
00135 datalen = MIN_SOCKADDR_UN_LEN + encodedPath.length();
00136 if (type == KLocalSocket::AbstractUnixSocket)
00137 ++datalen;
00138 data.resize(datalen);
00139
00140 sockaddr_un *saddr = reinterpret_cast<sockaddr_un *>(data.data());
00141 saddr->sun_family = AF_UNIX;
00142 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
00143 saddr->sun_len = datalen;
00144 #endif
00145
00146 if (type == KLocalSocket::UnixSocket) {
00147 strcpy(saddr->sun_path, encodedPath.constData());
00148 } else if (type == KLocalSocket::AbstractUnixSocket) {
00149 *saddr->sun_path = '\0';
00150 strcpy(saddr->sun_path + 1, encodedPath.constData());
00151 } else {
00152 datalen = 0;
00153 }
00154 }
00155
00156 static bool setNonBlocking(int fd)
00157 {
00158 int fdflags = fcntl(fd, F_GETFL, 0);
00159 if (fdflags == -1)
00160 return false;
00161
00162 fdflags |= O_NONBLOCK;
00163 if (fcntl(fd, F_SETFL, fdflags) == -1)
00164 return false;
00165
00166 return true;
00167 }
00168
00169 void KLocalSocketPrivate::connectToPath(const QString &path, KLocalSocket::LocalSocketType aType,
00170 QAbstractSocket::OpenMode openMode)
00171 {
00172 if (aType == KLocalSocket::UnixSocket || aType == KLocalSocket::AbstractUnixSocket) {
00173
00174 KSockaddrUn addr(path, aType);
00175 if (!addr.ok()) {
00176 emitError(QAbstractSocket::NetworkError, "Specified socket path is invalid");
00177 return;
00178 }
00179
00180
00181 int fd = kSocket(AF_UNIX, SOCK_STREAM, 0);
00182 if (fd == -1) {
00183
00184 emitError(QAbstractSocket::UnsupportedSocketOperationError,
00185 "The socket operation is not supported");
00186 return;
00187 }
00188
00189
00190
00191 if (kConnect(fd, addr.address(), addr.length()) == -1) {
00192
00193 int error = errno;
00194 ::close(fd);
00195
00196 switch (error) {
00197 case ECONNREFUSED:
00198 emitError(QAbstractSocket::ConnectionRefusedError, "Connection refused");
00199 return;
00200
00201 case EACCES:
00202 case EPERM:
00203 emitError(QAbstractSocket::SocketAccessError, "Permission denied");
00204 return;
00205
00206 case ETIMEDOUT:
00207 emitError(QAbstractSocket::SocketTimeoutError, "Connection timed out");
00208 return;
00209
00210 default:
00211 emitError(QAbstractSocket::UnknownSocketError, "Unknown error");
00212 return;
00213 }
00214 }
00215
00216
00217 if (!setNonBlocking(fd)) {
00218 ::close(fd);
00219 emitError(QAbstractSocket::UnknownSocketError, "Could not set non-blocking mode");
00220 return;
00221 }
00222
00223
00224 peerPath = path;
00225 type = aType;
00226
00227
00228 q->setSocketDescriptor(fd, QAbstractSocket::ConnectedState, openMode);
00229 emit q->connected();
00230 } else {
00231 emitError(QAbstractSocket::UnsupportedSocketOperationError,
00232 "The socket operation is not supported");
00233 }
00234 }
00235
00236 bool KLocalSocketServerPrivate::listen(const QString &path, KLocalSocket::LocalSocketType aType)
00237 {
00238 qDeleteAll(pendingConnections);
00239 pendingConnections.clear();
00240
00241 if (aType == KLocalSocket::UnixSocket || aType == KLocalSocket::AbstractUnixSocket) {
00242 KSockaddrUn addr(path, aType);
00243 if (!addr.ok()) {
00244 emitError(QAbstractSocket::NetworkError, "Specified socket path is invalid");
00245 return false;
00246 }
00247
00248
00249 descriptor = kSocket(AF_UNIX, SOCK_STREAM, 0);
00250 if (descriptor == -1) {
00251
00252 emitError(QAbstractSocket::UnsupportedSocketOperationError,
00253 "The socket operation is not supported");
00254 return false;
00255 }
00256
00257
00258 localPath = path;
00259 if (kBind(descriptor, addr.address(), addr.length()) == -1 ||
00260 kListen(descriptor, 5) == -1) {
00261 int error = errno;
00262 close();
00263
00264 switch (error) {
00265 case EACCES:
00266 emitError(QAbstractSocket::SocketAccessError, "Permission denied");
00267 return false;
00268
00269 case EADDRINUSE:
00270 emitError(QAbstractSocket::AddressInUseError, "Address is already in use");
00271 return false;
00272
00273 case ELOOP:
00274 case ENAMETOOLONG:
00275 emitError(QAbstractSocket::NetworkError, "Path cannot be used");
00276 return false;
00277
00278 case ENOENT:
00279 emitError(QAbstractSocket::HostNotFoundError, "No such file or directory");
00280 return false;
00281
00282 case ENOTDIR:
00283 emitError(QAbstractSocket::HostNotFoundError, "Not a directory");
00284 return false;
00285
00286 case EROFS:
00287 emitError(QAbstractSocket::SocketResourceError, "Read-only filesystem");
00288 return false;
00289
00290 default:
00291 emitError(QAbstractSocket::UnknownSocketError, "Unknown error");
00292 return false;
00293 }
00294 }
00295
00296
00297 if (!setNonBlocking(descriptor)) {
00298 close();
00299 emitError(QAbstractSocket::UnknownSocketError, "Could not set non-blocking mode");
00300 return false;
00301 }
00302
00303
00304 state = QAbstractSocket::ListeningState;
00305 type = aType;
00306 readNotifier = new QSocketNotifier(descriptor, QSocketNotifier::Read, q);
00307 readNotifier->setEnabled(maxPendingConnections > 0);
00308 QObject::connect(readNotifier, SIGNAL(activated(int)),
00309 q, SLOT(_k_newConnectionActivity()));
00310 return true;
00311 }
00312
00313 return false;
00314 }
00315
00316 void KLocalSocketServerPrivate::close()
00317 {
00318 if (descriptor != -1)
00319 ::close(descriptor);
00320 descriptor = -1;
00321
00322 delete readNotifier;
00323 readNotifier = 0;
00324
00325 if (type == KLocalSocket::UnixSocket)
00326 QFile::remove(localPath);
00327 localPath.clear();
00328 type = KLocalSocket::UnknownLocalSocketType;
00329
00330 state = QAbstractSocket::UnconnectedState;
00331 error = QAbstractSocket::UnknownSocketError;
00332 errorString.clear();
00333 }
00334
00335 bool KLocalSocketServerPrivate::waitForNewConnection(int msec, bool *timedOut)
00336 {
00337 timeval tv;
00338 tv.tv_sec = msec / 1000;
00339 tv.tv_usec = (msec % 1000) * 1000;
00340
00341 fd_set readset;
00342 FD_ZERO(&readset);
00343 FD_SET(descriptor, &readset);
00344
00345 while (descriptor != -1) {
00346 int code = ::select(descriptor + 1, &readset, 0, 0, &tv);
00347 if (code == -1 && errno == EINTR) {
00348
00349 continue;
00350 } else if (code == -1) {
00351
00352 emitError(QAbstractSocket::UnknownSocketError, "Unknown socket error");
00353 close();
00354 return false;
00355 } else if (code == 0) {
00356
00357 if (timedOut)
00358 *timedOut = true;
00359 return false;
00360 }
00361
00362
00363 if (processSocketActivity()) {
00364 if (timedOut)
00365 *timedOut = false;
00366 return true;
00367 }
00368 }
00369 return false;
00370 }
00371
00372 bool KLocalSocketServerPrivate::processSocketActivity()
00373 {
00374
00375
00376 int newDescriptor = kAccept(descriptor);
00377 if (newDescriptor == -1) {
00378 switch (errno) {
00379 case EAGAIN:
00380
00381 return false;
00382
00383 default:
00384 emitError(QAbstractSocket::UnknownSocketError, "Unknown socket error");
00385
00386 }
00387
00388 close();
00389 return false;
00390 }
00391
00392 q->incomingConnection(newDescriptor);
00393 readNotifier->setEnabled(pendingConnections.size() < maxPendingConnections);
00394 return true;
00395 }
00396
00397 void KLocalSocketServerPrivate::_k_newConnectionActivity()
00398 {
00399 if (descriptor == -1)
00400 return;
00401
00402 processSocketActivity();
00403 }