diff --git a/Makefile b/Makefile index 60d9adb..e90c8a7 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,9 @@ SRCS=\ hodu_grpc.pb.go \ packet.go \ server.go \ + server-ctl.go \ server-peer.go \ + server-ws.go \ cmd/main.go all: hodu diff --git a/client.go b/client.go index 537ecad..17b1069 100644 --- a/client.go +++ b/client.go @@ -39,10 +39,11 @@ type Client struct { ctx context.Context ctx_cancel context.CancelFunc tlscfg *tls.Config - api_prefix string + ctl_prefix string ext_mtx sync.Mutex ext_svcs []Service + ctl_mux *http.ServeMux ctl *http.Server // control server cts_mtx sync.Mutex @@ -54,7 +55,6 @@ type Client struct { stop_chan chan bool log Logger - mux *http.ServeMux } // client connection to server @@ -840,7 +840,7 @@ func (cts *ClientConn) ReportEvent (route_id uint32, pts_id uint32, event_type P // -------------------------------------------------------------------- -func NewClient(ctx context.Context, listen_on string, logger Logger, tlscfg *tls.Config) *Client { +func NewClient(ctx context.Context, ctl_addr string, logger Logger, tlscfg *tls.Config) *Client { var c Client c.ctx, c.ctx_cancel = context.WithCancel(ctx) @@ -851,21 +851,21 @@ func NewClient(ctx context.Context, listen_on string, logger Logger, tlscfg *tls c.stop_req.Store(false) c.stop_chan = make(chan bool, 8) c.log = logger - c.api_prefix = "" // TODO: + c.ctl_prefix = "" // TODO: - c.mux = http.NewServeMux() - c.mux.Handle(c.api_prefix + "/client-conns", &client_ctl_client_conns{c: &c}) - c.mux.Handle(c.api_prefix + "/client-conns/{conn_id}", &client_ctl_client_conns_id{c: &c}) - c.mux.Handle(c.api_prefix + "/client-conns/{conn_id}/routes", &client_ctl_client_conns_id_routes{c: &c}) - c.mux.Handle(c.api_prefix + "/client-conns/{conn_id}/routes/{route_id}", &client_ctl_client_conns_id_routes_id{c: &c}) - c.mux.Handle(c.api_prefix + "/client-conns/{conn_id}/routes/{route_id}/peers", &client_ctl_client_conns_id_routes_id_peers{c: &c}) - c.mux.Handle(c.api_prefix + "/client-conns/{conn_id}/routes/{route_id}/peers/{peer_id}", &client_ctl_client_conns_id_routes_id_peers_id{c: &c}) - c.mux.Handle(c.api_prefix + "/server-conns", &client_ctl_clients{c: &c}) - c.mux.Handle(c.api_prefix + "/server-conns/{id}", &client_ctl_clients_id{c: &c}) + c.ctl_mux = http.NewServeMux() + c.ctl_mux.Handle(c.ctl_prefix + "/client-conns", &client_ctl_client_conns{c: &c}) + c.ctl_mux.Handle(c.ctl_prefix + "/client-conns/{conn_id}", &client_ctl_client_conns_id{c: &c}) + c.ctl_mux.Handle(c.ctl_prefix + "/client-conns/{conn_id}/routes", &client_ctl_client_conns_id_routes{c: &c}) + c.ctl_mux.Handle(c.ctl_prefix + "/client-conns/{conn_id}/routes/{route_id}", &client_ctl_client_conns_id_routes_id{c: &c}) + c.ctl_mux.Handle(c.ctl_prefix + "/client-conns/{conn_id}/routes/{route_id}/peers", &client_ctl_client_conns_id_routes_id_peers{c: &c}) + c.ctl_mux.Handle(c.ctl_prefix + "/client-conns/{conn_id}/routes/{route_id}/peers/{peer_id}", &client_ctl_client_conns_id_routes_id_peers_id{c: &c}) + c.ctl_mux.Handle(c.ctl_prefix + "/server-conns", &client_ctl_clients{c: &c}) + c.ctl_mux.Handle(c.ctl_prefix + "/server-conns/{id}", &client_ctl_clients_id{c: &c}) c.ctl = &http.Server{ - Addr: listen_on, - Handler: c.mux, + Addr: ctl_addr, + Handler: c.ctl_mux, // TODO: more settings } diff --git a/cmd/main.go b/cmd/main.go index 4c89902..49682e5 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -146,7 +146,7 @@ func (sh *signal_handler) WriteLog(id string, level hodu.LogLevel, fmt string, a sh.svc.WriteLog(id, level, fmt, args...) } -func server_main(laddrs []string) error { +func server_main(ctl_addr string, laddrs []string) error { var s *hodu.Server var err error var cert tls.Certificate @@ -156,12 +156,13 @@ func server_main(laddrs []string) error { return fmt.Errorf("ERROR: failed to load key pair - %s\n", err) } - s, err = hodu.NewServer(context.Background(), laddrs, &AppLogger{id: "server", out: os.Stderr}, &tls.Config{Certificates: []tls.Certificate{cert}}) + s, err = hodu.NewServer(context.Background(), ctl_addr, laddrs, &AppLogger{id: "server", out: os.Stderr}, &tls.Config{Certificates: []tls.Certificate{cert}}) if err != nil { return fmt.Errorf("ERROR: failed to create new server - %s", err.Error()) } s.StartService(nil) + s.StartCtlService() s.StartExtService(&signal_handler{svc:s}, nil) s.WaitForTermination() @@ -170,7 +171,7 @@ func server_main(laddrs []string) error { // -------------------------------------------------------------------- -func client_main(listen_on string, server_addr string, peer_addrs []string) error { +func client_main(ctl_addr string, server_addr string, peer_addrs []string) error { var c *hodu.Client var cert_pool *x509.CertPool var tlscfg *tls.Config @@ -187,7 +188,8 @@ func client_main(listen_on string, server_addr string, peer_addrs []string) erro InsecureSkipVerify: true, } - c = hodu.NewClient(context.Background(), listen_on, &AppLogger{id: "client", out: os.Stderr}, tlscfg) +// TODO: support multiple ctl addrs + c = hodu.NewClient(context.Background(), ctl_addr, &AppLogger{id: "client", out: os.Stderr}, tlscfg) cc.ServerAddr = server_addr cc.PeerAddrs = peer_addrs @@ -209,14 +211,19 @@ func main() { } if strings.EqualFold(os.Args[1], "server") { var la []string + var ctl_addr string la = make([]string, 0) flgs = flag.NewFlagSet("", flag.ContinueOnError) - flgs.Func("listen-on", "specify a listening address", func(v string) error { + flgs.Func("rpc-on", "specify a rpc listening address", func(v string) error { la = append(la, v) return nil }) + flgs.Func("ctl-on", "specify a listening address for control channel", func(v string) error { + ctl_addr = v // TODO: support multiple addrs + return nil + }) flgs.SetOutput(io.Discard) // prevent usage output err = flgs.Parse(os.Args[2:]) if err != nil { @@ -224,11 +231,11 @@ func main() { goto wrong_usage } - if len(la) < 0 || flgs.NArg() > 0 { + if ctl_addr == "" || len(la) < 0 || flgs.NArg() > 0 { goto wrong_usage } - err = server_main(la) + err = server_main(ctl_addr, la) if err != nil { fmt.Fprintf(os.Stderr, "ERROR: server error - %s\n", err.Error()) goto oops @@ -241,11 +248,11 @@ func main() { sa = make([]string, 0) flgs = flag.NewFlagSet("", flag.ContinueOnError) - flgs.Func("listen-on", "specify a control channel address", func(v string) error { + flgs.Func("rpc-on", "specify a control channel address", func(v string) error { la = append(la, v) return nil }) - flgs.Func("server", "specify a server address", func(v string) error { + flgs.Func("rpc-server", "specify a rpc server address", func(v string) error { sa = append(sa, v) return nil }) @@ -271,8 +278,8 @@ func main() { os.Exit(0) wrong_usage: - fmt.Fprintf(os.Stderr, "USAGE: %s server --listen-on=addr:port\n", os.Args[0]) - fmt.Fprintf(os.Stderr, " %s client --listen-on=addr:port --server=addr:port peer-addr:peer-port\n", os.Args[0]) + fmt.Fprintf(os.Stderr, "USAGE: %s server --rpc-on=addr:port --ctl-on=addr:port \n", os.Args[0]) + fmt.Fprintf(os.Stderr, " %s client --rpc-server=addr:port --ctl-on=addr:port peer-addr:peer-port\n", os.Args[0]) os.Exit(1) oops: diff --git a/server-ctl.go b/server-ctl.go new file mode 100644 index 0000000..5d2b0fe --- /dev/null +++ b/server-ctl.go @@ -0,0 +1,13 @@ +package hodu + +import "net/http" + +type server_ctl_client_conns struct { + s *Server +} + +// ------------------------------------ + +func (ctl *server_ctl_client_conns) ServeHTTP(w http.ResponseWriter, req *http.Request) { + w.Write([]byte("hello")) +} diff --git a/server-ws.go b/server-ws.go new file mode 100644 index 0000000..3a9c3fb --- /dev/null +++ b/server-ws.go @@ -0,0 +1,40 @@ +package hodu + +import "fmt" +import "net/http" +import "golang.org/x/net/websocket" + +type server_ctl_ws_tty struct { + s *Server + h websocket.Handler +} + +func server_ws_tty (ws* websocket.Conn) { + var msg []byte + var err error + + ws.Write([]byte("hello world\r\n")) + ws.Write([]byte("it's so wrong. it's awesome\r\n")) + ws.Write([]byte("it's so wrong. 동키가 지나간다.it's awesome\r\n")) + + + for { + err = websocket.Message.Receive(ws, &msg) + if err != nil { + break + } else if len(msg) == 0 { + continue + } + +fmt.Printf ("RECEIVED MESSAGE [%v]\n", msg) + } +} + +func (ctl *server_ctl_ws_tty) ServeHTTP(w http.ResponseWriter, req *http.Request) { + ctl.h.ServeHTTP(w, req) +} + + + + + diff --git a/server.go b/server.go index cdaebb4..e082060 100644 --- a/server.go +++ b/server.go @@ -8,14 +8,16 @@ import "io" import "math/rand" import "net" import "net/http" +import "os" import "sync" import "sync/atomic" -//import "time" import "google.golang.org/grpc" //import "google.golang.org/grpc/metadata" import "google.golang.org/grpc/peer" import "google.golang.org/grpc/stats" +import "golang.org/x/net/websocket" + const PTS_LIMIT = 8192 @@ -34,6 +36,8 @@ type Server struct { stop_req atomic.Bool stop_chan chan bool + ctl_prefix string + ctl_mux *http.ServeMux ctl *http.Server // control server l []*net.TCPListener // main listener for grpc @@ -689,13 +693,14 @@ func unaryInterceptor(ctx context.Context, req any, _ *grpc.UnaryServerInfo, han return m, err } -func NewServer(ctx context.Context, laddrs []string, logger Logger, tlscfg *tls.Config) (*Server, error) { +func NewServer(ctx context.Context, ctl_addr string, laddrs []string, logger Logger, tlscfg *tls.Config) (*Server, error) { var s Server var l *net.TCPListener var laddr *net.TCPAddr var err error var addr string var gl *net.TCPListener + var cwd string if len(laddrs) <= 0 { return nil, fmt.Errorf("no server addresses provided") @@ -738,6 +743,21 @@ func NewServer(ctx context.Context, laddrs []string, logger Logger, tlscfg *tls. ) // TODO: have this outside the server struct? RegisterHoduServer(s.gs, &s) + s.ctl_prefix = "" // TODO: + + s.ctl_mux = http.NewServeMux() + cwd, _ = os.Getwd() + s.ctl_mux.Handle(s.ctl_prefix + "/ui/", http.StripPrefix(s.ctl_prefix, http.FileServer(http.Dir(cwd)))) // TODO: proper directory. it must not use the current working directory... + //s.ctl_mux.HandleFunc(s.ctl_prefix + "/ws/tty", websocket.Handler(server_ws_tty).ServeHTTP) + s.ctl_mux.Handle(s.ctl_prefix + "/ws/tty", &server_ctl_ws_tty{s: &s, h: websocket.Handler(server_ws_tty)}) + s.ctl_mux.Handle(s.ctl_prefix + "/server-conns", &server_ctl_client_conns{s: &s}) + + s.ctl = &http.Server{ + Addr: ctl_addr, + Handler: s.ctl_mux, + // TODO: more settings + } + return &s, nil oops: @@ -921,6 +941,11 @@ func (s *Server) StartExtService(svc Service, data interface{}) { go svc.RunTask(&s.wg) } +func (s *Server) StartCtlService() { + s.wg.Add(1) + go s.RunCtlTask(&s.wg) +} + func (s *Server) StopServices() { var ext_svc Service s.ReqStop()