1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company 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 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qplatformdefs.h"
43 #include "qwssocket_qws.h"
44
45 #ifndef QT_NO_QWS_MULTIPROCESS
46
47 #include <fcntl.h>
48 #include <netdb.h>
49 #include <errno.h>
50 #include <stdio.h>
51 #include <sys/file.h>
52 #include <sys/time.h>
53 #include <sys/un.h>
54
55 #ifdef __MIPSEL__
56 # ifndef SOCK_DGRAM
57 # define SOCK_DGRAM 1
58 # endif
59 # ifndef SOCK_STREAM
60 # define SOCK_STREAM 2
61 # endif
62 #endif
63
64 #if defined(Q_OS_SOLARIS) || defined (QT_LINUXBASE)
65 // uff-da apparently Solaris doesn't have the SUN_LEN macro, here is
66 // an implementation of it...
67 # ifndef SUN_LEN
68 # define SUN_LEN(su) \
69 sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)
70 # endif
71
72 // nor the POSIX names of UNIX domain sockets *sigh*
73 # ifndef AF_LOCAL
74 # define AF_LOCAL AF_UNIX
75 # endif
76 # ifndef PF_LOCAL
77 # define PF_LOCAL PF_UNIX
78 # endif
79 #endif // Q_OS_SOLARIS || QT_LINUXBASE
80
81 QT_BEGIN_NAMESPACE
82
83 /***********************************************************************
84 *
85 * QWSSocket
86 *
87 **********************************************************************/
QWSSocket(QObject * parent)88 QWSSocket::QWSSocket(QObject *parent)
89 : QWS_SOCK_BASE(parent)
90 {
91 #ifndef QT_NO_SXE
92 QObject::connect( this, SIGNAL(stateChanged(SocketState)),
93 this, SLOT(forwardStateChange(SocketState)));
94 #endif
95 }
96
~QWSSocket()97 QWSSocket::~QWSSocket()
98 {
99 }
100
101 #ifndef QT_NO_SXE
errorString()102 QString QWSSocket::errorString()
103 {
104 switch (QUnixSocket::error()) {
105 case NoError:
106 return QString();
107 case InvalidPath:
108 case NonexistentPath:
109 return QLatin1String("Bad path"); // NO_TR
110 default:
111 return QLatin1String("Bad socket"); // NO TR
112 }
113 }
114
forwardStateChange(QUnixSocket::SocketState st)115 void QWSSocket::forwardStateChange(QUnixSocket::SocketState st )
116 {
117 switch ( st )
118 {
119 case ConnectedState:
120 emit connected();
121 break;
122 case ClosingState:
123 break;
124 case UnconnectedState:
125 emit disconnected();
126 break;
127 default:
128 // nothing
129 break;
130 }
131 if ( QUnixSocket::error() != NoError )
132 emit error((QAbstractSocket::SocketError)0);
133 }
134 #endif
135
connectToLocalFile(const QString & file)136 bool QWSSocket::connectToLocalFile(const QString &file)
137 {
138 #ifndef QT_NO_SXE
139 bool result = QUnixSocket::connect( file.toLocal8Bit() );
140 if ( !result )
141 {
142 perror( "QWSSocketAuth::connectToLocalFile could not connect:" );
143 emit error(QAbstractSocket::ConnectionRefusedError);
144 return false;
145 }
146 return true;
147 #else
148 // create socket
149 int s = ::socket(PF_LOCAL, SOCK_STREAM, 0);
150
151 // connect to socket
152 struct sockaddr_un a;
153 memset(&a, 0, sizeof(a));
154 a.sun_family = PF_LOCAL;
155 strncpy(a.sun_path, file.toLocal8Bit().constData(), sizeof(a.sun_path) - 1);
156 int r = ::connect(s, (struct sockaddr*)&a, SUN_LEN(&a));
157 if (r == 0) {
158 setSocketDescriptor(s);
159 } else {
160 perror("QWSSocket::connectToLocalFile could not connect:");
161 ::close(s);
162 emit error(ConnectionRefusedError);
163 return false;
164 }
165 #endif
166 return true;
167 }
168
169
170 /***********************************************************************
171 *
172 * QWSServerSocket
173 *
174 **********************************************************************/
QWSServerSocket(const QString & file,QObject * parent)175 QWSServerSocket::QWSServerSocket(const QString& file, QObject *parent)
176 #ifndef QT_NO_SXE
177 : QUnixSocketServer(parent)
178 #else
179 : QTcpServer(parent)
180 #endif
181 {
182 init(file);
183 }
184
init(const QString & file)185 void QWSServerSocket::init(const QString &file)
186 {
187 #ifndef QT_NO_SXE
188 QByteArray fn = file.toLocal8Bit();
189 bool result = QUnixSocketServer::listen( fn );
190 if ( !result )
191 {
192 QUnixSocketServer::ServerError err = serverError();
193 switch ( err )
194 {
195 case InvalidPath:
196 qWarning("QWSServerSocket:: invalid path %s", qPrintable(file));
197 break;
198 case ResourceError:
199 case BindError:
200 case ListenError:
201 qWarning("QWSServerSocket:: could not listen on path %s", qPrintable(file));
202 break;
203 default:
204 break;
205 }
206 }
207 #else
208 int backlog = 16; //#####
209
210 // create socket
211 int s = ::socket(PF_LOCAL, SOCK_STREAM, 0);
212 if (s == -1) {
213 perror("QWSServerSocket::init");
214 qWarning("QWSServerSocket: unable to create socket.");
215 return;
216 }
217
218 QByteArray fn = file.toLocal8Bit();
219 unlink(fn.constData()); // doesn't have to succeed
220
221 // bind socket
222 struct sockaddr_un a;
223 memset(&a, 0, sizeof(a));
224 a.sun_family = PF_LOCAL;
225 strncpy(a.sun_path, fn.constData(), sizeof(a.sun_path) - 1);
226 int r = ::bind(s, (struct sockaddr*)&a, SUN_LEN(&a));
227 if (r < 0) {
228 perror("QWSServerSocket::init");
229 qWarning("QWSServerSocket: could not bind to file %s", fn.constData());
230 ::close(s);
231 return;
232 }
233
234 if (chmod(fn.constData(), 0600) < 0) {
235 perror("QWSServerSocket::init");
236 qWarning("Could not set permissions of %s", fn.constData());
237 ::close(s);
238 return;
239 }
240
241 // listen
242 if (::listen(s, backlog) == 0) {
243 if (!setSocketDescriptor(s))
244 qWarning( "QWSServerSocket could not set descriptor %d : %s", s, errorString().toLatin1().constData());
245 } else {
246 perror("QWSServerSocket::init");
247 qWarning("QWSServerSocket: could not listen to file %s", fn.constData());
248 ::close(s);
249 }
250 #endif
251 }
252
~QWSServerSocket()253 QWSServerSocket::~QWSServerSocket()
254 {
255 }
256
257 #ifndef QT_NO_SXE
258
incomingConnection(int socketDescriptor)259 void QWSServerSocket::incomingConnection(int socketDescriptor)
260 {
261 inboundConnections.append( socketDescriptor );
262 emit newConnection();
263 }
264
265
nextPendingConnection()266 QWSSocket *QWSServerSocket::nextPendingConnection()
267 {
268 QMutexLocker locker( &ssmx );
269 if ( inboundConnections.count() == 0 )
270 return 0;
271 QWSSocket *s = new QWSSocket();
272 s->setSocketDescriptor( inboundConnections.takeFirst() );
273 return s;
274 }
275
276 #endif // QT_NO_SXE
277
278 QT_END_NAMESPACE
279
280 #endif //QT_NO_QWS_MULTIPROCESS
281