1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Copyright (C) 2016 Intel Corporation. |
5 | ** Contact: https://www.qt.io/licensing/ |
6 | ** |
7 | ** This file is part of the QtNetwork module of the Qt Toolkit. |
8 | ** |
9 | ** $QT_BEGIN_LICENSE:LGPL$ |
10 | ** Commercial License Usage |
11 | ** Licensees holding valid commercial Qt licenses may use this file in |
12 | ** accordance with the commercial license agreement provided with the |
13 | ** Software or, alternatively, in accordance with the terms contained in |
14 | ** a written agreement between you and The Qt Company. For licensing terms |
15 | ** and conditions see https://www.qt.io/terms-conditions. For further |
16 | ** information use the contact form at https://www.qt.io/contact-us. |
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 3 as published by the Free Software |
21 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
22 | ** packaging of this file. Please review the following information to |
23 | ** ensure the GNU Lesser General Public License version 3 requirements |
24 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
25 | ** |
26 | ** GNU General Public License Usage |
27 | ** Alternatively, this file may be used under the terms of the GNU |
28 | ** General Public License version 2.0 or (at your option) the GNU General |
29 | ** Public license version 3 or any later version approved by the KDE Free |
30 | ** Qt Foundation. The licenses are as published by the Free Software |
31 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
32 | ** included in the packaging of this file. Please review the following |
33 | ** information to ensure the GNU General Public License requirements will |
34 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
35 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
36 | ** |
37 | ** $QT_END_LICENSE$ |
38 | ** |
39 | ****************************************************************************/ |
40 | |
41 | #ifndef QNATIVESOCKETENGINE_P_H |
42 | #define QNATIVESOCKETENGINE_P_H |
43 | |
44 | // |
45 | // W A R N I N G |
46 | // ------------- |
47 | // |
48 | // This file is not part of the Qt API. It exists purely as an |
49 | // implementation detail. This header file may change from version to |
50 | // version without notice, or even be removed. |
51 | // |
52 | // We mean it. |
53 | // |
54 | |
55 | #include <QtNetwork/private/qtnetworkglobal_p.h> |
56 | #include "QtNetwork/qhostaddress.h" |
57 | #include "QtNetwork/qnetworkinterface.h" |
58 | #include "private/qabstractsocketengine_p.h" |
59 | #ifndef Q_OS_WIN |
60 | # include "qplatformdefs.h" |
61 | # include <netinet/in.h> |
62 | #else |
63 | # include <winsock2.h> |
64 | # include <ws2tcpip.h> |
65 | # include <mswsock.h> |
66 | #endif |
67 | |
68 | QT_BEGIN_NAMESPACE |
69 | |
70 | #ifdef Q_OS_WIN |
71 | # define QT_SOCKLEN_T int |
72 | # define QT_SOCKOPTLEN_T int |
73 | |
74 | // The following definitions are copied from the MinGW header mswsock.h which |
75 | // was placed in the public domain. The WSASendMsg and WSARecvMsg functions |
76 | // were introduced with Windows Vista, so some Win32 headers are lacking them. |
77 | // There are no known versions of Windows CE or Embedded that contain them. |
78 | # ifndef WSAID_WSARECVMSG |
79 | typedef INT (WINAPI *LPFN_WSARECVMSG)(SOCKET s, LPWSAMSG lpMsg, |
80 | LPDWORD lpdwNumberOfBytesRecvd, |
81 | LPWSAOVERLAPPED lpOverlapped, |
82 | LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); |
83 | # define WSAID_WSARECVMSG {0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}} |
84 | # endif // !WSAID_WSARECVMSG |
85 | # ifndef WSAID_WSASENDMSG |
86 | typedef struct { |
87 | LPWSAMSG lpMsg; |
88 | DWORD dwFlags; |
89 | LPDWORD lpNumberOfBytesSent; |
90 | LPWSAOVERLAPPED lpOverlapped; |
91 | LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine; |
92 | } WSASENDMSG, *LPWSASENDMSG; |
93 | |
94 | typedef INT (WSAAPI *LPFN_WSASENDMSG)(SOCKET s, LPWSAMSG lpMsg, DWORD dwFlags, |
95 | LPDWORD lpNumberOfBytesSent, |
96 | LPWSAOVERLAPPED lpOverlapped, |
97 | LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); |
98 | |
99 | # define WSAID_WSASENDMSG {0xa441e712,0x754f,0x43ca,{0x84,0xa7,0x0d,0xee,0x44,0xcf,0x60,0x6d}} |
100 | # endif // !WSAID_WSASENDMSG |
101 | #endif // Q_OS_WIN |
102 | |
103 | union qt_sockaddr { |
104 | sockaddr a; |
105 | sockaddr_in a4; |
106 | sockaddr_in6 a6; |
107 | }; |
108 | |
109 | namespace { |
110 | namespace SetSALen { |
111 | template <typename T> void set(T *sa, typename std::enable_if<(&T::sa_len, true), QT_SOCKLEN_T>::type len) |
112 | { sa->sa_len = len; } |
113 | template <typename T> void set(T *sin6, typename std::enable_if<(&T::sin6_len, true), QT_SOCKLEN_T>::type len) |
114 | { sin6->sin6_len = len; } |
115 | template <typename T> void set(T *, ...) {} |
116 | } |
117 | } |
118 | |
119 | class QNativeSocketEnginePrivate; |
120 | #ifndef QT_NO_NETWORKINTERFACE |
121 | class QNetworkInterface; |
122 | #endif |
123 | |
124 | class Q_AUTOTEST_EXPORT QNativeSocketEngine : public QAbstractSocketEngine |
125 | { |
126 | Q_OBJECT |
127 | public: |
128 | QNativeSocketEngine(QObject *parent = nullptr); |
129 | ~QNativeSocketEngine(); |
130 | |
131 | bool initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::IPv4Protocol) override; |
132 | bool initialize(qintptr socketDescriptor, QAbstractSocket::SocketState socketState = QAbstractSocket::ConnectedState) override; |
133 | |
134 | qintptr socketDescriptor() const override; |
135 | |
136 | bool isValid() const override; |
137 | |
138 | bool connectToHost(const QHostAddress &address, quint16 port) override; |
139 | bool connectToHostByName(const QString &name, quint16 port) override; |
140 | bool bind(const QHostAddress &address, quint16 port) override; |
141 | bool listen() override; |
142 | int accept() override; |
143 | void close() override; |
144 | |
145 | qint64 bytesAvailable() const override; |
146 | |
147 | qint64 read(char *data, qint64 maxlen) override; |
148 | qint64 write(const char *data, qint64 len) override; |
149 | |
150 | #ifndef QT_NO_UDPSOCKET |
151 | #ifndef QT_NO_NETWORKINTERFACE |
152 | bool joinMulticastGroup(const QHostAddress &groupAddress, |
153 | const QNetworkInterface &iface) override; |
154 | bool leaveMulticastGroup(const QHostAddress &groupAddress, |
155 | const QNetworkInterface &iface) override; |
156 | QNetworkInterface multicastInterface() const override; |
157 | bool setMulticastInterface(const QNetworkInterface &iface) override; |
158 | #endif |
159 | |
160 | bool hasPendingDatagrams() const override; |
161 | qint64 pendingDatagramSize() const override; |
162 | #endif // QT_NO_UDPSOCKET |
163 | |
164 | qint64 (char *data, qint64 maxlen, QIpPacketHeader * = nullptr, |
165 | PacketHeaderOptions = WantNone) override; |
166 | qint64 (const char *data, qint64 len, const QIpPacketHeader &) override; |
167 | qint64 bytesToWrite() const override; |
168 | |
169 | #if 0 // currently unused |
170 | qint64 receiveBufferSize() const; |
171 | void setReceiveBufferSize(qint64 bufferSize); |
172 | |
173 | qint64 sendBufferSize() const; |
174 | void setSendBufferSize(qint64 bufferSize); |
175 | #endif |
176 | |
177 | int option(SocketOption option) const override; |
178 | bool setOption(SocketOption option, int value) override; |
179 | |
180 | bool waitForRead(int msecs = 30000, bool *timedOut = nullptr) override; |
181 | bool waitForWrite(int msecs = 30000, bool *timedOut = nullptr) override; |
182 | bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, |
183 | bool checkRead, bool checkWrite, |
184 | int msecs = 30000, bool *timedOut = nullptr) override; |
185 | |
186 | bool isReadNotificationEnabled() const override; |
187 | void setReadNotificationEnabled(bool enable) override; |
188 | bool isWriteNotificationEnabled() const override; |
189 | void setWriteNotificationEnabled(bool enable) override; |
190 | bool isExceptionNotificationEnabled() const override; |
191 | void setExceptionNotificationEnabled(bool enable) override; |
192 | |
193 | public Q_SLOTS: |
194 | // non-virtual override; |
195 | void connectionNotification(); |
196 | |
197 | private: |
198 | Q_DECLARE_PRIVATE(QNativeSocketEngine) |
199 | Q_DISABLE_COPY_MOVE(QNativeSocketEngine) |
200 | }; |
201 | |
202 | class QSocketNotifier; |
203 | |
204 | class QNativeSocketEnginePrivate : public QAbstractSocketEnginePrivate |
205 | { |
206 | Q_DECLARE_PUBLIC(QNativeSocketEngine) |
207 | public: |
208 | QNativeSocketEnginePrivate(); |
209 | ~QNativeSocketEnginePrivate(); |
210 | |
211 | qintptr socketDescriptor; |
212 | |
213 | QSocketNotifier *readNotifier, *writeNotifier, *exceptNotifier; |
214 | |
215 | #if defined(Q_OS_WIN) |
216 | LPFN_WSASENDMSG sendmsg; |
217 | LPFN_WSARECVMSG recvmsg; |
218 | # endif |
219 | enum ErrorString { |
220 | NonBlockingInitFailedErrorString, |
221 | BroadcastingInitFailedErrorString, |
222 | NoIpV6ErrorString, |
223 | RemoteHostClosedErrorString, |
224 | TimeOutErrorString, |
225 | ResourceErrorString, |
226 | OperationUnsupportedErrorString, |
227 | ProtocolUnsupportedErrorString, |
228 | InvalidSocketErrorString, |
229 | HostUnreachableErrorString, |
230 | NetworkUnreachableErrorString, |
231 | AccessErrorString, |
232 | ConnectionTimeOutErrorString, |
233 | ConnectionRefusedErrorString, |
234 | AddressInuseErrorString, |
235 | AddressNotAvailableErrorString, |
236 | AddressProtectedErrorString, |
237 | DatagramTooLargeErrorString, |
238 | SendDatagramErrorString, |
239 | ReceiveDatagramErrorString, |
240 | WriteErrorString, |
241 | ReadErrorString, |
242 | PortInuseErrorString, |
243 | NotSocketErrorString, |
244 | InvalidProxyTypeString, |
245 | TemporaryErrorString, |
246 | NetworkDroppedConnectionErrorString, |
247 | ConnectionResetErrorString, |
248 | |
249 | UnknownSocketErrorString = -1 |
250 | }; |
251 | |
252 | void setError(QAbstractSocket::SocketError error, ErrorString errorString) const; |
253 | QHostAddress adjustAddressProtocol(const QHostAddress &address) const; |
254 | |
255 | // native functions |
256 | int option(QNativeSocketEngine::SocketOption option) const; |
257 | bool setOption(QNativeSocketEngine::SocketOption option, int value); |
258 | |
259 | bool createNewSocket(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol &protocol); |
260 | |
261 | bool nativeConnect(const QHostAddress &address, quint16 port); |
262 | bool nativeBind(const QHostAddress &address, quint16 port); |
263 | bool nativeListen(int backlog); |
264 | int nativeAccept(); |
265 | #ifndef QT_NO_NETWORKINTERFACE |
266 | bool nativeJoinMulticastGroup(const QHostAddress &groupAddress, |
267 | const QNetworkInterface &iface); |
268 | bool nativeLeaveMulticastGroup(const QHostAddress &groupAddress, |
269 | const QNetworkInterface &iface); |
270 | QNetworkInterface nativeMulticastInterface() const; |
271 | bool nativeSetMulticastInterface(const QNetworkInterface &iface); |
272 | #endif |
273 | qint64 nativeBytesAvailable() const; |
274 | |
275 | bool nativeHasPendingDatagrams() const; |
276 | qint64 nativePendingDatagramSize() const; |
277 | qint64 (char *data, qint64 maxLength, QIpPacketHeader *, |
278 | QAbstractSocketEngine::PacketHeaderOptions options); |
279 | qint64 (const char *data, qint64 length, const QIpPacketHeader &); |
280 | qint64 nativeRead(char *data, qint64 maxLength); |
281 | qint64 nativeWrite(const char *data, qint64 length); |
282 | int nativeSelect(int timeout, bool selectForRead) const; |
283 | int nativeSelect(int timeout, bool checkRead, bool checkWrite, |
284 | bool *selectForRead, bool *selectForWrite) const; |
285 | |
286 | void nativeClose(); |
287 | |
288 | bool checkProxy(const QHostAddress &address); |
289 | bool fetchConnectionParameters(); |
290 | |
291 | #if QT_CONFIG(networkinterface) |
292 | static uint scopeIdFromString(const QString &scopeid) |
293 | { return QNetworkInterface::interfaceIndexFromName(name: scopeid); } |
294 | #endif |
295 | |
296 | /*! \internal |
297 | Sets \a address and \a port in the \a aa sockaddr structure and the size in \a sockAddrSize. |
298 | The address \a is converted to IPv6 if the current socket protocol is also IPv6. |
299 | */ |
300 | void setPortAndAddress(quint16 port, const QHostAddress &address, qt_sockaddr *aa, QT_SOCKLEN_T *sockAddrSize) |
301 | { |
302 | if (address.protocol() == QAbstractSocket::IPv6Protocol |
303 | || address.protocol() == QAbstractSocket::AnyIPProtocol |
304 | || socketProtocol == QAbstractSocket::IPv6Protocol |
305 | || socketProtocol == QAbstractSocket::AnyIPProtocol) { |
306 | memset(s: &aa->a6, c: 0, n: sizeof(sockaddr_in6)); |
307 | aa->a6.sin6_family = AF_INET6; |
308 | #if QT_CONFIG(networkinterface) |
309 | aa->a6.sin6_scope_id = scopeIdFromString(scopeid: address.scopeId()); |
310 | #endif |
311 | aa->a6.sin6_port = htons(hostshort: port); |
312 | Q_IPV6ADDR tmp = address.toIPv6Address(); |
313 | memcpy(dest: &aa->a6.sin6_addr, src: &tmp, n: sizeof(tmp)); |
314 | *sockAddrSize = sizeof(sockaddr_in6); |
315 | SetSALen::set(&aa->a, sizeof(sockaddr_in6)); |
316 | } else { |
317 | memset(s: &aa->a, c: 0, n: sizeof(sockaddr_in)); |
318 | aa->a4.sin_family = AF_INET; |
319 | aa->a4.sin_port = htons(hostshort: port); |
320 | aa->a4.sin_addr.s_addr = htonl(hostlong: address.toIPv4Address()); |
321 | *sockAddrSize = sizeof(sockaddr_in); |
322 | SetSALen::set(&aa->a, sizeof(sockaddr_in)); |
323 | } |
324 | } |
325 | |
326 | }; |
327 | |
328 | QT_END_NAMESPACE |
329 | |
330 | #endif // QNATIVESOCKETENGINE_P_H |
331 | |