- bool success = false;
- uint port = Quassel::optionValue("port").toUInt();
-
- const QString listen = Quassel::optionValue("listen");
- const QStringList listen_list = listen.split(",", QString::SkipEmptyParts);
- if(listen_list.size() > 0) {
- foreach (const QString listen_term, listen_list) { // TODO: handle multiple interfaces for same TCP version gracefully
- QHostAddress addr;
- if(!addr.setAddress(listen_term)) {
- qCritical() << qPrintable(
- tr("Invalid listen address %1")
- .arg(listen_term)
- );
- } else {
- switch(addr.protocol()) {
- case QAbstractSocket::IPv4Protocol:
- if(_server.listen(addr, port)) {
- quInfo() << qPrintable(
- tr("Listening for GUI clients on IPv4 %1 port %2 using protocol version %3")
- .arg(addr.toString())
- .arg(_server.serverPort())
- .arg(Quassel::buildInfo().protocolVersion)
- );
- success = true;
- } else
- quWarning() << qPrintable(
- tr("Could not open IPv4 interface %1:%2: %3")
- .arg(addr.toString())
- .arg(port)
- .arg(_server.errorString()));
- break;
- case QAbstractSocket::IPv6Protocol:
- if(_v6server.listen(addr, port)) {
- quInfo() << qPrintable(
- tr("Listening for GUI clients on IPv6 %1 port %2 using protocol version %3")
- .arg(addr.toString())
- .arg(_v6server.serverPort())
- .arg(Quassel::buildInfo().protocolVersion)
- );
- success = true;
- } else {
- // if v4 succeeded on Any, the port will be already in use - don't display the error then
- // FIXME: handle this more sanely, make sure we can listen to both v4 and v6 by default!
- if(!success || _v6server.serverError() != QAbstractSocket::AddressInUseError)
- quWarning() << qPrintable(
- tr("Could not open IPv6 interface %1:%2: %3")
- .arg(addr.toString())
- .arg(port)
- .arg(_v6server.errorString()));
- }
- break;
- default:
- qCritical() << qPrintable(
- tr("Invalid listen address %1, unknown network protocol")
- .arg(listen_term)
- );
- break;
- }
- }
- }
- }
- if(!success)
- quError() << qPrintable(tr("Could not open any network interfaces to listen on!"));
-
- return success;
-}
-
-void Core::stopListening(const QString &reason) {
- bool wasListening = false;
- if(_server.isListening()) {
- wasListening = true;
- _server.close();
- }
- if(_v6server.isListening()) {
- wasListening = true;
- _v6server.close();
- }
- if(wasListening) {
- if(reason.isEmpty())
- quInfo() << "No longer listening for GUI clients.";
- else
- quInfo() << qPrintable(reason);
- }
-}
-
-void Core::incomingConnection() {
- QTcpServer *server = qobject_cast<QTcpServer *>(sender());
- Q_ASSERT(server);
- while(server->hasPendingConnections()) {
- QTcpSocket *socket = server->nextPendingConnection();
- connect(socket, SIGNAL(disconnected()), this, SLOT(clientDisconnected()));
- connect(socket, SIGNAL(readyRead()), this, SLOT(clientHasData()));
- connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)));
-
- QVariantMap clientInfo;
- blocksizes.insert(socket, (quint32)0);
- quInfo() << qPrintable(tr("Client connected from")) << qPrintable(socket->peerAddress().toString());
-
- if(!_configured) {
- stopListening(tr("Closing server for basic setup."));
- }
- }
-}
-
-void Core::clientHasData() {
- QTcpSocket *socket = dynamic_cast<QTcpSocket*>(sender());
- Q_ASSERT(socket && blocksizes.contains(socket));
- QVariant item;
- while(SignalProxy::readDataFromDevice(socket, blocksizes[socket], item)) {
- QVariantMap msg = item.toMap();
- processClientMessage(socket, msg);
- if(!blocksizes.contains(socket)) break; // this socket is no longer ours to handle!
- }
-}
-
-void Core::processClientMessage(QTcpSocket *socket, const QVariantMap &msg) {
- if(!msg.contains("MsgType")) {
- // Client is way too old, does not even use the current init format
- qWarning() << qPrintable(tr("Antique client trying to connect... refusing."));
- socket->close();
- return;
- }
- // OK, so we have at least an init message format we can understand
- if(msg["MsgType"] == "ClientInit") {
- QVariantMap reply;
-
- // Just version information -- check it!
- uint ver = msg["ProtocolVersion"].toUInt();
- if(ver < Quassel::buildInfo().coreNeedsProtocol) {
- reply["MsgType"] = "ClientInitReject";
- reply["Error"] = tr("<b>Your Quassel Client is too old!</b><br>"
- "This core needs at least client/core protocol version %1.<br>"
- "Please consider upgrading your client.").arg(Quassel::buildInfo().coreNeedsProtocol);
- SignalProxy::writeDataToDevice(socket, reply);
- qWarning() << qPrintable(tr("Client")) << qPrintable(socket->peerAddress().toString()) << qPrintable(tr("too old, rejecting."));
- socket->close(); return;
- }
-
- reply["CoreVersion"] = Quassel::buildInfo().fancyVersionString;
- reply["CoreDate"] = Quassel::buildInfo().buildDate;
- reply["ProtocolVersion"] = Quassel::buildInfo().protocolVersion;
- // TODO: Make the core info configurable
- int uptime = startTime().secsTo(QDateTime::currentDateTime().toUTC());
- int updays = uptime / 86400; uptime %= 86400;
- int uphours = uptime / 3600; uptime %= 3600;
- int upmins = uptime / 60;
- reply["CoreInfo"] = tr("<b>Quassel Core Version %1</b><br>"
- "Built: %2<br>"
- "Up %3d%4h%5m (since %6)").arg(Quassel::buildInfo().fancyVersionString)
- .arg(Quassel::buildInfo().buildDate)
- .arg(updays).arg(uphours,2,10,QChar('0')).arg(upmins,2,10,QChar('0')).arg(startTime().toString(Qt::TextDate));