source: trunk/src/network/socket/qlocalsocket_os2.cpp@ 603

Last change on this file since 603 was 568, checked in by Dmitry A. Kuminov, 15 years ago

network: Adopted to 4.6.1 changes.

File size: 18.2 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** Copyright (C) 2009 netlabs.org. OS/2 parts.
8**
9** This file is part of the QtNetwork module of the Qt Toolkit.
10**
11** $QT_BEGIN_LICENSE:LGPL$
12** Commercial Usage
13** Licensees holding valid Qt Commercial licenses may use this file in
14** accordance with the Qt Commercial License Agreement provided with the
15** Software or, alternatively, in accordance with the terms contained in
16** a written agreement between you and Nokia.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 2.1 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 2.1 requirements
24** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25**
26** In addition, as a special exception, Nokia gives you certain additional
27** rights. These rights are described in the Nokia Qt LGPL Exception
28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29**
30** GNU General Public License Usage
31** Alternatively, this file may be used under the terms of the GNU
32** General Public License version 3.0 as published by the Free Software
33** Foundation and appearing in the file LICENSE.GPL included in the
34** packaging of this file. Please review the following information to
35** ensure the GNU General Public License version 3.0 requirements will be
36** met: http://www.gnu.org/copyleft/gpl.html.
37**
38** If you have questions regarding the use of this file, please contact
39** Nokia at [email protected].
40** $QT_END_LICENSE$
41**
42****************************************************************************/
43
44#include "qlocalsocket.h"
45#include "qlocalsocket_p.h"
46
47#ifndef QT_NO_LOCALSOCKET
48
49#include <sys/types.h>
50#include <sys/socket.h>
51#include <sys/un.h>
52#include <unistd.h>
53#include <fcntl.h>
54#include <errno.h>
55
56#include <qdatetime.h>
57#include <qdir.h>
58#include <qdebug.h>
59
60#define QT_CONNECT_TIMEOUT 30000
61
62QT_BEGIN_NAMESPACE
63
64QLocalSocketPrivate::QLocalSocketPrivate() : QIODevicePrivate(),
65 delayConnect(0),
66 connectTimer(0),
67 connectingSocket(-1),
68 connectingOpenMode(0),
69 state(QLocalSocket::UnconnectedState)
70{
71}
72
73void QLocalSocketPrivate::init()
74{
75 Q_Q(QLocalSocket);
76 // QIODevice signals
77 q->connect(&unixSocket, SIGNAL(aboutToClose()), q, SIGNAL(aboutToClose()));
78 q->connect(&unixSocket, SIGNAL(bytesWritten(qint64)),
79 q, SIGNAL(bytesWritten(qint64)));
80 q->connect(&unixSocket, SIGNAL(readyRead()), q, SIGNAL(readyRead()));
81 // QAbstractSocket signals
82 q->connect(&unixSocket, SIGNAL(connected()), q, SIGNAL(connected()));
83 q->connect(&unixSocket, SIGNAL(disconnected()), q, SIGNAL(disconnected()));
84 q->connect(&unixSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
85 q, SLOT(_q_stateChanged(QAbstractSocket::SocketState)));
86 q->connect(&unixSocket, SIGNAL(error(QAbstractSocket::SocketError)),
87 q, SLOT(_q_error(QAbstractSocket::SocketError)));
88 q->connect(&unixSocket, SIGNAL(readChannelFinished()), q, SIGNAL(readChannelFinished()));
89 unixSocket.setParent(q);
90}
91
92void QLocalSocketPrivate::_q_error(QAbstractSocket::SocketError socketError)
93{
94 Q_Q(QLocalSocket);
95 QString function = QLatin1String("QLocalSocket");
96 QLocalSocket::LocalSocketError error = (QLocalSocket::LocalSocketError)socketError;
97 QString errorString = generateErrorString(error, function);
98 q->setErrorString(errorString);
99 emit q->error(error);
100}
101
102void QLocalSocketPrivate::_q_stateChanged(QAbstractSocket::SocketState newState)
103{
104 Q_Q(QLocalSocket);
105 QLocalSocket::LocalSocketState currentState = state;
106 switch(newState) {
107 case QAbstractSocket::UnconnectedState:
108 state = QLocalSocket::UnconnectedState;
109 serverName = QString();
110 fullServerName = QString();
111 break;
112 case QAbstractSocket::ConnectingState:
113 state = QLocalSocket::ConnectingState;
114 break;
115 case QAbstractSocket::ConnectedState:
116 state = QLocalSocket::ConnectedState;
117 break;
118 case QAbstractSocket::ClosingState:
119 state = QLocalSocket::ClosingState;
120 break;
121 default:
122#if defined QLOCALSOCKET_DEBUG
123 qWarning() << "QLocalSocket::Unhandled socket state change:" << newState;
124#endif
125 return;
126 }
127 if (currentState != state)
128 emit q->stateChanged(state);
129}
130
131QString QLocalSocketPrivate::generateErrorString(QLocalSocket::LocalSocketError error, const QString &function) const
132{
133 QString errorString;
134 switch (error) {
135 case QLocalSocket::ConnectionRefusedError:
136 errorString = QLocalSocket::tr("%1: Connection refused").arg(function);
137 break;
138 case QLocalSocket::PeerClosedError:
139 errorString = QLocalSocket::tr("%1: Remote closed").arg(function);
140 break;
141 case QLocalSocket::ServerNotFoundError:
142 errorString = QLocalSocket::tr("%1: Invalid name").arg(function);
143 break;
144 case QLocalSocket::SocketAccessError:
145 errorString = QLocalSocket::tr("%1: Socket access error").arg(function);
146 break;
147 case QLocalSocket::SocketResourceError:
148 errorString = QLocalSocket::tr("%1: Socket resource error").arg(function);
149 break;
150 case QLocalSocket::SocketTimeoutError:
151 errorString = QLocalSocket::tr("%1: Socket operation timed out").arg(function);
152 break;
153 case QLocalSocket::DatagramTooLargeError:
154 errorString = QLocalSocket::tr("%1: Datagram too large").arg(function);
155 break;
156 case QLocalSocket::ConnectionError:
157 errorString = QLocalSocket::tr("%1: Connection error").arg(function);
158 break;
159 case QLocalSocket::UnsupportedSocketOperationError:
160 errorString = QLocalSocket::tr("%1: The socket operation is not supported").arg(function);
161 break;
162 case QLocalSocket::UnknownSocketError:
163 default:
164 errorString = QLocalSocket::tr("%1: Unknown error %2").arg(function).arg(errno);
165 }
166 return errorString;
167}
168
169void QLocalSocketPrivate::errorOccurred(QLocalSocket::LocalSocketError error, const QString &function)
170{
171 Q_Q(QLocalSocket);
172 switch (error) {
173 case QLocalSocket::ConnectionRefusedError:
174 unixSocket.setSocketError(QAbstractSocket::ConnectionRefusedError);
175 break;
176 case QLocalSocket::PeerClosedError:
177 unixSocket.setSocketError(QAbstractSocket::RemoteHostClosedError);
178 break;
179 case QLocalSocket::ServerNotFoundError:
180 unixSocket.setSocketError(QAbstractSocket::HostNotFoundError);
181 break;
182 case QLocalSocket::SocketAccessError:
183 unixSocket.setSocketError(QAbstractSocket::SocketAccessError);
184 break;
185 case QLocalSocket::SocketResourceError:
186 unixSocket.setSocketError(QAbstractSocket::SocketResourceError);
187 break;
188 case QLocalSocket::SocketTimeoutError:
189 unixSocket.setSocketError(QAbstractSocket::SocketTimeoutError);
190 break;
191 case QLocalSocket::DatagramTooLargeError:
192 unixSocket.setSocketError(QAbstractSocket::DatagramTooLargeError);
193 break;
194 case QLocalSocket::ConnectionError:
195 unixSocket.setSocketError(QAbstractSocket::NetworkError);
196 break;
197 case QLocalSocket::UnsupportedSocketOperationError:
198 unixSocket.setSocketError(QAbstractSocket::UnsupportedSocketOperationError);
199 break;
200 case QLocalSocket::UnknownSocketError:
201 default:
202 unixSocket.setSocketError(QAbstractSocket::UnknownSocketError);
203 }
204
205 QString errorString = generateErrorString(error, function);
206 q->setErrorString(errorString);
207 emit q->error(error);
208
209 // errors cause a disconnect
210 unixSocket.setSocketState(QAbstractSocket::UnconnectedState);
211 bool stateChanged = (state != QLocalSocket::UnconnectedState);
212 state = QLocalSocket::UnconnectedState;
213 q->close();
214 if (stateChanged)
215 q->emit stateChanged(state);
216}
217
218void QLocalSocket::connectToServer(const QString &name, OpenMode openMode)
219{
220 Q_D(QLocalSocket);
221 if (state() == ConnectedState
222 || state() == ConnectingState)
223 return;
224
225 d->errorString = QString();
226 d->unixSocket.setSocketState(QAbstractSocket::ConnectingState);
227 d->state = ConnectingState;
228 emit stateChanged(d->state);
229
230 if (name.isEmpty()) {
231 d->errorOccurred(ServerNotFoundError,
232 QLatin1String("QLocalSocket::connectToServer"));
233 return;
234 }
235
236 // create the socket
237 if (-1 == (d->connectingSocket = ::socket(PF_UNIX, SOCK_STREAM, 0))) {
238 d->errorOccurred(UnsupportedSocketOperationError,
239 QLatin1String("QLocalSocket::connectToServer"));
240 return;
241 }
242
243 // set non blocking so we can try to connect and it wont wait
244 int flags = fcntl(d->connectingSocket, F_GETFL, 0);
245 if (-1 == flags
246 || -1 == (fcntl(d->connectingSocket, F_SETFL, flags | O_NONBLOCK))) {
247 d->errorOccurred(UnknownSocketError,
248 QLatin1String("QLocalSocket::connectToServer"));
249 return;
250 }
251
252 // _q_connectToSocket does the actual connecting
253 d->connectingName = name;
254 d->connectingOpenMode = openMode;
255 d->_q_connectToSocket();
256}
257
258/*!
259 \internal
260
261 Tries to connect connectingName and connectingOpenMode
262
263 \sa connectToServer() waitForConnected()
264 */
265void QLocalSocketPrivate::_q_connectToSocket()
266{
267 Q_Q(QLocalSocket);
268 QString connectingPathName;
269
270 // determine the full server path
271 if (connectingName.startsWith(QLatin1Char('/'))) {
272 connectingPathName = connectingName;
273 } else {
274 connectingPathName = QDir::tempPath();
275 connectingPathName += QLatin1Char('/') + connectingName;
276 }
277
278 struct sockaddr_un name;
279 name.sun_family = PF_UNIX;
280 if (sizeof(name.sun_path) < (uint)connectingPathName.toLatin1().size() + 1) {
281 QString function = QLatin1String("QLocalSocket::connectToServer");
282 errorOccurred(QLocalSocket::ServerNotFoundError, function);
283 return;
284 }
285 ::memcpy(name.sun_path, connectingPathName.toLatin1().data(),
286 connectingPathName.toLatin1().size() + 1);
287 if (-1 == ::connect(connectingSocket, (struct sockaddr *)&name, sizeof(name))) {
288 QString function = QLatin1String("QLocalSocket::connectToServer");
289 switch (errno)
290 {
291 case EINVAL:
292 case ECONNREFUSED:
293 errorOccurred(QLocalSocket::ConnectionRefusedError, function);
294 break;
295 case ENOENT:
296 errorOccurred(QLocalSocket::ServerNotFoundError, function);
297 break;
298 case EACCES:
299 case EPERM:
300 errorOccurred(QLocalSocket::SocketAccessError, function);
301 break;
302 case ETIMEDOUT:
303 errorOccurred(QLocalSocket::SocketTimeoutError, function);
304 break;
305 case EAGAIN:
306 // Try again later, all of the sockets listening are full
307 if (!delayConnect) {
308 delayConnect = new QSocketNotifier(connectingSocket, QSocketNotifier::Write, q);
309 q->connect(delayConnect, SIGNAL(activated(int)), q, SLOT(_q_connectToSocket()));
310 }
311 if (!connectTimer) {
312 connectTimer = new QTimer(q);
313 q->connect(connectTimer, SIGNAL(timeout()),
314 q, SLOT(_q_abortConnectionAttempt()),
315 Qt::DirectConnection);
316 connectTimer->start(QT_CONNECT_TIMEOUT);
317 }
318 delayConnect->setEnabled(true);
319 break;
320 default:
321 errorOccurred(QLocalSocket::UnknownSocketError, function);
322 }
323 return;
324 }
325
326 // connected!
327 cancelDelayedConnect();
328
329 serverName = connectingName;
330 fullServerName = connectingPathName;
331 if (unixSocket.setSocketDescriptor(connectingSocket,
332 QAbstractSocket::ConnectedState, connectingOpenMode)) {
333 q->QIODevice::open(connectingOpenMode);
334 q->emit connected();
335 } else {
336 QString function = QLatin1String("QLocalSocket::connectToServer");
337 errorOccurred(QLocalSocket::UnknownSocketError, function);
338 }
339 connectingSocket = -1;
340 connectingName = QString();
341 connectingOpenMode = 0;
342}
343
344bool QLocalSocket::setSocketDescriptor(quintptr socketDescriptor,
345 LocalSocketState socketState, OpenMode openMode)
346{
347 Q_D(QLocalSocket);
348 QAbstractSocket::SocketState newSocketState = QAbstractSocket::UnconnectedState;
349 switch (socketState) {
350 case ConnectingState:
351 newSocketState = QAbstractSocket::ConnectingState;
352 break;
353 case ConnectedState:
354 newSocketState = QAbstractSocket::ConnectedState;
355 break;
356 case ClosingState:
357 newSocketState = QAbstractSocket::ClosingState;
358 break;
359 case UnconnectedState:
360 newSocketState = QAbstractSocket::UnconnectedState;
361 break;
362 }
363 QIODevice::open(openMode);
364 d->state = socketState;
365 return d->unixSocket.setSocketDescriptor(socketDescriptor,
366 newSocketState, openMode);
367}
368
369void QLocalSocketPrivate::_q_abortConnectionAttempt()
370{
371 Q_Q(QLocalSocket);
372 q->close();
373}
374
375void QLocalSocketPrivate::cancelDelayedConnect()
376{
377 if (delayConnect) {
378 delayConnect->setEnabled(false);
379 delete delayConnect;
380 delayConnect = 0;
381 connectTimer->stop();
382 delete connectTimer;
383 connectTimer = 0;
384 }
385}
386
387quintptr QLocalSocket::socketDescriptor() const
388{
389 Q_D(const QLocalSocket);
390 return d->unixSocket.socketDescriptor();
391}
392
393qint64 QLocalSocket::readData(char *data, qint64 c)
394{
395 Q_D(QLocalSocket);
396 return d->unixSocket.readData(data, c);
397}
398
399qint64 QLocalSocket::writeData(const char *data, qint64 c)
400{
401 Q_D(QLocalSocket);
402 return d->unixSocket.writeData(data, c);
403}
404
405void QLocalSocket::abort()
406{
407 Q_D(QLocalSocket);
408 d->unixSocket.abort();
409}
410
411qint64 QLocalSocket::bytesAvailable() const
412{
413 Q_D(const QLocalSocket);
414 return QIODevice::bytesAvailable() + d->unixSocket.bytesAvailable();
415}
416
417qint64 QLocalSocket::bytesToWrite() const
418{
419 Q_D(const QLocalSocket);
420 return d->unixSocket.bytesToWrite();
421}
422
423bool QLocalSocket::canReadLine() const
424{
425 Q_D(const QLocalSocket);
426 return QIODevice::canReadLine() || d->unixSocket.canReadLine();
427}
428
429void QLocalSocket::close()
430{
431 Q_D(QLocalSocket);
432 d->unixSocket.close();
433 d->cancelDelayedConnect();
434 if (d->connectingSocket != -1)
435 ::close(d->connectingSocket);
436 d->connectingSocket = -1;
437 d->connectingName = QString();
438 d->connectingOpenMode = 0;
439 d->serverName = QString();
440 d->fullServerName = QString();
441 QIODevice::close();
442}
443
444bool QLocalSocket::waitForBytesWritten(int msecs)
445{
446 Q_D(QLocalSocket);
447 return d->unixSocket.waitForBytesWritten(msecs);
448}
449
450bool QLocalSocket::flush()
451{
452 Q_D(QLocalSocket);
453 return d->unixSocket.flush();
454}
455
456void QLocalSocket::disconnectFromServer()
457{
458 Q_D(QLocalSocket);
459 d->unixSocket.disconnectFromHost();
460}
461
462QLocalSocket::LocalSocketError QLocalSocket::error() const
463{
464 Q_D(const QLocalSocket);
465 switch (d->unixSocket.error()) {
466 case QAbstractSocket::ConnectionRefusedError:
467 return QLocalSocket::ConnectionRefusedError;
468 case QAbstractSocket::RemoteHostClosedError:
469 return QLocalSocket::PeerClosedError;
470 case QAbstractSocket::HostNotFoundError:
471 return QLocalSocket::ServerNotFoundError;
472 case QAbstractSocket::SocketAccessError:
473 return QLocalSocket::SocketAccessError;
474 case QAbstractSocket::SocketResourceError:
475 return QLocalSocket::SocketResourceError;
476 case QAbstractSocket::SocketTimeoutError:
477 return QLocalSocket::SocketTimeoutError;
478 case QAbstractSocket::DatagramTooLargeError:
479 return QLocalSocket::DatagramTooLargeError;
480 case QAbstractSocket::NetworkError:
481 return QLocalSocket::ConnectionError;
482 case QAbstractSocket::UnsupportedSocketOperationError:
483 return QLocalSocket::UnsupportedSocketOperationError;
484 case QAbstractSocket::UnknownSocketError:
485 return QLocalSocket::UnknownSocketError;
486 default:
487#if defined QLOCALSOCKET_DEBUG
488 qWarning() << "QLocalSocket error not handled:" << d->unixSocket.error();
489#endif
490 break;
491 }
492 return UnknownSocketError;
493}
494
495bool QLocalSocket::isValid() const
496{
497 Q_D(const QLocalSocket);
498 return d->unixSocket.isValid();
499}
500
501qint64 QLocalSocket::readBufferSize() const
502{
503 Q_D(const QLocalSocket);
504 return d->unixSocket.readBufferSize();
505}
506
507void QLocalSocket::setReadBufferSize(qint64 size)
508{
509 Q_D(QLocalSocket);
510 d->unixSocket.setReadBufferSize(size);
511}
512
513bool QLocalSocket::waitForConnected(int msec)
514{
515 Q_D(QLocalSocket);
516 if (state() != ConnectingState)
517 return (state() == ConnectedState);
518
519 fd_set fds;
520 FD_ZERO(&fds);
521 FD_SET(d->connectingSocket, &fds);
522
523 timeval timeout;
524 timeout.tv_sec = msec / 1000;
525 timeout.tv_usec = (msec % 1000) * 1000;
526
527 // timeout can not be 0 or else select will return an error.
528 if (0 == msec)
529 timeout.tv_usec = 1000;
530
531 int result = -1;
532 // on Linux timeout will be updated by select, but _not_ on other systems.
533 QTime timer;
534 timer.start();
535 while (state() == ConnectingState
536 && (-1 == msec || timer.elapsed() < msec)) {
537 result = ::select(d->connectingSocket + 1, &fds, 0, 0, &timeout);
538 if (-1 == result && errno != EINTR) {
539 d->errorOccurred( QLocalSocket::UnknownSocketError,
540 QLatin1String("QLocalSocket::waitForConnected"));
541 break;
542 }
543 if (result > 0)
544 d->_q_connectToSocket();
545 }
546
547 return (state() == ConnectedState);
548}
549
550bool QLocalSocket::waitForDisconnected(int msecs)
551{
552 Q_D(QLocalSocket);
553 if (state() == UnconnectedState) {
554 qWarning() << "QLocalSocket::waitForDisconnected() is not allowed in UnconnectedState";
555 return false;
556 }
557 return (d->unixSocket.waitForDisconnected(msecs));
558}
559
560bool QLocalSocket::waitForReadyRead(int msecs)
561{
562 Q_D(QLocalSocket);
563 if (state() == QLocalSocket::UnconnectedState)
564 return false;
565 return (d->unixSocket.waitForReadyRead(msecs));
566}
567
568QT_END_NAMESPACE
569
570#endif
Note: See TracBrowser for help on using the repository browser.