Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mumble-voip/mumble.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThorvald Natvig <slicer@users.sourceforge.net>2011-05-11 09:25:56 +0400
committerThorvald Natvig <slicer@users.sourceforge.net>2011-05-11 09:25:56 +0400
commit07bf14614a6da2fff0205c562f18566774e38e8c (patch)
tree2e434debe277e98f4f81dff337ec67e6c73ddb9d
parentd96648ef25bdf214afe24ee306d12bfb4d0f8de4 (diff)
Use TCP destination as UDP source
-rw-r--r--src/Net.cpp13
-rw-r--r--src/Net.h1
-rw-r--r--src/murmur/Server.cpp85
-rw-r--r--src/murmur/ServerUser.cpp1
-rw-r--r--src/murmur/ServerUser.h1
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]);
}
diff --git a/src/Net.h b/src/Net.h
index c05560dcc..6317e1ba8 100644
--- a/src/Net.h
+++ b/src/Net.h
@@ -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);
};