blob: 586898b15156d8e04a2d13310cd89bcd722953a8 [file] [log] [blame]
#include "upnp/upnp_control.h"
#include "upnp/upnp_context.h"
#include "string_utils.h"
#include <asio/executor_work_guard.hpp>
#include <opendht/log.h>
#include <readline/readline.h>
#include <readline/history.h>
void
print_help()
{
fmt::print("Commands:\n"
" help, h, ?\n"
" quit, exit, q, x\n"
" ip\n"
" open <port> <protocol>\n");
}
std::string to_lower(std::string_view str_v) {
std::string str(str_v);
std::transform(str.begin(), str.end(), str.begin(),
[](unsigned char c){ return std::tolower(c); }
);
return str;
}
int
main(int argc, char** argv)
{
auto ioContext = std::make_shared<asio::io_context>();
std::shared_ptr<dht::log::Logger> logger = dht::log::getStdLogger();
auto upnpContext = std::make_shared<dhtnet::upnp::UPnPContext>(ioContext, logger);
auto ioContextRunner = std::make_shared<std::thread>([context = ioContext]() {
try {
auto work = asio::make_work_guard(*context);
context->run();
} catch (const std::exception& ex) {
// print the error;
}
});
auto controller = std::make_shared<dhtnet::upnp::Controller>(upnpContext);
std::set<std::shared_ptr<dhtnet::upnp::Mapping>> mappings;
while (true) {
char* l = readline("> ");
if (not l)
break;
std::string_view line{l};
if (line.empty())
continue;
add_history(l);
auto args = dhtnet::split_string(line, ' ');
auto command = args[0];
if (command == "quit" || command == "exit" || command == "q" || command == "x")
break;
else if (command == "help" || command == "h" || command == "?") {
print_help();
}
else if (command == "ip") {
fmt::print("{}\n", controller->getExternalIP().toString());
} else if (command == "open") {
if (args.size() < 3) {
fmt::print("Usage: open <port> <protocol>\n");
continue;
}
auto protocol = to_lower(args[2]) == "udp" ? dhtnet::upnp::PortType::UDP : dhtnet::upnp::PortType::TCP;
mappings.emplace(controller->reserveMapping(dhtnet::to_int<in_port_t>(args[1]), protocol));
} else if (command == "close") {
if (args.size() < 2) {
fmt::print("Usage: close <port>\n");
continue;
}
auto port = dhtnet::to_int<in_port_t>(args[1]);
for (auto it = mappings.begin(); it != mappings.end(); ) {
if ((*it)->getExternalPort() == port) {
controller->releaseMapping(**it);
it = mappings.erase(it);
} else {
++it;
}
}
} else {
fmt::print("Unknown command: {}\n", command);
}
}
fmt::print("Stopping...");
for (auto c: mappings)
controller->releaseMapping(*c);
mappings.clear();
ioContext->stop();
ioContextRunner->join();
}