From a4ef87c031735f4f00ade158cde1910c7615cc03 Mon Sep 17 00:00:00 2001
From: hyung-hwan <hyunghwan.chung@gmail.com>
Date: Mon, 16 Dec 2024 01:43:46 +0900
Subject: [PATCH] added the new type ClientRouteConfig. client-side route info
 is populated to a ClientRouteCofnig slice

---
 client.go   | 82 +++++++++++------------------------------------------
 cmd/main.go | 74 +++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 89 insertions(+), 67 deletions(-)

diff --git a/client.go b/client.go
index b18f657..11e4efc 100644
--- a/client.go
+++ b/client.go
@@ -8,7 +8,6 @@ import "log"
 //import "math/rand"
 import "net"
 import "net/http"
-import "strings"
 import "sync"
 import "sync/atomic"
 import "time"
@@ -28,9 +27,18 @@ type ClientPeerConnMap = map[PeerId]*ClientPeerConn
 type ClientPeerCancelFuncMap = map[PeerId]context.CancelFunc
 
 // --------------------------------------------------------------------
+type ClientRouteConfig struct {
+	PeerAddr        string
+	PeerName        string
+	Option      RouteOption
+	ServiceAddr string // server-peer-service-addr
+	ServiceNet  string // server-peer-service-net
+}
+
 type ClientConfig struct {
 	ServerAddrs []string
-	PeerAddrs []string
+	//PeerAddrs []string
+	Routes      []ClientRouteConfig
 	ServerSeedTmout time.Duration
 	ServerAuthority string // http2 :authority header
 }
@@ -710,67 +718,12 @@ func (cts *ClientConn) FindClientRouteById(route_id RouteId) *ClientRoute {
 	return r
 }
 
