github.com/ethereum/go-ethereum@v1.16.1/rpc/server.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package rpc 18 19 import ( 20 "context" 21 "errors" 22 "io" 23 "net" 24 "sync" 25 "sync/atomic" 26 27 "github.com/ethereum/go-ethereum/log" 28 ) 29 30 const MetadataApi = "rpc" 31 const EngineApi = "engine" 32 33 // CodecOption specifies which type of messages a codec supports. 34 // 35 // Deprecated: this option is no longer honored by Server. 36 type CodecOption int 37 38 const ( 39 // OptionMethodInvocation is an indication that the codec supports RPC method calls 40 OptionMethodInvocation CodecOption = 1 << iota 41 42 // OptionSubscriptions is an indication that the codec supports RPC notifications 43 OptionSubscriptions = 1 << iota // support pub sub 44 ) 45 46 // Server is an RPC server. 47 type Server struct { 48 services serviceRegistry 49 idgen func() ID 50 51 mutex sync.Mutex 52 codecs map[ServerCodec]struct{} 53 run atomic.Bool 54 batchItemLimit int 55 batchResponseLimit int 56 httpBodyLimit int 57 } 58 59 // NewServer creates a new server instance with no registered handlers. 60 func NewServer() *Server { 61 server := &Server{ 62 idgen: randomIDGenerator(), 63 codecs: make(map[ServerCodec]struct{}), 64 httpBodyLimit: defaultBodyLimit, 65 } 66 server.run.Store(true) 67 // Register the default service providing meta information about the RPC service such 68 // as the services and methods it offers. 69 rpcService := &RPCService{server} 70 server.RegisterName(MetadataApi, rpcService) 71 return server 72 } 73 74 // SetBatchLimits sets limits applied to batch requests. There are two limits: 'itemLimit' 75 // is the maximum number of items in a batch. 'maxResponseSize' is the maximum number of 76 // response bytes across all requests in a batch. 77 // 78 // This method should be called before processing any requests via ServeCodec, ServeHTTP, 79 // ServeListener etc. 80 func (s *Server) SetBatchLimits(itemLimit, maxResponseSize int) { 81 s.batchItemLimit = itemLimit 82 s.batchResponseLimit = maxResponseSize 83 } 84 85 // SetHTTPBodyLimit sets the size limit for HTTP requests. 86 // 87 // This method should be called before processing any requests via ServeHTTP. 88 func (s *Server) SetHTTPBodyLimit(limit int) { 89 s.httpBodyLimit = limit 90 } 91 92 // RegisterName creates a service for the given receiver type under the given name. When no 93 // methods on the given receiver match the criteria to be either an RPC method or a 94 // subscription an error is returned. Otherwise a new service is created and added to the 95 // service collection this server provides to clients. 96 func (s *Server) RegisterName(name string, receiver interface{}) error { 97 return s.services.registerName(name, receiver) 98 } 99 100 // ServeCodec reads incoming requests from codec, calls the appropriate callback and writes 101 // the response back using the given codec. It will block until the codec is closed or the 102 // server is stopped. In either case the codec is closed. 103 // 104 // Note that codec options are no longer supported. 105 func (s *Server) ServeCodec(codec ServerCodec, options CodecOption) { 106 defer codec.close() 107 108 if !s.trackCodec(codec) { 109 return 110 } 111 defer s.untrackCodec(codec) 112 113 cfg := &clientConfig{ 114 idgen: s.idgen, 115 batchItemLimit: s.batchItemLimit, 116 batchResponseLimit: s.batchResponseLimit, 117 } 118 c := initClient(codec, &s.services, cfg) 119 <-codec.closed() 120 c.Close() 121 } 122 123 func (s *Server) trackCodec(codec ServerCodec) bool { 124 s.mutex.Lock() 125 defer s.mutex.Unlock() 126 127 if !s.run.Load() { 128 return false // Don't serve if server is stopped. 129 } 130 s.codecs[codec] = struct{}{} 131 return true 132 } 133 134 func (s *Server) untrackCodec(codec ServerCodec) { 135 s.mutex.Lock() 136 defer s.mutex.Unlock() 137 138 delete(s.codecs, codec) 139 } 140 141 // serveSingleRequest reads and processes a single RPC request from the given codec. This 142 // is used to serve HTTP connections. Subscriptions and reverse calls are not allowed in 143 // this mode. 144 func (s *Server) serveSingleRequest(ctx context.Context, codec ServerCodec) { 145 // Don't serve if server is stopped. 146 if !s.run.Load() { 147 return 148 } 149 150 h := newHandler(ctx, codec, s.idgen, &s.services, s.batchItemLimit, s.batchResponseLimit) 151 h.allowSubscribe = false 152 defer h.close(io.EOF, nil) 153 154 reqs, batch, err := codec.readBatch() 155 if err != nil { 156 if msg := messageForReadError(err); msg != "" { 157 resp := errorMessage(&invalidMessageError{msg}) 158 codec.writeJSON(ctx, resp, true) 159 } 160 return 161 } 162 if batch { 163 h.handleBatch(reqs) 164 } else { 165 h.handleMsg(reqs[0]) 166 } 167 } 168 169 func messageForReadError(err error) string { 170 var netErr net.Error 171 if errors.As(err, &netErr) { 172 if netErr.Timeout() { 173 return "read timeout" 174 } else { 175 return "read error" 176 } 177 } else if err != io.EOF { 178 return "parse error" 179 } 180 return "" 181 } 182 183 // Stop stops reading new requests, waits for stopPendingRequestTimeout to allow pending 184 // requests to finish, then closes all codecs which will cancel pending requests and 185 // subscriptions. 186 func (s *Server) Stop() { 187 s.mutex.Lock() 188 defer s.mutex.Unlock() 189 190 if s.run.CompareAndSwap(true, false) { 191 log.Debug("RPC server shutting down") 192 for codec := range s.codecs { 193 codec.close() 194 } 195 } 196 } 197 198 // RPCService gives meta information about the server. 199 // e.g. gives information about the loaded modules. 200 type RPCService struct { 201 server *Server 202 } 203 204 // Modules returns the list of RPC services with their version number 205 func (s *RPCService) Modules() map[string]string { 206 s.server.services.mu.Lock() 207 defer s.server.services.mu.Unlock() 208 209 modules := make(map[string]string) 210 for name := range s.server.services.services { 211 modules[name] = "1.0" 212 } 213 return modules 214 } 215 216 // PeerInfo contains information about the remote end of the network connection. 217 // 218 // This is available within RPC method handlers through the context. Call 219 // PeerInfoFromContext to get information about the client connection related to 220 // the current method call. 221 type PeerInfo struct { 222 // Transport is name of the protocol used by the client. 223 // This can be "http", "ws" or "ipc". 224 Transport string 225 226 // Address of client. This will usually contain the IP address and port. 227 RemoteAddr string 228 229 // Additional information for HTTP and WebSocket connections. 230 HTTP struct { 231 // Protocol version, i.e. "HTTP/1.1". This is not set for WebSocket. 232 Version string 233 // Header values sent by the client. 234 UserAgent string 235 Origin string 236 Host string 237 } 238 } 239 240 type peerInfoContextKey struct{} 241 242 // PeerInfoFromContext returns information about the client's network connection. 243 // Use this with the context passed to RPC method handler functions. 244 // 245 // The zero value is returned if no connection info is present in ctx. 246 func PeerInfoFromContext(ctx context.Context) PeerInfo { 247 info, _ := ctx.Value(peerInfoContextKey{}).(PeerInfo) 248 return info 249 }