code: func (c *client) call(req []byte) (reply interface{}, err error) {
  	c.mu.Lock()
  	defer c.mu.Unlock()
  
  	msg := make([]byte, 4+len(req))
  	binary.BigEndian.PutUint32(msg, uint32(len(req)))
  	copy(msg[4:], req)
  	if _, err = c.conn.Write(msg); err != nil {
  		return nil, clientErr(err)
  	}
  
  	var respSizeBuf [4]byte
  	if _, err = io.ReadFull(c.conn, respSizeBuf[:]); err != nil {
  		return nil, clientErr(err)
  	}
  	respSize := binary.BigEndian.Uint32(respSizeBuf[:])
  	if respSize > maxAgentResponseBytes {
  		return nil, clientErr(err)
  	}
  
  	buf := make([]byte, respSize)
  	if _, err = io.ReadFull(c.conn, buf); err != nil {
  		return nil, clientErr(err)
  	}
  	reply, err = unmarshal(buf)
  	if err != nil {
  		return nil, clientErr(err)
  	}
  	return reply, err
  }
docs: // call sends an RPC to the agent. On success, the reply is
  // unmarshaled into reply and replyType is set to the first byte of
  // the reply, which contains the type of the message.