static void
network_pex_send_ping(struct network *net, struct network_peer *peer)
{
+ if (peer->state.pinged || !peer->state.endpoint.sa.sa_family)
+ return;
+
pex_msg_init(net, PEX_MSG_PING);
pex_msg_send(net, peer);
+ peer->state.pinged = true;
}
static void
if (!network_pex_active(&net->pex))
return;
- if (peer)
- D_PEER(net, peer, "PEX event type=%d", ev);
- else
- D_NET(net, "PEX event type=%d", ev);
-
switch (ev) {
case PEX_EV_HANDSHAKE:
pex_send_hello(net, peer);
if (!len)
continue;
- if (len < sizeof(*hdr))
- continue;
-
- hdr->len = ntohs(hdr->len);
- if (len - sizeof(hdr) < hdr->len)
+ hdr = pex_rx_accept(buf, len, false);
+ if (!hdr)
continue;
peer = pex_msg_peer(net, hdr->id);
{
struct network_pex *pex = &net->pex;
struct network_pex_host *host, *tmp;
+ uint64_t now = unet_gettime();
uloop_timeout_cancel(&pex->request_update_timer);
list_for_each_entry_safe(host, tmp, &pex->hosts, list) {
if (host->timeout)
continue;
+ if (host->last_active + UNETD_PEX_HOST_ACITVE_TIMEOUT >= now)
+ continue;
+
list_del(&host->list);
free(host);
}
}
static void
-global_pex_recv(struct pex_hdr *hdr, struct sockaddr_in6 *addr)
+global_pex_set_active(struct network *net, struct sockaddr_in6 *addr)
+{
+ struct network_pex *pex = &net->pex;
+ struct network_pex_host *host;
+
+ list_for_each_entry(host, &pex->hosts, list) {
+ if (memcmp(&host->endpoint.in6, addr, sizeof(*addr)) != 0)
+ continue;
+
+ host->last_active = unet_gettime();
+ }
+}
+
+static void
+global_pex_recv(void *msg, size_t msg_len, struct sockaddr_in6 *addr)
{
- struct pex_ext_hdr *ehdr = (void *)(hdr + 1);
+ struct pex_hdr *hdr;
+ struct pex_ext_hdr *ehdr;
struct network_peer *peer;
struct network *net;
- void *data = (void *)(ehdr + 1);
char buf[INET6_ADDRSTRLEN];
+ void *data;
int addr_len;
+ hdr = pex_rx_accept(msg, msg_len, true);
+ if (!hdr)
+ return;
+
+ ehdr = (void *)(hdr + 1);
+ data = (void *)(ehdr + 1);
+
if (hdr->version != 0)
return;
*(uint64_t *)hdr->id ^= pex_network_hash(net->config.auth_key, ehdr->nonce);
+ global_pex_set_active(net, addr);
+
D("PEX global rx op=%d", hdr->opcode);
switch (hdr->opcode) {
case PEX_MSG_HELLO:
if (!peer)
break;
- if (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) {
- struct sockaddr_in *sin = (struct sockaddr_in *)addr;
- struct in_addr in = *(struct in_addr *)&addr->sin6_addr.s6_addr[12];
- int port = addr->sin6_port;
-
- memset(addr, 0, sizeof(*addr));
- sin->sin_port = port;
- sin->sin_family = AF_INET;
- sin->sin_addr = in;
- }
-
D_PEER(net, peer, "receive endpoint notification from %s",
inet_ntop(addr->sin6_family, network_endpoint_addr((void *)addr, &addr_len),
buf, sizeof(buf)));
}
}
-int global_pex_open(void)
+static void
+pex_recv_control(struct pex_msg_local_control *msg, int len)
+{
+ struct network *net;
+
+ if (msg->msg_type != 0)
+ return;
+
+ net = global_pex_find_network(msg->auth_id);
+ if (!net)
+ return;
+
+ if (!msg->timeout)
+ msg->timeout = 60;
+ network_pex_create_host(net, &msg->ep, msg->timeout);
+}
+
+int global_pex_open(const char *unix_path)
{
struct sockaddr_in6 sin6 = {};
+ int ret;
sin6.sin6_family = AF_INET6;
sin6.sin6_port = htons(global_pex_port);
- return pex_open(&sin6, sizeof(sin6), global_pex_recv, true);
+ ret = pex_open(&sin6, sizeof(sin6), global_pex_recv, true);
+
+ if (unix_path)
+ pex_unix_open(unix_path, pex_recv_control);
+
+ return ret;
}