QNativeSocketEngine: add code to send extra IP header data
authorThiago Macieira <thiago.macieira@intel.com>
Wed, 11 Mar 2015 00:03:42 +0000 (17:03 -0700)
committerThiago Macieira <thiago.macieira@intel.com>
Sat, 22 Aug 2015 22:26:37 +0000 (22:26 +0000)
Change-Id: Iee8cbc07c4434ce9b560ffff13ca48c053bd88ed
Reviewed-by: Richard J. Moore <rich@kde.org>
src/network/socket/qnativesocketengine_unix.cpp
src/network/socket/qnativesocketengine_win.cpp

index 7e794e8c0ff49fd7bcf6f3cfca43ddf33b97056b..f2fac66cd6a352d7f9171c93b156e40ddfbe8ca5 100644 (file)
@@ -975,6 +975,10 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS
 
 qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 len, const QIpPacketHeader &header)
 {
+    // we use quintptr to force the alignment
+    quintptr cbuf[(CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int)) + sizeof(quintptr) - 1) / sizeof(quintptr)];
+
+    struct cmsghdr *cmsgptr = reinterpret_cast<struct cmsghdr *>(cbuf);
     struct msghdr msg;
     struct iovec vec;
     qt_sockaddr aa;
@@ -986,6 +990,7 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l
     msg.msg_iov = &vec;
     msg.msg_iovlen = 1;
     msg.msg_name = &aa.a;
+    msg.msg_control = &cbuf;
 
     if (header.destinationAddress.protocol() == QAbstractSocket::IPv6Protocol
         || socketProtocol == QAbstractSocket::IPv6Protocol
@@ -997,17 +1002,70 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l
         Q_IPV6ADDR tmp = header.destinationAddress.toIPv6Address();
         memcpy(&aa.a6.sin6_addr, &tmp, sizeof(tmp));
         msg.msg_namelen = sizeof(aa.a6);
+
+        if (header.hopLimit != -1) {
+            msg.msg_controllen += CMSG_SPACE(sizeof(int));
+            cmsgptr->cmsg_len = CMSG_LEN(sizeof(int));
+            cmsgptr->cmsg_level = IPPROTO_IPV6;
+            cmsgptr->cmsg_type = IPV6_HOPLIMIT;
+            memcpy(CMSG_DATA(cmsgptr), &header.hopLimit, sizeof(int));
+            cmsgptr = reinterpret_cast<cmsghdr *>(reinterpret_cast<char *>(cmsgptr) + CMSG_SPACE(sizeof(int)));
+        }
+        if (header.ifindex != 0 || !header.senderAddress.isNull()) {
+            struct in6_pktinfo *data = reinterpret_cast<in6_pktinfo *>(CMSG_DATA(cmsgptr));
+            memset(data, 0, sizeof(*data));
+            msg.msg_controllen += CMSG_SPACE(sizeof(*data));
+            cmsgptr->cmsg_len = CMSG_LEN(sizeof(*data));
+            cmsgptr->cmsg_level = IPPROTO_IPV6;
+            cmsgptr->cmsg_type = IPV6_PKTINFO;
+            data->ipi6_ifindex = header.ifindex;
+
+            tmp = header.senderAddress.toIPv6Address();
+            memcpy(&data->ipi6_addr, &tmp, sizeof(tmp));
+            cmsgptr = reinterpret_cast<cmsghdr *>(reinterpret_cast<char *>(cmsgptr) + CMSG_SPACE(sizeof(*data)));
+        }
     } else if (header.destinationAddress.protocol() == QAbstractSocket::IPv4Protocol) {
         aa.a4.sin_family = AF_INET;
         aa.a4.sin_port = htons(header.destinationPort);
         aa.a4.sin_addr.s_addr = htonl(header.destinationAddress.toIPv4Address());
         msg.msg_namelen = sizeof(aa.a4);
+
+        if (header.hopLimit != -1) {
+            msg.msg_controllen += CMSG_SPACE(sizeof(int));
+            cmsgptr->cmsg_len = CMSG_LEN(sizeof(int));
+            cmsgptr->cmsg_level = IPPROTO_IP;
+            cmsgptr->cmsg_type = IP_TTL;
+            memcpy(CMSG_DATA(cmsgptr), &header.hopLimit, sizeof(int));
+            cmsgptr = reinterpret_cast<cmsghdr *>(reinterpret_cast<char *>(cmsgptr) + CMSG_SPACE(sizeof(int)));
+        }
+
+#if defined(IP_PKTINFO) || defined(IP_SENDSRCADDR)
+        if (header.ifindex != 0 || !header.senderAddress.isNull()) {
+#  ifdef IP_PKTINFO
+            struct in_pktinfo *data = reinterpret_cast<in_pktinfo *>(CMSG_DATA(cmsgptr));
+            memset(data, 0, sizeof(*data));
+            cmsgptr->cmsg_type = IP_PKTINFO;
+            data->ipi_ifindex = header.ifindex;
+            data->ipi_addr.s_addr = htonl(header.senderAddress.toIPv4Address());
+#  elif defined(IP_SENDSRCADDR)
+            struct in_addr *data = reinterpret_cast<in_addr *>(CMSG_DATA(cmsgptr));
+            cmsgptr->cmsg_type = IP_SENDSRCADDR;
+            addr->s_addr = htonl(header.senderAddress.toIPv4Address());
+#  endif
+            cmsgptr->cmsg_level = IPPROTO_IP;
+            msg.msg_controllen += CMSG_SPACE(sizeof(*data));
+            cmsgptr->cmsg_len = CMSG_LEN(sizeof(*data));
+            cmsgptr = reinterpret_cast<cmsghdr *>(reinterpret_cast<char *>(cmsgptr) + CMSG_SPACE(sizeof(*data)));
+        }
+#endif
     } else {
         // Don't know what IP type this is, let's hope it sends
         msg.msg_name = 0;
         msg.msg_namelen = 0;
     }
 
