Commit 70c0ff3d authored by YI's avatar YI
Browse files

connect to client with user provided meta info

parent 868f68b4
......@@ -2,3 +2,4 @@
*.o
.DS_Store
*.swp
.ccls-cache/
CC = gcc
CFLAGS = -g -Wall
all: nat_traversal
all: nat_traversal punch_server stun_server_test
# clang warn about unused argument, it requires -pthread when compiling but not when linking
nat_traversal: main.o nat_traversal.o nat_type.o
nat_traversal: main.o nat_traversal.o nat_type.o
$(CC) $(CFLAGS) -o nat_traversal main.o nat_traversal.o nat_type.o -pthread
punch_server: punch_server.go
go build punch_server.go
stun_server_test: stun_server_test.c
gcc stun_host_test.c nat_type.c -o stun_host_test
main.o: main.c
$(CC) $(CFLAGS) -c main.c
nat_traversal.o: nat_traversal.c
nat_traversal.o: nat_traversal.c
$(CC) $(CFLAGS) -c nat_traversal.c
nat_type.o: nat_type.c
$(CC) $(CFLAGS) -c nat_type.c
clean:
$(RM) nat_traversal *.o *~
clean:
$(RM) stun_host_test punch_server nat_traversal *.o *~
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "nat_traversal.h"
#include "utils.h"
#define DEFAULT_SERVER_PORT 9988
#define MSG_BUF_SIZE 512
// use public stun servers to detect port allocation rule
static char *stun_servers[] = {
"stun.ideasip.com",
"stun.ekiga.net",
"203.183.172.196"
};
#define STUN_SERVER_RETRIES 3
// definition checked against extern declaration
int verbose = 0;
int main(int argc, char** argv)
{
char* stun_server = stun_servers[0];
char local_ip[16] = "0.0.0.0";
uint16_t stun_port = DEFAULT_STUN_SERVER_PORT;
uint16_t local_port = DEFAULT_LOCAL_PORT;
char* punch_server = NULL;
uint32_t peer_id = 0;
int ttl = 10;
static char usage[] = "usage: [-h] [-H STUN_HOST] [-t ttl] [-P STUN_PORT] [-s punch server] [-d id] [-i SOURCE_IP] [-p SOURCE_PORT] [-v verbose]\n";
int opt;
while ((opt = getopt (argc, argv, "H:h:t:P:p:s:d:i:v")) != -1)
{
switch (opt)
{
case 'h':
printf("%s", usage);
break;
case 'H':
stun_server = optarg;
break;
case 't':
ttl = atoi(optarg);
break;
case 'P':
stun_port = atoi(optarg);
break;
case 'p':
local_port = atoi(optarg);
break;
case 's':
punch_server = optarg;
break;
case 'd':
peer_id = atoi(optarg);
break;
case 'i':
strncpy(local_ip, optarg, 16);
break;
case 'v':
verbose = 1;
break;
case '?':
default:
printf("invalid option: %c\n", opt);
printf("%s", usage);
return -1;
}
int main(int argc, char **argv) {
char *stun_server = NULL;
char local_ip[16] = "0.0.0.0";
uint16_t stun_port = DEFAULT_STUN_SERVER_PORT;
uint16_t local_port = DEFAULT_LOCAL_PORT;
char *punch_server = NULL;
char *meta = NULL;
char *peer_meta = NULL;
uint32_t peer_id = 0;
int ttl = 10;
int get_info = 0;
int get_info_from_meta = 0;
static char usage[] =
"usage: [-h] [-H STUN_HOST] [-t ttl] [-P STUN_PORT] [-s punch server] "
"[-d id] [-i SOURCE_IP] [-p SOURCE_PORT] [-v verbose]\n";
int opt;
while ((opt = getopt(argc, argv, "H:h:I:t:P:p:s:m:o:d:i:vzZ")) != -1) {
switch (opt) {
case 'h':
printf("%s", usage);
break;
case 'z':
get_info = 1;
break;
case 'Z':
get_info_from_meta = 1;
break;
case 'H':
stun_server = optarg;
break;
case 't':
ttl = atoi(optarg);
break;
case 'P':
stun_port = atoi(optarg);
break;
case 'p':
local_port = atoi(optarg);
break;
case 's':
punch_server = optarg;
break;
case 'm':
meta = optarg;
break;
case 'o':
peer_meta = optarg;
break;
case 'd':
peer_id = atoi(optarg);
break;
case 'i':
strncpy(local_ip, optarg, 16);
break;
case 'v':
verbose = 1;
break;
case '?':
default:
printf("invalid option: %c\n", opt);
printf("%s", usage);
return -1;
}
}
if (punch_server == NULL) {
printf("please specify punch server\n");
return -1;
}
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(punch_server);
server_addr.sin_port = htons(DEFAULT_SERVER_PORT);
if (get_info) {
client cli;
struct peer_info peer;
int res = init(server_addr, &cli);
if (res) {
printf("init punch server socket failed\n");
return res;
}
char ext_ip[16] = {0};
uint16_t ext_port = 0;
if (!peer_id) {
printf("failed to get peer_id\n");
return -1;
}
// TODO we should try another STUN server if failed
nat_type type = detect_nat_type(stun_server, stun_port, local_ip, local_port, ext_ip, &ext_port);
int n = get_peer_info(&cli, peer_id, &peer);
if (n) {
verbose_log("get_peer_info() returned %d\n", n);
printf("failed to get info of remote peer\n");
return -1;
}
return 0;
}
printf("NAT type: %s\n", get_nat_desc(type));
if (ext_port) {
printf("external address: %s:%d\n", ext_ip, ext_port);
} else {
return -1;
if (get_info_from_meta) {
client cli;
struct peer_info peer;
int res = init(server_addr, &cli);
if (res) {
printf("init punch server socket failed\n");
return res;
}
if (!punch_server) {
printf("please specify punch server\n");
return -1;
if (peer_meta == NULL) {
printf("failed to get peer_meta\n");
return -1;
}
int n = get_peer_info_from_meta(&cli, peer_meta, &peer);
if (n) {
printf("failed to get info of remote peer\n");
return -1;
}
struct peer_info self;
strncpy(self.ip, ext_ip, 16);
self.port = ext_port;
self.type = type;
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(punch_server);
server_addr.sin_port = htons(DEFAULT_SERVER_PORT);
client c;
c.type = type;
c.ttl = ttl;
if (enroll(self, server_addr, &c) < 0) {
printf("failed to enroll\n");
return -1;
return 0;
}
char ext_ip[16] = {0};
uint16_t ext_port = 0;
// TODO we should try another STUN server if failed
int i;
nat_type type;
for (i = 0; i < STUN_SERVER_RETRIES; i++) {
type = detect_nat_type(stun_server, stun_port, local_ip, local_port, ext_ip,
&ext_port);
if (type != 0) {
break;
}
printf("enroll successfully, ID: %d\n", c.id);
}
if (!ext_port) {
return -1;
}
verbose_log("nat detect got ip: %s, port %d\n", ext_ip, ext_port);
struct peer_info self;
self.meta = malloc(32);
strcpy(self.ip, ext_ip);
self.port = ext_port;
self.type = type;
/* printf("first %s %ld\n", meta, strlen(meta)); */
if (meta != NULL) {
strcpy(self.meta, meta);
} else {
gen_random_string(self.meta, 20);
}
/* printf("first %s %ld\n", self.meta, strlen(self.meta)); */
/* strncpy(self.meta, meta, strlen(meta)); */
/* printf(""); */
/* printf("second %s %ld\n", meta, strlen(meta)); */
client c;
c.type = type;
c.ttl = ttl;
/* printf("third %s %ld\n", self.meta, strlen(self.meta)); */
if (enroll(self, server_addr, &c) < 0) {
printf("failed to enroll\n");
return -1;
}
verbose_log("enroll successfully, ID: %d\n", c.id);
if (peer_id) {
verbose_log("connecting to peer %d\n", peer_id);
if (connect_to_peer(&c, peer_id) < 0) {
verbose_log("failed to connect to peer %d\n", peer_id);
return -1;
}
}
if (peer_id) {
printf("connecting to peer %d\n", peer_id);
if (connect_to_peer(&c, peer_id) < 0) {
printf("failed to connect to peer %d\n", peer_id);
if (peer_meta != NULL) {
verbose_log("connecting to peer %s\n", peer_meta);
if (connect_to_peer_from_meta(&c, peer_meta) < 0) {
verbose_log("failed to connect to peer %s\n", peer_meta);
return -1;
}
return -1;
}
}
pthread_t tid = wait_for_command(&c.sfd);
pthread_t tid = wait_for_command(&c.sfd);
pthread_join(tid, NULL);
return 0;
pthread_join(tid, NULL);
return 0;
}
This diff is collapsed.
......@@ -4,35 +4,54 @@
typedef struct client client;
struct client {
int sfd;
uint32_t id;
char buf[128];
//use a stack-based buffer to prevent memory allocation every time
char* msg_buf;
nat_type type;
char ext_ip[16];
uint16_t ext_port;
// ttl of hole punching packets,
// it should be greater than the number of hops between host to NAT of own side
// and less than the number of hops between host to NAT of remote side,
// so that the hole punching packets just die in the way
int ttl;
int sfd;
uint32_t id;
char buf[128];
// use a stack-based buffer to prevent memory allocation every time
char *msg_buf;
nat_type type;
char ext_ip[16];
uint16_t ext_port;
// ttl of hole punching packets,
// it should be greater than the number of hops between host to NAT of own
// side and less than the number of hops between host to NAT of remote side,
// so that the hole punching packets just die in the way
int ttl;
};
struct my_peer_info {
uint32_t id;
char ip[16];
uint16_t port;
uint16_t type;
uint8_t len;
} __attribute__((packed));
struct peer_info {
char ip[16];
uint16_t port;
uint16_t type;
uint32_t id;
char ip[16];
uint16_t port;
uint16_t type;
char *meta;
};
enum msg_type {
Enroll = 0x01,
GetPeerInfo = 0x02,
NotifyPeer = 0x03,
};
enum msg_type {
Enroll = 0x01,
GetPeerInfo = 0x02,
NotifyPeer = 0x03,
GetPeerInfoFromMeta = 0x04,
NotifyPeerFromMeta = 0x05,
};
// public functions
int enroll(struct peer_info self, struct sockaddr_in punch_server, client* c);
pthread_t wait_for_command(int* server_sock);
int connect_to_peer(client* cli, uint32_t peer_id);
int enroll(struct peer_info self, struct sockaddr_in punch_server, client *c);
pthread_t wait_for_command(int *server_sock);
int connect_to_peer(client *cli, uint32_t peer_id);
int connect_to_peer_from_meta(client *cli, char *peer_meta);
void on_connected(int sock);
int get_peer_info(client *cli, uint32_t peer_id, struct peer_info *peer);
int get_peer_info_from_meta(client *cli, char *peer_meta,
struct peer_info *peer);
int init(struct sockaddr_in punch_server, client *c);
void hexDump(char *desc, void *addr, int len);
int send_get_peer_info_request(client *cli, struct peer_info *peer);
This diff is collapsed.
......@@ -73,6 +73,7 @@ typedef struct
} addr;
} StunAtrAddress;
char* encode8(char* buf, size_t data);
char* encode16(char* buf, uint16_t data);
char* encode32(char* buf, uint32_t data);
char* encode(char* buf, const char* data, unsigned int length);
......@@ -83,6 +84,7 @@ extern int verbose;
printf(format, ##__VA_ARGS__); \
} while(0)
nat_type detect_nat_type(const char* stun_host, uint16_t stun_port, const char* local_host, uint16_t local_port, char* ext_ip, uint16_t* ext_port);
nat_type detect_nat_type(char* stun_host, uint16_t stun_port, const char* local_host, uint16_t local_port, char* ext_ip, uint16_t* ext_port);
const char* get_nat_desc(nat_type type);
void gen_random_string(char *s, const int len);
23.21.150.121
iphone-stun.strato-iphone.de
numb.viagenie.ca
s1.taraba.net
s2.taraba.net
stun.12connect.com
stun.12voip.com
stun.1und1.de
stun.2talk.co.nz
stun.2talk.com
stun.3clogic.com
stun.3cx.com
stun.a-mm.tv
stun.aa.net.uk
stun.acrobits.cz
stun.actionvoip.com
stun.advfn.com
stun.aeta-audio.com
stun.aeta.com
stun.alltel.com.au
stun.altar.com.pl
stun.annatel.net
stun.antisip.com
stun.arbuz.ru
stun.avigora.com
stun.avigora.fr
stun.awa-shima.com
stun.awt.be
stun.b2b2c.ca
stun.bahnhof.net
stun.barracuda.com
stun.bluesip.net
stun.bmwgs.cz
stun.botonakis.com
stun.budgetphone.nl
stun.budgetsip.com
stun.cablenet-as.net
stun.callromania.ro
stun.callwithus.com
stun.cbsys.net
stun.chathelp.ru
stun.cheapvoip.com
stun.ciktel.com
stun.cloopen.com
stun.colouredlines.com.au
stun.comfi.com
stun.commpeak.com
stun.comtube.com
stun.comtube.ru
stun.cope.es
stun.counterpath.com
stun.counterpath.net
stun.cryptonit.net
stun.darioflaccovio.it
stun.datamanagement.it
stun.dcalling.de
stun.decanet.fr
stun.demos.ru
stun.develz.org
stun.dingaling.ca
stun.doublerobotics.com
stun.drogon.net
stun.duocom.es
stun.dus.net
stun.e-fon.ch
stun.easybell.de
stun.easycall.pl
stun.easyvoip.com
stun.efficace-factory.com
stun.einsundeins.com
stun.einsundeins.de
stun.ekiga.net
stun.epygi.com
stun.etoilediese.fr
stun.eyeball.com
stun.faktortel.com.au
stun.freecall.com
stun.freeswitch.org
stun.freevoipdeal.com
stun.fuzemeeting.com
stun.gmx.de
stun.gmx.net
stun.gradwell.com
stun.halonet.pl
stun.hellonanu.com
stun.hoiio.com
stun.hosteurope.de
stun.ideasip.com
stun.imesh.com
stun.infra.net
stun.internetcalls.com
stun.intervoip.com
stun.ipcomms.net
stun.ipfire.org
stun.ippi.fr
stun.ipshka.com
stun.iptel.org
stun.irian.at
stun.it1.hr
stun.ivao.aero
stun.jappix.com
stun.jumblo.com
stun.justvoip.com
stun.kanet.ru
stun.kiwilink.co.nz
stun.kundenserver.de
stun.linea7.net
stun.linphone.org
stun.liveo.fr
stun.lowratevoip.com
stun.lugosoft.com
stun.lundimatin.fr
stun.magnet.ie
stun.manle.com
stun.mgn.ru
stun.mit.de
stun.mitake.com.tw
stun.miwifi.com
stun.modulus.gr
stun.mozcom.com
stun.myvoiptraffic.com
stun.mywatson.it
stun.nas.net
stun.neotel.co.za
stun.netappel.com
stun.netappel.fr
stun.netgsm.com.tr
stun.nfon.net
stun.noblogs.org
stun.noc.ams-ix.net
stun.node4.co.uk
stun.nonoh.net
stun.nottingham.ac.uk
stun.nova.is
stun.nventure.com
stun.on.net.mk
stun.ooma.com
stun.ooonet.ru
stun.oriontelekom.rs
stun.outland-net.de
stun.ozekiphone.com
stun.patlive.com
stun.personal-voip.de
stun.petcube.com
stun.phone.com
stun.phoneserve.com
stun.pjsip.org
stun.poivy.com
stun.powerpbx.org
stun.powervoip.com
stun.ppdi.com
stun.prizee.com
stun.qq.com
stun.qvod.com
stun.rackco.com
stun.rapidnet.de
stun.rb-net.com
stun.refint.net
stun.remote-learner.net
stun.rixtelecom.se
stun.rockenstein.de
stun.rolmail.net
stun.rounds.com
stun.rynga.com
stun.samsungsmartcam.com
stun.schlund.de
stun.services.mozilla.com
stun.sigmavoip.com
stun.sip.us
stun.sipdiscount.com
stun.sipgate.net
stun.siplogin.de
stun.sipnet.net
stun.sipnet.ru
stun.siportal.it
stun.sippeer.dk
stun.siptraffic.com
stun.skylink.ru
stun.sma.de
stun.smartvoip.com
stun.smsdiscount.com
stun.snafu.de
stun.softjoys.com
stun.solcon.nl
stun.solnet.ch
stun.sonetel.com
stun.sonetel.net
stun.sovtest.ru
stun.speedy.com.ar
stun.spokn.com
stun.srce.hr
stun.ssl7.net
stun.stunprotocol.org
stun.symform.com
stun.symplicity.com
stun.sysadminman.net
stun.t-online.de
stun.tagan.ru
stun.tatneft.ru
stun.teachercreated.com
stun.tel.lu
stun.telbo.com
stun.telefacil.com
stun.tis-dialog.ru
stun.tng.de
stun.twt.it
stun.u-blox.com
stun.ucallweconn.net
stun.ucsb.edu
stun.ucw.cz
stun.uls.co.za
stun.unseen.is
stun.usfamily.net
stun.veoh.com
stun.vidyo.com
stun.vipgroup.net
stun.virtual-call.com
stun.viva.gr
stun.vivox.com
stun.vline.com
stun.vo.lu
stun.vodafone.ro
stun.voicetrading.com
stun.voip.aebc.com
stun.voip.blackberry.com
stun.voip.eutelia.it
stun.voiparound.com
stun.voipblast.com
stun.voipbuster.com
stun.voipbusterpro.com
stun.voipcheap.co.uk
stun.voipcheap.com
stun.voipfibre.com
stun.voipgain.com
stun.voipgate.com
stun.voipinfocenter.com
stun.voipplanet.nl
stun.voippro.com
stun.voipraider.com
stun.voipstunt.com
stun.voipwise.com
stun.voipzoom.com
stun.vopium.com
stun.voxgratia.org
stun.voxox.com
stun.voys.nl
stun.voztele.com
stun.vyke.com
stun.webcalldirect.com
stun.whoi.edu
stun.wifirst.net
stun.wwdl.net
stun.xs4all.nl
stun.xtratelecom.es
stun.yesss.at
stun.zadarma.com
stun.zadv.com
stun.zoiper.com
stun1.faktortel.com.au
stun1.voiceeclipse.net
stunserver.org
package main
import (
"bytes"
"encoding/binary"
"fmt"
"errors"
"io"
"math/rand"
"net"
"os"
"sync"
"time"
log "github.com/sirupsen/logrus"
)
type nat_info struct {
Ip [16]byte
Port uint16
Nat_type uint16
type PeerInfo struct {
IP [16]byte
Port uint16
NatType uint16
Meta string
ID uint32
}
type natInfo struct {
IP [16]byte
Port uint16
NatType uint16
}
const (
Enroll = 1
GetPeerInfo = 2
NotifyPeer = 3
_ = iota
Enroll
GetPeerInfo
NotifyPeer
GetPeerInfoFromMeta
NotifyPeerFromMeta
PeerOffline = 1
PeerError = 2
ListeningPort = ":9988"
)
var seq uint32 = 1
var peers map[uint32]nat_info
var peers_conn map[uint32]net.Conn
var m sync.Mutex
var (
seq uint32 = 1
peers map[uint32]PeerInfo
peersFromMeta map[string]PeerInfo
peerConn map[uint32]net.Conn
peerConnFromMeta map[string]net.Conn
mutex sync.RWMutex
letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
ErrPeerNotFound = errors.New("Peer not found")
ErrConnNotFound = errors.New("Connection not found, peer maybe is now offline")
)
func main() {
peers = make(map[uint32]nat_info)
peers_conn = make(map[uint32]net.Conn)
func init() {
peers = make(map[uint32]PeerInfo)
peersFromMeta = make(map[string]PeerInfo)
peerConn = make(map[uint32]net.Conn)
peerConnFromMeta = make(map[string]net.Conn)
rand.Seed(time.Now().UnixNano())
l, _ := net.Listen("tcp", ":9988")
log.SetOutput(os.Stdout)
log.SetLevel(log.DebugLevel)
}
func main() {
l, err := net.Listen("tcp", ListeningPort)
if err != nil {
log.WithFields(log.Fields{
"err": err,
}).Fatal("Unable to start server")
}
defer l.Close()
go dumpPeers()
for {
conn, err := l.Accept()
if err != nil {
log.WithFields(log.Fields{
"err": err,
}).Error("Accepting connection failed")
continue
}
log.Info("New connection received")
go handleConn(conn)
}
}
func dumpPeers() {
for {
time.Sleep(10 * time.Second)
mutex.RLock()
for k, v := range peers {
log.WithFields(log.Fields{
"Key": k,
"ID": v.ID,
"Meta": v.Meta,
"IP": string(v.IP[:]),
"Port": v.Port,
"NatType": v.NatType,
}).Debug("peer info")
}
mutex.RUnlock()
}
}
func RandStringRunes(n int) string {
b := make([]rune, n)
for i := range b {
b[i] = letterRunes[rand.Intn(len(letterRunes))]
}
return string(b)
}
func readMeta(c io.Reader) (meta string, err error) {
var metaSize uint8
err = binary.Read(c, binary.BigEndian, &metaSize)
if err != nil || metaSize == 0 {
log.WithFields(log.Fields{
"err": err,
"metaSize": metaSize,
}).Info("reading meta failed")
return
}
data := make([]byte, metaSize)
if _, err = c.Read(data); err != nil {
log.WithFields(log.Fields{
"err": err,
}).Info("reading meta failed")
return
}
meta = string(data)
return
}
func writeMeta(c io.Writer, meta string) (err error) {
err = binary.Write(c, binary.BigEndian, uint8(len(meta)))
if err != nil {
return
}
return binary.Write(c, binary.BigEndian, []byte(meta))
}
func readPeerInfo(r io.Reader) (p PeerInfo, err error) {
var IP [16]byte
var Port uint16
var NatType uint16
if err = binary.Read(r, binary.BigEndian, &IP); err != nil {
return
}
if err = binary.Read(r, binary.BigEndian, &Port); err != nil {
return
}
if err = binary.Read(r, binary.BigEndian, &NatType); err != nil {
return
}
p = PeerInfo{
IP: IP,
Port: Port,
NatType: NatType,
}
meta, err := readMeta(r)
if err != nil {
log.WithFields(log.Fields{
"err": err,
}).Warn("reading meta failed")
meta = RandStringRunes(18)
}
p.Meta = meta
log.WithFields(log.Fields{
"meta": meta,
}).Info("reading meta succeeded")
return
}
func writePeerInfo(w io.Writer, p PeerInfo) (err error) {
p1 := natInfo{
IP: p.IP,
Port: p.Port,
NatType: p.NatType,
}
var buf bytes.Buffer
if err = binary.Write(&buf, binary.BigEndian, p.ID); err != nil {
return
}
if err = binary.Write(&buf, binary.BigEndian, p1); err != nil {
return
}
if err = writeMeta(&buf, p.Meta); err != nil {
return
}
return binary.Write(w, binary.BigEndian, (&buf).Bytes())
}
func getPeerInfo(p PeerInfo) (p1 PeerInfo, err error) {
var ok bool
mutex.RLock()
defer mutex.RUnlock()
if p.ID != 0 {
if p1, ok = peers[p.ID]; ok {
return
}
}
if p.Meta != "" {
if p1, ok = peersFromMeta[p.Meta]; ok {
return
}
}
err = ErrPeerNotFound
return
}
func getConn(p PeerInfo) (c net.Conn, err error) {
var ok bool
mutex.RLock()
defer mutex.RUnlock()
if p.ID != 0 {
if c, ok = peerConn[p.ID]; ok {
return
}
}
if p.Meta != "" {
if c, ok = peerConnFromMeta[p.Meta]; ok {
return
}
}
err = ErrConnNotFound
return
}
// 2 bytes for message type
func handleConn(c net.Conn) {
defer c.Close()
var peerID uint32 = 0
log.Info("new connection received!")
var myInfo PeerInfo
for {
// read message type first
var myBuf bytes.Buffer
w := io.MultiWriter(&myBuf, c)
data := make([]byte, 2)
_, err := c.Read(data)
log.WithFields(log.Fields{
"header": data,
}).Info("new received header")
if err != nil {
m.Lock()
fmt.Printf("error: %v, peer %d disconnected\n", err, peerID)
delete(peers, peerID)
delete(peers_conn, peerID)
m.Unlock()
mutex.Lock()
delete(peers, myInfo.ID)
delete(peerConn, myInfo.ID)
delete(peersFromMeta, myInfo.Meta)
delete(peerConnFromMeta, myInfo.Meta)
mutex.Unlock()
log.WithFields(log.Fields{
"err": err,
"myID": myInfo.ID,
}).Info("peer left")
return
}
switch binary.BigEndian.Uint16(data[:]) {
t := binary.BigEndian.Uint16(data[:])
switch t {
case Enroll:
var peer nat_info
err = binary.Read(c, binary.BigEndian, &peer)
var err error
myInfo, err = readPeerInfo(c)
if err != nil {
continue
log.WithFields(log.Fields{
"err": err,
}).Warn("Reading meta failed")
break
}
fmt.Println("peer enrolled, addr: ", string(peer.Ip[:]), peer.Port, peer.Nat_type)
m.Lock()
mutex.Lock()
seq++
peerID = seq
peers[peerID] = peer
peers_conn[peerID] = c
fmt.Println("new peer, id : ", peerID)
m.Unlock()
err = binary.Write(c, binary.BigEndian, peerID)
myInfo.ID = seq
peers[myInfo.ID] = myInfo
peerConn[myInfo.ID] = c
if myInfo.Meta != "" {
peersFromMeta[myInfo.Meta] = myInfo
peerConnFromMeta[myInfo.Meta] = c
}
mutex.Unlock()
log.WithFields(log.Fields{
"ID": myInfo.ID,
"Meta": myInfo.Meta,
"IP": string(myInfo.IP[:]),
"Port": myInfo.Port,
"NatType": myInfo.NatType,
}).Debug("New peer enrolled")
err = binary.Write(w, binary.BigEndian, myInfo.ID)
if err != nil {
continue
log.WithFields(log.Fields{
"err": err,
"ID": myInfo.ID,
"Meta": myInfo.Meta,
"IP": string(myInfo.IP[:]),
"Port": myInfo.Port,
"NatType": myInfo.NatType,
}).Warn("Unable to return my peer info")
break
}
case GetPeerInfo:
var peer_id uint32
binary.Read(c, binary.BigEndian, &peer_id)
if val, ok := peers[peer_id]; ok {
binary.Write(c, binary.BigEndian, val)
} else {
var offline uint8 = 0
binary.Write(c, binary.BigEndian, offline)
fmt.Printf("%d offline\n", peer_id)
var peerID uint32
err = binary.Read(c, binary.BigEndian, &peerID)
if err != nil {
log.WithFields(log.Fields{
"err": err,
"peerID": peerID,
"myID": myInfo.ID,
}).Warn("Unable to get peer id")
binary.Write(c, binary.BigEndian, PeerOffline)
break
}
peer, err := getPeerInfo(PeerInfo{ID: peerID})
if err != nil {
log.WithFields(log.Fields{
"err": err,
"peerID": peerID,
"myID": myInfo.ID,
}).Warn("Unable to get peer info")
break
}
err = writePeerInfo(w, peer)
if err != nil {
log.WithFields(log.Fields{
"err": err,
"peerID": peerID,
"myID": myInfo.ID,
}).Warn("Unable to write peer info")
break
}
case NotifyPeer:
var peer_id uint32
binary.Read(c, binary.BigEndian, &peer_id)
fmt.Println("notify to peer", peer_id)
if val, ok := peers_conn[peer_id]; ok {
if err = binary.Write(val, binary.BigEndian, peers[peerID]); err != nil {
// unable to notify peer
fmt.Println("offline")
}
} else {
fmt.Println("offline")
var peerID uint32
err = binary.Read(c, binary.BigEndian, &peerID)
if err != nil {
log.WithFields(log.Fields{
"err": err,
"peerID": peerID,
"myID": myInfo.ID,
}).Warn("Unable to get peer id")
break
}
conn, err := getConn(PeerInfo{ID: peerID})
if err != nil {
log.WithFields(log.Fields{
"err": err,
"peerID": peerID,
"myID": myInfo.ID,
}).Warn("Unable to get peer conn")
binary.Write(c, binary.BigEndian, PeerOffline)
break
}
err = writePeerInfo(conn, myInfo)
if err != nil {
log.WithFields(log.Fields{
"err": err,
"peerID": peerID,
"myID": myInfo.ID,
}).Warn("Unable to write my peer info to peer connection")
break
}
case GetPeerInfoFromMeta:
peerMeta, err := readMeta(c)
if err != nil {
log.WithFields(log.Fields{
"err": err,
"myMeta": myInfo.Meta,
}).Warn("Unable to get peer meta")
break
}
peer, err := getPeerInfo(PeerInfo{Meta: peerMeta})
if err != nil {
log.WithFields(log.Fields{
"err": err,
"meta": peerMeta,
"myMeta": myInfo.Meta,
}).Warn("Unable to get peer info")
break
}
err = writePeerInfo(w, peer)
if err != nil {
log.WithFields(log.Fields{
"err": err,
"peerMeta": peer.Meta,
"myMeta": myInfo.Meta,
}).Warn("Unable to write peer info")
break
}
case NotifyPeerFromMeta:
peerMeta, err := readMeta(c)
if err != nil {
log.WithFields(log.Fields{
"err": err,
"myMeta": myInfo.Meta,
}).Warn("Unable to get peer id")
break
}
conn, err := getConn(PeerInfo{Meta: peerMeta})
if err != nil {
log.WithFields(log.Fields{
"err": err,
"meta": peerMeta,
"myMeta": myInfo.Meta,
}).Warn("Unable to get peer conn")
binary.Write(c, binary.BigEndian, PeerOffline)
break
}
err = writePeerInfo(conn, myInfo)
if err != nil {
log.WithFields(log.Fields{
"err": err,
"peerMeta": peerMeta,
"myMeta": myInfo.Meta,
}).Warn("Unable to write my peer to peer connection")
break
}
default:
fmt.Println("illegal message")
log.WithFields(log.Fields{
"type": t,
}).Warn("Illegal message")
}
log.WithFields(log.Fields{
"response": (&myBuf).Bytes(),
}).Debug("Response sent")
}
return
......
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "nat_type.h"
#define DEFAULT_STUN_SERVER_PORT 3478
#define DEFAULT_LOCAL_PORT 34780
int appendToFile(char *c, nat_type type) {
FILE *fp;
int retval;
fp = fopen("public_stun_list-working.txt", "a");
if (fp == NULL)
return -1;
retval = fprintf(fp, "%s, %d\n", c, type);
fclose(fp);
return retval;
}
int main() {
uint16_t stun_port = DEFAULT_STUN_SERVER_PORT;
uint16_t local_port = DEFAULT_LOCAL_PORT;
char ext_ip[16] = {0};
uint16_t ext_port = 0;
char local_ip[16] = "0.0.0.0";
FILE *fp;
char *line = NULL;
size_t len = 0;
ssize_t read;
/* from https://gist.github.com/mondain/b0ec1cf5f60ae726202e */
fp = fopen("public-stun-list.txt", "r");
if (fp == NULL)
exit(EXIT_FAILURE);
while ((read = getline(&line, &len, fp)) != -1) {
printf("Retrieved line of length %zu:\n", read);
printf("%s\n", line);
line[strcspn(line, "\n")] = 0;
char *stun_server = line;
printf("Testing stun server %s\n", stun_server);
nat_type type = detect_nat_type(stun_server, stun_port, local_ip,
local_port, ext_ip, &ext_port);
printf("The return value is %d (%s)\n", type, get_nat_desc(type));
if (type != 0) {
appendToFile(stun_server, type);
};
;
}
fclose(fp);
if (line)
free(line);
exit(EXIT_SUCCESS);
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment