uloop_timeout_cancel(&net->reload_timer);
network_do_update(net, false);
network_pex_close(net);
+ network_pex_free(net);
network_hosts_free(net);
network_services_free(net);
wg_cleanup_network(net);
uloop_timeout_set(t, 5000);
+retry:
if (list_empty(&pex->hosts))
return;
host = list_first_entry(&pex->hosts, struct network_pex_host, list);
+ if (host->timeout && host->timeout < unet_gettime()) {
+ list_del(&host->list);
+ free(host);
+ goto retry;
+ }
+
list_move_tail(&host->list, &pex->hosts);
network_pex_host_request_update(net, host);
}
}
}
-static void
-network_pex_create_host(struct network *net, union network_endpoint *ep)
+void network_pex_create_host(struct network *net, union network_endpoint *ep,
+ unsigned int timeout)
{
struct network_pex *pex = &net->pex;
struct network_pex_host *host;
+ bool new_host = false;
+
+ list_for_each_entry(host, &pex->hosts, list) {
+ if (memcmp(&host->endpoint, ep, sizeof(host->endpoint)) != 0)
+ continue;
+
+ list_move_tail(&host->list, &pex->hosts);
+ goto out;
+ }
host = calloc(1, sizeof(*host));
+ new_host = true;
memcpy(&host->endpoint, ep, sizeof(host->endpoint));
list_add_tail(&host->list, &pex->hosts);
+
+out:
+ if (timeout && (new_host || host->timeout))
+ host->timeout = timeout + unet_gettime();
network_pex_host_request_update(net, host);
}
continue;
ep.in.sin_port = htons(UNETD_GLOBAL_PEX_PORT);
- network_pex_create_host(net, &ep);
+ network_pex_create_host(net, &ep, 0);
}
if (!net->config.auth_connect)
UNETD_GLOBAL_PEX_PORT, 0) < 0)
continue;
- network_pex_create_host(net, &ep);
+ network_pex_create_host(net, &ep, 0);
}
}
uloop_timeout_cancel(&pex->request_update_timer);
list_for_each_entry_safe(host, tmp, &pex->hosts, list) {
+ if (host->timeout)
+ continue;
+
list_del(&host->list);
free(host);
}
network_pex_init(net);
}
+void network_pex_free(struct network *net)
+{
+ struct network_pex *pex = &net->pex;
+ struct network_pex_host *host, *tmp;
+
+ list_for_each_entry_safe(host, tmp, &pex->hosts, list) {
+ list_del(&host->list);
+ free(host);
+ }
+}
+
static struct network *
global_pex_find_network(const uint8_t *id)
{
struct network_pex_host {
struct list_head list;
+ uint64_t timeout;
union network_endpoint endpoint;
};
void network_pex_init(struct network *net);
int network_pex_open(struct network *net);
void network_pex_close(struct network *net);
+void network_pex_free(struct network *net);
void network_pex_event(struct network *net, struct network_peer *peer,
enum pex_event ev);
+void network_pex_create_host(struct network *net, union network_endpoint *ep,
+ unsigned int timeout);
static inline bool network_pex_active(struct network_pex *pex)
{
return 0;
}
+enum {
+ CONNECT_ATTR_NAME,
+ CONNECT_ATTR_ADDRESS,
+ CONNECT_ATTR_TIMEOUT,
+ __CONNECT_ATTR_MAX
+};
+
+static const struct blobmsg_policy connect_policy[__CONNECT_ATTR_MAX] = {
+ [CONNECT_ATTR_NAME] = { "name", BLOBMSG_TYPE_STRING },
+ [CONNECT_ATTR_ADDRESS] = { "address", BLOBMSG_TYPE_STRING },
+ [CONNECT_ATTR_TIMEOUT] = { "timeout", BLOBMSG_TYPE_INT32 },
+};
+
+static int
+ubus_network_connect(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct blob_attr *tb[__CONNECT_ATTR_MAX];
+ union network_endpoint ep = {};
+ struct blob_attr *cur;
+ struct network *net;
+ unsigned int timeout;
+ const char *name;
+
+ blobmsg_parse(connect_policy, __CONNECT_ATTR_MAX, tb,
+ blobmsg_data(msg), blobmsg_len(msg));
+
+ if ((cur = tb[CONNECT_ATTR_NAME]) != NULL)
+ name = blobmsg_get_string(cur);
+ else
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ if ((cur = tb[CONNECT_ATTR_TIMEOUT]) != NULL)
+ timeout = blobmsg_get_u32(cur);
+ else
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ if ((cur = tb[CONNECT_ATTR_ADDRESS]) == NULL ||
+ network_get_endpoint(&ep, blobmsg_get_string(cur), UNETD_GLOBAL_PEX_PORT, 0) < 0 ||
+ !ep.in.sin_port)
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ net = avl_find_element(&networks, name, net, node);
+ if (!net)
+ return UBUS_STATUS_NOT_FOUND;
+
+ if (net->config.type != NETWORK_TYPE_DYNAMIC)
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ network_pex_create_host(net, &ep, timeout);
+
+ return 0;
+}
+
+
static const struct ubus_method unetd_methods[] = {
UBUS_METHOD("network_add", ubus_network_add, network_policy),
UBUS_METHOD_MASK("network_del", ubus_network_del, network_policy,
(1 << NETWORK_ATTR_NAME)),
UBUS_METHOD_MASK("network_get", ubus_network_get, network_policy,
(1 << NETWORK_ATTR_NAME)),
+ UBUS_METHOD("network_connect", ubus_network_connect, connect_policy),
UBUS_METHOD("service_get", ubus_service_get, service_policy),
};
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
+
+#include <libubox/utils.h>
+
#include "unetd.h"
int network_get_endpoint(union network_endpoint *dest, const char *str,
*len = 0;
return NULL;
}
+
+uint64_t unet_gettime(void)
+{
+ struct timespec ts;
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ return ts.tv_sec;
+}
int rtnl_init(void);
int rtnl_call(struct nl_msg *msg);
+uint64_t unet_gettime(void);
+
#endif