-func (cts *ClientConn) AddClientRoutes(peer_addrs []string) error {
-	var v string
-	var port string
-	var option RouteOption
-	var va []string
-	var svc_addr string
-	var ptc_name string
+func (cts *ClientConn) AddClientRoutes(routes []ClientRouteConfig) error {
+	var v ClientRouteConfig
 	var err error
 
-	for _, v = range peer_addrs {
-		va = strings.Split(v, ",")
-		if len(va) <= 0 { return fmt.Errorf("blank value") }
-		if len(va) >= 5 { return fmt.Errorf("too many fields in %v", v) }
-
-		_, port, err = net.SplitHostPort(strings.TrimSpace(va[0]))
-		if err != nil {
-			return fmt.Errorf("invalid address %s", va[0], err.Error())
-		}
-
-		if len(va) >= 2 {
-			var f string
-			f = strings.TrimSpace(va[1])
-			_, _, err = net.SplitHostPort(f)
-			if err != nil {
-				return fmt.Errorf("invalid address %s", va[1], err.Error())
-			}
-			svc_addr = f
-		}
-
-		option = RouteOption(ROUTE_OPTION_TCP)
-		if len(va) >= 3 {
-			switch strings.ToLower(strings.TrimSpace(va[2])) {
-				case "ssh":
-					option |= RouteOption(ROUTE_OPTION_SSH)
-				case "http":
-					option |= RouteOption(ROUTE_OPTION_HTTP)
-				case "https":
-					option |= RouteOption(ROUTE_OPTION_HTTPS)
-
-				case "":
-					fallthrough
-				case "auto":
-					// automatic determination of protocol for common ports
-					switch port {
-						case "22":
-							option |= RouteOption(ROUTE_OPTION_SSH)
-						case "80":
-							option |= RouteOption(ROUTE_OPTION_HTTP)
-						case "443":
-							option |= RouteOption(ROUTE_OPTION_HTTPS)
-					}
-				default:
-					return fmt.Errorf("invalid option value %s", va[2])
-			}
-		}
-
-		if len(va) >= 4 {
-			ptc_name = strings.TrimSpace(va[3])
-		}
-
-		_, err = cts.AddNewClientRoute(va[0], ptc_name, svc_addr, "", option)
+	for _, v = range routes {
+		_, err = cts.AddNewClientRoute(v.PeerAddr, v.PeerName, v.ServiceAddr, "", v.Option)
 		if err != nil {
 			return fmt.Errorf("unable to add client route for %s - %s", v, err.Error())
 		}
@@ -892,16 +845,15 @@ start_over:
 
 	cts.psc = &GuardedPacketStreamClient{Hodu_PacketStreamClient: psc}
 
-	if len(cts.cfg.PeerAddrs) > 0 {
+	if len(cts.cfg.Routes) > 0 {
 		// the connection structure to a server is ready.
 		// let's add routes to the client-side peers if given
-		err = cts.AddClientRoutes(cts.cfg.PeerAddrs)
+		err = cts.AddClientRoutes(cts.cfg.Routes)
 		if err != nil {
-			cts.cli.log.Write(cts.sid, LOG_ERROR, "Failed to add routes to server[%s] %s for %v - %s", cts.cfg.Index, cts.cfg.ServerAddrs[cts.cfg.Index], cts.cfg.PeerAddrs, err.Error())
+			cts.cli.log.Write(cts.sid, LOG_ERROR, "Failed to add routes to server[%d] %s for %v - %s", cts.cfg.Index, cts.cfg.ServerAddrs[cts.cfg.Index], cts.cfg.Routes, err.Error())
 			goto done
 		}
 	}
-// TODO: remember the previouslyu POSTed routes and readd them??
 
 	for {
 		var pkt *Packet
diff --git a/cmd/main.go b/cmd/main.go
index a6ff02f..6684bbb 100644
--- a/cmd/main.go
+++ b/cmd/main.go
@@ -7,6 +7,7 @@ import "flag"
 import "fmt"
 import "hodu"
 import "io"
+import "net"
 import "os"
 import "os/signal"
 import "strings"
@@ -176,7 +177,69 @@ func server_main(ctl_addrs []string, rpc_addrs []string, pxy_addrs []string, cfg
 
 // --------------------------------------------------------------------
 
-func client_main(ctl_addrs []string, rpc_addrs []string, peer_addrs []string, cfg *ClientConfig) error {
+func parse_client_route_config(v string) (*hodu.ClientRouteConfig, error) {
+	var va []string
+	var ptc_name string
+	var svc_addr string
+	var option hodu.RouteOption
+	var port string
+	var err error
+
+	va = strings.Split(v, ",")
+
+	if len(va) <= 0 { return nil, fmt.Errorf("blank value") }
+	if len(va) >= 5 { return nil, fmt.Errorf("too many fields in %v", v) }
+
+	_, port, err = net.SplitHostPort(strings.TrimSpace(va[0]))
+	if err != nil {
+		return nil, fmt.Errorf("invalid address %s", va[0], err.Error())
+	}
+
+	if len(va) >= 2 {
+		var f string
+		f = strings.TrimSpace(va[1])
+		_, _, err = net.SplitHostPort(f)
+		if err != nil {
+			return nil, fmt.Errorf("invalid address %s", va[1], err.Error())
+		}
+		svc_addr = f
+	}
+
+	option = hodu.RouteOption(hodu.ROUTE_OPTION_TCP)
+	if len(va) >= 3 {
+		switch strings.ToLower(strings.TrimSpace(va[2])) {
+			case "ssh":
+				option |= hodu.RouteOption(hodu.ROUTE_OPTION_SSH)
+			case "http":
+				option |= hodu.RouteOption(hodu.ROUTE_OPTION_HTTP)
+			case "https":
+				option |= hodu.RouteOption(hodu.ROUTE_OPTION_HTTPS)
+
+			case "":
+				fallthrough
+			case "auto":
+				// automatic determination of protocol for common ports
+				switch port {
+					case "22":
+						option |= hodu.RouteOption(hodu.ROUTE_OPTION_SSH)
+					case "80":
+						option |= hodu.RouteOption(hodu.ROUTE_OPTION_HTTP)
+					case "443":
+						option |= hodu.RouteOption(hodu.ROUTE_OPTION_HTTPS)
+				}
+			default:
+				return nil, fmt.Errorf("invalid option value %s", va[2])
+		}
+	}
+
+	if len(va) >= 4 {
+		ptc_name = strings.TrimSpace(va[3])
+	}
+
+	return &hodu.ClientRouteConfig{PeerAddr: va[0], PeerName: ptc_name, Option: option, ServiceAddr: svc_addr}, nil // TODO: other fields
+}
+
+func client_main(ctl_addrs []string, rpc_addrs []string, route_configs []string, cfg *ClientConfig) error {
 	var c *hodu.Client
 	var ctltlscfg *tls.Config
 	var rpctlscfg *tls.Config
@@ -190,6 +253,7 @@ func client_main(ctl_addrs []string, rpc_addrs []string, peer_addrs []string, cf
 	var max_rpc_conns int
 	var max_peers int
 	var peer_conn_tmout time.Duration
+	var i int
 	var err error
 
 	log_mask = hodu.LOG_ALL
@@ -221,7 +285,13 @@ func client_main(ctl_addrs []string, rpc_addrs []string, peer_addrs []string, cf
 	// unlke the server, we allow the client to start with no rpc address.
 	// no check if len(rpc_addrs) <= 0 is mdde here.
 	cc.ServerAddrs = rpc_addrs
-	cc.PeerAddrs = peer_addrs
+	cc.Routes = make([]hodu.ClientRouteConfig, len(route_configs))
+	for i, _ = range route_configs {
+		var c *hodu.ClientRouteConfig
+		c, err = parse_client_route_config(route_configs[i])
+		if err != nil { return err }
+		cc.Routes[i] = *c
+	}
 
 	if logfile == "" {
 		logger = NewAppLogger("server", os.Stderr, log_mask)