diff options
author | Thorvald Natvig <slicer@users.sourceforge.net> | 2009-06-22 22:01:27 +0400 |
---|---|---|
committer | Thorvald Natvig <slicer@users.sourceforge.net> | 2009-06-22 22:01:44 +0400 |
commit | 3976433cc7758726b29313b9fa0996551b2480ec (patch) | |
tree | 0ee35b87a219d5feff1304b4913de9f9bd881e64 /src | |
parent | 9b226cafaa5411abb447bd1db44ba2cbb71be338 (diff) |
Multibind for nix
Diffstat (limited to 'src')
-rw-r--r-- | src/Net.cpp | 25 | ||||
-rw-r--r-- | src/Net.h | 1 | ||||
-rw-r--r-- | src/OSInfo.cpp | 8 | ||||
-rw-r--r-- | src/OSInfo.h | 4 | ||||
-rw-r--r-- | src/murmur/Cert.cpp | 2 | ||||
-rw-r--r-- | src/murmur/Messages.cpp | 2 | ||||
-rw-r--r-- | src/murmur/Meta.cpp | 48 | ||||
-rw-r--r-- | src/murmur/Meta.h | 2 | ||||
-rw-r--r-- | src/murmur/MurmurIce.cpp | 2 | ||||
-rw-r--r-- | src/murmur/Register.cpp | 2 | ||||
-rw-r--r-- | src/murmur/Server.cpp | 335 | ||||
-rw-r--r-- | src/murmur/Server.h | 22 | ||||
-rw-r--r-- | src/murmur/murmur_pch.h | 1 |
13 files changed, 291 insertions, 163 deletions
diff --git a/src/Net.cpp b/src/Net.cpp index 43dc69bbc..fb90f767f 100644 --- a/src/Net.cpp +++ b/src/Net.cpp @@ -66,6 +66,21 @@ HostAddress::HostAddress(const QHostAddress &address) { } } +HostAddress::HostAddress(const sockaddr_storage &address) { + if (address.ss_family == AF_INET) { + const struct sockaddr_in *in = reinterpret_cast<const struct sockaddr_in *>(&address); + addr[0] = 0ULL; + shorts[4] = 0; + shorts[5] = 0xffff; + hash[3] = in->sin_addr.s_addr; + } else if (address.ss_family == AF_INET6) { + const struct sockaddr_in6 *in6 = reinterpret_cast<const struct sockaddr_in6 *>(&address); + memcpy(qip6.c, in6->sin6_addr.s6_addr, 16); + } else { + addr[0] = addr[1] = 0ULL; + } +} + bool HostAddress::operator < (const HostAddress &other) const { return memcmp(qip6.c, other.qip6.c, 16) < 0; } @@ -119,9 +134,13 @@ quint32 qHash(const HostAddress &ha) { QString HostAddress::toString() const { if (isV6()) { - QString qs; - qs.sprintf("[%x:%x:%x:%x:%x:%x:%x:%x]", ntohs(shorts[0]), ntohs(shorts[1]), ntohs(shorts[2]), ntohs(shorts[3]), ntohs(shorts[4]), ntohs(shorts[5]), ntohs(shorts[6]), ntohs(shorts[7])); - return qs.replace(QRegExp(QLatin1String("(:0)+")),QLatin1String(":")); + if (isValid()) { + QString qs; + qs.sprintf("[%x:%x:%x:%x:%x:%x:%x:%x]", ntohs(shorts[0]), ntohs(shorts[1]), ntohs(shorts[2]), ntohs(shorts[3]), ntohs(shorts[4]), ntohs(shorts[5]), ntohs(shorts[6]), ntohs(shorts[7])); + return qs.replace(QRegExp(QLatin1String("(:0)+")),QLatin1String(":")); + } else { + return QLatin1String("[::]"); + } } else { return QHostAddress(ntohl(hash[3])).toString(); } @@ -46,6 +46,7 @@ struct HostAddress { HostAddress(const std::string &); HostAddress(const QHostAddress &); HostAddress(const QByteArray &); + HostAddress(const struct sockaddr_storage &); bool isV6() const; bool isValid() const; diff --git a/src/OSInfo.cpp b/src/OSInfo.cpp index 5da91d144..78d46671f 100644 --- a/src/OSInfo.cpp +++ b/src/OSInfo.cpp @@ -39,7 +39,7 @@ #include <mach-o/arch.h> #endif -QString OSInfo::getMacHash(const QHostAddress &qhaBind) { +QString OSInfo::getMacHash(const QList<QHostAddress> &qlBind) { QString first, second, third; foreach(const QNetworkInterface &qni, QNetworkInterface::allInterfaces()) { if (! qni.isValid()) @@ -62,7 +62,7 @@ QString OSInfo::getMacHash(const QHostAddress &qhaBind) { foreach(const QNetworkAddressEntry &qnae, qni.addressEntries()) { const QHostAddress &qha = qnae.ip(); - if (((qhaBind == QHostAddress::Any) && (qha.protocol() == QAbstractSocket::IPv4Protocol)) || (qha == qhaBind)) { + if (qlBind.isEmpty() || qlBind.contains(qha)) { if (first.isEmpty() || first > hash) first = hash; } @@ -144,14 +144,14 @@ QString OSInfo::getOSVersion() { #endif } -void OSInfo::fillXml(QDomDocument &doc, QDomElement &root, const QString &os, const QString &osver, const QHostAddress &qhaBind) { +void OSInfo::fillXml(QDomDocument &doc, QDomElement &root, const QString &os, const QString &osver, const QList<QHostAddress> &qlBind) { QDomElement tag; QDomText t; bool bIs64; tag=doc.createElement(QLatin1String("machash")); root.appendChild(tag); - t=doc.createTextNode(OSInfo::getMacHash(qhaBind)); + t=doc.createTextNode(OSInfo::getMacHash(qlBind)); tag.appendChild(t); tag=doc.createElement(QLatin1String("version")); diff --git a/src/OSInfo.h b/src/OSInfo.h index 900b21a4d..b453947fb 100644 --- a/src/OSInfo.h +++ b/src/OSInfo.h @@ -35,10 +35,10 @@ class OSInfo { public: - static QString getMacHash(const QHostAddress & = QHostAddress(QHostAddress::Any)); + static QString getMacHash(const QList<QHostAddress> & = QList<QHostAddress>()); static QString getOS(); static QString getOSVersion(); - static void fillXml(QDomDocument &doc, QDomElement &root, const QString &os = OSInfo::getOS(), const QString &osver = OSInfo::getOSVersion(), const QHostAddress & = QHostAddress(QHostAddress::Any)); + static void fillXml(QDomDocument &doc, QDomElement &root, const QString &os = OSInfo::getOS(), const QString &osver = OSInfo::getOSVersion(), const QList<QHostAddress> & = QList<QHostAddress>()); }; #endif diff --git a/src/murmur/Cert.cpp b/src/murmur/Cert.cpp index 573aca284..d53ef6976 100644 --- a/src/murmur/Cert.cpp +++ b/src/murmur/Cert.cpp @@ -120,7 +120,7 @@ void Server::initializeCert() { qskKey = QSslKey(); } - if (!qscCert.isNull() && (qscCert.issuerInfo(QSslCertificate::CommonName) == QLatin1String("Murmur Autogenerated Certificate v2")) && ! Meta::mp.qscCert.isNull() && ! Meta::mp.qskKey.isNull() && (Meta::mp.qhaBind == qhaBind)) { + if (!qscCert.isNull() && (qscCert.issuerInfo(QSslCertificate::CommonName) == QLatin1String("Murmur Autogenerated Certificate v2")) && ! Meta::mp.qscCert.isNull() && ! Meta::mp.qskKey.isNull() && (Meta::mp.qlBind == qlBind)) { qscCert = Meta::mp.qscCert; qskKey = Meta::mp.qskKey; } diff --git a/src/murmur/Messages.cpp b/src/murmur/Messages.cpp index 26a465c01..a583def67 100644 --- a/src/murmur/Messages.cpp +++ b/src/murmur/Messages.cpp @@ -137,6 +137,8 @@ void Server::msgAuthenticate(ServerUser *uSource, MumbleProto::Authenticate &msg uSource->disconnectSocket(); return; } + + startThread(); // Kick ghost if (uOld) { diff --git a/src/murmur/Meta.cpp b/src/murmur/Meta.cpp index 6c2a1d6d4..5c31127ee 100644 --- a/src/murmur/Meta.cpp +++ b/src/murmur/Meta.cpp @@ -53,7 +53,6 @@ MetaParams::MetaParams() { qsDBusService = "net.sourceforge.mumble.murmur"; qsDBDriver = "QSQLITE"; qsLogfile = "murmur.log"; - qhaBind = QHostAddress(QHostAddress::AnyIPv6); iLogDays = 31; @@ -126,20 +125,35 @@ void MetaParams::read(QString fname) { QString qsHost = qs.value("host", QString()).toString(); if (! qsHost.isEmpty()) { - if (! qhaBind.setAddress(qsHost)) { - QHostInfo hi = QHostInfo::fromName(qsHost); - foreach(QHostAddress qha, hi.addresses()) { - if ((qha.protocol() == QAbstractSocket::IPv4Protocol) || (qha.protocol() == QAbstractSocket::IPv6Protocol)) { - qhaBind = qha; - break; + foreach(const QString &host, qsHost.split(QRegExp(QLatin1String("\\s+")), QString::SkipEmptyParts)) { + QHostAddress qhaddr; + if (qhaddr.setAddress(host)) { + qlBind << qhaddr; + } else { + bool found = false; + QHostInfo hi = QHostInfo::fromName(host); + foreach(QHostAddress qha, hi.addresses()) { + if ((qha.protocol() == QAbstractSocket::IPv4Protocol) || (qha.protocol() == QAbstractSocket::IPv6Protocol)) { + qlBind << qha; + found = true; + } + } + if (! found) { + qFatal("Lookup of bind hostname %s failed", qPrintable(host)); } } - if ((qhaBind == QHostAddress::AnyIPv6) || (qhaBind.isNull())) { - qFatal("Lookup of bind hostname %s failed", qPrintable(qsHost)); - } - } - qWarning("Binding to address %s", qPrintable(qhaBind.toString())); + foreach(const QHostAddress &qha, qlBind) + qWarning("Binding to address %s", qPrintable(qha.toString())); + } + + if (qlBind.isEmpty()) { +#ifdef Q_OS_WIN + if (QSysInfo::windowsVersion() < QSysInfo::WV_VISTA) + qlBind << QHostAddress(QHostAddress::Any) + else +#endif + qlBind << QHostAddress(QHostAddress::AnyIPv6); } qsPassword = qs.value("serverpassword", qsPassword).toString(); @@ -295,7 +309,11 @@ void MetaParams::read(QString fname) { QSslSocket::setDefaultCiphers(pref); qmConfig.clear(); - qmConfig.insert(QLatin1String("host"),qhaBind.toString()); + QStringList hosts; + foreach(const QHostAddress &qha, qlBind) { + hosts << qha.toString(); + } + qmConfig.insert(QLatin1String("host"),hosts.join(" ")); qmConfig.insert(QLatin1String("password"),qsPassword); qmConfig.insert(QLatin1String("port"),QString::number(usPort)); qmConfig.insert(QLatin1String("timeout"),QString::number(iTimeout)); @@ -361,6 +379,10 @@ bool Meta::boot(int srvnum) { if (! ServerDB::serverExists(srvnum)) return false; Server *s = new Server(srvnum, this); + if (! s->bValid) { + delete s; + return false; + } qhServers.insert(srvnum, s); emit started(s); return true; diff --git a/src/murmur/Meta.h b/src/murmur/Meta.h index 2e9b4942c..386f2cd36 100644 --- a/src/murmur/Meta.h +++ b/src/murmur/Meta.h @@ -39,7 +39,7 @@ struct MetaParams { QDir qdBasePath; - QHostAddress qhaBind; + QList<QHostAddress> qlBind; unsigned short usPort; int iTimeout; int iMaxBandwidth; diff --git a/src/murmur/MurmurIce.cpp b/src/murmur/MurmurIce.cpp index 20fd7ec17..4d028ae90 100644 --- a/src/murmur/MurmurIce.cpp +++ b/src/murmur/MurmurIce.cpp @@ -95,7 +95,7 @@ static void userToUser(const ::User *p, Murmur::User &mp) { mp.context = u->ssContext; mp.idlesecs = u->bwr.idleSeconds(); - mp.tcponly = (u->saiUdpAddress.sin_port == 0); + mp.tcponly = ! u->bUdp; ::Murmur::NetAddress addr(16, 0); const Q_IPV6ADDR &a = u->haAddress.qip6; diff --git a/src/murmur/Register.cpp b/src/murmur/Register.cpp index 732b5f351..8c90ab7aa 100644 --- a/src/murmur/Register.cpp +++ b/src/murmur/Register.cpp @@ -69,7 +69,7 @@ void Server::update() { QDomElement root=doc.createElement(QLatin1String("server")); doc.appendChild(root); - OSInfo::fillXml(doc, root, meta->qsOS, meta->qsOSVersion, qhaBind); + OSInfo::fillXml(doc, root, meta->qsOS, meta->qsOSVersion, qlBind); QDomElement tag; QDomText t; diff --git a/src/murmur/Server.cpp b/src/murmur/Server.cpp index 378b80b2e..7178d6805 100644 --- a/src/murmur/Server.cpp +++ b/src/murmur/Server.cpp @@ -69,9 +69,9 @@ QSslSocket *SslServer::nextPendingSSLConnection() { } ServerUser::ServerUser(Server *p, QSslSocket *socket) : Connection(p, socket), User() { - saiUdpAddress.sin_port = 0; - saiUdpAddress.sin_addr.s_addr = htonl(socket->peerAddress().toIPv4Address()); - saiUdpAddress.sin_family = AF_INET; + sUdpSocket = INVALID_SOCKET; + + memset(&saiUdpAddress, 0, sizeof(saiUdpAddress)); bUdp = true; uiVersion = 0; @@ -81,61 +81,87 @@ ServerUser::ServerUser(Server *p, QSslSocket *socket) : Connection(p, socket), U Server::Server(int snum, QObject *p) : QThread(p) { bValid = true; iServerNum = snum; + + aiNotify[0] = aiNotify[1] = -1; readParams(); initialize(); - qtsServer = new SslServer(this); + foreach(const QHostAddress &qha, qlBind) { + SslServer *ss = new SslServer(this); - connect(qtsServer, SIGNAL(newConnection()), this, SLOT(newClient()), Qt::QueuedConnection); + connect(ss, SIGNAL(newConnection()), this, SLOT(newClient()), Qt::QueuedConnection); - if (! qtsServer->listen(qhaBind, usPort)) { - log(QString("Server: TCP Listen on port %1 failed").arg(usPort)); - bValid = false; - } else { - log(QString("Server listening on port %1").arg(usPort)); + if (! ss->listen(qha, usPort)) { + log(QString("Server: TCP Listen on %1 failed").arg(addressToString(qha,usPort))); + bValid = false; + } else { + log(QString("Server listening on %1").arg(addressToString(qha,usPort))); + } + qlServer << ss; } - sUdpSocket = INVALID_SOCKET; + if (! bValid) + return; - if (bValid) { + foreach(SslServer *ss, qlServer) { + sockaddr_storage addr; #ifdef Q_OS_UNIX - sUdpSocket = ::socket(PF_INET, SOCK_DGRAM, 0); + int tcpsock = ss->socketDescriptor(); + socklen_t len = sizeof(addr); +#else + SOCKET tcpsock = ss->socketDescriptor(); + int len = sizeof(addr); +#endif + memset(&addr, 0, sizeof(addr)); + getsockname(tcpsock, reinterpret_cast<struct sockaddr *>(&addr), &len); +#ifdef Q_OS_UNIX + int sock = ::socket(addr.ss_family, SOCK_DGRAM, 0); #else #ifndef SIO_UDP_CONNRESET #define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12) #endif - sUdpSocket = ::WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, WSA_FLAG_OVERLAPPED); + SOCKET sock = ::WSASocket(addr.ss_family, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, WSA_FLAG_OVERLAPPED); DWORD dwBytesReturned = 0; BOOL bNewBehaviour = FALSE; - if (WSAIoctl(sUdpSocket, SIO_UDP_CONNRESET, &bNewBehaviour, sizeof(bNewBehaviour), NULL, 0, &dwBytesReturned, NULL, NULL) == SOCKET_ERROR) { + if (WSAIoctl(sock, SIO_UDP_CONNRESET, &bNewBehaviour, sizeof(bNewBehaviour), NULL, 0, &dwBytesReturned, NULL, NULL) == SOCKET_ERROR) { log(QString("Failed to set SIO_UDP_CONNRESET: %1").arg(WSAGetLastError())); } #endif - if (sUdpSocket == INVALID_SOCKET) { + if (sock == INVALID_SOCKET) { log("Failed to create UDP Socket"); bValid = false; + return; } else { - struct sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(usPort); - addr.sin_addr.s_addr = htonl(qhaBind.toIPv4Address()); - if (::bind(sUdpSocket, reinterpret_cast<sockaddr *>(&addr), sizeof(addr)) == SOCKET_ERROR) { - log(QString("Failed to bind UDP Socket to port %1").arg(usPort)); + if (::bind(sock, reinterpret_cast<sockaddr *>(&addr), len) == SOCKET_ERROR) { + log(QString("Failed to bind UDP Socket to %1").arg(addressToString(ss->serverAddress(), usPort))); } else { #ifdef Q_OS_UNIX int val = 0xe0; - if (setsockopt(sUdpSocket, IPPROTO_IP, IP_TOS, &val, sizeof(val))) { + if (setsockopt(sock, IPPROTO_IP, IP_TOS, &val, sizeof(val))) { val = 0x80; - if (setsockopt(sUdpSocket, IPPROTO_IP, IP_TOS, &val, sizeof(val))) + if (setsockopt(sock, IPPROTO_IP, IP_TOS, &val, sizeof(val))) log("Server: Failed to set TOS for UDP Socket"); } #endif } + qlUdpSocket << sock; } } + bValid = bValid && (qlServer.count() == qlBind.count()) && (qlUdpSocket.count() == qlBind.count()); + if (! bValid) + return; + +#ifdef Q_OS_UNIX + if (socketpair(AF_UNIX, SOCK_STREAM, 0, aiNotify) != 0) { + log("Failed to create notify socket"); + bValid = false; + return; + } +#else +#endif + connect(this, SIGNAL(tcpTransmit(QByteArray, unsigned int)), this, SLOT(tcpTransmitData(QByteArray, unsigned int)), Qt::QueuedConnection); connect(this, SIGNAL(reqSync(unsigned int)), this, SLOT(doSync(unsigned int))); @@ -150,8 +176,7 @@ Server::Server(int snum, QObject *p) : QThread(p) { readLinks(); initializeCert(); - if (bValid) - initRegister(); + initRegister(); } void Server::startThread() { @@ -178,23 +203,34 @@ void Server::startThread() { void Server::stopThread() { bRunning = false; if (isRunning()) { - qrwlUsers.lockForWrite(); - terminate(); +#ifdef Q_OS_UNIX + unsigned char val = 0; + ::write(aiNotify[1], &val, 1); +#else + panic; +#endif wait(); - qrwlUsers.unlock(); } qtTimeout->stop(); } Server::~Server() { stopThread(); - if (sUdpSocket != INVALID_SOCKET) + #ifdef Q_OS_UNIX - close(sUdpSocket); + foreach(int s, qlUdpSocket) + close(s); + + if (aiNotify[0] >= 0) + close(aiNotify[0]); + if (aiNotify[1] >= 0) + close(aiNotify[1]); #else - closesocket(sUdpSocket); + foreach(SOCKET s, qlUdpSocket) + closesocket(s); #endif clearACLCache(); + log("Stopped"); } @@ -206,7 +242,7 @@ void Server::readParams() { iMaxUsers = Meta::mp.iMaxUsers; iDefaultChan = Meta::mp.iDefaultChan; qsWelcomeText = Meta::mp.qsWelcomeText; - qhaBind = Meta::mp.qhaBind; + qlBind = Meta::mp.qlBind; qsRegName = Meta::mp.qsRegName; qsRegPassword = Meta::mp.qsRegPassword; qsRegHost = Meta::mp.qsRegHost; @@ -216,21 +252,29 @@ void Server::readParams() { QString qsHost = getConf("host", QString()).toString(); if (! qsHost.isEmpty()) { - if (! qhaBind.setAddress(qsHost)) { - QHostInfo hi = QHostInfo::fromName(qsHost); - foreach(QHostAddress qha, hi.addresses()) { - if ((qha.protocol() == QAbstractSocket::IPv4Protocol) || (qha.protocol() == QAbstractSocket::IPv6Protocol)) { - qhaBind = qha; - break; + qlBind.clear(); + foreach(const QString &host, qsHost.split(QRegExp(QLatin1String("\\s+")), QString::SkipEmptyParts)) { + QHostAddress qhaddr; + if (qhaddr.setAddress(qsHost)) { + qlBind << qhaddr; + } else { + bool found = false; + QHostInfo hi = QHostInfo::fromName(host); + foreach(QHostAddress qha, hi.addresses()) { + if ((qha.protocol() == QAbstractSocket::IPv4Protocol) || (qha.protocol() == QAbstractSocket::IPv6Protocol)) { + qlBind << qha; + found = true; + } + } + if (! found) { + log(QString("Lookup of bind hostname %1 failed").arg(host)); } } - if ((qhaBind == QHostAddress::AnyIPv6) || (qhaBind.isNull())) { - log(QString("Lookup of bind hostname %1 failed").arg(qsHost)); - qhaBind = Meta::mp.qhaBind; - } - } - log(QString("Binding to address %1").arg(qhaBind.toString())); + foreach(const QHostAddress &qha, qlBind) + log(QString("Binding to address %1").arg(qha.toString())); + if (qlBind.isEmpty()) + qlBind = Meta::mp.qlBind; } qsPassword = getConf("password", qsPassword).toString(); @@ -325,6 +369,7 @@ int BandwidthRecord::bandwidth() const { } void Server::run() { + qint32 len; #if defined(__LP64__) char encbuff[512+8]; @@ -334,103 +379,130 @@ void Server::run() { #endif char buffer[512]; - sockaddr_in from; + sockaddr_storage from; #ifdef Q_OS_UNIX socklen_t fromlen; #else int fromlen; #endif - if (sUdpSocket == INVALID_SOCKET) - return; + int nfds = qlUdpSocket.count(); + STACKVAR(struct pollfd, fds, nfds+1); + + for (int i=0;i<nfds;++i) { + fds[i].fd = qlUdpSocket.at(i); + fds[i].events = POLLIN; + fds[i].revents = 0; + } + + fds[nfds].fd=aiNotify[0]; + fds[nfds].events = POLLIN; + fds[nfds].revents = 0; + + nfds++; + + log("Starting voice thread"); while (bRunning) { -#ifdef Q_OS_DARWIN - /* - * Pthreads on Darwin suck. They won't allow us to shut down the - * server thread while we're in the recvfrom() syscall. - * - * We use this little hack to loop through our outer loop once in - * a while to determine if we should still be running. - */ - static struct pollfd fds = { - sUdpSocket, POLLIN, 0 - }; - int ret = poll(&fds, 1, 1000); - - if (ret == 0) { - continue; - } else if (ret == -1) { - qCritical("poll() failed: %s", strerror(errno)); + int pret = poll(fds, nfds, -1); + if (pret <= 0) { + log("poll failure"); + bRunning = false; break; } -#endif - fromlen = sizeof(from); + if (fds[nfds - 1].revents) { + // Drain pipe + unsigned char val; + while(::recv(aiNotify[0], &val, 1, MSG_DONTWAIT) == 1) {}; + break; + } + + for (int i=0;i<nfds-1;++i) { + if (fds[i].revents) { + if (fds[i].revents & (POLLHUP | POLLERR | POLLNVAL)) { + log("poll event failure"); + bRunning = false; + break; + } + + int sock = fds[i].fd; + + fromlen = sizeof(from); #ifdef Q_OS_WIN - len=::recvfrom(sUdpSocket, encrypt, 512, 0, reinterpret_cast<struct sockaddr *>(&from), &fromlen); + len=::recvfrom(sock, encrypt, 512, 0, reinterpret_cast<struct sockaddr *>(&from), &fromlen); #else - len=static_cast<qint32>(::recvfrom(sUdpSocket, encrypt, 512, MSG_TRUNC, reinterpret_cast<struct sockaddr *>(&from), &fromlen)); + len=static_cast<qint32>(::recvfrom(sock, encrypt, 512, MSG_TRUNC, reinterpret_cast<struct sockaddr *>(&from), &fromlen)); #endif - if (len == 0) { - break; - } else if (len == SOCKET_ERROR) { - break; - } else if (len < 5) { - // 4 bytes crypt header + type + session - continue; - } else if (len > 512) { - continue; - } + if (len == 0) { + break; + } else if (len == SOCKET_ERROR) { + break; + } else if (len < 5) { + // 4 bytes crypt header + type + session + continue; + } else if (len > 512) { + continue; + } - QReadLocker rl(&qrwlUsers); + QReadLocker rl(&qrwlUsers); - quint64 key = (static_cast<unsigned long long>(from.sin_addr.s_addr) << 16) ^ from.sin_port; + quint16 port = (from.ss_family == AF_INET6) ? (reinterpret_cast<sockaddr_in6 *>(&from)->sin6_port) : (reinterpret_cast<sockaddr_in *>(&from)->sin_port); + const HostAddress &ha = HostAddress(from); - ServerUser *u = qhPeerUsers.value(key); - if (u) { - if (! checkDecrypt(u, encrypt, buffer, len)) { - continue; - } - } else { - // Unknown peer - foreach(ServerUser *usr, qhHostUsers.value(from.sin_addr.s_addr)) { - if (usr->csCrypt.isValid() && checkDecrypt(usr, encrypt, buffer, len)) { - // Every time we relock, reverify users' existance. - // The main thread might delete the user while the lock isn't held. - unsigned int uiSession = usr->uiSession; - rl.unlock(); - qrwlUsers.lockForWrite(); - if (qhUsers.contains(uiSession)) { - u = usr; - qhHostUsers[from.sin_addr.s_addr].remove(u); - qhPeerUsers.insert(key, u); - u->saiUdpAddress.sin_port = from.sin_port; - qrwlUsers.unlock(); - rl.relock(); - if (! qhUsers.contains(uiSession)) - u = NULL; + qWarning() << "Got UDP From" << ha.toString(); + + const QPair<HostAddress, quint16> &key = QPair<HostAddress, quint16>(ha, port); + + ServerUser *u = qhPeerUsers.value(key); + if (u) { + if (! checkDecrypt(u, encrypt, buffer, len)) { + continue; + } + } else { + // Unknown peer + foreach(ServerUser *usr, qhHostUsers.value(ha)) { + if (usr->csCrypt.isValid() && checkDecrypt(usr, encrypt, buffer, len)) { + // Every time we relock, reverify users' existance. + // The main thread might delete the user while the lock isn't held. + unsigned int uiSession = usr->uiSession; + rl.unlock(); + qrwlUsers.lockForWrite(); + if (qhUsers.contains(uiSession)) { + u = usr; + u->sUdpSocket = sock; + memcpy(& u->saiUdpAddress, &from, sizeof(from)); + qhHostUsers[from].remove(u); + qhPeerUsers.insert(key, u); + qrwlUsers.unlock(); + rl.relock(); + if (! qhUsers.contains(uiSession)) + u = NULL; + } + break; + } + } + if (! u) { + continue; } - break; } - } - if (! u) { - continue; - } - } - len -= 4; + len -= 4; - unsigned int msgType = (buffer[0] >> 5) & 0x7; + unsigned int msgType = (buffer[0] >> 5) & 0x7; - if (msgType == MessageHandler::UDPPing) { - QByteArray qba; - sendMessage(u, buffer, len, qba, true); - } else if (msgType == MessageHandler::UDPVoice) { - u->bUdp = true; - processMsg(u, buffer, len); + if (msgType == MessageHandler::UDPPing) { + QByteArray qba; + sendMessage(u, buffer, len, qba, true); + } else if (msgType == MessageHandler::UDPVoice) { + u->bUdp = true; + processMsg(u, buffer, len); + } + fds[i].revents = 0; + } } } + log("Ending voice thread"); } bool Server::checkDecrypt(ServerUser *u, const char *encrypt, char *plain, unsigned int len) { @@ -447,7 +519,7 @@ bool Server::checkDecrypt(ServerUser *u, const char *encrypt, char *plain, unsig } void Server::sendMessage(ServerUser *u, const char *data, int len, QByteArray &cache, bool force) { - if ((u->bUdp || force) && (u->saiUdpAddress.sin_port != 0) && u->csCrypt.isValid()) { + if ((u->bUdp || force) && (u->sUdpSocket != INVALID_SOCKET) && u->csCrypt.isValid()) { #if defined(__LP64__) STACKVAR(char, ebuffer, len+4+16); char *buffer = reinterpret_cast<char *>(((reinterpret_cast<quint64>(ebuffer) + 8) & ~7) + 4); @@ -458,12 +530,13 @@ void Server::sendMessage(ServerUser *u, const char *data, int len, QByteArray &c #ifdef Q_OS_WIN DWORD dwFlow = 0; if (Meta::hQoS) - QOSAddSocketToFlow(Meta::hQoS, sUdpSocket, reinterpret_cast<struct sockaddr *>(& u->saiUdpAddress), QOSTrafficTypeVoice, QOS_NON_ADAPTIVE_FLOW, &dwFlow); - ::sendto(sUdpSocket, buffer, len+4, 0, reinterpret_cast<struct sockaddr *>(& u->saiUdpAddress), sizeof(u->saiUdpAddress)); + QOSAddSocketToFlow(Meta::hQoS, u->sUdpSocket, reinterpret_cast<struct sockaddr *>(& u->saiUdpAddress), QOSTrafficTypeVoice, QOS_NON_ADAPTIVE_FLOW, &dwFlow); +#endif + ::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)); +#ifdef Q_OS_WIN if (Meta::hQoS && dwFlow) QOSRemoveSocketFromFlow(Meta::hQoS, 0, dwFlow, 0); #else - ::sendto(sUdpSocket, buffer, len+4, 0, reinterpret_cast<struct sockaddr *>(& u->saiUdpAddress), sizeof(u->saiUdpAddress)); #endif @@ -644,8 +717,11 @@ void Server::log(const QString &msg) { } void Server::newClient() { + SslServer *ss = qobject_cast<SslServer *>(sender()); + if (! ss) + return; forever { - QSslSocket *sock = qtsServer->nextPendingSSLConnection(); + QSslSocket *sock = ss->nextPendingSSLConnection(); if (! sock) return; @@ -679,9 +755,6 @@ void Server::newClient() { return; } - if (qhUsers.isEmpty()) - startThread(); - ServerUser *u = new ServerUser(this, sock); u->uiSession = qqIds.dequeue(); u->haAddress = ha; @@ -689,7 +762,7 @@ void Server::newClient() { { QWriteLocker wl(&qrwlUsers); qhUsers.insert(u->uiSession, u); - qhHostUsers[htonl(sock->peerAddress().toIPv4Address())].insert(u); + qhHostUsers[ha].insert(u); } connect(u, SIGNAL(connectionClosed(const QString &)), this, SLOT(connectionClosed(const QString &))); @@ -786,8 +859,10 @@ void Server::connectionClosed(const QString &reason) { QWriteLocker wl(&qrwlUsers); qhUsers.remove(u->uiSession); - qhHostUsers[u->saiUdpAddress.sin_addr.s_addr].remove(u); - quint64 key = (static_cast<unsigned long long>(u->saiUdpAddress.sin_addr.s_addr) << 16) ^ u->saiUdpAddress.sin_port; + qhHostUsers[u->haAddress].remove(u); + + quint16 port = (u->saiUdpAddress.ss_family == AF_INET6) ? (reinterpret_cast<sockaddr_in6 *>(&u->saiUdpAddress)->sin6_port) : (reinterpret_cast<sockaddr_in *>(&u->saiUdpAddress)->sin_port); + const QPair<HostAddress, quint16> &key = QPair<HostAddress, quint16>(u->haAddress, port); qhPeerUsers.remove(key); if (u->cChannel) diff --git a/src/murmur/Server.h b/src/murmur/Server.h index 51cd8c9ad..4971ba05d 100644 --- a/src/murmur/Server.h +++ b/src/murmur/Server.h @@ -132,8 +132,14 @@ class ServerUser : public Connection, public User { typedef QPair<QSet<ServerUser *>, QSet<ServerUser *> > TargetCache; QMap<int, TargetCache> qmTargetCache; +#ifdef Q_OS_UNIX + int sUdpSocket; +#else + SOCKET sUdpSocket; +#endif + BandwidthRecord bwr; - struct sockaddr_in saiUdpAddress; + struct sockaddr_storage saiUdpAddress; ServerUser(Server *parent, QSslSocket *socket); }; @@ -149,7 +155,7 @@ class Server : public QThread { // Former ServerParams public: - QHostAddress qhaBind; + QList<QHostAddress> qlBind; unsigned short usPort; int iTimeout; int iMaxBandwidth; @@ -206,18 +212,20 @@ class Server : public QThread { public: int iServerNum; QQueue<int> qqIds; - SslServer *qtsServer; + QList<SslServer *> qlServer; QTimer *qtTimeout; #ifdef Q_OS_UNIX - int sUdpSocket; + int aiNotify[2]; + QList<int> qlUdpSocket; #else - SOCKET sUdpSocket; + HANDLE hNotify; + QList<SOCKET> qlUdpSocket; #endif QHash<unsigned int, ServerUser *> qhUsers; - QHash<quint64, ServerUser *> qhPeerUsers; - QHash<unsigned int, QSet<ServerUser *> > qhHostUsers; + QHash<QPair<HostAddress, quint16>, ServerUser *> qhPeerUsers; + QHash<HostAddress, QSet<ServerUser *> > qhHostUsers; QHash<unsigned int, Channel *> qhChannels; QReadWriteLock qrwlUsers; ChanACL::ACLCache acCache; diff --git a/src/murmur/murmur_pch.h b/src/murmur/murmur_pch.h index afec0a796..a420001e1 100644 --- a/src/murmur/murmur_pch.h +++ b/src/murmur/murmur_pch.h @@ -62,6 +62,7 @@ #include <netinet/ip.h> #include <errno.h> #include <signal.h> +#include <poll.h> #define INVALID_SOCKET -1 #define SOCKET_ERROR -1 #ifdef Q_OS_DARWIN |