212 lines
4.4 KiB
C
212 lines
4.4 KiB
C
#include"net_hi.h"
|
|
|
|
#include<stddef.h>
|
|
#include"enet.h"
|
|
#include<stdlib.h>
|
|
#include"stoon.h"
|
|
#include"net_server.h"
|
|
#include"net_client.h"
|
|
#include<math.h>
|
|
#include"k3.h"
|
|
|
|
/*
|
|
* Handles networking on a higher-level, combining hole punching with
|
|
* basic client & server interface
|
|
* */
|
|
|
|
static void *ReqPeercodeUD;
|
|
static void(*ReqPeercodeCB)(void*, struct StoonPeercode *peercode);
|
|
|
|
static struct Stoon stoon;
|
|
|
|
static bool inited = false;
|
|
static bool isHost;
|
|
|
|
typedef struct {
|
|
ENetAddress pv4;
|
|
ENetAddress pv6;
|
|
|
|
ENetAddress lv4;
|
|
ENetAddress lv6;
|
|
} ToPunch;
|
|
static ToPunch *topunch = NULL;
|
|
static size_t topunchCount = 0;
|
|
|
|
static double Timeout = 0;
|
|
|
|
static bool connected = false;
|
|
|
|
static uint16_t servport = 0;
|
|
|
|
bool net_hi_request_peercode(void *ud, void(*callback)(void*, struct StoonPeercode *peercode)) {
|
|
if(inited) return false;
|
|
|
|
ReqPeercodeUD = ud;
|
|
ReqPeercodeCB = callback;
|
|
|
|
for(size_t port = 25000; port <= 26656; port++) {
|
|
stoon = stoon_init("stun.easybell.de", 3478, port);
|
|
|
|
if(stoon.fd4 >= 0 || stoon.fd6 >= 0) {
|
|
servport = port;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Timeout = 0;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool net_hi_setup(bool host) {
|
|
if(inited) return false;
|
|
|
|
stoon_kill(&stoon);
|
|
|
|
inited = true;
|
|
isHost = host;
|
|
|
|
if(host) {
|
|
net_server_init(servport);
|
|
} else {
|
|
net_client_init();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void net_hi_update(double now) {
|
|
if(now <= Timeout) return;
|
|
|
|
if(ReqPeercodeCB) {
|
|
|
|
if(stoon_req(&stoon)) {
|
|
if(stoon_listen(&stoon)) {
|
|
ReqPeercodeCB(ReqPeercodeUD, &stoon.peercode);
|
|
|
|
ReqPeercodeCB = NULL;
|
|
} else {
|
|
k3Log(k3_INFO, "stoon_listen failure");
|
|
|
|
Timeout = now + 1;
|
|
}
|
|
} else {
|
|
k3Log(k3_INFO, "stoon_req failure");
|
|
|
|
Timeout = now + 1;
|
|
}
|
|
|
|
} else if(!inited) {
|
|
|
|
stoon_keepalive(&stoon);
|
|
|
|
Timeout = now + 1;
|
|
|
|
} else {
|
|
|
|
if(isHost) {
|
|
|
|
ENetHost *h = net_server_get_enethost();
|
|
|
|
ENetBuffer buf = {.data = "Punch!", .dataLength = 6};
|
|
|
|
for(size_t tpi = 0; tpi < topunchCount; tpi++) {
|
|
ToPunch *tp = &topunch[tpi];
|
|
|
|
if(tp->lv6.port) enet_socket_send(h->socket, &tp->lv6, &buf, 1);
|
|
if(tp->lv4.port) enet_socket_send(h->socket, &tp->lv4, &buf, 1);
|
|
|
|
if(tp->pv6.port) enet_socket_send(h->socket, &tp->pv6, &buf, 1);
|
|
if(tp->pv4.port) enet_socket_send(h->socket, &tp->pv4, &buf, 1);
|
|
}
|
|
|
|
}
|
|
|
|
Timeout = now + 1;
|
|
|
|
}
|
|
}
|
|
|
|
static bool stoonpeer_to_enet4(uint8_t *publicV4, uint8_t *publicP4, ENetAddress *enet) {
|
|
memset(enet, 0, sizeof(*enet));
|
|
|
|
if(*(uint32_t*) publicV4 == 0 || *(uint16_t*) publicP4 == 0) {
|
|
return false;
|
|
}
|
|
|
|
uint8_t *addr8 = (uint8_t*) &enet->host;
|
|
|
|
memset(addr8, 0, 16);
|
|
addr8[10] = 0xFF;
|
|
addr8[11] = 0xFF;
|
|
addr8[12] = publicV4[0];
|
|
addr8[13] = publicV4[1];
|
|
addr8[14] = publicV4[2];
|
|
addr8[15] = publicV4[3];
|
|
enet->port = *(uint16_t*) publicP4;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool stoonpeer_to_enet6(uint8_t *publicV6, uint8_t *publicP6, ENetAddress *enet) {
|
|
memset(enet, 0, sizeof(*enet));
|
|
|
|
if(*(uint32_t*) publicV6 == 0 || *(uint16_t*) publicP6 == 0) {
|
|
return false;
|
|
}
|
|
|
|
uint8_t *addr8 = (uint8_t*) &enet->host;
|
|
|
|
memcpy(addr8, publicV6, 16);
|
|
enet->port = *(uint16_t*) publicP6;
|
|
|
|
return true;
|
|
}
|
|
|
|
void net_hi_add_punch(struct StoonPeercode *peercode) {
|
|
topunch = realloc(topunch, sizeof(*topunch) * (++topunchCount));
|
|
ToPunch *tp = &topunch[topunchCount - 1];
|
|
|
|
stoonpeer_to_enet4(peercode->publicV4, peercode->publicP4, &tp->pv4);
|
|
stoonpeer_to_enet6(peercode->publicV6, peercode->publicP6, &tp->pv6);
|
|
|
|
stoonpeer_to_enet4(peercode->localV4, peercode->localP4, &tp->lv4);
|
|
stoonpeer_to_enet6(peercode->localV6, peercode->localP6, &tp->lv6);
|
|
}
|
|
|
|
bool net_hi_connect(struct StoonPeercode *peercode) {
|
|
if(!inited) return false;
|
|
|
|
if(connected) return false;
|
|
|
|
ENetAddress pv4, pv6;
|
|
stoonpeer_to_enet4(peercode->publicV4, peercode->publicP4, &pv4);
|
|
stoonpeer_to_enet6(peercode->publicV6, peercode->publicP6, &pv6);
|
|
|
|
ENetAddress lv4, lv6;
|
|
stoonpeer_to_enet4(peercode->localV4, peercode->localP4, &lv4);
|
|
stoonpeer_to_enet6(peercode->localV6, peercode->localP6, &lv6);
|
|
|
|
if(lv6.port && net_client_connect(lv6)) {
|
|
k3Log(k3_INFO, "Found local IPv6");
|
|
return true;
|
|
}
|
|
if(lv4.port && net_client_connect(lv4)) {
|
|
k3Log(k3_INFO, "Found local IPv4");
|
|
return true;
|
|
}
|
|
|
|
if(pv6.port && net_client_connect(pv6)) {
|
|
k3Log(k3_INFO, "Found remote IPv6");
|
|
return true;
|
|
}
|
|
if(pv4.port && net_client_connect(pv4)) {
|
|
k3Log(k3_INFO, "Found remote IPv4");
|
|
return true;
|
|
}
|
|
|
|
k3Log(k3_INFO, "Failed to establish connection");
|
|
|
|
return false;
|
|
}
|