From a3897abe1758876b16e76748f0ad3061b6ab36b3 Mon Sep 17 00:00:00 2001 From: chenglch Date: Mon, 13 Nov 2017 18:21:25 +0800 Subject: [PATCH] Fix the bugs about signal handler and closed conn This commit coplete the following tasks: - Handle the SIGCONT and SIGSTOP with default signal handler. fix issue #3 - Receive the message from closed connection at first, then report EOF. --- common/network.go | 8 ++-- common/signal.go | 2 +- console/cli.go | 15 +++---- console/server.go | 104 +++++++++++++++++++++++++++------------------- 4 files changed, 76 insertions(+), 53 deletions(-) diff --git a/common/network.go b/common/network.go index b04ad07..885236f 100644 --- a/common/network.go +++ b/common/network.go @@ -42,6 +42,9 @@ func (s *Network) ReceiveInt(conn net.Conn) (int, error) { for n < 4 { tmp, err := conn.Read(b[n:]) if err != nil { + if err == io.EOF && tmp+n == 4 { + return BytesToInt(b), err + } return 0, err } n += tmp @@ -58,9 +61,8 @@ func (s *Network) ReceiveIntTimeout(conn net.Conn, timeout time.Duration) (int, } tmp, err := conn.Read(b[n:]) if err != nil { - if err == io.EOF && tmp == n { - n += tmp - break + if err == io.EOF && tmp+n == 4 { + return BytesToInt(b), err } return 0, err } diff --git a/common/signal.go b/common/signal.go index 69795f0..c0da8bb 100644 --- a/common/signal.go +++ b/common/signal.go @@ -18,7 +18,7 @@ func DoSignal() { for sig := range s.GetSigMap() { sigs = append(sigs, sig) } - signal.Notify(c) + signal.Notify(c, sigs...) sig := <-c err := s.Handle(sig, nil) if err != nil { diff --git a/console/cli.go b/console/cli.go index 1068172..25d6a30 100644 --- a/console/cli.go +++ b/console/cli.go @@ -5,10 +5,10 @@ import ( "github.com/chenglch/goconserver/common" "github.com/spf13/cobra" "os" + "sort" "strconv" "strings" "time" - "sort" ) var ( @@ -58,6 +58,7 @@ type nodeHost struct { host string } type nodeHostSlice []nodeHost + func (a nodeHostSlice) Len() int { return len(a) } @@ -123,7 +124,7 @@ func (c *CongoCli) list(cmd *cobra.Command, args []string) { tempNodes := make([]nodeHost, 0, len(nodes)) for _, v := range nodes { node := v.(map[string]interface{}) - tempNodes = append(tempNodes, nodeHost{name:node["name"].(string), + tempNodes = append(tempNodes, nodeHost{name: node["name"].(string), host: node["host"].(string)}) } sort.Sort(nodeHostSlice(tempNodes)) @@ -148,7 +149,7 @@ func (c *CongoCli) show(cmd *cobra.Command, args []string) { fmt.Fprintf(os.Stderr, "Usage: congo show \n") os.Exit(1) } - if strings.HasPrefix(".", args[0]) || strings.HasPrefix("/", args[0]){ + if strings.HasPrefix(".", args[0]) || strings.HasPrefix("/", args[0]) { fmt.Fprintf(os.Stderr, "Error: node name could not start with '.' or '/'\n") os.Exit(1) } @@ -177,7 +178,7 @@ func (c *CongoCli) logging(cmd *cobra.Command, args []string) { fmt.Fprintf(os.Stderr, "Usage: congo logging on/off \n") os.Exit(1) } - if strings.HasPrefix(".", args[0]) || strings.HasPrefix("/", args[0]){ + if strings.HasPrefix(".", args[0]) || strings.HasPrefix("/", args[0]) { fmt.Fprintf(os.Stderr, "Error: node name could not start with '.' or '/'\n") os.Exit(1) } @@ -208,7 +209,7 @@ func (c *CongoCli) delete(cmd *cobra.Command, args []string) { fmt.Fprintf(os.Stderr, "Usage: congo delete \n") os.Exit(1) } - if strings.HasPrefix(".", args[0]) || strings.HasPrefix("/", args[0]){ + if strings.HasPrefix(".", args[0]) || strings.HasPrefix("/", args[0]) { fmt.Fprintf(os.Stderr, "Error: node name could not start with '.' or '/'\n") os.Exit(1) } @@ -239,7 +240,7 @@ func (c *CongoCli) create(cmd *cobra.Command, args []string) { fmt.Fprintf(os.Stderr, "Usage: congo create driver=ssh ondemand=true --param key=val,key=val\n") os.Exit(1) } - if strings.HasPrefix(".", args[0]) || strings.HasPrefix("/", args[0]){ + if strings.HasPrefix(".", args[0]) || strings.HasPrefix("/", args[0]) { fmt.Fprintf(os.Stderr, "Error: node name could not start with '.' or '/'\n") os.Exit(1) } @@ -277,7 +278,7 @@ func (c *CongoCli) console(cmd *cobra.Command, args []string) { fmt.Fprintf(os.Stderr, "Usage: congo console \n") os.Exit(1) } - if strings.HasPrefix(".", args[0]) || strings.HasPrefix("/", args[0]){ + if strings.HasPrefix(".", args[0]) || strings.HasPrefix("/", args[0]) { fmt.Fprintf(os.Stderr, "Error: node name could not start with '.' or '/'\n") os.Exit(1) } diff --git a/console/server.go b/console/server.go index 52ccfc1..e6a7e6e 100644 --- a/console/server.go +++ b/console/server.go @@ -237,20 +237,20 @@ func NewConsoleServer(host string, port string) *ConsoleServer { return &ConsoleServer{host: host, port: port} } -func (c *ConsoleServer) handle(conn interface{}) { - var err error - plog.Debug("New client connection received.") +func (c *ConsoleServer) getConnectionInfo(conn interface{}) (string, string) { + var node, command string + var ok bool clientTimeout := time.Duration(serverConfig.Console.ClientTimeout) size, err := c.ReceiveIntTimeout(conn.(net.Conn), clientTimeout) if err != nil { conn.(net.Conn).Close() - return + return "", "" } b, err := c.ReceiveBytesTimeout(conn.(net.Conn), size, clientTimeout) if err != nil { - conn.(net.Conn).Close() - return + return "", "" } + plog.Debug(fmt.Sprintf("Receive connection from client: %s", string(b))) data := make(map[string]string) if err := json.Unmarshal(b, &data); err != nil { plog.Error(err) @@ -258,55 +258,76 @@ func (c *ConsoleServer) handle(conn interface{}) { if err != nil { plog.Error(err) } + return "", "" + } + if node, ok = data["name"]; !ok { + plog.Error("Could not get the node from client") + return "", "" + } + if command, ok = data["command"]; !ok { + plog.Error("Could not get the command from client") + return "", "" + } + return node, command +} + +func (c *ConsoleServer) redirect(conn interface{}, node string) { + var err error + nodeWithHost := nodeManager.stor.ListNodeWithHost() + clientTimeout := time.Duration(serverConfig.Console.ClientTimeout) + if _, ok := nodeWithHost[node]; !ok { + plog.ErrorNode(node, "Could not find this node.") + err = c.SendIntWithTimeout(conn.(net.Conn), STATUS_NOTFOUND, clientTimeout) + if err != nil { + plog.ErrorNode(node, err) + } + return + } + host := nodeWithHost[node] + err = c.SendIntWithTimeout(conn.(net.Conn), STATUS_REDIRECT, clientTimeout) + if err != nil { + plog.ErrorNode(node, err) + return + } + err = c.SendByteWithLength(conn.(net.Conn), []byte(host)) + if err != nil { + plog.ErrorNode(node, err) + return + } + plog.InfoNode(node, fmt.Sprintf("Redirect the session to %s", host)) +} + +func (c *ConsoleServer) handle(conn interface{}) { + var err error + clientTimeout := time.Duration(serverConfig.Console.ClientTimeout) + plog.Debug("New client connection received.") + name, command := c.getConnectionInfo(conn) + if name == "" && command == "" { conn.(net.Conn).Close() return } - plog.Debug(fmt.Sprintf("Receive connection from client: %s", string(b))) - if _, ok := nodeManager.Nodes[data["name"]]; !ok { - defer func() { - time.Sleep(time.Duration(1) * time.Second) - conn.(net.Conn).Close() - }() + if _, ok := nodeManager.Nodes[name]; !ok { + defer conn.(net.Conn).Close() if !nodeManager.stor.SupportWatcher() { - plog.ErrorNode(data["name"], "Could not find this node.") + plog.ErrorNode(name, "Could not find this node.") err = c.SendIntWithTimeout(conn.(net.Conn), STATUS_NOTFOUND, clientTimeout) if err != nil { - plog.ErrorNode(data["name"], err) + plog.ErrorNode(name, err) } return } else { - nodeWithHost := nodeManager.stor.ListNodeWithHost() - if _, ok := nodeWithHost[data["name"]]; !ok { - plog.ErrorNode(data["name"], "Could not find this node.") - err = c.SendIntWithTimeout(conn.(net.Conn), STATUS_NOTFOUND, clientTimeout) - if err != nil { - plog.ErrorNode(data["name"], err) - } - return - } - host := nodeWithHost[data["name"]] - err = c.SendIntWithTimeout(conn.(net.Conn), STATUS_REDIRECT, clientTimeout) - if err != nil { - plog.ErrorNode(data["name"], err) - return - } - err = c.SendByteWithLength(conn.(net.Conn), []byte(host)) - if err != nil { - plog.ErrorNode(data["name"], err) - return - } - plog.InfoNode(data["name"], fmt.Sprintf("Redirect the session to %s", host)) + c.redirect(conn, name) } return } - node := nodeManager.Nodes[data["name"]] - if data["command"] == COMMAND_START_CONSOLE { + node := nodeManager.Nodes[name] + if command == COMMAND_START_CONSOLE { if node.status != STATUS_CONNECTED { if err = node.RequireLock(false); err != nil { plog.ErrorNode(node.StorageNode.Name, fmt.Sprintf("Could not start console, error: %s.", err)) err = c.SendIntWithTimeout(conn.(net.Conn), STATUS_ERROR, clientTimeout) if err != nil { - plog.ErrorNode(data["name"], err) + plog.ErrorNode(name, err) } conn.(net.Conn).Close() return @@ -320,7 +341,7 @@ func (c *ConsoleServer) handle(conn interface{}) { node.Release(false) err = c.SendIntWithTimeout(conn.(net.Conn), STATUS_ERROR, clientTimeout) if err != nil { - plog.ErrorNode(data["name"], err) + plog.ErrorNode(name, err) } conn.(net.Conn).Close() return @@ -333,7 +354,7 @@ func (c *ConsoleServer) handle(conn interface{}) { // reply success message to the client err := c.SendIntWithTimeout(conn.(net.Conn), STATUS_CONNECTED, clientTimeout) if err != nil { - plog.ErrorNode(data["name"], err) + plog.ErrorNode(name, err) conn.(net.Conn).Close() return } @@ -341,7 +362,7 @@ func (c *ConsoleServer) handle(conn interface{}) { } else { err := c.SendIntWithTimeout(conn.(net.Conn), STATUS_ERROR, clientTimeout) if err != nil { - plog.ErrorNode(data["name"], err) + plog.ErrorNode(name, err) conn.(net.Conn).Close() return } @@ -395,7 +416,6 @@ func (c *ConsoleServer) registerSignal() { signalSet.Register(syscall.SIGINT, exitHandler) signalSet.Register(syscall.SIGTERM, exitHandler) signalSet.Register(syscall.SIGHUP, reloadHandler) - signalSet.Register(syscall.SIGCHLD, ignoreHandler) signalSet.Register(syscall.SIGWINCH, ignoreHandler) signalSet.Register(syscall.SIGPIPE, ignoreHandler) go common.DoSignal()