source: trunk/src/network/socket/qlocalserver_unix.cpp@ 1165

Last change on this file since 1165 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 8.2 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtNetwork module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qlocalserver.h"
43#include "qlocalserver_p.h"
44#include "qlocalsocket.h"
45#include "qlocalsocket_p.h"
46#include "qnet_unix_p.h"
47
48#ifndef QT_NO_LOCALSERVER
49
50#include <sys/socket.h>
51#include <sys/un.h>
52
53#include <qdebug.h>
54#include <qdir.h>
55#include <qdatetime.h>
56
57#ifdef Q_OS_VXWORKS
58# include <selectLib.h>
59#endif
60
61QT_BEGIN_NAMESPACE
62
63void QLocalServerPrivate::init()
64{
65}
66
67bool QLocalServerPrivate::removeServer(const QString &name)
68{
69 QString fileName;
70 if (name.startsWith(QLatin1Char('/'))) {
71 fileName = name;
72 } else {
73 fileName = QDir::cleanPath(QDir::tempPath());
74 fileName += QLatin1Char('/') + name;
75 }
76 if (QFile::exists(fileName))
77 return QFile::remove(fileName);
78 else
79 return true;
80}
81
82bool QLocalServerPrivate::listen(const QString &requestedServerName)
83{
84 Q_Q(QLocalServer);
85
86 // determine the full server path
87 if (requestedServerName.startsWith(QLatin1Char('/'))) {
88 fullServerName = requestedServerName;
89 } else {
90 fullServerName = QDir::cleanPath(QDir::tempPath());
91 fullServerName += QLatin1Char('/') + requestedServerName;
92 }
93 serverName = requestedServerName;
94
95 // create the unix socket
96 listenSocket = qt_safe_socket(PF_UNIX, SOCK_STREAM, 0);
97 if (-1 == listenSocket) {
98 setError(QLatin1String("QLocalServer::listen"));
99 closeServer();
100 return false;
101 }
102
103 // Construct the unix address
104 struct ::sockaddr_un addr;
105 addr.sun_family = PF_UNIX;
106 if (sizeof(addr.sun_path) < (uint)fullServerName.toLatin1().size() + 1) {
107 setError(QLatin1String("QLocalServer::listen"));
108 closeServer();
109 return false;
110 }
111 ::memcpy(addr.sun_path, fullServerName.toLatin1().data(),
112 fullServerName.toLatin1().size() + 1);
113
114#ifdef Q_OS_SYMBIAN
115 // In SYMBIAN OS it can currently happen that accept is called twice,
116 // once from waitForNewConnection and once via QSocketNotfier activity
117 //
118 // As an workaround, we set the socket to non blocking so possible
119 // subsequent call to accept will not block in any case
120 //
121 // This change can be removed once more generic fix to select thread
122 // synchronization problem is implemented.
123 int flags = fcntl(listenSocket, F_GETFL, 0);
124 if (-1 == flags
125 || -1 == (fcntl(listenSocket, F_SETFL, flags | O_NONBLOCK))) {
126 setError(QLatin1String("QLocalServer::listen"));
127 closeServer();
128 return false;
129 }
130#endif
131
132 // bind
133 if(-1 == QT_SOCKET_BIND(listenSocket, (sockaddr *)&addr, sizeof(sockaddr_un))) {
134 setError(QLatin1String("QLocalServer::listen"));
135 // if address is in use already, just close the socket, but do not delete the file
136 if(errno == EADDRINUSE)
137 QT_CLOSE(listenSocket);
138 // otherwise, close the socket and delete the file
139 else
140 closeServer();
141 listenSocket = -1;
142 return false;
143 }
144
145 // listen for connections
146 if (-1 == qt_safe_listen(listenSocket, 50)) {
147 setError(QLatin1String("QLocalServer::listen"));
148 closeServer();
149 listenSocket = -1;
150 if (error != QAbstractSocket::AddressInUseError)
151 QFile::remove(fullServerName);
152 return false;
153 }
154 Q_ASSERT(!socketNotifier);
155 socketNotifier = new QSocketNotifier(listenSocket,
156 QSocketNotifier::Read, q);
157 q->connect(socketNotifier, SIGNAL(activated(int)),
158 q, SLOT(_q_onNewConnection()));
159 socketNotifier->setEnabled(maxPendingConnections > 0);
160 return true;
161}
162
163/*!
164 \internal
165
166 \sa QLocalServer::closeServer()
167 */
168void QLocalServerPrivate::closeServer()
169{
170 if (-1 != listenSocket)
171 QT_CLOSE(listenSocket);
172 listenSocket = -1;
173
174 if (socketNotifier) {
175 socketNotifier->setEnabled(false); // Otherwise, closed socket is checked before deleter runs
176 socketNotifier->deleteLater();
177 socketNotifier = 0;
178 }
179
180 if (!fullServerName.isEmpty())
181 QFile::remove(fullServerName);
182}
183
184/*!
185 \internal
186
187 We have received a notification that we can read on the listen socket.
188 Accept the new socket.
189 */
190void QLocalServerPrivate::_q_onNewConnection()
191{
192 Q_Q(QLocalServer);
193 if (-1 == listenSocket)
194 return;
195
196 ::sockaddr_un addr;
197 QT_SOCKLEN_T length = sizeof(sockaddr_un);
198 int connectedSocket = qt_safe_accept(listenSocket, (sockaddr *)&addr, &length);
199 if(-1 == connectedSocket) {
200 setError(QLatin1String("QLocalSocket::activated"));
201 closeServer();
202 } else {
203 socketNotifier->setEnabled(pendingConnections.size()
204 <= maxPendingConnections);
205 q->incomingConnection(connectedSocket);
206 }
207}
208
209void QLocalServerPrivate::waitForNewConnection(int msec, bool *timedOut)
210{
211 fd_set readfds;
212 FD_ZERO(&readfds);
213 FD_SET(listenSocket, &readfds);
214
215 timeval timeout;
216 timeout.tv_sec = msec / 1000;
217 timeout.tv_usec = (msec % 1000) * 1000;
218
219 int result = -1;
220 result = qt_safe_select(listenSocket + 1, &readfds, 0, 0, (msec == -1) ? 0 : &timeout);
221 if (-1 == result) {
222 setError(QLatin1String("QLocalServer::waitForNewConnection"));
223 closeServer();
224 }
225 if (result > 0)
226 _q_onNewConnection();
227 if (timedOut)
228 *timedOut = (result == 0);
229}
230
231void QLocalServerPrivate::setError(const QString &function)
232{
233 if (EAGAIN == errno)
234 return;
235
236 switch (errno) {
237 case EACCES:
238 errorString = QLocalServer::tr("%1: Permission denied").arg(function);
239 error = QAbstractSocket::SocketAccessError;
240 break;
241 case ELOOP:
242 case ENOENT:
243 case ENAMETOOLONG:
244 case EROFS:
245 case ENOTDIR:
246 errorString = QLocalServer::tr("%1: Name error").arg(function);
247 error = QAbstractSocket::HostNotFoundError;
248 break;
249 case EADDRINUSE:
250 errorString = QLocalServer::tr("%1: Address in use").arg(function);
251 error = QAbstractSocket::AddressInUseError;
252 break;
253
254 default:
255 errorString = QLocalServer::tr("%1: Unknown error %2")
256 .arg(function).arg(errno);
257 error = QAbstractSocket::UnknownSocketError;
258#if defined QLOCALSERVER_DEBUG
259 qWarning() << errorString << "fullServerName:" << fullServerName;
260#endif
261 }
262}
263
264QT_END_NAMESPACE
265
266#endif // QT_NO_LOCALSERVER
Note: See TracBrowser for help on using the repository browser.