github.com/palisadeinc/bor@v0.0.0-20230615125219-ab7196213d15/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 "fmt" 22 "io" 23 "sync/atomic" 24 "time" 25 26 mapset "github.com/deckarep/golang-set" 27 28 "github.com/ethereum/go-ethereum/log" 29 ) 30 31 const MetadataApi = "rpc" 32 const EngineApi = "engine" 33 34 // CodecOption specifies which type of messages a codec supports. 35 // 36 // Deprecated: this option is no longer honored by Server. 37 type CodecOption int 38 39 const ( 40 // OptionMethodInvocation is an indication that the codec supports RPC method calls 41 OptionMethodInvocation CodecOption = 1 << iota 42 43 // OptionSubscriptions is an indication that the codec supports RPC notifications 44 OptionSubscriptions = 1 << iota // support pub sub 45 ) 46 47 // Server is an RPC server. 48 type Server struct { 49 services serviceRegistry 50 idgen func() ID 51 run int32 52 codecs mapset.Set 53 54 BatchLimit uint64 55 executionPool *SafePool 56 } 57 58 // NewServer creates a new server instance with no registered handlers. 59 func NewServer(executionPoolSize uint64, executionPoolRequesttimeout time.Duration) *Server { 60 server := &Server{ 61 idgen: randomIDGenerator(), 62 codecs: mapset.NewSet(), 63 run: 1, 64 executionPool: NewExecutionPool(int(executionPoolSize), executionPoolRequesttimeout), 65 } 66 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 func (s *Server) SetRPCBatchLimit(batchLimit uint64) { 75 s.BatchLimit = batchLimit 76 } 77 78 func (s *Server) SetExecutionPoolSize(n int) { 79 s.executionPool.ChangeSize(n) 80 } 81 82 func (s *Server) SetExecutionPoolRequestTimeout(n time.Duration) { 83 s.executionPool.ChangeTimeout(n) 84 } 85 86 func (s *Server) GetExecutionPoolRequestTimeout() time.Duration { 87 return s.executionPool.Timeout() 88 } 89 90 func (s *Server) GetExecutionPoolSize() int { 91 return s.executionPool.Size() 92 } 93 94 // RegisterName creates a service for the given receiver type under the given name. When no 95 // methods on the given receiver match the criteria to be either a RPC method or a 96 // subscription an error is returned. Otherwise a new service is created and added to the 97 // service collection this server provides to clients. 98 func (s *Server) RegisterName(name string, receiver interface{}) error { 99 return s.services.registerName(name, receiver) 100 } 101 102 // ServeCodec reads incoming requests from codec, calls the appropriate callback and writes 103 // the response back using the given codec. It will block until the codec is closed or the 104 // server is stopped. In either case the codec is closed. 105 // 106 // Note that codec options are no longer supported. 107 func (s *Server) ServeCodec(codec ServerCodec, options CodecOption) { 108 defer codec.close() 109 110 // Don't serve if server is stopped. 111 if atomic.LoadInt32(&s.run) == 0 { 112 return 113 } 114 115 // Add the codec to the set so it can be closed by Stop. 116 s.codecs.Add(codec) 117 defer s.codecs.Remove(codec) 118 119 c := initClient(codec, s.idgen, &s.services) 120 <-codec.closed() 121 c.Close() 122 } 123 124 // serveSingleRequest reads and processes a single RPC request from the given codec. This 125 // is used to serve HTTP connections. Subscriptions and reverse calls are not allowed in 126 // this mode. 127 func (s *Server) serveSingleRequest(ctx context.Context, codec ServerCodec) { 128 // Don't serve if server is stopped. 129 if atomic.LoadInt32(&s.run) == 0 { 130 return 131 } 132 133 h := newHandler(ctx, codec, s.idgen, &s.services, s.executionPool) 134 135 h.allowSubscribe = false 136 defer h.close(io.EOF, nil) 137 138 reqs, batch, err := codec.readBatch() 139 if err != nil { 140 if err != io.EOF { 141 if err1 := codec.writeJSON(ctx, err); err1 != nil { 142 log.Warn("WARNING - error in reading batch", "err", err1) 143 return 144 } 145 } 146 return 147 } 148 149 if batch { 150 if s.BatchLimit > 0 && len(reqs) > int(s.BatchLimit) { 151 if err1 := codec.writeJSON(ctx, errorMessage(fmt.Errorf("batch limit %d exceeded: %d requests given", s.BatchLimit, len(reqs)))); err1 != nil { 152 log.Warn("WARNING - requests given exceeds the batch limit", "err", err1) 153 log.Debug("batch limit %d exceeded: %d requests given", s.BatchLimit, len(reqs)) 154 } 155 } else { 156 //nolint:contextcheck 157 h.handleBatch(reqs) 158 } 159 } else { 160 //nolint:contextcheck 161 h.handleMsg(reqs[0]) 162 } 163 } 164 165 // Stop stops reading new requests, waits for stopPendingRequestTimeout to allow pending 166 // requests to finish, then closes all codecs which will cancel pending requests and 167 // subscriptions. 168 func (s *Server) Stop() { 169 if atomic.CompareAndSwapInt32(&s.run, 1, 0) { 170 log.Debug("RPC server shutting down") 171 s.codecs.Each(func(c interface{}) bool { 172 c.(ServerCodec).close() 173 return true 174 }) 175 } 176 } 177 178 // RPCService gives meta information about the server. 179 // e.g. gives information about the loaded modules. 180 type RPCService struct { 181 server *Server 182 } 183 184 // Modules returns the list of RPC services with their version number 185 func (s *RPCService) Modules() map[string]string { 186 s.server.services.mu.Lock() 187 defer s.server.services.mu.Unlock() 188 189 modules := make(map[string]string) 190 for name := range s.server.services.services { 191 modules[name] = "1.0" 192 } 193 return modules 194 } 195 196 // PeerInfo contains information about the remote end of the network connection. 197 // 198 // This is available within RPC method handlers through the context. Call 199 // PeerInfoFromContext to get information about the client connection related to 200 // the current method call. 201 type PeerInfo struct { 202 // Transport is name of the protocol used by the client. 203 // This can be "http", "ws" or "ipc". 204 Transport string 205 206 // Address of client. This will usually contain the IP address and port. 207 RemoteAddr string 208 209 // Addditional information for HTTP and WebSocket connections. 210 HTTP struct { 211 // Protocol version, i.e. "HTTP/1.1". This is not set for WebSocket. 212 Version string 213 // Header values sent by the client. 214 UserAgent string 215 Origin string 216 Host string 217 } 218 } 219 220 type peerInfoContextKey struct{} 221 222 // PeerInfoFromContext returns information about the client's network connection. 223 // Use this with the context passed to RPC method handler functions. 224 // 225 // The zero value is returned if no connection info is present in ctx. 226 func PeerInfoFromContext(ctx context.Context) PeerInfo { 227 info, _ := ctx.Value(peerInfoContextKey{}).(PeerInfo) 228 return info 229 }