+    if (msg.msg_controllen == 0)
+        msg.msg_control = 0;
     ssize_t sentBytes = qt_safe_sendmsg(socketDescriptor, &msg, 0);
 
     if (sentBytes < 0) {
index 2e505d62f0921f84126cec235d07a733b741d7e4..ebaa3f0c6672c10880f2d26e22f9801c0545ac76 100644 (file)
@@ -1334,6 +1334,11 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxL
 qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 len,
                                                       const QIpPacketHeader &header)
 {
+    union {
+        char cbuf[WSA_CMSG_SPACE(sizeof(struct in6_pktinfo)) + WSA_CMSG_SPACE(sizeof(int))];
+        WSACMSGHDR align;    // ensures alignment
+    };
+    WSACMSGHDR *cmsgptr = &align;
     WSAMSG msg;
     WSABUF buf;
     qt_sockaddr aa;
@@ -1353,6 +1358,59 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l
     setPortAndAddress(&aa.a4, &aa.a6, header.destinationPort,
                       header.destinationAddress, &msg.name, &msg.namelen);
 
+    if (msg.namelen == sizeof(aa.a6)) {
+        // sending IPv6
+        if (header.hopLimit != -1) {
+            msg.Control.len += WSA_CMSG_SPACE(sizeof(int));
+            cmsgptr->cmsg_len = WSA_CMSG_LEN(sizeof(int));
+            cmsgptr->cmsg_level = IPPROTO_IPV6;
+            cmsgptr->cmsg_type = IPV6_HOPLIMIT;
+            memcpy(WSA_CMSG_DATA(cmsgptr), &header.hopLimit, sizeof(int));
+            cmsgptr = reinterpret_cast<WSACMSGHDR *>(reinterpret_cast<char *>(cmsgptr)
+                                                     + WSA_CMSG_SPACE(sizeof(int)));
+        }
+        if (header.ifindex != 0 || !header.senderAddress.isNull()) {
+            struct in6_pktinfo *data = reinterpret_cast<in6_pktinfo *>(WSA_CMSG_DATA(cmsgptr));
+            memset(data, 0, sizeof(*data));
+            msg.Control.len += WSA_CMSG_SPACE(sizeof(*data));
+            cmsgptr->cmsg_len = WSA_CMSG_LEN(sizeof(*data));
+            cmsgptr->cmsg_level = IPPROTO_IPV6;
+            cmsgptr->cmsg_type = IPV6_PKTINFO;
+            data->ipi6_ifindex = header.ifindex;
+
+            Q_IPV6ADDR tmp = header.senderAddress.toIPv6Address();
+            memcpy(&data->ipi6_addr, &tmp, sizeof(tmp));
+            cmsgptr = reinterpret_cast<WSACMSGHDR *>(reinterpret_cast<char *>(cmsgptr)
+                                                     + WSA_CMSG_SPACE(sizeof(*data)));
+        }
+    } else {
+        // sending IPv4
+        if (header.hopLimit != -1) {
+            msg.Control.len += WSA_CMSG_SPACE(sizeof(int));
+            cmsgptr->cmsg_len = WSA_CMSG_LEN(sizeof(int));
+            cmsgptr->cmsg_level = IPPROTO_IP;
+            cmsgptr->cmsg_type = IP_TTL;
+            memcpy(WSA_CMSG_DATA(cmsgptr), &header.hopLimit, sizeof(int));
+            cmsgptr = reinterpret_cast<WSACMSGHDR *>(reinterpret_cast<char *>(cmsgptr)
+                                                     + WSA_CMSG_SPACE(sizeof(int)));
+        }
+        if (header.ifindex != 0 || !header.senderAddress.isNull()) {
+            struct in_pktinfo *data = reinterpret_cast<in_pktinfo *>(WSA_CMSG_DATA(cmsgptr));
+            memset(data, 0, sizeof(*data));
+            msg.Control.len += WSA_CMSG_SPACE(sizeof(*data));
+            cmsgptr->cmsg_len = WSA_CMSG_LEN(sizeof(*data));
+            cmsgptr->cmsg_level = IPPROTO_IP;
+            cmsgptr->cmsg_type = IP_PKTINFO;
+            data->ipi_ifindex = header.ifindex;
+            WSAHtonl(socketDescriptor, header.senderAddress.toIPv4Address(), &data->ipi_addr.s_addr);
+            cmsgptr = reinterpret_cast<WSACMSGHDR *>(reinterpret_cast<char *>(cmsgptr)
+                                                     + WSA_CMSG_SPACE(sizeof(*data)));
+        }
+    }
+
+    if (msg.Control.len != 0)
+        msg.Control.buf = cbuf;
+
     DWORD flags = 0;
     DWORD bytesSent = 0;
     qint64 ret = -1;