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
}