Source file src/net/rpc/server.go

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  /*
     6  Package rpc provides access to the exported methods of an object across a
     7  network or other I/O connection.
     8  
     9  The net/rpc package is frozen and is not accepting new features.
    10  
    11  A server registers an object, making it visible
    12  as a service with the name of the type of the object.  After registration, exported
    13  methods of the object will be accessible remotely.  A server may register multiple
    14  objects (services) of different types but it is an error to register multiple
    15  objects of the same type.
    16  
    17  Only methods that satisfy these criteria will be made available for remote access;
    18  other methods will be ignored:
    19  
    20    - the method's type is exported.
    21    - the method is exported.
    22    - the method has two arguments, both exported (or builtin) types.
    23    - the method's second argument is a pointer.
    24    - the method has return type error.
    25  
    26  In effect, the method must look schematically like
    27  
    28  	func (t *T) MethodName(argType T1, replyType *T2) error
    29  
    30  where T1 and T2 can be marshaled by encoding/gob.
    31  These requirements apply even if a different codec is used.
    32  (In the future, these requirements may soften for custom codecs.)
    33  
    34  The method's first argument represents the arguments provided by the caller; the
    35  second argument represents the result parameters to be returned to the caller.
    36  The method's return value, if non-nil, is passed back as a string that the client
    37  sees as if created by [errors.New].  If an error is returned, the reply parameter
    38  will not be sent back to the client.
    39  
    40  The server may handle requests on a single connection by calling [ServeConn].  More
    41  typically it will create a network listener and call [Accept] or, for an HTTP
    42  listener, [HandleHTTP] and [http.Serve].
    43  
    44  A client wishing to use the service establishes a connection and then invokes
    45  [NewClient] on the connection.  The convenience function [Dial] ([DialHTTP]) performs
    46  both steps for a raw network connection (an HTTP connection).  The resulting
    47  [Client] object has two methods, [Call] and Go, that specify the service and method to
    48  call, a pointer containing the arguments, and a pointer to receive the result
    49  parameters.
    50  
    51  The Call method waits for the remote call to complete while the Go method
    52  launches the call asynchronously and signals completion using the Call
    53  structure's Done channel.
    54  
    55  Unless an explicit codec is set up, package [encoding/gob] is used to
    56  transport the data.
    57  
    58  Here is a simple example.  A server wishes to export an object of type Arith:
    59  
    60  	package server
    61  
    62  	import "errors"
    63  
    64  	type Args struct {
    65  		A, B int
    66  	}
    67  
    68  	type Quotient struct {
    69  		Quo, Rem int
    70  	}
    71  
    72  	type Arith int
    73  
    74  	func (t *Arith) Multiply(args *Args, reply *int) error {
    75  		*reply = args.A * args.B
    76  		return nil
    77  	}
    78  
    79  	func (t *Arith) Divide(args *Args, quo *Quotient) error {
    80  		if args.B == 0 {
    81  			return errors.New("divide by zero")
    82  		}
    83  		quo.Quo = args.A / args.B
    84  		quo.Rem = args.A % args.B
    85  		return nil
    86  	}
    87  
    88  The server calls (for HTTP service):
    89  
    90  	arith := new(Arith)
    91  	rpc.Register(arith)
    92  	rpc.HandleHTTP()
    93  	l, err := net.Listen("tcp", ":1234")
    94  	if err != nil {
    95  		log.Fatal("listen error:", err)
    96  	}
    97  	go http.Serve(l, nil)
    98  
    99  At this point, clients can see a service "Arith" with methods "Arith.Multiply" and
   100  "Arith.Divide".  To invoke one, a client first dials the server:
   101  
   102  	client, err := rpc.DialHTTP("tcp", serverAddress + ":1234")
   103  	if err != nil {
   104  		log.Fatal("dialing:", err)
   105  	}
   106  
   107  Then it can make a remote call:
   108  
   109  	// Synchronous call
   110  	args := &server.Args{7,8}
   111  	var reply int
   112  	err = client.Call("Arith.Multiply", args, &reply)
   113  	if err != nil {
   114  		log.Fatal("arith error:", err)
   115  	}
   116  	fmt.Printf("Arith: %d*%d=%d", args.A, args.B, reply)
   117  
   118  or
   119  
   120  	// Asynchronous call
   121  	quotient := new(Quotient)
   122  	divCall := client.Go("Arith.Divide", args, quotient, nil)
   123  	replyCall := <-divCall.Done	// will be equal to divCall
   124  	// check errors, print, etc.
   125  
   126  A server implementation will often provide a simple, type-safe wrapper for the
   127  client.
   128  */
   129  package rpc
   130  
   131  import (
   132  	"bufio"
   133  	"encoding/gob"
   134  	"errors"
   135  	"go/token"
   136  	"io"
   137  	"log"
   138  	"net"
   139  	"net/http"
   140  	"reflect"
   141  	"strings"
   142  	"sync"
   143  )
   144  
   145  const (
   146  	// Defaults used by HandleHTTP
   147  	DefaultRPCPath   = "/_goRPC_"
   148  	DefaultDebugPath = "/debug/rpc"
   149  )
   150  
   151  // Precompute the reflect type for error.
   152  var typeOfError = reflect.TypeFor[error]()
   153  
   154  type methodType struct {
   155  	sync.Mutex // protects counters
   156  	method     reflect.Method
   157  	ArgType    reflect.Type
   158  	ReplyType  reflect.Type
   159  	numCalls   uint
   160  }
   161  
   162  type service struct {
   163  	name   string                 // name of service
   164  	rcvr   reflect.Value          // receiver of methods for the service
   165  	typ    reflect.Type           // type of the receiver
   166  	method map[string]*methodType // registered methods
   167  }
   168  
   169  // Request is a header written before every RPC call. It is used internally
   170  // but documented here as an aid to debugging, such as when analyzing
   171  // network traffic.
   172  type Request struct {
   173  	ServiceMethod string   // format: "Service.Method"
   174  	Seq           uint64   // sequence number chosen by client
   175  	next          *Request // for free list in Server
   176  }
   177  
   178  // Response is a header written before every RPC return. It is used internally
   179  // but documented here as an aid to debugging, such as when analyzing
   180  // network traffic.
   181  type Response struct {
   182  	ServiceMethod string    // echoes that of the Request
   183  	Seq           uint64    // echoes that of the request
   184  	Error         string    // error, if any.
   185  	next          *Response // for free list in Server
   186  }
   187  
   188  // Server represents an RPC Server.
   189  type Server struct {
   190  	serviceMap sync.Map   // map[string]*service
   191  	reqLock    sync.Mutex // protects freeReq
   192  	freeReq    *Request
   193  	respLock   sync.Mutex // protects freeResp
   194  	freeResp   *Response
   195  }
   196  
   197  // NewServer returns a new [Server].
   198  func NewServer() *Server {
   199  	return &Server{}
   200  }
   201  
   202  // DefaultServer is the default instance of [*Server].
   203  var DefaultServer = NewServer()
   204  
   205  // Is this type exported or a builtin?
   206  func isExportedOrBuiltinType(t reflect.Type) bool {
   207  	for t.Kind() == reflect.Pointer {
   208  		t = t.Elem()
   209  	}
   210  	// PkgPath will be non-empty even for an exported type,
   211  	// so we need to check the type name as well.
   212  	return token.IsExported(t.Name()) || t.PkgPath() == ""
   213  }
   214  
   215  // Register publishes in the server the set of methods of the
   216  // receiver value that satisfy the following conditions:
   217  //   - exported method of exported type
   218  //   - two arguments, both of exported type
   219  //   - the second argument is a pointer
   220  //   - one return value, of type error
   221  //
   222  // It returns an error if the receiver is not an exported type or has
   223  // no suitable methods. It also logs the error using package log.
   224  // The client accesses each method using a string of the form "Type.Method",
   225  // where Type is the receiver's concrete type.
   226  func (server *Server) Register(rcvr any) error {
   227  	return server.register(rcvr, "", false)
   228  }
   229  
   230  // RegisterName is like [Register] but uses the provided name for the type
   231  // instead of the receiver's concrete type.
   232  func (server *Server) RegisterName(name string, rcvr any) error {
   233  	return server.register(rcvr, name, true)
   234  }
   235  
   236  // logRegisterError specifies whether to log problems during method registration.
   237  // To debug registration, recompile the package with this set to true.
   238  const logRegisterError = false
   239  
   240  func (server *Server) register(rcvr any, name string, useName bool) error {
   241  	s := new(service)
   242  	s.typ = reflect.TypeOf(rcvr)
   243  	s.rcvr = reflect.ValueOf(rcvr)
   244  	sname := name
   245  	if !useName {
   246  		sname = reflect.Indirect(s.rcvr).Type().Name()
   247  	}
   248  	if sname == "" {
   249  		s := "rpc.Register: no service name for type " + s.typ.String()
   250  		log.Print(s)
   251  		return errors.New(s)
   252  	}
   253  	if !useName && !token.IsExported(sname) {
   254  		s := "rpc.Register: type " + sname + " is not exported"
   255  		log.Print(s)
   256  		return errors.New(s)
   257  	}
   258  	s.name = sname
   259  
   260  	// Install the methods
   261  	s.method = suitableMethods(s.typ, logRegisterError)
   262  
   263  	if len(s.method) == 0 {
   264  		str := ""
   265  
   266  		// To help the user, see if a pointer receiver would work.
   267  		method := suitableMethods(reflect.PointerTo(s.typ), false)
   268  		if len(method) != 0 {
   269  			str = "rpc.Register: type " + sname + " has no exported methods of suitable type (hint: pass a pointer to value of that type)"
   270  		} else {
   271  			str = "rpc.Register: type " + sname + " has no exported methods of suitable type"
   272  		}
   273  		log.Print(str)
   274  		return errors.New(str)
   275  	}
   276  
   277  	if _, dup := server.serviceMap.LoadOrStore(sname, s); dup {
   278  		return errors.New("rpc: service already defined: " + sname)
   279  	}
   280  	return nil
   281  }
   282  
   283  // suitableMethods returns suitable Rpc methods of typ. It will log
   284  // errors if logErr is true.
   285  func suitableMethods(typ reflect.Type, logErr bool) map[string]*methodType {
   286  	methods := make(map[string]*methodType)
   287  	for m := 0; m < typ.NumMethod(); m++ {
   288  		method := typ.Method(m)
   289  		mtype := method.Type
   290  		mname := method.Name
   291  		// Method must be exported.
   292  		if !method.IsExported() {
   293  			continue
   294  		}
   295  		// Method needs three ins: receiver, *args, *reply.
   296  		if mtype.NumIn() != 3 {
   297  			if logErr {
   298  				log.Printf("rpc.Register: method %q has %d input parameters; needs exactly three\n", mname, mtype.NumIn())
   299  			}
   300  			continue
   301  		}
   302  		// First arg need not be a pointer.
   303  		argType := mtype.In(1)
   304  		if !isExportedOrBuiltinType(argType) {
   305  			if logErr {
   306  				log.Printf("rpc.Register: argument type of method %q is not exported: %q\n", mname, argType)
   307  			}
   308  			continue
   309  		}
   310  		// Second arg must be a pointer.
   311  		replyType := mtype.In(2)
   312  		if replyType.Kind() != reflect.Pointer {
   313  			if logErr {
   314  				log.Printf("rpc.Register: reply type of method %q is not a pointer: %q\n", mname, replyType)
   315  			}
   316  			continue
   317  		}
   318  		// Reply type must be exported.
   319  		if !isExportedOrBuiltinType(replyType) {
   320  			if logErr {
   321  				log.Printf("rpc.Register: reply type of method %q is not exported: %q\n", mname, replyType)
   322  			}
   323  			continue
   324  		}
   325  		// Method needs one out.
   326  		if mtype.NumOut() != 1 {
   327  			if logErr {
   328  				log.Printf("rpc.Register: method %q has %d output parameters; needs exactly one\n", mname, mtype.NumOut())
   329  			}
   330  			continue
   331  		}
   332  		// The return type of the method must be error.
   333  		if returnType := mtype.Out(0); returnType != typeOfError {
   334  			if logErr {
   335  				log.Printf("rpc.Register: return type of method %q is %q, must be error\n", mname, returnType)
   336  			}
   337  			continue
   338  		}
   339  		methods[mname] = &methodType{method: method, ArgType: argType, ReplyType: replyType}
   340  	}
   341  	return methods
   342  }
   343  
   344  // A value sent as a placeholder for the server's response value when the server
   345  // receives an invalid request. It is never decoded by the client since the Response
   346  // contains an error when it is used.
   347  var invalidRequest = struct{}{}
   348  
   349  func (server *Server) sendResponse(sending *sync.Mutex, req *Request, reply any, codec ServerCodec, errmsg string) {
   350  	resp := server.getResponse()
   351  	// Encode the response header
   352  	resp.ServiceMethod = req.ServiceMethod
   353  	if errmsg != "" {
   354  		resp.Error = errmsg
   355  		reply = invalidRequest
   356  	}
   357  	resp.Seq = req.Seq
   358  	sending.Lock()
   359  	err := codec.WriteResponse(resp, reply)
   360  	if debugLog && err != nil {
   361  		log.Println("rpc: writing response:", err)
   362  	}
   363  	sending.Unlock()
   364  	server.freeResponse(resp)
   365  }
   366  
   367  func (m *methodType) NumCalls() (n uint) {
   368  	m.Lock()
   369  	n = m.numCalls
   370  	m.Unlock()
   371  	return n
   372  }
   373  
   374  func (s *service) call(server *Server, sending *sync.Mutex, wg *sync.WaitGroup, mtype *methodType, req *Request, argv, replyv reflect.Value, codec ServerCodec) {
   375  	if wg != nil {
   376  		defer wg.Done()
   377  	}
   378  	mtype.Lock()
   379  	mtype.numCalls++
   380  	mtype.Unlock()
   381  	function := mtype.method.Func
   382  	// Invoke the method, providing a new value for the reply.
   383  	returnValues := function.Call([]reflect.Value{s.rcvr, argv, replyv})
   384  	// The return value for the method is an error.
   385  	errInter := returnValues[0].Interface()
   386  	errmsg := ""
   387  	if errInter != nil {
   388  		errmsg = errInter.(error).Error()
   389  	}
   390  	server.sendResponse(sending, req, replyv.Interface(), codec, errmsg)
   391  	server.freeRequest(req)
   392  }
   393  
   394  type gobServerCodec struct {
   395  	rwc    io.ReadWriteCloser
   396  	dec    *gob.Decoder
   397  	enc    *gob.Encoder
   398  	encBuf *bufio.Writer
   399  	closed bool
   400  }
   401  
   402  func (c *gobServerCodec) ReadRequestHeader(r *Request) error {
   403  	return c.dec.Decode(r)
   404  }
   405  
   406  func (c *gobServerCodec) ReadRequestBody(body any) error {
   407  	return c.dec.Decode(body)
   408  }
   409  
   410  func (c *gobServerCodec) WriteResponse(r *Response, body any) (err error) {
   411  	if err = c.enc.Encode(r); err != nil {
   412  		if c.encBuf.Flush() == nil {
   413  			// Gob couldn't encode the header. Should not happen, so if it does,
   414  			// shut down the connection to signal that the connection is broken.
   415  			log.Println("rpc: gob error encoding response:", err)
   416  			c.Close()
   417  		}
   418  		return
   419  	}
   420  	if err = c.enc.Encode(body); err != nil {
   421  		if c.encBuf.Flush() == nil {
   422  			// Was a gob problem encoding the body but the header has been written.
   423  			// Shut down the connection to signal that the connection is broken.
   424  			log.Println("rpc: gob error encoding body:", err)
   425  			c.Close()
   426  		}
   427  		return
   428  	}
   429  	return c.encBuf.Flush()
   430  }
   431  
   432  func (c *gobServerCodec) Close() error {
   433  	if c.closed {
   434  		// Only call c.rwc.Close once; otherwise the semantics are undefined.
   435  		return nil
   436  	}
   437  	c.closed = true
   438  	return c.rwc.Close()
   439  }
   440  
   441  // ServeConn runs the server on a single connection.
   442  // ServeConn blocks, serving the connection until the client hangs up.
   443  // The caller typically invokes ServeConn in a go statement.
   444  // ServeConn uses the gob wire format (see package gob) on the
   445  // connection. To use an alternate codec, use [ServeCodec].
   446  // See [NewClient]'s comment for information about concurrent access.
   447  func (server *Server) ServeConn(conn io.ReadWriteCloser) {
   448  	buf := bufio.NewWriter(conn)
   449  	srv := &gobServerCodec{
   450  		rwc:    conn,
   451  		dec:    gob.NewDecoder(conn),
   452  		enc:    gob.NewEncoder(buf),
   453  		encBuf: buf,
   454  	}
   455  	server.ServeCodec(srv)
   456  }
   457  
   458  // ServeCodec is like [ServeConn] but uses the specified codec to
   459  // decode requests and encode responses.
   460  func (server *Server) ServeCodec(codec ServerCodec) {
   461  	sending := new(sync.Mutex)
   462  	wg := new(sync.WaitGroup)
   463  	for {
   464  		service, mtype, req, argv, replyv, keepReading, err := server.readRequest(codec)
   465  		if err != nil {
   466  			if debugLog && err != io.EOF {
   467  				log.Println("rpc:", err)
   468  			}
   469  			if !keepReading {
   470  				break
   471  			}
   472  			// send a response if we actually managed to read a header.
   473  			if req != nil {
   474  				server.sendResponse(sending, req, invalidRequest, codec, err.Error())
   475  				server.freeRequest(req)
   476  			}
   477  			continue
   478  		}
   479  		wg.Add(1)
   480  		go service.call(server, sending, wg, mtype, req, argv, replyv, codec)
   481  	}
   482  	// We've seen that there are no more requests.
   483  	// Wait for responses to be sent before closing codec.
   484  	wg.Wait()
   485  	codec.Close()
   486  }
   487  
   488  // ServeRequest is like [ServeCodec] but synchronously serves a single request.
   489  // It does not close the codec upon completion.
   490  func (server *Server) ServeRequest(codec ServerCodec) error {
   491  	sending := new(sync.Mutex)
   492  	service, mtype, req, argv, replyv, keepReading, err := server.readRequest(codec)
   493  	if err != nil {
   494  		if !keepReading {
   495  			return err
   496  		}
   497  		// send a response if we actually managed to read a header.
   498  		if req != nil {
   499  			server.sendResponse(sending, req, invalidRequest, codec, err.Error())
   500  			server.freeRequest(req)
   501  		}
   502  		return err
   503  	}
   504  	service.call(server, sending, nil, mtype, req, argv, replyv, codec)
   505  	return nil
   506  }
   507  
   508  func (server *Server) getRequest() *Request {
   509  	server.reqLock.Lock()
   510  	req := server.freeReq
   511  	if req == nil {
   512  		req = new(Request)
   513  	} else {
   514  		server.freeReq = req.next
   515  		*req = Request{}
   516  	}
   517  	server.reqLock.Unlock()
   518  	return req
   519  }
   520  
   521  func (server *Server) freeRequest(req *Request) {
   522  	server.reqLock.Lock()
   523  	req.next = server.freeReq
   524  	server.freeReq = req
   525  	server.reqLock.Unlock()
   526  }
   527  
   528  func (server *Server) getResponse() *Response {
   529  	server.respLock.Lock()
   530  	resp := server.freeResp
   531  	if resp == nil {
   532  		resp = new(Response)
   533  	} else {
   534  		server.freeResp = resp.next
   535  		*resp = Response{}
   536  	}
   537  	server.respLock.Unlock()
   538  	return resp
   539  }
   540  
   541  func (server *Server) freeResponse(resp *Response) {
   542  	server.respLock.Lock()
   543  	resp.next = server.freeResp
   544  	server.freeResp = resp
   545  	server.respLock.Unlock()
   546  }
   547  
   548  func (server *Server) readRequest(codec ServerCodec) (service *service, mtype *methodType, req *Request, argv, replyv reflect.Value, keepReading bool, err error) {
   549  	service, mtype, req, keepReading, err = server.readRequestHeader(codec)
   550  	if err != nil {
   551  		if !keepReading {
   552  			return
   553  		}
   554  		// discard body
   555  		codec.ReadRequestBody(nil)
   556  		return
   557  	}
   558  
   559  	// Decode the argument value.
   560  	argIsValue := false // if true, need to indirect before calling.
   561  	if mtype.ArgType.Kind() == reflect.Pointer {
   562  		argv = reflect.New(mtype.ArgType.Elem())
   563  	} else {
   564  		argv = reflect.New(mtype.ArgType)
   565  		argIsValue = true
   566  	}
   567  	// argv guaranteed to be a pointer now.
   568  	if err = codec.ReadRequestBody(argv.Interface()); err != nil {
   569  		return
   570  	}
   571  	if argIsValue {
   572  		argv = argv.Elem()
   573  	}
   574  
   575  	replyv = reflect.New(mtype.ReplyType.Elem())
   576  
   577  	switch mtype.ReplyType.Elem().Kind() {
   578  	case reflect.Map:
   579  		replyv.Elem().Set(reflect.MakeMap(mtype.ReplyType.Elem()))
   580  	case reflect.Slice:
   581  		replyv.Elem().Set(reflect.MakeSlice(mtype.ReplyType.Elem(), 0, 0))
   582  	}
   583  	return
   584  }
   585  
   586  func (server *Server) readRequestHeader(codec ServerCodec) (svc *service, mtype *methodType, req *Request, keepReading bool, err error) {
   587  	// Grab the request header.
   588  	req = server.getRequest()
   589  	err = codec.ReadRequestHeader(req)
   590  	if err != nil {
   591  		req = nil
   592  		if err == io.EOF || err == io.ErrUnexpectedEOF {
   593  			return
   594  		}
   595  		err = errors.New("rpc: server cannot decode request: " + err.Error())
   596  		return
   597  	}
   598  
   599  	// We read the header successfully. If we see an error now,
   600  	// we can still recover and move on to the next request.
   601  	keepReading = true
   602  
   603  	dot := strings.LastIndex(req.ServiceMethod, ".")
   604  	if dot < 0 {
   605  		err = errors.New("rpc: service/method request ill-formed: " + req.ServiceMethod)
   606  		return
   607  	}
   608  	serviceName := req.ServiceMethod[:dot]
   609  	methodName := req.ServiceMethod[dot+1:]
   610  
   611  	// Look up the request.
   612  	svci, ok := server.serviceMap.Load(serviceName)
   613  	if !ok {
   614  		err = errors.New("rpc: can't find service " + req.ServiceMethod)
   615  		return
   616  	}
   617  	svc = svci.(*service)
   618  	mtype = svc.method[methodName]
   619  	if mtype == nil {
   620  		err = errors.New("rpc: can't find method " + req.ServiceMethod)
   621  	}
   622  	return
   623  }
   624  
   625  // Accept accepts connections on the listener and serves requests
   626  // for each incoming connection. Accept blocks until the listener
   627  // returns a non-nil error. The caller typically invokes Accept in a
   628  // go statement.
   629  func (server *Server) Accept(lis net.Listener) {
   630  	for {
   631  		conn, err := lis.Accept()
   632  		if err != nil {
   633  			log.Print("rpc.Serve: accept:", err.Error())
   634  			return
   635  		}
   636  		go server.ServeConn(conn)
   637  	}
   638  }
   639  
   640  // Register publishes the receiver's methods in the [DefaultServer].
   641  func Register(rcvr any) error { return DefaultServer.Register(rcvr) }
   642  
   643  // RegisterName is like [Register] but uses the provided name for the type
   644  // instead of the receiver's concrete type.
   645  func RegisterName(name string, rcvr any) error {
   646  	return DefaultServer.RegisterName(name, rcvr)
   647  }
   648  
   649  // A ServerCodec implements reading of RPC requests and writing of
   650  // RPC responses for the server side of an RPC session.
   651  // The server calls [ServerCodec.ReadRequestHeader] and [ServerCodec.ReadRequestBody] in pairs
   652  // to read requests from the connection, and it calls [ServerCodec.WriteResponse] to
   653  // write a response back. The server calls [ServerCodec.Close] when finished with the
   654  // connection. ReadRequestBody may be called with a nil
   655  // argument to force the body of the request to be read and discarded.
   656  // See [NewClient]'s comment for information about concurrent access.
   657  type ServerCodec interface {
   658  	ReadRequestHeader(*Request) error
   659  	ReadRequestBody(any) error
   660  	WriteResponse(*Response, any) error
   661  
   662  	// Close can be called multiple times and must be idempotent.
   663  	Close() error
   664  }
   665  
   666  // ServeConn runs the [DefaultServer] on a single connection.
   667  // ServeConn blocks, serving the connection until the client hangs up.
   668  // The caller typically invokes ServeConn in a go statement.
   669  // ServeConn uses the gob wire format (see package gob) on the
   670  // connection. To use an alternate codec, use [ServeCodec].
   671  // See [NewClient]'s comment for information about concurrent access.
   672  func ServeConn(conn io.ReadWriteCloser) {
   673  	DefaultServer.ServeConn(conn)
   674  }
   675  
   676  // ServeCodec is like [ServeConn] but uses the specified codec to
   677  // decode requests and encode responses.
   678  func ServeCodec(codec ServerCodec) {
   679  	DefaultServer.ServeCodec(codec)
   680  }
   681  
   682  // ServeRequest is like [ServeCodec] but synchronously serves a single request.
   683  // It does not close the codec upon completion.
   684  func ServeRequest(codec ServerCodec) error {
   685  	return DefaultServer.ServeRequest(codec)
   686  }
   687  
   688  // Accept accepts connections on the listener and serves requests
   689  // to [DefaultServer] for each incoming connection.
   690  // Accept blocks; the caller typically invokes it in a go statement.
   691  func Accept(lis net.Listener) { DefaultServer.Accept(lis) }
   692  
   693  // Can connect to RPC service using HTTP CONNECT to rpcPath.
   694  var connected = "200 Connected to Go RPC"
   695  
   696  // ServeHTTP implements an [http.Handler] that answers RPC requests.
   697  func (server *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
   698  	if req.Method != "CONNECT" {
   699  		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
   700  		w.WriteHeader(http.StatusMethodNotAllowed)
   701  		io.WriteString(w, "405 must CONNECT\n")
   702  		return
   703  	}
   704  	conn, _, err := w.(http.Hijacker).Hijack()
   705  	if err != nil {
   706  		log.Print("rpc hijacking ", req.RemoteAddr, ": ", err.Error())
   707  		return
   708  	}
   709  	io.WriteString(conn, "HTTP/1.0 "+connected+"\n\n")
   710  	server.ServeConn(conn)
   711  }
   712  
   713  // HandleHTTP registers an HTTP handler for RPC messages on rpcPath,
   714  // and a debugging handler on debugPath.
   715  // It is still necessary to invoke [http.Serve](), typically in a go statement.
   716  func (server *Server) HandleHTTP(rpcPath, debugPath string) {
   717  	http.Handle(rpcPath, server)
   718  	http.Handle(debugPath, debugHTTP{server})
   719  }
   720  
   721  // HandleHTTP registers an HTTP handler for RPC messages to [DefaultServer]
   722  // on [DefaultRPCPath] and a debugging handler on [DefaultDebugPath].
   723  // It is still necessary to invoke [http.Serve](), typically in a go statement.
   724  func HandleHTTP() {
   725  	DefaultServer.HandleHTTP(DefaultRPCPath, DefaultDebugPath)
   726  }
   727  

View as plain text