#2 Inbound and outbound DCC chat, still need better NAT handling.
parent
4bfc9b2380
commit
29ea535243
@ -0,0 +1,43 @@ |
||||
/*
|
||||
* IdealIRC - Internet Relay Chat client |
||||
* Copyright (c) 2022 Tom-Andre Barstad. |
||||
* This software is licensed under the Software Attribution License. |
||||
* See LICENSE for more information. |
||||
*/ |
||||
|
||||
#include "ICommand/ICommandPriv.h" |
||||
#include "IRCClient/DCC.h" |
||||
#include <fmt/format.h> |
||||
|
||||
void ICommandPriv::cmd_dcc(const std::string& command, const std::string& target, const std::string& message) |
||||
{ |
||||
auto& mdi = MdiManager::instance(); |
||||
|
||||
if (command == "CHAT") { |
||||
auto result = connection.initiateDCC(); |
||||
if (result.second != IRCError::NoError) { |
||||
const auto code = static_cast<int>(result.second); |
||||
const auto errorStr = QString::fromStdString(IRCErrorToString(result.second)); |
||||
mdi.currentStatus()->printToActive(PrintType::ProgramInfo, QObject::tr("/DCC: Unable to initiate DCC Chat to %1 [%2 (%3)]") |
||||
.arg( QString::fromStdString(target), errorStr, QString::number(code)) ); |
||||
} |
||||
else { |
||||
const auto portno = result.first->port(); |
||||
auto* window = mdi.createDCCSubwindow(mdi.currentStatus(), IWin::Type::DCCChat, result.first, IRCPrefix(target)); |
||||
window->print(PrintType::ProgramInfo, QObject::tr("Initiated CHAT with %1 on port %2") |
||||
.arg( QString::fromStdString(target) ) |
||||
.arg(portno)); |
||||
|
||||
const auto myIp = findOwnIpAddress(); |
||||
const auto msg = fmt::format( "CHAT chat {} {}", |
||||
normalIpToLong(myIp), |
||||
portno |
||||
); |
||||
cmd_ctcp(target, "DCC", msg); |
||||
} |
||||
} |
||||
else { |
||||
mdi.currentStatus()->printToActive(PrintType::ProgramInfo, QObject::tr("/DCC: Unknown DCC method: %1") |
||||
.arg( QString::fromStdString(command) )); |
||||
} |
||||
} |
@ -0,0 +1,15 @@ |
||||
set(component "NATUtils") |
||||
|
||||
list(APPEND ${component}_SOURCES |
||||
${CMAKE_CURRENT_SOURCE_DIR}/PortMapping.h |
||||
${CMAKE_CURRENT_SOURCE_DIR}/PublicAddress.h |
||||
) |
||||
|
||||
list(APPEND ${component}_COMMANDS |
||||
${CMAKE_CURRENT_SOURCE_DIR}/PortMapping.cpp |
||||
${CMAKE_CURRENT_SOURCE_DIR}/PublicAddress.cpp |
||||
) |
||||
|
||||
add_library(${component} STATIC ${${component}_SOURCES} ${${component}_COMMANDS}) |
||||
target_link_libraries(${component} fmt natpmp) |
||||
target_include_directories(${component} PRIVATE ${CMAKE_SOURCE_DIR}) |
@ -0,0 +1,56 @@ |
||||
/*
|
||||
* IdealIRC - Internet Relay Chat client |
||||
* Copyright (c) 2022 Tom-Andre Barstad. |
||||
* This software is licensed under the Software Attribution License. |
||||
* See LICENSE for more information. |
||||
*/ |
||||
|
||||
#include "PortMapping.h" |
||||
#include <natpmp.h> |
||||
#include <chrono> |
||||
#include <thread> |
||||
|
||||
namespace { |
||||
bool portmapRequest(const std::string& ip, uint16_t intPort, uint16_t extPort, uint32_t timeout) |
||||
{ |
||||
natpmp_t request; |
||||
natpmpresp_t response; |
||||
|
||||
if (initnatpmp(&request, 0, 0) != 0) |
||||
return false; |
||||
|
||||
auto retry = 10; |
||||
auto res = sendnewportmappingrequest(&request, NATPMP_PROTOCOL_TCP, intPort, extPort, timeout); |
||||
while (res != 12 && retry > 0) { |
||||
if (res == NATPMP_ERR_NOGATEWAYSUPPORT) |
||||
return false; |
||||
|
||||
std::this_thread::sleep_for( std::chrono::milliseconds(10) ); |
||||
|
||||
res = sendnewportmappingrequest(&request, NATPMP_PROTOCOL_TCP, intPort, extPort, timeout); |
||||
--retry; |
||||
} |
||||
|
||||
auto readres = readnatpmpresponseorretry(&request, &response); |
||||
retry = 10; |
||||
while (readres != 0 && retry > 0) { |
||||
std::this_thread::sleep_for( std::chrono::milliseconds(10) ); |
||||
readres = readnatpmpresponseorretry(&request, &response); |
||||
--retry; |
||||
} |
||||
|
||||
return retry != 0; |
||||
} |
||||
} |
||||
|
||||
bool NATPortMapping::add(const std::string& ip, uint16_t intPort, uint16_t extPort) |
||||
{ |
||||
constexpr auto SecondsInWeek = 60 * 60 * 24 * 7; |
||||
return portmapRequest(ip, intPort, extPort, SecondsInWeek); |
||||
} |
||||
|
||||
bool NATPortMapping::remove(const std::string& ip, uint16_t intPort, uint16_t extPort) |
||||
{ |
||||
// Setting new timeout to '0' would cause the port mapping to be removed right away.
|
||||
return portmapRequest(ip, intPort, extPort, 0); |
||||
} |
@ -0,0 +1,31 @@ |
||||
/*
|
||||
* IdealIRC - Internet Relay Chat client |
||||
* Copyright (c) 2022 Tom-Andre Barstad. |
||||
* This software is licensed under the Software Attribution License. |
||||
* See LICENSE for more information. |
||||
*/ |
||||
|
||||
#ifndef NATPORTMAPPING_H |
||||
#define NATPORTMAPPING_H |
||||
|
||||
#include <cstdint> |
||||
#include <string> |
||||
|
||||
namespace NATPortMapping { |
||||
|
||||
/**
|
||||
* Add a port forwarding onto local network router using libnatpmp. |
||||
* The reservation is set to expire after one week to accommodate for clients on slow connections doing for example a file transfer taking a few days (it is theoretically possible.) |
||||
* Returns true on success. |
||||
*/ |
||||
bool add(const std::string& ip, uint16_t intPort, uint16_t extPort); |
||||
|
||||
/**
|
||||
* Remove a port forward using libnatpmp. |
||||
* Returns true on success. |
||||
*/ |
||||
bool remove(const std::string& ip, uint16_t intPort, uint16_t extPort); |
||||
|
||||
} |
||||
|
||||
#endif //NATPORTMAPPING_H
|
@ -0,0 +1,48 @@ |
||||
/*
|
||||
* IdealIRC - Internet Relay Chat client |
||||
* Copyright (c) 2022 Tom-Andre Barstad. |
||||
* This software is licensed under the Software Attribution License. |
||||
* See LICENSE for more information. |
||||
*/ |
||||
|
||||
#include "PublicAddress.h" |
||||
#include <natpmp.h> |
||||
#include <chrono> |
||||
#include <thread> |
||||
|
||||
std::optional<std::uint32_t> NATPublicAddress::get() |
||||
{ |
||||
natpmp_t request; |
||||
natpmpresp_t response; |
||||
|
||||
if (initnatpmp(&request, 0, 0) != 0) |
||||
return std::nullopt; |
||||
|
||||
auto retry = 10; |
||||
auto res = sendpublicaddressrequest(&request); |
||||
while (res != 2 && retry > 0) { |
||||
if (res == NATPMP_ERR_NOGATEWAYSUPPORT) |
||||
return std::nullopt; |
||||
|
||||
std::this_thread::sleep_for( std::chrono::milliseconds(10) ); |
||||
|
||||
res = sendpublicaddressrequest(&request); |
||||
--retry; |
||||
} |
||||
|
||||
if (retry == 0) |
||||
return std::nullopt; |
||||
|
||||
auto readres = readnatpmpresponseorretry(&request, &response); |
||||
retry = 10; |
||||
while (readres != 0 && retry > 0) { |
||||
std::this_thread::sleep_for( std::chrono::milliseconds(10) ); |
||||
readres = readnatpmpresponseorretry(&request, &response); |
||||
--retry; |
||||
} |
||||
|
||||
if (retry == 0) |
||||
return std::nullopt; |
||||
|
||||
return response.pnu.publicaddress.addr.s_addr; |
||||
} |
@ -0,0 +1,24 @@ |
||||
/*
|
||||
* IdealIRC - Internet Relay Chat client |
||||
* Copyright (c) 2022 Tom-Andre Barstad. |
||||
* This software is licensed under the Software Attribution License. |
||||
* See LICENSE for more information. |
||||
*/ |
||||
|
||||
#ifndef PUBLICADDRESS_H |
||||
#define PUBLICADDRESS_H |
||||
|
||||
#include <cstdint> |
||||
#include <optional> |
||||
#include <string> |
||||
|
||||
namespace NATPublicAddress { |
||||
|
||||
/**
|
||||
* Get the IP address used externally (aka. public IP address) using libnatpmp. |
||||
* Returns a nullopt on error. |
||||
*/ |
||||
std::optional<std::uint32_t> get(); |
||||
|
||||
} |
||||
#endif //PUBLICADDRESS_H
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 105 KiB |
Loading…
Reference in new issue