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