| 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 | |