mirror of
https://github.com/go-i2p/go-i2ptunnel.git
synced 2025-12-20 15:15:52 -05:00
Add missing methods to implement complete interfaces
This commit is contained in:
@@ -24,6 +24,7 @@ Key features:
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
@@ -69,7 +70,11 @@ func (h *HTTPClient) recordError(err error) {
|
||||
|
||||
// Get the tunnel's I2P address
|
||||
func (h *HTTPClient) Address() string {
|
||||
return h.Garlic.B32()
|
||||
// For HTTP client proxy, return the service address if available
|
||||
if h.Garlic != nil && h.Garlic.ServiceKeys != nil {
|
||||
return h.Garlic.ServiceKeys.Addr().Base32()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Get the tunnel's error message
|
||||
@@ -151,3 +156,44 @@ func (h *HTTPClient) Target() string {
|
||||
func (h *HTTPClient) Type() string {
|
||||
return h.TunnelConfig.Type
|
||||
}
|
||||
|
||||
// Get the tunnel's ID
|
||||
func (h *HTTPClient) ID() string {
|
||||
return i2ptunnel.Clean(h.Name())
|
||||
}
|
||||
|
||||
// Get the tunnel's options
|
||||
func (h *HTTPClient) Options() map[string]string {
|
||||
// Return basic configuration options as a map
|
||||
options := make(map[string]string)
|
||||
options["name"] = h.TunnelConfig.Name
|
||||
options["type"] = h.TunnelConfig.Type
|
||||
options["interface"] = h.TunnelConfig.Interface
|
||||
options["port"] = strconv.Itoa(h.TunnelConfig.Port)
|
||||
return options
|
||||
}
|
||||
|
||||
// Set the tunnel's options
|
||||
func (h *HTTPClient) SetOptions(opts map[string]string) error {
|
||||
// Apply configuration options from the map
|
||||
if name, ok := opts["name"]; ok {
|
||||
h.TunnelConfig.Name = name
|
||||
}
|
||||
if iface, ok := opts["interface"]; ok {
|
||||
h.TunnelConfig.Interface = iface
|
||||
}
|
||||
if portStr, ok := opts["port"]; ok {
|
||||
if port, err := strconv.Atoi(portStr); err == nil {
|
||||
h.TunnelConfig.Port = port
|
||||
} else {
|
||||
return fmt.Errorf("invalid port value: %s", portStr)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Load the tunnel config from file
|
||||
func (h *HTTPClient) LoadConfig(path string) error {
|
||||
// For now, return an error indicating this method needs configuration file support
|
||||
return fmt.Errorf("LoadConfig not yet implemented: would load configuration from %s", path)
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ func NewHTTPClient(config i2pconv.TunnelConfig, samAddr string) (*HTTPClient, er
|
||||
I2PTunnelStatus: i2ptunnel.I2PTunnelStatusStopped,
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
|
||||
return h, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ Key features:
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
@@ -64,7 +65,11 @@ func (h *HTTPServer) recordError(err error) {
|
||||
|
||||
// Get the tunnel's I2P address
|
||||
func (h *HTTPServer) Address() string {
|
||||
return h.Garlic.B32()
|
||||
// For HTTP server, return the service address if available
|
||||
if h.Garlic != nil && h.Garlic.ServiceKeys != nil {
|
||||
return h.Garlic.ServiceKeys.Addr().Base32()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Get the tunnel's error message
|
||||
@@ -141,3 +146,63 @@ func (h *HTTPServer) Target() string {
|
||||
func (h *HTTPServer) Type() string {
|
||||
return h.TunnelConfig.Type
|
||||
}
|
||||
|
||||
// Get the tunnel's ID
|
||||
func (h *HTTPServer) ID() string {
|
||||
return i2ptunnel.Clean(h.Name())
|
||||
}
|
||||
|
||||
// Get the tunnel's options
|
||||
func (h *HTTPServer) Options() map[string]string {
|
||||
// Return basic configuration options as a map
|
||||
options := make(map[string]string)
|
||||
options["name"] = h.TunnelConfig.Name
|
||||
options["type"] = h.TunnelConfig.Type
|
||||
options["interface"] = h.TunnelConfig.Interface
|
||||
options["port"] = strconv.Itoa(h.TunnelConfig.Port)
|
||||
options["maxconns"] = strconv.Itoa(h.LimitedConfig.MaxConns)
|
||||
options["ratelimit"] = strconv.FormatFloat(h.LimitedConfig.RateLimit, 'f', -1, 64)
|
||||
if h.Addr != nil {
|
||||
options["target"] = h.Addr.String()
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
// Set the tunnel's options
|
||||
func (h *HTTPServer) SetOptions(opts map[string]string) error {
|
||||
// Apply configuration options from the map
|
||||
if name, ok := opts["name"]; ok {
|
||||
h.TunnelConfig.Name = name
|
||||
}
|
||||
if iface, ok := opts["interface"]; ok {
|
||||
h.TunnelConfig.Interface = iface
|
||||
}
|
||||
if portStr, ok := opts["port"]; ok {
|
||||
if port, err := strconv.Atoi(portStr); err == nil {
|
||||
h.TunnelConfig.Port = port
|
||||
} else {
|
||||
return fmt.Errorf("invalid port value: %s", portStr)
|
||||
}
|
||||
}
|
||||
if maxconnsStr, ok := opts["maxconns"]; ok {
|
||||
if maxconns, err := strconv.Atoi(maxconnsStr); err == nil {
|
||||
h.LimitedConfig.MaxConns = maxconns
|
||||
} else {
|
||||
return fmt.Errorf("invalid maxconns value: %s", maxconnsStr)
|
||||
}
|
||||
}
|
||||
if ratelimitStr, ok := opts["ratelimit"]; ok {
|
||||
if ratelimit, err := strconv.ParseFloat(ratelimitStr, 64); err == nil {
|
||||
h.LimitedConfig.RateLimit = ratelimit
|
||||
} else {
|
||||
return fmt.Errorf("invalid ratelimit value: %s", ratelimitStr)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Load the tunnel config from file
|
||||
func (h *HTTPServer) LoadConfig(path string) error {
|
||||
// For now, return an error indicating this method needs configuration file support
|
||||
return fmt.Errorf("LoadConfig not yet implemented: would load configuration from %s", path)
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ When a local client connects to the I2P tunnel's destination, the traffic flows:
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
@@ -57,7 +58,11 @@ func (t *TCPClient) recordError(err error) {
|
||||
|
||||
// Get the tunnel's I2P address
|
||||
func (t *TCPClient) Address() string {
|
||||
return t.Garlic.StreamSession.Addr().Base32()
|
||||
// Return the target I2P address for client tunnels
|
||||
if t.I2PAddr != nil {
|
||||
return t.I2PAddr.Base32()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Get the tunnel's error message
|
||||
@@ -132,3 +137,54 @@ func (t *TCPClient) Target() string {
|
||||
func (t *TCPClient) Type() string {
|
||||
return t.TunnelConfig.Type
|
||||
}
|
||||
|
||||
// Get the tunnel's ID
|
||||
func (t *TCPClient) ID() string {
|
||||
return i2ptunnel.Clean(t.Name())
|
||||
}
|
||||
|
||||
// Get the tunnel's options
|
||||
func (t *TCPClient) Options() map[string]string {
|
||||
// Return basic configuration options as a map
|
||||
options := make(map[string]string)
|
||||
options["name"] = t.TunnelConfig.Name
|
||||
options["type"] = t.TunnelConfig.Type
|
||||
options["interface"] = t.TunnelConfig.Interface
|
||||
options["port"] = strconv.Itoa(t.TunnelConfig.Port)
|
||||
if t.I2PAddr != nil {
|
||||
options["target"] = t.I2PAddr.Base32()
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
// Set the tunnel's options
|
||||
func (t *TCPClient) SetOptions(opts map[string]string) error {
|
||||
// Apply configuration options from the map
|
||||
if name, ok := opts["name"]; ok {
|
||||
t.TunnelConfig.Name = name
|
||||
}
|
||||
if iface, ok := opts["interface"]; ok {
|
||||
t.TunnelConfig.Interface = iface
|
||||
}
|
||||
if portStr, ok := opts["port"]; ok {
|
||||
if port, err := strconv.Atoi(portStr); err == nil {
|
||||
t.TunnelConfig.Port = port
|
||||
} else {
|
||||
return fmt.Errorf("invalid port value: %s", portStr)
|
||||
}
|
||||
}
|
||||
if target, ok := opts["target"]; ok {
|
||||
addr, err := i2pkeys.Lookup(target)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid target address: %w", err)
|
||||
}
|
||||
t.I2PAddr = addr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Load the tunnel config from file
|
||||
func (t *TCPClient) LoadConfig(path string) error {
|
||||
// For now, return an error indicating this method needs configuration file support
|
||||
return fmt.Errorf("LoadConfig not yet implemented: would load configuration from %s", path)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ When an I2P peer connects to the tunnel's destination, the traffic flows:
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
@@ -52,8 +53,14 @@ func (t *TCPServer) recordError(err error) {
|
||||
|
||||
// Get the tunnel's I2P address
|
||||
func (t *TCPServer) Address() string {
|
||||
return t.Garlic.StreamListener.Addr().String()
|
||||
//B32()
|
||||
// For server tunnels, return the service address if available
|
||||
if t.Garlic != nil {
|
||||
// Use service keys to identify the tunnel's I2P address
|
||||
if t.Garlic.ServiceKeys != nil {
|
||||
return t.Garlic.ServiceKeys.Addr().Base32()
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Get the tunnel's error message
|
||||
@@ -129,3 +136,63 @@ func (t *TCPServer) Target() string {
|
||||
func (t *TCPServer) Type() string {
|
||||
return t.TunnelConfig.Type
|
||||
}
|
||||
|
||||
// Get the tunnel's ID
|
||||
func (t *TCPServer) ID() string {
|
||||
return i2ptunnel.Clean(t.Name())
|
||||
}
|
||||
|
||||
// Get the tunnel's options
|
||||
func (t *TCPServer) Options() map[string]string {
|
||||
// Return basic configuration options as a map
|
||||
options := make(map[string]string)
|
||||
options["name"] = t.TunnelConfig.Name
|
||||
options["type"] = t.TunnelConfig.Type
|
||||
options["interface"] = t.TunnelConfig.Interface
|
||||
options["port"] = strconv.Itoa(t.TunnelConfig.Port)
|
||||
options["maxconns"] = strconv.Itoa(t.LimitedConfig.MaxConns)
|
||||
options["ratelimit"] = strconv.FormatFloat(t.LimitedConfig.RateLimit, 'f', -1, 64)
|
||||
if t.Addr != nil {
|
||||
options["target"] = t.Addr.String()
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
// Set the tunnel's options
|
||||
func (t *TCPServer) SetOptions(opts map[string]string) error {
|
||||
// Apply configuration options from the map
|
||||
if name, ok := opts["name"]; ok {
|
||||
t.TunnelConfig.Name = name
|
||||
}
|
||||
if iface, ok := opts["interface"]; ok {
|
||||
t.TunnelConfig.Interface = iface
|
||||
}
|
||||
if portStr, ok := opts["port"]; ok {
|
||||
if port, err := strconv.Atoi(portStr); err == nil {
|
||||
t.TunnelConfig.Port = port
|
||||
} else {
|
||||
return fmt.Errorf("invalid port value: %s", portStr)
|
||||
}
|
||||
}
|
||||
if maxconnsStr, ok := opts["maxconns"]; ok {
|
||||
if maxconns, err := strconv.Atoi(maxconnsStr); err == nil {
|
||||
t.LimitedConfig.MaxConns = maxconns
|
||||
} else {
|
||||
return fmt.Errorf("invalid maxconns value: %s", maxconnsStr)
|
||||
}
|
||||
}
|
||||
if ratelimitStr, ok := opts["ratelimit"]; ok {
|
||||
if ratelimit, err := strconv.ParseFloat(ratelimitStr, 64); err == nil {
|
||||
t.LimitedConfig.RateLimit = ratelimit
|
||||
} else {
|
||||
return fmt.Errorf("invalid ratelimit value: %s", ratelimitStr)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Load the tunnel config from file
|
||||
func (t *TCPServer) LoadConfig(path string) error {
|
||||
// For now, return an error indicating this method needs configuration file support
|
||||
return fmt.Errorf("LoadConfig not yet implemented: would load configuration from %s", path)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package tcp
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
"testing"
|
||||
@@ -36,15 +35,19 @@ func RandomUDPPort() int {
|
||||
}
|
||||
|
||||
func TestTCPTunnel(t *testing.T) {
|
||||
t.Log("Starting TCP tunnel test")
|
||||
|
||||
// Generate test keys
|
||||
//keys, err := i2pkeys.LoadKeys("i2pkeys/test-server.i2p.private")
|
||||
t.Log("Loading test keys...")
|
||||
_, err := i2pkeys.LoadKeys("i2pkeys/test-server.i2p.private")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to load test keys: %v", err)
|
||||
}
|
||||
sport := RandomTCPPort()
|
||||
t.Logf("Selected server port: %d", sport)
|
||||
|
||||
// Setup server config
|
||||
t.Log("Setting up server configuration...")
|
||||
serverConfig := i2pconv.TunnelConfig{
|
||||
Name: "test-server",
|
||||
Type: "tcpserver",
|
||||
@@ -53,11 +56,13 @@ func TestTCPTunnel(t *testing.T) {
|
||||
}
|
||||
|
||||
// Create and start server
|
||||
t.Log("Creating TCP server...")
|
||||
srv, err := server.NewTCPServer(serverConfig, "127.0.0.1:7656")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create server: %v", err)
|
||||
}
|
||||
|
||||
t.Log("Starting TCP server...")
|
||||
go func() {
|
||||
if err := srv.Start(); err != nil {
|
||||
t.Errorf("Server error: %v", err)
|
||||
@@ -65,10 +70,13 @@ func TestTCPTunnel(t *testing.T) {
|
||||
}()
|
||||
defer srv.Stop()
|
||||
cport := RandomTCPPort()
|
||||
// Wait for server startup
|
||||
t.Logf("Selected client port: %d", cport)
|
||||
|
||||
t.Log("Waiting for server startup...")
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
// Setup client config
|
||||
t.Log("Setting up client configuration...")
|
||||
clientConfig := i2pconv.TunnelConfig{
|
||||
Name: "test-client",
|
||||
Type: "tcpclient",
|
||||
@@ -78,11 +86,13 @@ func TestTCPTunnel(t *testing.T) {
|
||||
}
|
||||
|
||||
// Create and start client
|
||||
t.Log("Creating TCP client...")
|
||||
cli, err := client.NewTCPClient(clientConfig, "127.0.0.1:7656")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create client: %v", err)
|
||||
}
|
||||
|
||||
t.Log("Starting TCP client...")
|
||||
go func() {
|
||||
if err := cli.Start(); err != nil {
|
||||
t.Errorf("Client error: %v", err)
|
||||
@@ -90,29 +100,39 @@ func TestTCPTunnel(t *testing.T) {
|
||||
}()
|
||||
defer cli.Stop()
|
||||
|
||||
// Wait for client startup
|
||||
t.Log("Waiting for client startup...")
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
// Test data transfer
|
||||
testData := []byte("Hello I2P!")
|
||||
t.Log("Attempting to establish connection...")
|
||||
conn, err := net.Dial("tcp", net.JoinHostPort("127.0.0.1", strconv.Itoa(cport)))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
t.Log("Connection established successfully")
|
||||
|
||||
t.Logf("Writing test data: %q", testData)
|
||||
n, err := conn.Write(testData)
|
||||
if err != nil || n != len(testData) {
|
||||
t.Fatalf("Failed to write test data: %v", err)
|
||||
}
|
||||
t.Logf("Successfully wrote %d bytes", n)
|
||||
|
||||
t.Log("Reading response...")
|
||||
buf := make([]byte, len(testData))
|
||||
n, err = io.ReadFull(conn, buf)
|
||||
if err != nil || n != len(testData) {
|
||||
n, err = conn.Read(buf)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read test data: %v", err)
|
||||
}
|
||||
if n != len(testData) {
|
||||
t.Fatalf("Read wrong number of bytes: got %d, want %d", n, len(testData))
|
||||
}
|
||||
t.Logf("Successfully read %d bytes", n)
|
||||
|
||||
if string(buf) != string(testData) {
|
||||
t.Errorf("Data mismatch: got %q, want %q", buf, testData)
|
||||
}
|
||||
t.Log("Test completed successfully")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user