/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2023, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by copyright law, and
* remains the property of nymea GmbH. All rights, including reproduction, publication,
* editing and translation, are reserved. The use of this project is subject to the terms of a
* license agreement to be concluded with nymea GmbH in accordance with the terms
* of use of nymea GmbH, available under https://nymea.io/license
*
* GNU General Public License Usage
* Alternatively, this project may be redistributed and/or modified under
* the terms of the GNU General Public License as published by the Free Software Foundation,
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this project.
* If not, see .
*
* For any further details and any questions please contact us under contact@nymea.io
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include
#include
#include
#include
#include
#include
#include
#include "serverconnection.h"
#include "clientconnection.h"
#include "../version.h"
static QHash s_loggingFilters;
static const char *const normal = "\033[0m";
static const char *const warning = "\e[33m";
static const char *const error = "\e[31m";
static void loggingCategoryFilter(QLoggingCategory *category)
{
if (s_loggingFilters.contains(category->categoryName())) {
bool debugEnabled = s_loggingFilters.value(category->categoryName());
category->setEnabled(QtDebugMsg, debugEnabled);
category->setEnabled(QtWarningMsg, debugEnabled || s_loggingFilters.value("Warnings"));
} else {
// Enable default debug output
category->setEnabled(QtDebugMsg, true);
category->setEnabled(QtWarningMsg, s_loggingFilters.value("qml") || s_loggingFilters.value("Warnings"));
}
}
static void consoleLogHandler(QtMsgType type, const QMessageLogContext& context, const QString& message)
{
switch (type) {
case QtInfoMsg:
if (context.category == QStringLiteral("default")) {
fprintf(stdout, "%s\n", message.toUtf8().data());
} else {
fprintf(stdout, "%s: %s\n", context.category, message.toUtf8().data());
}
break;
case QtDebugMsg:
if (context.category == QStringLiteral("default")) {
fprintf(stdout, "%s\n", message.toUtf8().data());
} else {
fprintf(stdout, "%s: %s\n", context.category, message.toUtf8().data());
}
break;
case QtWarningMsg:
fprintf(stdout, "%s%s: %s%s\n", warning, context.category, message.toUtf8().data(), normal);
break;
case QtCriticalMsg:
fprintf(stdout, "%s%s: %s%s\n", error, context.category, message.toUtf8().data(), normal);
break;
case QtFatalMsg:
fprintf(stdout, "%s%s: %s%s\n", error, context.category, message.toUtf8().data(), normal);
break;
}
fflush(stdout);
}
int main(int argc, char *argv[])
{
qInstallMessageHandler(consoleLogHandler);
QCoreApplication application(argc, argv);
application.setApplicationName(SERVER_NAME_STRING);
application.setOrganizationName("nymea");
application.setApplicationVersion(SERVER_VERSION_STRING);
// Default debug categories
s_loggingFilters.insert("RemoteProxyClientJsonRpc", false);
s_loggingFilters.insert("RemoteProxyClientJsonRpcTraffic", false);
s_loggingFilters.insert("RemoteProxyClientWebSocket", false);
s_loggingFilters.insert("RemoteProxyClientTcpSocket", false);
s_loggingFilters.insert("RemoteProxyClientConnection", false);
s_loggingFilters.insert("RemoteProxyClientConnectionTraffic", false);
s_loggingFilters.insert("TunnelProxySocketServer", false);
s_loggingFilters.insert("TunnelProxySocketServerTraffic", false);
s_loggingFilters.insert("TunnelProxyRemoteConnection", false);
QCommandLineParser parser;
parser.addHelpOption();
parser.addVersionOption();
parser.setApplicationDescription(QString("\nThe nymea remote proxy tunnel client application. This application allowes to register as client"
"or server on the tunnel proxy interface.\n\n"
"Version: %1\n"
"API version: %2\n\n"
"Copyright %3 %4 nymea GmbH \n")
.arg(SERVER_VERSION_STRING)
.arg(API_VERSION_STRING)
.arg(QChar(0xA9))
.arg(COPYRIGHT_YEAR_STRING));
QCommandLineOption urlOption(QStringList() << "u" << "url", "The proxy server url. Default ssl://dev-remoteproxy.nymea.io:2213", "url");
urlOption.setDefaultValue("ssl://dev-remoteproxy.nymea.io:2213");
parser.addOption(urlOption);
QCommandLineOption insecureOption(QStringList() << "i" << "ignore-ssl", "Ignore SSL certificate errors.");
parser.addOption(insecureOption);
QCommandLineOption serverOption(QStringList() << "s" << "server", "Connect as tunnel proxy server connection.");
parser.addOption(serverOption);
QCommandLineOption clientOption(QStringList() << "c" << "client", "Connect as tunnel proxy client connection. The server uuid is required.");
parser.addOption(clientOption);
QCommandLineOption nameOption(QStringList() << "n" << "name", "The name of the connecting client. If not specified a default name will be selected.", "name");
parser.addOption(nameOption);
QCommandLineOption randomDataOption(QStringList() << "r" << "random", "Send random data trough the tunnel. If you start a server, it will echo any client data received.");
parser.addOption(randomDataOption);
QCommandLineOption uuidOption(QStringList() << "uuid", "The uuid of the connecting client. If not specified, a new one will be created.", "uuid");
parser.addOption(uuidOption);
QCommandLineOption serverUuidOption(QStringList() << "server-uuid", "The uuid of the server you want to connect to as client connection.", "uuid");
parser.addOption(serverUuidOption);
QCommandLineOption verboseOption(QStringList() << "verbose", "Print more information about the connection.");
parser.addOption(verboseOption);
QCommandLineOption veryVerboseOption(QStringList() << "very-verbose", "Print the complete traffic information from the connection.");
parser.addOption(veryVerboseOption);
parser.process(application);
// Make sure not server and client given
if (parser.isSet(serverOption) && parser.isSet(clientOption)) {
qCritical() << "Please specify either beeing a client or a server connection, not both.";
exit(EXIT_FAILURE);
}
// Get the uuid to pick for the connection
QUuid uuid(parser.value(uuidOption));
if (uuid.isNull()) {
uuid = QUuid::createUuid();
qDebug() << "Picking automatic UUID" << uuid.toString();
}
QUrl serverUrl(parser.value(urlOption));
if (!serverUrl.isValid()) {
qCritical() << "Invalid proxy server url passed." << parser.value(urlOption);
exit(-1);
}
// Server, or if not specified server too
if (parser.isSet(serverOption) || (!parser.isSet(serverOption) && !parser.isSet(clientOption))) {
QString name = parser.value("name");
if (name.isEmpty()) {
name = "Server connection";
qDebug() << "Picking automatic name" << name;
}
// Enable verbose
if (parser.isSet(verboseOption) || parser.isSet(veryVerboseOption)) {
s_loggingFilters["default"] = true;
s_loggingFilters["TunnelProxySocketServer"] = true;
s_loggingFilters["TunnelProxyRemoteConnection"] = true;
}
// Enable very verbose
if (parser.isSet(veryVerboseOption)) {
s_loggingFilters["RemoteProxyClientJsonRpc"] = true;
s_loggingFilters["RemoteProxyClientJsonRpcTraffic"] = true;
s_loggingFilters["RemoteProxyClientWebSocket"] = true;
s_loggingFilters["RemoteProxyClientTcpSocket"] = true;
s_loggingFilters["RemoteProxyClientConnection"] = true;
s_loggingFilters["RemoteProxyClientConnectionTraffic"] = true;
s_loggingFilters["TunnelProxySocketServerTraffic"] = true;
}
QLoggingCategory::installFilter(loggingCategoryFilter);
// Create the server connection
ServerConnection *server = new ServerConnection(serverUrl, name, uuid, parser.isSet(insecureOption), parser.isSet(randomDataOption));
server->startServer();
} else {
// Client
QString name = parser.value("name");
if (name.isEmpty()) {
name = "Client connection";
qDebug() << "Picking automatic name" << name;
}
if (!parser.isSet(serverUuidOption)) {
qCritical() << "Please specify the server UUID you want to connect to using the --server-uuid parameter.";
exit(EXIT_FAILURE);
}
QUuid serverUuid(parser.value(serverUuidOption));
if (serverUuid.isNull()) {
qCritical() << "The given server uuid is not valid." << parser.value(serverUuidOption);
exit(EXIT_FAILURE);
}
// Enable verbose
if (parser.isSet(verboseOption) || parser.isSet(veryVerboseOption)) {
s_loggingFilters["default"] = true;
s_loggingFilters["TunnelProxySocketServer"] = true;
s_loggingFilters["TunnelProxyRemoteConnection"] = true;
}
// Enable very verbose
if (parser.isSet(veryVerboseOption)) {
s_loggingFilters["RemoteProxyClientJsonRpc"] = true;
s_loggingFilters["RemoteProxyClientJsonRpcTraffic"] = true;
s_loggingFilters["RemoteProxyClientWebSocket"] = true;
s_loggingFilters["RemoteProxyClientTcpSocket"] = true;
s_loggingFilters["RemoteProxyClientConnection"] = true;
s_loggingFilters["RemoteProxyClientConnectionTraffic"] = true;
s_loggingFilters["TunnelProxySocketServerTraffic"] = true;
}
QLoggingCategory::installFilter(loggingCategoryFilter);
// Create the server connection
ClientConnection *client = new ClientConnection(serverUrl, name, uuid, serverUuid, parser.isSet(insecureOption), parser.isSet(randomDataOption));
client->connectToServer();
}
return application.exec();
}