File transfer server now respects the port and host settings set via the config.yml

This commit is contained in:
WolverinDEV
2020-06-13 01:08:49 +02:00
parent ed7cbd38e8
commit a23002ce66
11 changed files with 263 additions and 122 deletions
+144 -79
View File
@@ -168,95 +168,161 @@ void FileClient::flush_network_buffer() {
}
NetworkingStartResult LocalFileTransfer::start_networking() {
std::lock_guard nlock{this->network.mutex};
assert(!this->network.active);
this->network.active = true;
this->network.event_base = event_base_new();
if(!this->network.event_base) return NetworkingStartResult::OUT_OF_MEMORY;
bool bound{false};
for(auto& binding : this->network.bindings) {
binding->file_descriptor = socket(binding->address.ss_family, SOCK_STREAM | SOCK_NONBLOCK, 0);
if(!binding->file_descriptor) {
logWarning(LOG_FT, "Failed to allocate socket for {}: {}/{}", binding->hostname, errno, strerror(errno));
continue;
}
int enable = 1, disabled = 0;
if (setsockopt(binding->file_descriptor, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0)
logWarning(LOG_FT, "Failed to activate SO_REUSEADDR for binding {} ({} | {})", binding->hostname, errno, strerror(errno));
if(setsockopt(binding->file_descriptor, IPPROTO_TCP, TCP_NOPUSH, &disabled, sizeof disabled) < 0)
logWarning(LOG_FT, "Failed to deactivate TCP_NOPUSH for binding {} ({} | {})", binding->hostname, errno, strerror(errno));
if(binding->address.ss_family == AF_INET6) {
if(setsockopt(binding->file_descriptor, IPPROTO_IPV6, IPV6_V6ONLY, &enable, sizeof(int)) < 0)
logWarning(LOG_FT, "Failed to activate IPV6_V6ONLY for IPv6 binding {} ({} | {})", binding->hostname, errno, strerror(errno));
}
if(fcntl(binding->file_descriptor, F_SETFD, FD_CLOEXEC) < 0)
logWarning(LOG_FT, "Failed to set flag FD_CLOEXEC for binding {} ({} | {})", binding->hostname, errno, strerror(errno));
if (bind(binding->file_descriptor, (struct sockaddr *) &binding->address, sizeof(binding->address)) < 0) {
logError(LOG_FT, "Failed to bind server to {}. (Failed to bind socket: {} | {})", binding->hostname, errno, strerror(errno));
goto reset_binding;
}
if (listen(binding->file_descriptor, 8) < 0) {
logError(LOG_FT, "Failed to bind server to {}. (Failed to listen: {} | {})", binding->hostname, errno, strerror(errno));
goto reset_binding;
}
binding->handle = this;
binding->accept_event = event_new(this->network.event_base, binding->file_descriptor, (unsigned) EV_READ | (unsigned) EV_PERSIST, &LocalFileTransfer::callback_transfer_network_accept, &*binding);
if(!binding->accept_event)
goto reset_binding;
event_add(binding->accept_event, nullptr);
logMessage(LOG_FT, "Started to listen on {}:{}", binding->hostname, net::port(binding->address));
bound = true;
continue;
reset_binding:
if(binding->accept_event) {
event_free(binding->accept_event);
binding->accept_event = nullptr;
}
if(binding->file_descriptor > 0)
::close(binding->file_descriptor);
binding->file_descriptor = 0;
binding->handle = nullptr;
}
if(!bound) {
event_base_free(std::exchange(this->network.event_base, nullptr));
return NetworkingStartResult::NO_BINDINGS;
}
this->network.dispatch_thread = std::thread(&LocalFileTransfer::dispatch_loop_network, this);
return NetworkingStartResult::SUCCESS;
}
void LocalFileTransfer::shutdown_networking() {
if(!this->network.active) return;
this->network.active = false;
NetworkingBindResult LocalFileTransfer::add_network_binding(const NetworkBinding &binding) {
std::lock_guard nlock{this->network.mutex};
if(!this->network.active)
return NetworkingBindResult::NETWORKING_NOT_INITIALIZED;
for(auto& binding : this->network.bindings) {
if(binding->accept_event) {
event_del_block(binding->accept_event);
event_free(binding->accept_event);
binding->accept_event = nullptr;
for(const auto& abinding : this->network.bindings) {
if(net::address_equal(abinding->address, binding.address) && net::port(abinding->address) == net::port(binding.address))
return NetworkingBindResult::BINDING_ALREADY_EXISTS;
}
NetworkingBindResult result{NetworkingBindResult::SUCCESS};
auto abinding = std::make_shared<ActiveNetworkBinding>();
abinding->handle = this;
abinding->hostname = binding.hostname;
memcpy(&abinding->address, &binding.address, sizeof(binding.address));
abinding->file_descriptor = socket(abinding->address.ss_family, SOCK_STREAM | SOCK_NONBLOCK, 0);
if(!abinding->file_descriptor) {
//logWarning(LOG_FT, "Failed to allocate socket for {}: {}/{}", abinding->hostname, errno, strerror(errno));
return NetworkingBindResult::FAILED_TO_ALLOCATE_SOCKET;
}
int enable = 1, disabled = 0;
if (setsockopt(abinding->file_descriptor, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0)
logWarning(LOG_FT, "Failed to activate SO_REUSEADDR for binding {} ({}/{})", abinding->hostname, errno, strerror(errno));
if(setsockopt(abinding->file_descriptor, IPPROTO_TCP, TCP_NOPUSH, &disabled, sizeof disabled) < 0)
logWarning(LOG_FT, "Failed to deactivate TCP_NOPUSH for binding {} ({}/{})", abinding->hostname, errno, strerror(errno));
if(abinding->address.ss_family == AF_INET6) {
if(setsockopt(abinding->file_descriptor, IPPROTO_IPV6, IPV6_V6ONLY, &enable, sizeof(int)) < 0)
logWarning(LOG_FT, "Failed to activate IPV6_V6ONLY for IPv6 binding {} ({}/{})", abinding->hostname, errno, strerror(errno));
}
if(fcntl(abinding->file_descriptor, F_SETFD, FD_CLOEXEC) < 0)
logWarning(LOG_FT, "Failed to set flag FD_CLOEXEC for binding {} ({}/{})", abinding->hostname, errno, strerror(errno));
if (bind(abinding->file_descriptor, (struct sockaddr *) &abinding->address, sizeof(abinding->address)) < 0) {
//logError(LOG_FT, "Failed to bind server to {}. (Failed to bind socket: {}/{})", binding->hostname, errno, strerror(errno));
result = NetworkingBindResult::FAILED_TO_BIND;
goto reset_binding;
}
if (listen(abinding->file_descriptor, 8) < 0) {
//logError(LOG_FT, "Failed to bind server to {}. (Failed to listen: {}/{})", binding->hostname, errno, strerror(errno));
result = NetworkingBindResult::FAILED_TO_LISTEN;
goto reset_binding;
}
abinding->accept_event = event_new(this->network.event_base, abinding->file_descriptor, (unsigned) EV_READ | (unsigned) EV_PERSIST, &LocalFileTransfer::callback_transfer_network_accept, &*abinding);
if(!abinding->accept_event) {
result = NetworkingBindResult::OUT_OF_MEMORY;
goto reset_binding;
}
event_add(abinding->accept_event, nullptr);
logMessage(LOG_FT, "Started to listen on {}:{}", abinding->hostname, net::port(abinding->address));
this->network.bindings.push_back(std::move(abinding));
return NetworkingBindResult::SUCCESS;
reset_binding:
if(abinding->accept_event) {
event_free(abinding->accept_event);
abinding->accept_event = nullptr;
}
if(abinding->file_descriptor > 0)
::close(abinding->file_descriptor);
abinding->file_descriptor = 0;
abinding->handle = nullptr;
return result;
}
std::vector<NetworkBinding> LocalFileTransfer::active_network_bindings() {
std::lock_guard nlock{this->network.mutex};
std::vector<NetworkBinding> result{};
result.reserve(this->network.bindings.size());
for(const auto& binding : this->network.bindings) {
auto& rbinding = result.emplace_back();
rbinding.hostname = binding->hostname;
memcpy(&rbinding.address, &binding->address, sizeof(rbinding.address));
}
return result;
}
NetworkingUnbindResult LocalFileTransfer::remove_network_binding(const NetworkBinding &binding) {
std::lock_guard nlock{this->network.mutex};
std::shared_ptr<ActiveNetworkBinding> abinding{};
for(auto it = this->network.bindings.begin(); it != this->network.bindings.end(); it++) {
abinding = *it;
if(net::address_equal(abinding->address, binding.address) && net::port(abinding->address) == net::port(binding.address)) {
this->network.bindings.erase(it);
break;
}
abinding = nullptr;
}
if(binding->file_descriptor > 0)
::close(binding->file_descriptor);
binding->file_descriptor = 0;
if(!abinding)
return NetworkingUnbindResult::UNKNOWN_BINDING;
binding->handle = nullptr;
if(abinding->accept_event) {
event_del_block(abinding->accept_event);
event_free(abinding->accept_event);
abinding->accept_event = nullptr;
}
if(abinding->file_descriptor > 0)
::close(abinding->file_descriptor);
abinding->file_descriptor = 0;
abinding->handle = nullptr;
return NetworkingUnbindResult::SUCCESS;
}
void LocalFileTransfer::shutdown_networking() {
event_base* ev_base;
std::thread dispatch_thread{};
{
std::lock_guard nlock{this->network.mutex};
if(!this->network.active) return;
this->network.active = false;
for(auto& binding : this->network.bindings) {
if(binding->accept_event) {
event_del_block(binding->accept_event);
event_free(binding->accept_event);
binding->accept_event = nullptr;
}
if(binding->file_descriptor > 0)
::close(binding->file_descriptor);
binding->file_descriptor = 0;
binding->handle = nullptr;
}
this->network.bindings.clear();
ev_base = std::exchange(this->network.event_base, nullptr);
std::swap(this->network.dispatch_thread, dispatch_thread);
}
{
@@ -269,12 +335,11 @@ void LocalFileTransfer::shutdown_networking() {
}
}
auto ev_base = std::exchange(this->network.event_base, nullptr);
if(ev_base)
event_base_loopbreak(ev_base);
if(this->network.dispatch_thread.joinable())
this->network.dispatch_thread.join();
if(dispatch_thread.joinable())
dispatch_thread.join();
if(ev_base)
event_base_free(ev_base);
@@ -428,7 +493,7 @@ void LocalFileTransfer::finalize_client_ssl(const std::shared_ptr<FileClient> &c
}
void LocalFileTransfer::callback_transfer_network_accept(int fd, short, void *ptr_binding) {
auto binding = reinterpret_cast<NetworkBinding*>(ptr_binding);
auto binding = reinterpret_cast<ActiveNetworkBinding*>(ptr_binding);
auto transfer = binding->handle;
sockaddr_storage address{};