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 }