diff --git a/client-ctl.go b/client-ctl.go index dae262c..9595968 100644 --- a/client-ctl.go +++ b/client-ctl.go @@ -397,7 +397,6 @@ done: oops: c.log.Write("", LOG_ERROR, "[%s] %s %s - %s", req.RemoteAddr, req.Method, req.URL.String(), err.Error()) return - } // ------------------------------------ @@ -412,6 +411,7 @@ func (ctl *client_ctl_client_conns_id_routes_id) ServeHTTP(w http.ResponseWriter var route_nid uint64 var je *json.Encoder var cts *ClientConn + var r *ClientRoute defer func() { var err interface{} = recover() @@ -444,24 +444,27 @@ func (ctl *client_ctl_client_conns_id_routes_id) ServeHTTP(w http.ResponseWriter goto done } + r = cts.FindClientRouteById(uint32(route_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: - var r *ClientRoute - r = cts.FindClientRouteById(uint32(route_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 - } + status_code = http.StatusOK; w.WriteHeader(status_code) err = je.Encode(json_out_client_route{ Id: r.id, ClientPeerAddr: r.peer_addr, ServerPeerListenAddr: r.server_peer_listen_addr.String(), + ServerPeerNet: r.server_peer_net, + ServerPeerProto: r.server_peer_proto, }) if err != nil { goto oops } case http.MethodDelete: - cts.ReqStop() + r.ReqStop() status_code = http.StatusNoContent; w.WriteHeader(status_code) default: diff --git a/hodu.go b/hodu.go index 3e5235b..526e885 100644 --- a/hodu.go +++ b/hodu.go @@ -17,11 +17,11 @@ const ( ) type Logger interface { - Write (id string, level LogLevel, fmtstr string, args ...interface{}) + Write(id string, level LogLevel, fmtstr string, args ...interface{}) } type Service interface { - RunTask (wg *sync.WaitGroup) // blocking. run the actual task loop. it must call wg.Done() upon exit from itself. + RunTask(wg *sync.WaitGroup) // blocking. run the actual task loop. it must call wg.Done() upon exit from itself. StartService(data interface{}) // non-blocking. spin up a service. it may be invokded multiple times for multiple instances StopServices() // non-blocking. send stop request to all services spun up WaitForTermination() // blocking. must wait until all services are stopped diff --git a/hodu.proto b/hodu.proto index b7cd6d0..a23942a 100644 --- a/hodu.proto +++ b/hodu.proto @@ -2,7 +2,11 @@ syntax = "proto3"; option go_package = "./hodu"; -//package hodu; // no idea if it's still important... +// this one affects the full name of the the actual calls. +// /./ +// i want to keep the package line commented out such that +// the full name is // (e.g. /Hodu/GetSeed) +//package hodu; service Hodu { rpc GetSeed (Seed) returns (Seed) {} diff --git a/server-ctl.go b/server-ctl.go index 627a687..f802b67 100644 --- a/server-ctl.go +++ b/server-ctl.go @@ -202,7 +202,7 @@ func (ctl *server_ctl_server_conns_id) ServeHTTP(w http.ResponseWriter, req *htt } done: - s.log.Write("", LOG_DEBUG, "[%s] %s %s %d", req.RemoteAddr, req.Method, req.URL.String(), status_code) // TODO: time taken + s.log.Write("", LOG_DEBUG, "[%s] %s %s %d", req.RemoteAddr, req.Method, req.URL.String(), status_code) return oops: @@ -213,13 +213,157 @@ oops: // ------------------------------------ func (ctl *server_ctl_server_conns_id_routes) ServeHTTP(w http.ResponseWriter, req *http.Request) { - // TODO + var s *Server + var status_code int + var err error + var conn_id string + var conn_nid uint64 + var je *json.Encoder + var cts *ServerConn + + defer func() { + var err interface{} = recover() + if err != nil { dump_call_frame_and_exit(ctl.s.log, req, err) } + }() + + s = ctl.s + je = json.NewEncoder(w) + + conn_id = req.PathValue("conn_id") + + conn_nid, err = strconv.ParseUint(conn_id, 10, 32) + 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 + } + + cts = s.FindServerConnById(uint32(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 + } + + switch req.Method { + case http.MethodGet: + var r *ServerRoute + var jsp []json_out_server_route + + jsp = make([]json_out_server_route, 0) + cts.route_mtx.Lock() + for _, r = range cts.route_map { + jsp = append(jsp, json_out_server_route{ + Id: r.id, + ClientPeerAddr: r.ptc_addr, + ServerPeerListenAddr: r.svc_addr.String(), + ServerPeerNet: r.svc_permitted_net.String(), + ServerPeerProto: r.svc_proto, + }) + } + cts.route_mtx.Unlock() + + status_code = http.StatusOK; w.WriteHeader(status_code) + if err = je.Encode(jsp); err != nil { goto oops } + + case http.MethodDelete: + //cts.RemoveAllServerRoutes() + cts.ReqStopAllServerRoutes() + status_code = http.StatusNoContent; w.WriteHeader(status_code) + + default: + status_code = http.StatusBadRequest; w.WriteHeader(status_code) + } + +done: + s.log.Write("", LOG_DEBUG, "[%s] %s %s %d", req.RemoteAddr, req.Method, req.URL.String(), status_code) // TODO: time taken + return + +oops: + s.log.Write("", LOG_ERROR, "[%s] %s %s - %s", req.RemoteAddr, req.Method, req.URL.String(), err.Error()) + return } // ------------------------------------ func (ctl *server_ctl_server_conns_id_routes_id) ServeHTTP(w http.ResponseWriter, req *http.Request) { - // TODO + var s *Server + var status_code int + var err error + var conn_id string + var conn_nid uint64 + var route_id string + var route_nid uint64 + var je *json.Encoder + var cts *ServerConn + var r *ServerRoute + + defer func() { + var err interface{} = recover() + if err != nil { dump_call_frame_and_exit(ctl.s.log, req, err) } + }() + + s = ctl.s + je = json.NewEncoder(w) + + conn_id = req.PathValue("conn_id") + route_id = req.PathValue("route_id") + + conn_nid, err = strconv.ParseUint(conn_id, 10, 32) + 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 + } + route_nid, err = strconv.ParseUint(route_id, 10, 32) + if err != nil { + status_code = http.StatusBadRequest; w.WriteHeader(status_code) + if err = je.Encode(json_errmsg{Text: "wrong route id - " + route_id}); err != nil { goto oops } + goto done + } + + cts = s.FindServerConnById(uint32(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.FindServerRouteById(uint32(route_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.ptc_addr, + ServerPeerListenAddr: r.svc_addr.String(), + ServerPeerNet: r.svc_permitted_net.String(), + ServerPeerProto: r.svc_proto, + }) + 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: + // TODO: need to handle x-forwarded-for and other stuff? this is not a real web service, though + s.log.Write("", LOG_DEBUG, "[%s] %s %s %d", req.RemoteAddr, req.Method, req.URL.String(), status_code) // TODO: time taken + return + +oops: + s.log.Write("", LOG_ERROR, "[%s] %s %s - %s", req.RemoteAddr, req.Method, req.URL.String(), err.Error()) + return } // ------------------------------------ diff --git a/server.go b/server.go index c0edb38..427e247 100644 --- a/server.go +++ b/server.go @@ -401,6 +401,32 @@ func (cts *ServerConn) RemoveServerRouteById(route_id uint32) (*ServerRoute, err return r, nil } +func (cts *ServerConn) FindServerRouteById(route_id uint32) *ServerRoute { + var r *ServerRoute + var ok bool + + cts.route_mtx.Lock() + r, ok = cts.route_map[route_id] + if !ok { + cts.route_mtx.Unlock() + return nil + } + cts.route_mtx.Unlock() + + return r +} + +func (cts *ServerConn) ReqStopAllServerRoutes() { + var r *ServerRoute + + cts.route_mtx.Lock() + defer cts.route_mtx.Unlock() + + for _, r = range cts.route_map { + r.ReqStop() + } +} + func (cts *ServerConn) ReportEvent(route_id uint32, pts_id uint32, event_type PACKET_KIND, event_data interface{}) error { var r *ServerRoute var ok bool @@ -992,7 +1018,7 @@ func (s *Server) RunCtlTask(wg *sync.WaitGroup) { go func(i int, cs *http.Server) { var l net.Listener - s.log.Write ("", LOG_INFO, "Control channel[%d] started on %s", i, s.ctl_addr[i]) + s.log.Write("", LOG_INFO, "Control channel[%d] started on %s", i, s.ctl_addr[i]) // defeat hard-coded "tcp" in ListenAndServe() and ListenAndServeTLS() // err = cs.ListenAndServe() @@ -1141,7 +1167,7 @@ func (s *Server) RemoveServerConnByAddr(addr net.Addr) error { return nil } -func (s* Server) FindServerConnById(id uint32) *ServerConn { +func (s *Server) FindServerConnById(id uint32) *ServerConn { var cts *ServerConn var ok bool