#include"net_hi.h" #include #include"enet.h" #include #include"stoon.h" #include"net_server.h" #include"net_client.h" #include static void *ReqPeercodeUD; static void(*ReqPeercodeCB)(void*, const char *peercode); static struct Stoon stoon; static bool inited = false; static bool isHost; typedef struct { #define MASK_IPv4 1 #define MASK_IPv6 2 int mask; ENetAddress v4; ENetAddress v6; } ToPunch; static ToPunch *topunch = NULL; static size_t topunchCount = 0; static double Timeout = 0; static bool connected = false; bool net_hi_request_peercode(void *ud, void(*callback)(void*, const char *peercode)) { if(inited) return false; ReqPeercodeUD = ud; ReqPeercodeCB = callback; stoon = stoon_init("stun.easybell.de", 3478, 26656); 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(); } 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)) { uint8_t peercode[STOON_CONN_INFO_SIZE] = {}; stoon_serialize(&stoon, peercode); ReqPeercodeCB(ReqPeercodeUD, peercode); ReqPeercodeCB = NULL; } else { Timeout = now + 1; } } else { 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->mask & MASK_IPv4) { enet_socket_send(h->socket, &tp->v4, &buf, 1); } else if(tp->mask & MASK_IPv6) { enet_socket_send(h->socket, &tp->v6, &buf, 1); } } } Timeout = now + 1; } } static void stoonpeer_to_enets(const char *peercode, ENetAddress *v4, ENetAddress *v6, int *mask) { uint8_t *addr8 = (uint8_t*) &v4->host; memset(addr8, 0, 16); addr8[10] = 0xFF; addr8[11] = 0xFF; addr8[12] = peercode[0]; addr8[13] = peercode[1]; addr8[14] = peercode[2]; addr8[15] = peercode[3]; v4->port = ntohs(*(uint16_t*) &peercode[4]); memcpy(&v6->host, peercode + 6, 16); v6->port = ntohs(*(uint16_t*) &peercode[22]); *mask = 0; if(v4->port) { *mask |= MASK_IPv4; } if(v6->port) { *mask |= MASK_IPv6; } } void net_hi_add_punch(const char *peercode) { int mask; ENetAddress v4 = {}, v6 = {}; stoonpeer_to_enets(peercode, &v4, &v6, &mask); topunch = realloc(topunch, sizeof(*topunch) * (++topunchCount)); topunch[topunchCount - 1] = (ToPunch) { .v4 = v4, .v6 = v6, .mask = mask, }; } bool net_hi_connect(const char *peercode) { if(!inited) return false; if(connected) return false; char ip[64]; int port; if(*(uint16_t*) (peercode + 22) == 0) { inet_ntop(AF_INET, peercode, ip, sizeof(ip)); port = ntohs(*(uint16_t*) (peercode + 4)); } else { inet_ntop(AF_INET6, peercode + 6, ip, sizeof(ip)); port = ntohs(*(uint16_t*) (peercode + 22)); } return net_client_connect(ip, port); }