summaryrefslogtreecommitdiffstats
path: root/apps/http-proxy/src/forwarder_interface.cc
diff options
context:
space:
mode:
Diffstat (limited to 'apps/http-proxy/src/forwarder_interface.cc')
-rw-r--r--apps/http-proxy/src/forwarder_interface.cc262
1 files changed, 262 insertions, 0 deletions
diff --git a/apps/http-proxy/src/forwarder_interface.cc b/apps/http-proxy/src/forwarder_interface.cc
new file mode 100644
index 000000000..105d5a8e9
--- /dev/null
+++ b/apps/http-proxy/src/forwarder_interface.cc
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "forwarder_interface.h"
+
+#include <arpa/inet.h>
+#include <hicn/transport/utils/log.h>
+
+#include <chrono>
+#include <iostream>
+#include <thread>
+#include <unordered_set>
+
+namespace transport {
+
+ForwarderInterface::~ForwarderInterface() {}
+
+int ForwarderInterface::connectToForwarder() {
+ sock_ = hc_sock_create();
+ if (!sock_) return -1;
+
+ if (hc_sock_connect(sock_) < 0) {
+ hc_sock_free(sock_);
+ sock_ = nullptr;
+ return -1;
+ }
+
+ return 0;
+}
+
+void ForwarderInterface::close() {
+ internal_ioservice_.post([this]() {
+ work_.reset();
+ if (sock_) {
+ hc_sock_free(sock_);
+ sock_ = nullptr;
+ }
+ });
+
+ if (thread_->joinable()) {
+ thread_->join();
+ }
+}
+
+void ForwarderInterface::removeConnectedUserNow(uint32_t route_id) {
+ internalRemoveConnectedUser(route_id);
+}
+
+void ForwarderInterface::scheduleRemoveConnectedUser(uint32_t route_id) {
+ internal_ioservice_.post(
+ [this, route_id]() { internalRemoveConnectedUser(route_id); });
+}
+
+int32_t ForwarderInterface::getMainListenerPort() {
+ if (!sock_) return -1;
+
+ hc_data_t *data;
+ if (hc_listener_list(sock_, &data) < 0) return -1;
+
+ int ret = -1;
+ foreach_listener(l, data) {
+ std::string interface = std::string(l->interface_name);
+ if (interface.compare("lo") != 0) {
+ ret = l->local_port;
+ break;
+ }
+ }
+
+ hc_data_free(data);
+ return ret;
+}
+
+void ForwarderInterface::internalRemoveConnectedUser(uint32_t route_id) {
+ auto it = route_status_.find(route_id);
+ if (it == route_status_.end()) return;
+
+ if (!sock_) return;
+
+ // remove route
+ hc_data_t *data;
+ if (hc_route_list(sock_, &data) < 0) return;
+
+ std::vector<hc_route_t *> routes_to_remove;
+ foreach_route(r, data) {
+ char remote_addr[INET6_ADDRSTRLEN];
+ int ret = ip_address_ntop(&r->remote_addr, remote_addr, r->len, r->family);
+ if (ret < 0) continue;
+
+ std::string route_addr(remote_addr);
+ if (route_addr.compare(it->second->route_addr) == 0 &&
+ r->len == it->second->route_len) {
+ // route found
+ routes_to_remove.push_back(r);
+ }
+ }
+
+ route_status_.erase(it);
+
+ if (routes_to_remove.size() == 0) {
+ // nothing to do here
+ hc_data_free(data);
+ return;
+ }
+
+ std::unordered_set<uint32_t> connids_to_remove;
+ for (unsigned i = 0; i < routes_to_remove.size(); i++) {
+ connids_to_remove.insert(routes_to_remove[i]->face_id);
+ if (hc_route_delete(sock_, routes_to_remove[i]) < 0) {
+ TRANSPORT_LOGE("Error removing route from forwarder.");
+ }
+ }
+
+ // remove connection
+ if (hc_connection_list(sock_, &data) < 0) {
+ hc_data_free(data);
+ return;
+ }
+
+ // collects pointerst to the connections using the conn IDs
+ std::vector<hc_connection_t *> conns_to_remove;
+ foreach_connection(c, data) {
+ if (connids_to_remove.find(c->id) != connids_to_remove.end()) {
+ // conn found
+ conns_to_remove.push_back(c);
+ }
+ }
+
+ if (conns_to_remove.size() == 0) {
+ // nothing else to do here
+ hc_data_free(data);
+ return;
+ }
+
+ for (unsigned i = 0; i < conns_to_remove.size(); i++) {
+ if (hc_connection_delete(sock_, conns_to_remove[i]) < 0) {
+ TRANSPORT_LOGE("Error removing connection from forwarder.");
+ }
+ }
+
+ hc_data_free(data);
+}
+
+void ForwarderInterface::internalCreateFaceAndRoute(RouteInfoPtr route_info,
+ uint8_t max_try,
+ asio::steady_timer *timer,
+ SetRouteCallback callback) {
+ int ret = tryToCreateFaceAndRoute(route_info.get());
+
+ if (ret < 0 && max_try > 0) {
+ max_try--;
+ timer->expires_from_now(std::chrono::milliseconds(500));
+ timer->async_wait([this, _route_info = std::move(route_info), max_try,
+ timer, callback](std::error_code ec) {
+ if (ec) return;
+ internalCreateFaceAndRoute(std::move(_route_info), max_try, timer,
+ std::move(callback));
+ });
+ return;
+ }
+
+ if (max_try == 0 && ret < 0) {
+ pending_add_route_counter_--;
+ external_ioservice_.post([callback]() { callback(false, ~0); });
+ } else {
+ pending_add_route_counter_--;
+ route_status_[route_id_] = std::move(route_info);
+ external_ioservice_.post(
+ [route_id = route_id_, callback]() { callback(route_id, true); });
+ route_id_++;
+ }
+
+ delete timer;
+}
+
+int ForwarderInterface::tryToCreateFaceAndRoute(route_info_t *route_info) {
+ if (!sock_) return -1;
+
+ hc_data_t *data;
+ if (hc_listener_list(sock_, &data) < 0) {
+ return -1;
+ }
+
+ bool found = false;
+ uint32_t face_id;
+
+ foreach_listener(l, data) {
+ std::string interface = std::string(l->interface_name);
+ if (interface.compare("lo") != 0) {
+ found = true;
+
+ ip_address_t remote_ip;
+ if (ip_address_pton(route_info->remote_addr.c_str(), &remote_ip) < 0) {
+ hc_data_free(data);
+ return -1;
+ }
+
+ hc_face_t face;
+ memset(&face, 0, sizeof(hc_face_t));
+
+ face.face.type = FACE_TYPE_UDP;
+ face.face.family = route_info->family;
+ face.face.local_addr = l->local_addr;
+ face.face.remote_addr = remote_ip;
+ face.face.local_port = l->local_port;
+ face.face.remote_port = route_info->remote_port;
+
+ if (netdevice_set_name(&face.face.netdevice, l->interface_name) < 0) {
+ hc_data_free(data);
+ return -1;
+ }
+
+ if (hc_face_create(sock_, &face) < 0) {
+ hc_data_free(data);
+ return -1;
+ }
+
+ face_id = face.id;
+ break;
+ }
+ }
+
+ if (!found) {
+ hc_data_free(data);
+ return -1;
+ }
+
+ ip_address_t route_ip;
+ hc_route_t route;
+
+ if (ip_address_pton(route_info->route_addr.c_str(), &route_ip) < 0) {
+ hc_data_free(data);
+ return -1;
+ }
+
+ route.face_id = face_id;
+ route.family = AF_INET6;
+ route.remote_addr = route_ip;
+ route.len = route_info->route_len;
+ route.cost = 1;
+
+ if (hc_route_create(sock_, &route) < 0) {
+ hc_data_free(data);
+ return -1;
+ }
+
+ hc_data_free(data);
+ return 0;
+}
+
+} // namespace transport