func()

in google_guest_agent/command/command_monitor.go [118:228]


func (c *Server) start(ctx context.Context) error {
	if c.srv != nil {
		return errors.New("server already listening")
	}
	srv, err := listen(ctx, c.pipe, c.pipeMode, c.pipeGroup)
	if err != nil {
		return err
	}
	go func() {
		defer srv.Close()
		for {
			if ctx.Err() != nil {
				return
			}
			conn, err := srv.Accept()
			if err != nil {
				if err == net.ErrClosed {
					break
				}
				logger.Infof("error on connection to pipe %s: %v", c.pipe, err)
				continue
			}
			go func(conn net.Conn) {
				defer conn.Close()
				// Go has lots of helpers to do this for us but none of them return the byte
				// slice afterwards, and we need it for the handler
				var b []byte
				r := bufio.NewReader(conn)
				var depth int
				deadline := time.Now().Add(c.timeout)
				e := conn.SetReadDeadline(deadline)
				if e != nil {
					logger.Infof("could not set read deadline on command request: %v", e)
					return
				}
				for {
					if time.Now().After(deadline) {
						if b, err := json.Marshal(TimeoutError); err != nil {
							conn.Write(internalError)
						} else {
							conn.Write(b)
						}
						return
					}
					rune, _, err := r.ReadRune()
					if err != nil {
						logger.Debugf("connection read error: %v", err)
						if errors.Is(err, os.ErrDeadlineExceeded) {
							if b, err := json.Marshal(TimeoutError); err != nil {
								conn.Write(internalError)
							} else {
								conn.Write(b)
							}
						} else {
							if b, err := json.Marshal(ConnError); err != nil {
								conn.Write(internalError)
							} else {
								conn.Write(b)
							}
						}
						return
					}
					b = append(b, byte(rune))
					switch rune {
					case '{':
						depth++
					case '}':
						depth--
					}
					// Must check here because the first pass always depth = 0
					if depth == 0 {
						break
					}
				}
				var req Request
				err := json.Unmarshal(b, &req)
				if err != nil {
					if b, err := json.Marshal(BadRequestError); err != nil {
						conn.Write(internalError)
					} else {
						conn.Write(b)
					}
					return
				}
				c.monitor.handlersMu.RLock()
				defer c.monitor.handlersMu.RUnlock()
				handler, ok := c.monitor.handlers[req.Command]
				if !ok {
					if b, err := json.Marshal(CmdNotFoundError); err != nil {
						conn.Write(internalError)
					} else {
						conn.Write(b)
					}
					return
				}
				resp, err := handler(b)
				if err != nil {
					re := Response{Status: HandlerError.Status, StatusMessage: err.Error()}
					if b, err := json.Marshal(re); err != nil {
						resp = internalError
					} else {
						resp = b
					}
				}
				conn.Write(resp)
			}(conn)
		}
	}()
	c.srv = srv
	return nil
}