From a147ed64ecca4931ad4d9c71c2be6e50cc9bd7ce Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Thu, 9 Jan 2025 23:02:50 +0900 Subject: [PATCH] added a new client-side endpoint /_ctl/client-conns/{conn_id}/routes-spsp/{port_id} --- README.md | 2 +- client-ctl.go | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++ client.go | 57 +++++++++++++++++++++++++++ server.go | 2 +- 4 files changed, 164 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5385581..7501c40 100644 --- a/README.md +++ b/README.md @@ -37,5 +37,5 @@ Run this command: ``` -curl -X POST --data-binary @client-route.json http://127.0.0.1:7777/_ctl/client-conns/0/routes +curl -X POST --data-binary @client-route.json http://127.0.0.1:7777/_ctl/client-conns/1/routes ``` diff --git a/client-ctl.go b/client-ctl.go index bb4b5ac..41eb5e5 100644 --- a/client-ctl.go +++ b/client-ctl.go @@ -121,6 +121,10 @@ type client_ctl_client_conns_id_routes_id struct { client_ctl } +type client_ctl_client_conns_id_routes_spsp struct { + client_ctl +} + type client_ctl_client_conns_id_routes_id_peers struct { client_ctl } @@ -566,6 +570,107 @@ oops: // ------------------------------------ +func (ctl *client_ctl_client_conns_id_routes_spsp) ServeHTTP(w http.ResponseWriter, req *http.Request) (int, error) { + var c *Client + var status_code int + var err error + var conn_id string + var port_id string + var conn_nid uint64 + var port_nid uint64 + var je *json.Encoder + var cts *ClientConn + var r *ClientRoute + + defer func() { + var err interface{} = recover() + if err != nil { dump_call_frame_and_exit(ctl.c.log, req, err) } + }() + + c = ctl.c + je = json.NewEncoder(w) + + conn_id = req.PathValue("conn_id") + port_id = req.PathValue("port_id") + + conn_nid, err = strconv.ParseUint(conn_id, 10, int(unsafe.Sizeof(ConnId(0)) * 8)) + if err != nil { + status_code = http.StatusBadRequest; w.WriteHeader(status_code) + if err = je.Encode(json_errmsg{Text: "wrong connection id - " + conn_id}); err != nil { goto oops } + goto done + } + port_nid, err = strconv.ParseUint(port_id, 10, int(unsafe.Sizeof(PortId(0)) * 8)) + if err != nil { + status_code = http.StatusBadRequest; w.WriteHeader(status_code) + if err = je.Encode(json_errmsg{Text: "wrong route id - " + port_id}); err != nil { goto oops } + goto done + } + + cts = c.FindClientConnById(ConnId(conn_nid)) + if cts == nil { + status_code = http.StatusNotFound; w.WriteHeader(status_code) + if err = je.Encode(json_errmsg{Text: "non-existent connection id - " + conn_id}); err != nil { goto oops } + goto done + } + + r = cts.FindClientRouteByServerPeerSvcPortId(PortId(port_nid)) + if r == nil { + status_code = http.StatusNotFound; w.WriteHeader(status_code) + if err = je.Encode(json_errmsg{Text: "non-existent route id - " + conn_id}); err != nil { goto oops } + goto done + } + + switch req.Method { + case http.MethodGet: + status_code = http.StatusOK; w.WriteHeader(status_code) + err = je.Encode(json_out_client_route{ + Id: r.id, + ClientPeerAddr: r.peer_addr, + ClientPeerName: r.peer_name, + ServerPeerListenAddr: r.server_peer_listen_addr.String(), + ServerPeerNet: r.server_peer_net, + ServerPeerOption: r.server_peer_option.string(), + Lifetime: r.lifetime.String(), + }) + if err != nil { goto oops } + + case http.MethodPut: + var jcr json_in_client_route_update + var lifetime time.Duration + + err = json.NewDecoder(req.Body).Decode(&jcr) + if err != nil { + status_code = http.StatusBadRequest; w.WriteHeader(status_code) + goto oops + } + + lifetime, err = parse_duration_string(jcr.Lifetime) + if err != nil { + status_code = http.StatusBadRequest; w.WriteHeader(status_code) + err = fmt.Errorf("wrong lifetime value %s - %s", jcr.Lifetime, err.Error()) + goto oops + } + + err = r.ResetLifetime(lifetime) + if err != nil { goto oops } + + case http.MethodDelete: + r.ReqStop() + status_code = http.StatusNoContent; w.WriteHeader(status_code) + + default: + status_code = http.StatusBadRequest; w.WriteHeader(status_code) + } + +done: + return status_code, nil + +oops: + return status_code, err +} + +// ------------------------------------ + func (ctl *client_ctl_client_conns_id_routes_id_peers) ServeHTTP(w http.ResponseWriter, req *http.Request) (int, error) { var c *Client var status_code int diff --git a/client.go b/client.go index 2667abf..dfb2fa8 100644 --- a/client.go +++ b/client.go @@ -764,6 +764,28 @@ func (cts *ClientConn) RemoveClientRouteById(route_id RouteId) error { return nil } +func (cts *ClientConn) RemoveClientRouteByServerPeerSvcPortId(port_id PortId) error { + var r *ClientRoute + + // this is slow as there is no indexing by the service side port id + // the use of this function is not really recommended. the best is to + // use the actual route id for finding. + cts.route_mtx.Lock() + for _, r = range cts.route_map { + if r.server_peer_listen_addr.Port == int(port_id) { + delete(cts.route_map, r.id) + cts.cli.stats.routes.Add(-1) + cts.route_mtx.Unlock() + cts.cli.log.Write(cts.sid, LOG_INFO, "Removed route(%d,%s)", r.id, r.peer_addr) + r.ReqStop() + return nil + } + } + cts.route_mtx.Unlock() + + return fmt.Errorf("non-existent server peer service port id - %d", port_id) +} + func (cts *ClientConn) FindClientRouteById(route_id RouteId) *ClientRoute { var r *ClientRoute var ok bool @@ -779,6 +801,24 @@ func (cts *ClientConn) FindClientRouteById(route_id RouteId) *ClientRoute { return r } +func (cts *ClientConn) FindClientRouteByServerPeerSvcPortId(port_id PortId) *ClientRoute { + var r *ClientRoute + + // this is slow as there is no indexing by the service side port id + // the use of this function is not really recommended. the best is to + // use the actual route id for finding. + cts.route_mtx.Lock() + for _, r = range cts.route_map { + if r.server_peer_listen_addr.Port == int(port_id) { + cts.route_mtx.Unlock() + return r; // return the first match + } + } + cts.route_mtx.Unlock() + + return nil +} + func (cts *ClientConn) AddClientRouteConfig (route *ClientRouteConfig) { cts.route_mtx.Lock() cts.cfg.Routes = append(cts.cfg.Routes, *route) @@ -1200,6 +1240,8 @@ func NewClient(ctx context.Context, logger Logger, ctl_addrs []string, ctl_prefi c.wrap_http_handler(&client_ctl_client_conns_id_routes{client_ctl{c: &c, id: "ctl"}})) c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/client-conns/{conn_id}/routes/{route_id}", c.wrap_http_handler(&client_ctl_client_conns_id_routes_id{client_ctl{c: &c, id: "ctl"}})) + c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/client-conns/{conn_id}/routes-spsp/{port_id}", + c.wrap_http_handler(&client_ctl_client_conns_id_routes_spsp{client_ctl{c: &c, id: "ctl"}})) c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/client-conns/{conn_id}/routes/{route_id}/peers", c.wrap_http_handler(&client_ctl_client_conns_id_routes_id_peers{client_ctl{c: &c, id: "ctl"}})) c.ctl_mux.Handle(c.ctl_prefix + "/_ctl/client-conns/{conn_id}/routes/{route_id}/peers/{peer_id}", @@ -1381,6 +1423,21 @@ func (c *Client) FindClientRouteById(conn_id ConnId, route_id RouteId) *ClientRo return cts.FindClientRouteById(route_id) } +func (c *Client) FindClientRouteByServerPeerSvcPortId(conn_id ConnId, port_id PortId) *ClientRoute { + var cts *ClientConn + var ok bool + + c.cts_mtx.Lock() + defer c.cts_mtx.Unlock() + + cts, ok = c.cts_map[conn_id] + if !ok { + return nil + } + + return cts.FindClientRouteByServerPeerSvcPortId(port_id) +} + func (c *Client) FindClientPeerConnById(conn_id ConnId, route_id RouteId, peer_id PeerId) *ClientPeerConn { var cts *ClientConn var r *ClientRoute diff --git a/server.go b/server.go index ab3eb04..80e645c 100644 --- a/server.go +++ b/server.go @@ -1105,7 +1105,7 @@ func NewServer(ctx context.Context, logger Logger, ctl_addrs []string, rpc_addrs s.wrap_http_handler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: "wpx"}, file: "xterm.css"})) s.wpx_mux.Handle("/_ssh/{port_id}", s.wrap_http_handler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: "wpx"}, file: "xterm.html"})) - s.pxy_mux.Handle("/_ssh/", + s.wpx_mux.Handle("/_ssh/", s.wrap_http_handler(&server_proxy_xterm_file{server_proxy: server_proxy{s: &s, id: "wpx"}, file: "_forbidden"})) s.wpx_mux.Handle("/{port_id}/{trailer...}",