diff options
author | Thorvald Natvig <slicer@users.sourceforge.net> | 2011-05-11 09:25:56 +0400 |
---|---|---|
committer | Thorvald Natvig <slicer@users.sourceforge.net> | 2011-05-11 09:25:56 +0400 |
commit | 07bf14614a6da2fff0205c562f18566774e38e8c (patch) | |
tree | 2e434debe277e98f4f81dff337ec67e6c73ddb9d /src | |
parent | d96648ef25bdf214afe24ee306d12bfb4d0f8de4 (diff) |
Use TCP destination as UDP source
Diffstat (limited to 'src')
-rw-r--r-- | src/Net.cpp | 13 | ||||
-rw-r--r-- | src/Net.h | 1 | ||||
-rw-r--r-- | src/murmur/Server.cpp | 85 | ||||
-rw-r--r-- | src/murmur/ServerUser.cpp | 1 | ||||
-rw-r--r-- | src/murmur/ServerUser.h | 1 |
5 files changed, 92 insertions, 9 deletions
diff --git a/src/Net.cpp b/src/Net.cpp index b993bc194..5c9c5a2f3 100644 --- a/src/Net.cpp +++ b/src/Net.cpp @@ -128,6 +128,19 @@ QByteArray HostAddress::toByteArray() const { return QByteArray(reinterpret_cast<const char *>(qip6.c), 16); } +void HostAddress::toSockaddr(sockaddr_storage *dst) const { + memset(dst, 0, sizeof(*dst)); + if(isV6()) { + struct sockaddr_in6 *in6 = reinterpret_cast<struct sockaddr_in6 *>(dst); + dst->ss_family = AF_INET6; + memcpy(in6->sin6_addr.s6_addr, qip6.c, 16); + } else { + struct sockaddr_in *in = reinterpret_cast<struct sockaddr_in *>(dst); + dst->ss_family = AF_INET; + in->sin_addr.s_addr = hash[3]; + } +} + quint32 qHash(const HostAddress &ha) { return (ha.hash[0] ^ ha.hash[1] ^ ha.hash[2] ^ ha.hash[3]); } @@ -65,6 +65,7 @@ struct HostAddress { std::string toStdString() const; QHostAddress toAddress() const; QByteArray toByteArray() const; + void toSockaddr(struct sockaddr_storage *dst) const; }; Q_DECLARE_TYPEINFO(HostAddress, Q_MOVABLE_TYPE); diff --git a/src/murmur/Server.cpp b/src/murmur/Server.cpp index dd53b481b..0c53bacc6 100644 --- a/src/murmur/Server.cpp +++ b/src/murmur/Server.cpp @@ -132,6 +132,9 @@ Server::Server(int snum, QObject *p) : QThread(p) { int sockopt = 1; if (setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &sockopt, sizeof(sockopt))) log(QString("Failed to set IP_PKTINFO for %1").arg(addressToString(ss->serverAddress(), usPort))); + sockopt = 1; + if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &sockopt, sizeof(sockopt))) + log(QString("Failed to set IPV6_RECVPKTINFO for %1").arg(addressToString(ss->serverAddress(), usPort))); #endif #else #ifndef SIO_UDP_CONNRESET @@ -402,9 +405,10 @@ void Server::setLiveConf(const QString &key, const QString &value) { sendAll(mpsc); } } else if (key == "users") { + // FIXME: And what if it goes down, then up again? int newmax = i ? i : Meta::mp.iMaxUsers; - for (int i=iMaxUsers*2;i<newmax*2;++i) - qqIds.enqueue(i); + for (int id=iMaxUsers*2;id<newmax*2;++id) + qqIds.enqueue(id); iMaxUsers = newmax; } else if (key == "usersperchannel") iMaxUsersPerChannel = i ? i : Meta::mp.iMaxUsersPerChannel; @@ -482,11 +486,11 @@ void Server::setLiveConf(const QString &key, const QString &value) { else if (key == "channelname") qrChannelName=!v.isNull() ? QRegExp(v) : Meta::mp.qrChannelName; else if (key == "suggestversion") - qvSuggestVersion = ! v.isNull() ? (v.isEmpty() ? QVariant() : v ) : Meta::mp.qvSuggestVersion; + qvSuggestVersion = ! v.isNull() ? (v.isEmpty() ? QVariant() : v) : Meta::mp.qvSuggestVersion; else if (key == "suggestpositional") - qvSuggestPositional = ! v.isNull() ? (v.isEmpty() ? QVariant() : v ) : Meta::mp.qvSuggestPositional; + qvSuggestPositional = ! v.isNull() ? (v.isEmpty() ? QVariant() : v) : Meta::mp.qvSuggestPositional; else if (key == "suggestpushtotalk") - qvSuggestPushToTalk = ! v.isNull() ? (v.isEmpty() ? QVariant() : v ) : Meta::mp.qvSuggestPushToTalk; + qvSuggestPushToTalk = ! v.isNull() ? (v.isEmpty() ? QVariant() : v) : Meta::mp.qvSuggestPushToTalk; } #ifdef USE_BONJOUR @@ -525,7 +529,7 @@ void Server::udpActivated(int socket) { iov[0].iov_base = encrypt; iov[0].iov_len = UDP_PACKET_SIZE; - u_char controldata[CMSG_SPACE(sizeof(struct in_pktinfo))]; + u_char controldata[CMSG_SPACE(MAX(sizeof(struct in6_pktinfo),sizeof(struct in_pktinfo)))]; memset(&msg, 0, sizeof(msg)); msg.msg_name = reinterpret_cast<struct sockaddr *>(&from); @@ -653,8 +657,28 @@ void Server::run() { #ifdef Q_OS_WIN len=::recvfrom(sock, encrypt, UDP_PACKET_SIZE, 0, reinterpret_cast<struct sockaddr *>(&from), &fromlen); #else +#ifdef Q_OS_LINUX + struct msghdr msg; + struct iovec iov[1]; + + iov[0].iov_base = encrypt; + iov[0].iov_len = UDP_PACKET_SIZE; + + u_char controldata[CMSG_SPACE(MAX(sizeof(struct in6_pktinfo),sizeof(struct in_pktinfo)))]; + + memset(&msg, 0, sizeof(msg)); + msg.msg_name = reinterpret_cast<struct sockaddr *>(&from); + msg.msg_namelen = sizeof(from); + msg.msg_iov = iov; + msg.msg_iovlen = 1; + msg.msg_control = controldata; + msg.msg_controllen = sizeof(controldata); + + len=static_cast<quint32>(::recvmsg(sock, &msg, MSG_TRUNC)); +#else len=static_cast<qint32>(::recvfrom(sock, encrypt, UDP_PACKET_SIZE, MSG_TRUNC, reinterpret_cast<struct sockaddr *>(&from), &fromlen)); #endif +#endif if (len == 0) { break; } else if (len == SOCKET_ERROR) { @@ -677,7 +701,12 @@ void Server::run() { ping[4] = qToBigEndian(static_cast<quint32>(iMaxUsers)); ping[5] = qToBigEndian(static_cast<quint32>(iMaxBandwidth)); +#ifdef Q_OS_LINUX + iov[0].iov_len = 6 * sizeof(quint32); + ::sendmsg(sock, &msg, 0); +#else ::sendto(sock, encrypt, 6 * sizeof(quint32), 0, reinterpret_cast<struct sockaddr *>(&from), fromlen); +#endif continue; } @@ -721,7 +750,6 @@ void Server::run() { } len -= 4; - MessageHandler::UDPMessageType msgType = static_cast<MessageHandler::UDPMessageType>((buffer[0] >> 5) & 0x7); switch (msgType) { @@ -778,14 +806,52 @@ void Server::sendMessage(ServerUser *u, const char *data, int len, QByteArray &c if (Meta::hQoS) QOSAddSocketToFlow(Meta::hQoS, u->sUdpSocket, reinterpret_cast<struct sockaddr *>(& u->saiUdpAddress), QOSTrafficTypeVoice, QOS_NON_ADAPTIVE_FLOW, &dwFlow); #endif +#ifdef Q_OS_LINUX + struct msghdr msg; + struct iovec iov[1]; + + iov[0].iov_base = buffer; + iov[0].iov_len = len+4; + + u_char controldata[CMSG_SPACE(MAX(sizeof(struct in6_pktinfo),sizeof(struct in_pktinfo)))]; + memset(controldata, 0, sizeof(controldata)); + + memset(&msg, 0, sizeof(msg)); + msg.msg_name = reinterpret_cast<struct sockaddr *>(& u->saiUdpAddress); + msg.msg_namelen = (u->saiUdpAddress.ss_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); + msg.msg_iov = iov; + msg.msg_iovlen = 1; + msg.msg_control = controldata; + msg.msg_controllen = sizeof(controldata); + + struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); + if (u->saiTcpLocalAddress.ss_family == AF_INET6) { + cmsg->cmsg_level = IPPROTO_IPV6; + cmsg->cmsg_type = IPV6_PKTINFO; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + struct in6_pktinfo *pktinfo = reinterpret_cast<struct in6_pktinfo *>(CMSG_DATA(cmsg)); + memset(pktinfo, 0, sizeof(*pktinfo)); + pktinfo->ipi6_addr = reinterpret_cast<struct sockaddr_in6 *>(& u->saiTcpLocalAddress)->sin6_addr; + qWarning() << pktinfo->ipi6_addr.s6_addr32[0]; + } else { + cmsg->cmsg_level = IPPROTO_IP; + cmsg->cmsg_type = IP_PKTINFO; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); + struct in_pktinfo *pktinfo = reinterpret_cast<struct in_pktinfo *>(CMSG_DATA(cmsg)); + memset(pktinfo, 0, sizeof(*pktinfo)); + pktinfo->ipi_spec_dst = reinterpret_cast<struct sockaddr_in *>(& u->saiTcpLocalAddress)->sin_addr; + } + + + ::sendmsg(u->sUdpSocket, &msg, 0); +#else ::sendto(u->sUdpSocket, buffer, len+4, 0, reinterpret_cast<struct sockaddr *>(& u->saiUdpAddress), (u->saiUdpAddress.ss_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); +#endif #ifdef Q_OS_WIN if (Meta::hQoS && dwFlow) QOSRemoveSocketFromFlow(Meta::hQoS, 0, dwFlow, 0); #else #endif - - } else { if (cache.isEmpty()) cache = QByteArray(data, len); @@ -1018,6 +1084,7 @@ void Server::newClient() { ServerUser *u = new ServerUser(this, sock); u->uiSession = qqIds.dequeue(); u->haAddress = ha; + HostAddress(sock->localAddress()).toSockaddr(& u->saiTcpLocalAddress); { QWriteLocker wl(&qrwlUsers); diff --git a/src/murmur/ServerUser.cpp b/src/murmur/ServerUser.cpp index 41b8a9189..57c54772f 100644 --- a/src/murmur/ServerUser.cpp +++ b/src/murmur/ServerUser.cpp @@ -39,6 +39,7 @@ ServerUser::ServerUser(Server *p, QSslSocket *socket) : Connection(p, socket), U sUdpSocket = INVALID_SOCKET; memset(&saiUdpAddress, 0, sizeof(saiUdpAddress)); + memset(&saiTcpLocalAddress, 0, sizeof(saiTcpLocalAddress)); dUDPPingAvg = dUDPPingVar = 0.0f; dTCPPingAvg = dTCPPingVar = 0.0f; diff --git a/src/murmur/ServerUser.h b/src/murmur/ServerUser.h index 5d3270163..2ad872070 100644 --- a/src/murmur/ServerUser.h +++ b/src/murmur/ServerUser.h @@ -120,6 +120,7 @@ class ServerUser : public Connection, public User { #endif BandwidthRecord bwr; struct sockaddr_storage saiUdpAddress; + struct sockaddr_storage saiTcpLocalAddress; ServerUser(Server *parent, QSslSocket *socket); }; |