github.com/neilgarb/delve@v1.9.2-nobreaks/service/rpccommon/server.go (about)

     1  package rpccommon
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"encoding/json"
     7  	"fmt"
     8  	"io"
     9  	"net"
    10  	"net/rpc"
    11  	"net/rpc/jsonrpc"
    12  	"os"
    13  	"reflect"
    14  	"runtime"
    15  	"sync"
    16  	"unicode"
    17  	"unicode/utf8"
    18  
    19  	"github.com/go-delve/delve/pkg/logflags"
    20  	"github.com/go-delve/delve/pkg/version"
    21  	"github.com/go-delve/delve/service"
    22  	"github.com/go-delve/delve/service/api"
    23  	"github.com/go-delve/delve/service/dap"
    24  	"github.com/go-delve/delve/service/debugger"
    25  	"github.com/go-delve/delve/service/internal/sameuser"
    26  	"github.com/go-delve/delve/service/rpc1"
    27  	"github.com/go-delve/delve/service/rpc2"
    28  	"github.com/sirupsen/logrus"
    29  )
    30  
    31  // ServerImpl implements a JSON-RPC server that can switch between two
    32  // versions of the API.
    33  type ServerImpl struct {
    34  	// config is all the information necessary to start the debugger and server.
    35  	config *service.Config
    36  	// listener is used to serve HTTP.
    37  	listener net.Listener
    38  	// stopChan is used to stop the listener goroutine.
    39  	stopChan chan struct{}
    40  	// debugger is the debugger service.
    41  	debugger *debugger.Debugger
    42  	// s1 is APIv1 server.
    43  	s1 *rpc1.RPCServer
    44  	// s2 is APIv2 server.
    45  	s2 *rpc2.RPCServer
    46  	// maps of served methods, one for each supported API.
    47  	methodMaps []map[string]*methodType
    48  	log        *logrus.Entry
    49  }
    50  
    51  type RPCCallback struct {
    52  	s         *ServerImpl
    53  	sending   *sync.Mutex
    54  	codec     rpc.ServerCodec
    55  	req       rpc.Request
    56  	setupDone chan struct{}
    57  }
    58  
    59  var _ service.RPCCallback = &RPCCallback{}
    60  
    61  // RPCServer implements the RPC method calls common to all versions of the API.
    62  type RPCServer struct {
    63  	s *ServerImpl
    64  }
    65  
    66  type methodType struct {
    67  	method      reflect.Method
    68  	Rcvr        reflect.Value
    69  	ArgType     reflect.Type
    70  	ReplyType   reflect.Type
    71  	Synchronous bool
    72  }
    73  
    74  // NewServer creates a new RPCServer.
    75  func NewServer(config *service.Config) *ServerImpl {
    76  	logger := logflags.RPCLogger()
    77  	if config.APIVersion < 2 {
    78  		logger.Info("Using API v1")
    79  	}
    80  	if config.Debugger.Foreground {
    81  		// Print listener address
    82  		logflags.WriteAPIListeningMessage(config.Listener.Addr())
    83  		logger.Debug("API server pid = ", os.Getpid())
    84  	}
    85  	return &ServerImpl{
    86  		config:   config,
    87  		listener: config.Listener,
    88  		stopChan: make(chan struct{}),
    89  		log:      logger,
    90  	}
    91  }
    92  
    93  // Stop stops the JSON-RPC server.
    94  func (s *ServerImpl) Stop() error {
    95  	s.log.Debug("stopping")
    96  	close(s.stopChan)
    97  	if s.config.AcceptMulti {
    98  		s.listener.Close()
    99  	}
   100  	if s.debugger.IsRunning() {
   101  		s.debugger.Command(&api.DebuggerCommand{Name: api.Halt}, nil)
   102  	}
   103  	kill := s.config.Debugger.AttachPid == 0
   104  	return s.debugger.Detach(kill)
   105  }
   106  
   107  // Run starts a debugger and exposes it with an HTTP server. The debugger
   108  // itself can be stopped with the `detach` API. Run blocks until the HTTP
   109  // server stops.
   110  func (s *ServerImpl) Run() error {
   111  	var err error
   112  
   113  	if s.config.APIVersion < 2 {
   114  		s.config.APIVersion = 1
   115  	}
   116  	if s.config.APIVersion > 2 {
   117  		return fmt.Errorf("unknown API version")
   118  	}
   119  
   120  	// Create and start the debugger
   121  	config := s.config.Debugger
   122  	if s.debugger, err = debugger.New(&config, s.config.ProcessArgs); err != nil {
   123  		return err
   124  	}
   125  
   126  	s.s1 = rpc1.NewServer(s.config, s.debugger)
   127  	s.s2 = rpc2.NewServer(s.config, s.debugger)
   128  
   129  	rpcServer := &RPCServer{s}
   130  
   131  	s.methodMaps = make([]map[string]*methodType, 2)
   132  
   133  	s.methodMaps[0] = map[string]*methodType{}
   134  	s.methodMaps[1] = map[string]*methodType{}
   135  	suitableMethods(s.s1, s.methodMaps[0], s.log)
   136  	suitableMethods(rpcServer, s.methodMaps[0], s.log)
   137  	suitableMethods(s.s2, s.methodMaps[1], s.log)
   138  	suitableMethods(rpcServer, s.methodMaps[1], s.log)
   139  
   140  	go func() {
   141  		defer s.listener.Close()
   142  		for {
   143  			c, err := s.listener.Accept()
   144  			if err != nil {
   145  				select {
   146  				case <-s.stopChan:
   147  					// We were supposed to exit, do nothing and return
   148  					return
   149  				default:
   150  					panic(err)
   151  				}
   152  			}
   153  
   154  			if s.config.CheckLocalConnUser {
   155  				if !sameuser.CanAccept(s.listener.Addr(), c.LocalAddr(), c.RemoteAddr()) {
   156  					c.Close()
   157  					continue
   158  				}
   159  			}
   160  
   161  			go s.serveConnectionDemux(c)
   162  			if !s.config.AcceptMulti {
   163  				break
   164  			}
   165  		}
   166  	}()
   167  	return nil
   168  }
   169  
   170  type bufReadWriteCloser struct {
   171  	*bufio.Reader
   172  	io.WriteCloser
   173  }
   174  
   175  func (s *ServerImpl) serveConnectionDemux(c io.ReadWriteCloser) {
   176  	conn := &bufReadWriteCloser{bufio.NewReader(c), c}
   177  	b, err := conn.Peek(1)
   178  	if err != nil {
   179  		s.log.Warnf("error determining new connection protocol: %v", err)
   180  		return
   181  	}
   182  	if b[0] == 'C' { // C is for DAP's Content-Length
   183  		s.log.Debugf("serving DAP on new connection")
   184  		ds := dap.NewSession(conn, &dap.Config{Config: s.config, StopTriggered: s.stopChan}, s.debugger)
   185  		go ds.ServeDAPCodec()
   186  	} else {
   187  		s.log.Debugf("serving JSON-RPC on new connection")
   188  		go s.serveJSONCodec(conn)
   189  	}
   190  }
   191  
   192  // Precompute the reflect type for error.  Can't use error directly
   193  // because Typeof takes an empty interface value.  This is annoying.
   194  var typeOfError = reflect.TypeOf((*error)(nil)).Elem()
   195  
   196  // Is this an exported - upper case - name?
   197  func isExported(name string) bool {
   198  	ch, _ := utf8.DecodeRuneInString(name)
   199  	return unicode.IsUpper(ch)
   200  }
   201  
   202  // Is this type exported or a builtin?
   203  func isExportedOrBuiltinType(t reflect.Type) bool {
   204  	for t.Kind() == reflect.Ptr {
   205  		t = t.Elem()
   206  	}
   207  	// PkgPath will be non-empty even for an exported type,
   208  	// so we need to check the type name as well.
   209  	return isExported(t.Name()) || t.PkgPath() == ""
   210  }
   211  
   212  // Fills methods map with the methods of receiver that should be made
   213  // available through the RPC interface.
   214  // These are all the public methods of rcvr that have one of those
   215  // two signatures:
   216  //
   217  //	func (rcvr ReceiverType) Method(in InputType, out *ReplyType) error
   218  //	func (rcvr ReceiverType) Method(in InputType, cb service.RPCCallback)
   219  func suitableMethods(rcvr interface{}, methods map[string]*methodType, log *logrus.Entry) {
   220  	typ := reflect.TypeOf(rcvr)
   221  	rcvrv := reflect.ValueOf(rcvr)
   222  	sname := reflect.Indirect(rcvrv).Type().Name()
   223  	if sname == "" {
   224  		log.Debugf("rpc.Register: no service name for type %s", typ)
   225  		return
   226  	}
   227  	for m := 0; m < typ.NumMethod(); m++ {
   228  		method := typ.Method(m)
   229  		mname := method.Name
   230  		mtype := method.Type
   231  		// method must be exported
   232  		if method.PkgPath != "" {
   233  			continue
   234  		}
   235  		// Method needs three ins: (receive, *args, *reply) or (receiver, *args, *RPCCallback)
   236  		if mtype.NumIn() != 3 {
   237  			log.Warn("method", mname, "has wrong number of ins:", mtype.NumIn())
   238  			continue
   239  		}
   240  		// First arg need not be a pointer.
   241  		argType := mtype.In(1)
   242  		if !isExportedOrBuiltinType(argType) {
   243  			log.Warn(mname, "argument type not exported:", argType)
   244  			continue
   245  		}
   246  
   247  		replyType := mtype.In(2)
   248  		synchronous := replyType.String() != "service.RPCCallback"
   249  
   250  		if synchronous {
   251  			// Second arg must be a pointer.
   252  			if replyType.Kind() != reflect.Ptr {
   253  				log.Warn("method", mname, "reply type not a pointer:", replyType)
   254  				continue
   255  			}
   256  			// Reply type must be exported.
   257  			if !isExportedOrBuiltinType(replyType) {
   258  				log.Warn("method", mname, "reply type not exported:", replyType)
   259  				continue
   260  			}
   261  
   262  			// Method needs one out.
   263  			if mtype.NumOut() != 1 {
   264  				log.Warn("method", mname, "has wrong number of outs:", mtype.NumOut())
   265  				continue
   266  			}
   267  			// The return type of the method must be error.
   268  			if returnType := mtype.Out(0); returnType != typeOfError {
   269  				log.Warn("method", mname, "returns", returnType.String(), "not error")
   270  				continue
   271  			}
   272  		} else if mtype.NumOut() != 0 {
   273  			// Method needs zero outs.
   274  			log.Warn("method", mname, "has wrong number of outs:", mtype.NumOut())
   275  			continue
   276  		}
   277  		methods[sname+"."+mname] = &methodType{method: method, ArgType: argType, ReplyType: replyType, Synchronous: synchronous, Rcvr: rcvrv}
   278  	}
   279  }
   280  
   281  func (s *ServerImpl) serveJSONCodec(conn io.ReadWriteCloser) {
   282  	defer func() {
   283  		if !s.config.AcceptMulti && s.config.DisconnectChan != nil {
   284  			close(s.config.DisconnectChan)
   285  		}
   286  	}()
   287  
   288  	sending := new(sync.Mutex)
   289  	codec := jsonrpc.NewServerCodec(conn)
   290  	var req rpc.Request
   291  	var resp rpc.Response
   292  	for {
   293  		req = rpc.Request{}
   294  		err := codec.ReadRequestHeader(&req)
   295  		if err != nil {
   296  			if err != io.EOF {
   297  				s.log.Error("rpc:", err)
   298  			}
   299  			break
   300  		}
   301  
   302  		mtype, ok := s.methodMaps[s.config.APIVersion-1][req.ServiceMethod]
   303  		if !ok {
   304  			s.log.Errorf("rpc: can't find method %s", req.ServiceMethod)
   305  			s.sendResponse(sending, &req, &rpc.Response{}, nil, codec, fmt.Sprintf("unknown method: %s", req.ServiceMethod))
   306  			continue
   307  		}
   308  
   309  		var argv, replyv reflect.Value
   310  
   311  		// Decode the argument value.
   312  		argIsValue := false // if true, need to indirect before calling.
   313  		if mtype.ArgType.Kind() == reflect.Ptr {
   314  			argv = reflect.New(mtype.ArgType.Elem())
   315  		} else {
   316  			argv = reflect.New(mtype.ArgType)
   317  			argIsValue = true
   318  		}
   319  		// argv guaranteed to be a pointer now.
   320  		if err = codec.ReadRequestBody(argv.Interface()); err != nil {
   321  			return
   322  		}
   323  		if argIsValue {
   324  			argv = argv.Elem()
   325  		}
   326  
   327  		if mtype.Synchronous {
   328  			if logflags.RPC() {
   329  				argvbytes, _ := json.Marshal(argv.Interface())
   330  				s.log.Debugf("<- %s(%T%s)", req.ServiceMethod, argv.Interface(), argvbytes)
   331  			}
   332  			replyv = reflect.New(mtype.ReplyType.Elem())
   333  			function := mtype.method.Func
   334  			var returnValues []reflect.Value
   335  			var errInter interface{}
   336  			func() {
   337  				defer func() {
   338  					if ierr := recover(); ierr != nil {
   339  						errInter = newInternalError(ierr, 2)
   340  					}
   341  				}()
   342  				returnValues = function.Call([]reflect.Value{mtype.Rcvr, argv, replyv})
   343  				errInter = returnValues[0].Interface()
   344  			}()
   345  
   346  			errmsg := ""
   347  			if errInter != nil {
   348  				errmsg = errInter.(error).Error()
   349  			}
   350  			resp = rpc.Response{}
   351  			if logflags.RPC() {
   352  				replyvbytes, _ := json.Marshal(replyv.Interface())
   353  				s.log.Debugf("-> %T%s error: %q", replyv.Interface(), replyvbytes, errmsg)
   354  			}
   355  			s.sendResponse(sending, &req, &resp, replyv.Interface(), codec, errmsg)
   356  			if req.ServiceMethod == "RPCServer.Detach" && s.config.DisconnectChan != nil {
   357  				close(s.config.DisconnectChan)
   358  				s.config.DisconnectChan = nil
   359  			}
   360  		} else {
   361  			if logflags.RPC() {
   362  				argvbytes, _ := json.Marshal(argv.Interface())
   363  				s.log.Debugf("(async %d) <- %s(%T%s)", req.Seq, req.ServiceMethod, argv.Interface(), argvbytes)
   364  			}
   365  			function := mtype.method.Func
   366  			ctl := &RPCCallback{s, sending, codec, req, make(chan struct{})}
   367  			go func() {
   368  				defer func() {
   369  					if ierr := recover(); ierr != nil {
   370  						ctl.Return(nil, newInternalError(ierr, 2))
   371  					}
   372  				}()
   373  				function.Call([]reflect.Value{mtype.Rcvr, argv, reflect.ValueOf(ctl)})
   374  			}()
   375  			<-ctl.setupDone
   376  		}
   377  	}
   378  	codec.Close()
   379  }
   380  
   381  // A value sent as a placeholder for the server's response value when the server
   382  // receives an invalid request. It is never decoded by the client since the Response
   383  // contains an error when it is used.
   384  var invalidRequest = struct{}{}
   385  
   386  func (s *ServerImpl) sendResponse(sending *sync.Mutex, req *rpc.Request, resp *rpc.Response, reply interface{}, codec rpc.ServerCodec, errmsg string) {
   387  	resp.ServiceMethod = req.ServiceMethod
   388  	if errmsg != "" {
   389  		resp.Error = errmsg
   390  		reply = invalidRequest
   391  	}
   392  	resp.Seq = req.Seq
   393  	sending.Lock()
   394  	defer sending.Unlock()
   395  	err := codec.WriteResponse(resp, reply)
   396  	if err != nil {
   397  		s.log.Error("writing response:", err)
   398  	}
   399  }
   400  
   401  func (cb *RPCCallback) Return(out interface{}, err error) {
   402  	select {
   403  	case <-cb.setupDone:
   404  		// already closed
   405  	default:
   406  		close(cb.setupDone)
   407  	}
   408  	errmsg := ""
   409  	if err != nil {
   410  		errmsg = err.Error()
   411  	}
   412  	var resp rpc.Response
   413  	if logflags.RPC() {
   414  		outbytes, _ := json.Marshal(out)
   415  		cb.s.log.Debugf("(async %d) -> %T%s error: %q", cb.req.Seq, out, outbytes, errmsg)
   416  	}
   417  	cb.s.sendResponse(cb.sending, &cb.req, &resp, out, cb.codec, errmsg)
   418  }
   419  
   420  func (cb *RPCCallback) SetupDoneChan() chan struct{} {
   421  	return cb.setupDone
   422  }
   423  
   424  // GetVersion returns the version of delve as well as the API version
   425  // currently served.
   426  func (s *RPCServer) GetVersion(args api.GetVersionIn, out *api.GetVersionOut) error {
   427  	out.DelveVersion = version.DelveVersion.String()
   428  	out.APIVersion = s.s.config.APIVersion
   429  	return s.s.debugger.GetVersion(out)
   430  }
   431  
   432  // SetApiVersion changes version of the API being served.
   433  func (s *RPCServer) SetApiVersion(args api.SetAPIVersionIn, out *api.SetAPIVersionOut) error {
   434  	if args.APIVersion < 2 {
   435  		args.APIVersion = 1
   436  	}
   437  	if args.APIVersion > 2 {
   438  		return fmt.Errorf("unknown API version")
   439  	}
   440  	s.s.config.APIVersion = args.APIVersion
   441  	return nil
   442  }
   443  
   444  type internalError struct {
   445  	Err   interface{}
   446  	Stack []internalErrorFrame
   447  }
   448  
   449  type internalErrorFrame struct {
   450  	Pc   uintptr
   451  	Func string
   452  	File string
   453  	Line int
   454  }
   455  
   456  func newInternalError(ierr interface{}, skip int) *internalError {
   457  	r := &internalError{ierr, nil}
   458  	for i := skip; ; i++ {
   459  		pc, file, line, ok := runtime.Caller(i)
   460  		if !ok {
   461  			break
   462  		}
   463  		fname := "<unknown>"
   464  		fn := runtime.FuncForPC(pc)
   465  		if fn != nil {
   466  			fname = fn.Name()
   467  		}
   468  		r.Stack = append(r.Stack, internalErrorFrame{pc, fname, file, line})
   469  	}
   470  	return r
   471  }
   472  
   473  func (err *internalError) Error() string {
   474  	var out bytes.Buffer
   475  	fmt.Fprintf(&out, "Internal debugger error: %v\n", err.Err)
   476  	for _, frame := range err.Stack {
   477  		fmt.Fprintf(&out, "%s (%#x)\n\t%s:%d\n", frame.Func, frame.Pc, frame.File, frame.Line)
   478  	}
   479  	return out.String()
   480  }