Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package main

import (
"context"
"encoding/json"
"flag"
"fmt"
"log"
"strings"
"time"

"github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/multiformats/go-multiaddr"
)

type ClientInfo struct {
PeerID string `json:"peer_id"`
Addresses []string `json:"addresses"`
TargetPeer string `json:"target_peer,omitempty"`
ConnectionCount int `json:"connection_count"`
DirectConnection bool `json:"direct_connection"`
}

func main() {
printIDOnly := flag.Bool("print-id-only", false, "Print only peer ID and exit")
printInfo := flag.Bool("print-info", false, "Print client info as JSON and exit")
relayAddr := flag.String("relay", "", "Relay multiaddr")
targetPeerID := flag.String("target", "", "Target peer ID")
duration := flag.Int("duration", 60, "Test duration in seconds")
flag.Parse()

// Create libp2p host
h, err := libp2p.New(
libp2p.EnableRelay(),
)
if err != nil {
log.Fatal(err)
}
defer h.Close()

if *printIDOnly {
fmt.Print(h.ID().String())
return
}

log.Printf("Go hole punch client running on: %v", h.Addrs())
log.Printf("Go hole punch client peer ID: %s", h.ID())

// Log connection events
h.Network().Notify(&network.NotifyBundle{
ConnectedF: func(n network.Network, conn network.Conn) {
log.Printf("Connected to peer: %s via %s",
conn.RemotePeer(), conn.RemoteMultiaddr())
},
DisconnectedF: func(n network.Network, conn network.Conn) {
log.Printf("Disconnected from peer: %s", conn.RemotePeer())
},
})

// Connect to target through relay and attempt connection
if *relayAddr != "" && *targetPeerID != "" {
ma, err := multiaddr.NewMultiaddr(*relayAddr)
if err != nil {
log.Fatal(err)
}

targetID, err := peer.Decode(*targetPeerID)
if err != nil {
log.Fatal(err)
}

// Create circuit relay address for target
circuitAddr, err := multiaddr.NewMultiaddr(
ma.String() + "/p2p-circuit/p2p/" + *targetPeerID)
if err != nil {
log.Fatal(err)
}

log.Printf("Attempting to connect to target %s through relay...", targetID)

addrInfo := peer.AddrInfo{
ID: targetID,
Addrs: []multiaddr.Multiaddr{circuitAddr},
}

ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()

err = h.Connect(ctx, addrInfo)
if err != nil {
log.Printf("Failed to connect through relay: %v", err)
} else {
log.Printf("Connected to target through relay!")

// Check connection status
conns := h.Network().ConnsToPeer(targetID)
for _, conn := range conns {
log.Printf("Connection to %s: %s",
targetID, conn.RemoteMultiaddr())
}

// Try to open a test stream
stream, err := h.NewStream(ctx, targetID, "/test/ping/1.0.0")
if err != nil {
log.Printf("Failed to open test stream: %v", err)
} else {
log.Printf("Successfully opened test stream to target")

// Read response
buffer := make([]byte, 1024)
n, err := stream.Read(buffer)
if err != nil {
log.Printf("Failed to read from stream: %v", err)
} else {
log.Printf("Received response: %s", string(buffer[:n]))
}
stream.Close()
}
}
}

if *printInfo {
addrs := make([]string, len(h.Addrs()))
for i, addr := range h.Addrs() {
addrs[i] = addr.String()
}

directConn := false
if *targetPeerID != "" {
targetID, err := peer.Decode(*targetPeerID)
if err == nil {
conns := h.Network().ConnsToPeer(targetID)
for _, conn := range conns {
// Check if connection is not through circuit relay
if !strings.Contains(conn.RemoteMultiaddr().String(), "p2p-circuit") {
directConn = true
break
}
}
}
}

info := ClientInfo{
PeerID: h.ID().String(),
Addresses: addrs,
TargetPeer: *targetPeerID,
ConnectionCount: len(h.Network().Conns()),
DirectConnection: directConn,
}

jsonData, err := json.Marshal(info)
if err != nil {
log.Fatal(err)
}
fmt.Print(string(jsonData))
return
}

// Keep running for the specified duration
time.Sleep(time.Duration(*duration) * time.Second)
log.Println("Client test completed")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package main

import (
"context"
"encoding/json"
"flag"
"fmt"
"log"
"os"
"os/signal"
"syscall"
"time"

"github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/multiformats/go-multiaddr"
)

type ServerInfo struct {
PeerID string `json:"peer_id"`
Addresses []string `json:"addresses"`
Status string `json:"status"`
Connections int `json:"connections"`
}

func main() {
printIDOnly := flag.Bool("print-id-only", false, "Print only peer ID and exit")
printInfo := flag.Bool("print-info", false, "Print server info as JSON and exit")
relayAddr := flag.String("relay", "", "Relay multiaddr to connect to")
port := flag.Int("port", 0, "Port to listen on (0 for random)")
duration := flag.Int("duration", 120, "Server duration in seconds") // ADD THIS LINE
flag.Parse()

// Create libp2p host options
opts := []libp2p.Option{
libp2p.EnableRelay(),
}

if *port > 0 {
opts = append(opts, libp2p.ListenAddrStrings(fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", *port)))
}

// Create libp2p host
h, err := libp2p.New(opts...)
if err != nil {
log.Fatal(err)
}
defer h.Close()

if *printIDOnly {
fmt.Print(h.ID().String())
return
}

if *printInfo {
addrs := make([]string, len(h.Addrs()))
for i, addr := range h.Addrs() {
addrs[i] = addr.String()
}

info := ServerInfo{
PeerID: h.ID().String(),
Addresses: addrs,
Status: "active",
Connections: len(h.Network().Conns()),
}

jsonData, err := json.Marshal(info)
if err != nil {
log.Fatal(err)
}
fmt.Print(string(jsonData))
return
}

log.Printf("Go hole punch server running on: %v", h.Addrs())
log.Printf("Go hole punch server peer ID: %s", h.ID())

// Connect to relay if provided
if *relayAddr != "" {
ma, err := multiaddr.NewMultiaddr(*relayAddr)
if err != nil {
log.Fatal(err)
}

addrInfo, err := peer.AddrInfoFromP2pAddr(ma)
if err != nil {
log.Fatal(err)
}

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

err = h.Connect(ctx, *addrInfo)
if err != nil {
log.Printf("Warning: Failed to connect to relay: %v", err)
} else {
log.Printf("Connected to relay: %s", addrInfo.ID)
}
}

// Set up stream handler for testing
h.SetStreamHandler("/test/ping/1.0.0", handlePingStream)

// Log connection events
h.Network().Notify(&network.NotifyBundle{
ConnectedF: func(n network.Network, conn network.Conn) {
log.Printf("New connection from peer: %s via %s",
conn.RemotePeer(), conn.RemoteMultiaddr())
},
DisconnectedF: func(n network.Network, conn network.Conn) {
log.Printf("Disconnected from peer: %s", conn.RemotePeer())
},
})

// Wait for termination signal
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)

// Run for specified duration or until signal
select {
case <-c:
log.Println("Received shutdown signal")
case <-time.After(time.Duration(*duration) * time.Second): // USE THE DURATION FLAG
log.Println("Test duration completed")
}

log.Println("Shutting down hole punch server...")
}

func handlePingStream(s network.Stream) {
defer s.Close()
log.Printf("Received ping stream from: %s", s.Conn().RemotePeer())

// Echo back a simple response
response := map[string]interface{}{
"status": "pong",
"timestamp": time.Now().Unix(),
"peer_id": s.Conn().LocalPeer().String(),
}

data, _ := json.Marshal(response)
s.Write(data)
}
Loading
Loading