Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(30)

Delta Between Two Patch Sets: src/pkg/rpc/server.go

Issue 2696041: code review 2696041: rpc: expose Server type to allow multiple RPC Server in... (Closed)
Left Patch Set: code review 2696041: rpc: expose Server type to allow multiple RPC Server in... Created 14 years, 5 months ago
Right Patch Set: code review 2696041: rpc: expose Server type to allow multiple RPC Server in... Created 14 years, 5 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « src/pkg/rpc/debug.go ('k') | src/pkg/rpc/server_test.go » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 // Copyright 2009 The Go Authors. All rights reserved. 1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 /* 5 /*
6 » The rpc package provides access to the public methods of an object acros s a 6 » The rpc package provides access to the exported methods of an object acr oss a
7 network or other I/O connection. A server registers an object, making i t visible 7 network or other I/O connection. A server registers an object, making i t visible
8 » as a service with the name of the type of the object. After registratio n, public 8 » as a service with the name of the type of the object. After registratio n, exported
9 methods of the object will be accessible remotely. A server may registe r multiple 9 methods of the object will be accessible remotely. A server may registe r multiple
10 objects (services) of different types but it is an error to register mul tiple 10 objects (services) of different types but it is an error to register mul tiple
11 objects of the same type. 11 objects of the same type.
12 12
13 Only methods that satisfy these criteria will be made available for remo te access; 13 Only methods that satisfy these criteria will be made available for remo te access;
14 other methods will be ignored: 14 other methods will be ignored:
15 15
16 » » - the method receiver and name are publicly visible, that is, be gin with an upper case letter. 16 » » - the method receiver and name are exported, that is, begin with an upper case letter.
17 » » - the method has two arguments, both pointers to publicly visibl e types. 17 » » - the method has two arguments, both pointers to exported types.
18 - the method has return type os.Error. 18 - the method has return type os.Error.
19 19
20 The method's first argument represents the arguments provided by the cal ler; the 20 The method's first argument represents the arguments provided by the cal ler; the
21 second argument represents the result parameters to be returned to the c aller. 21 second argument represents the result parameters to be returned to the c aller.
22 The method's return value, if non-nil, is passed back as a string that t he client 22 The method's return value, if non-nil, is passed back as a string that t he client
23 sees as an os.ErrorString. 23 sees as an os.ErrorString.
24 24
25 The server may handle requests on a single connection by calling ServeCo nn. More 25 The server may handle requests on a single connection by calling ServeCo nn. More
26 typically it will create a network listener and call Accept or, for an H TTP 26 typically it will create a network listener and call Accept or, for an H TTP
27 listener, HandleHTTP and http.Serve. 27 listener, HandleHTTP and http.Serve.
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
116 "io" 116 "io"
117 "net" 117 "net"
118 "os" 118 "os"
119 "reflect" 119 "reflect"
120 "strings" 120 "strings"
121 "sync" 121 "sync"
122 "unicode" 122 "unicode"
123 "utf8" 123 "utf8"
124 ) 124 )
125 125
126 const (
127 // Defaults used by HandleHTTP
128 DefaultRPCPath = "/_goRPC_"
129 DefaultDebugPath = "/debug/rpc"
130 )
131
126 // Precompute the reflect type for os.Error. Can't use os.Error directly 132 // Precompute the reflect type for os.Error. Can't use os.Error directly
127 // because Typeof takes an empty interface value. This is annoying. 133 // because Typeof takes an empty interface value. This is annoying.
128 var unusedError *os.Error 134 var unusedError *os.Error
129 var typeOfOsError = reflect.Typeof(unusedError).(*reflect.PtrType).Elem() 135 var typeOfOsError = reflect.Typeof(unusedError).(*reflect.PtrType).Elem()
130 136
131 type methodType struct { 137 type methodType struct {
132 sync.Mutex // protects counters 138 sync.Mutex // protects counters
133 method reflect.Method 139 method reflect.Method
134 argType *reflect.PtrType 140 argType *reflect.PtrType
135 replyType *reflect.PtrType 141 replyType *reflect.PtrType
(...skipping 23 matching lines...) Expand all
159 Seq uint64 // echoes that of the request 165 Seq uint64 // echoes that of the request
160 Error string // error, if any. 166 Error string // error, if any.
161 } 167 }
162 168
163 // ClientInfo records information about an RPC client connection. 169 // ClientInfo records information about an RPC client connection.
164 type ClientInfo struct { 170 type ClientInfo struct {
165 LocalAddr string 171 LocalAddr string
166 RemoteAddr string 172 RemoteAddr string
167 } 173 }
168 174
175 // Server represents an RPC Server.
169 type Server struct { 176 type Server struct {
170 sync.Mutex // protects the serviceMap 177 sync.Mutex // protects the serviceMap
171 serviceMap map[string]*service 178 serviceMap map[string]*service
172 } 179 }
173 180
181 // NewServer returns a new Server.
174 func NewServer() *Server { 182 func NewServer() *Server {
175 return &Server{serviceMap: make(map[string]*service)} 183 return &Server{serviceMap: make(map[string]*service)}
176 } 184 }
177 185
178 // DefaultServer is the default instance of *Server. 186 // DefaultServer is the default instance of *Server.
179 var DefaultServer = NewServer() 187 var DefaultServer = NewServer()
180 188
181 // Is this a publicly visible - upper case - name? 189 // Is this an exported - upper case - name?
182 func isPublic(name string) bool { 190 func isExported(name string) bool {
183 rune, _ := utf8.DecodeRuneInString(name) 191 rune, _ := utf8.DecodeRuneInString(name)
184 return unicode.IsUpper(rune) 192 return unicode.IsUpper(rune)
185 } 193 }
186 194
187 // Register publishes in the server the set of methods of the 195 // Register publishes in the server the set of methods of the
188 // receiver value that satisfy the following conditions: 196 // receiver value that satisfy the following conditions:
189 //» - public method 197 //» - exported method
rsc1 2010/10/24 03:47:23 s/public/exported/
190 //» - two arguments, both pointers to public structs 198 //» - two arguments, both pointers to exported structs
191 //» - one return value of type os.Error 199 //» - one return value, of type os.Error
rsc1 2010/10/24 03:47:23 s/value/value,/
192 // It returns an error if the receiver is not public or has no 200 // It returns an error if the receiver is not an exported type or has no
rsc1 2010/10/24 03:47:23 s/public/an exported type/. I don't remember why t
193 // suitable methods. 201 // suitable methods.
194 func (server *Server) Register(rcvr interface{}) os.Error { 202 func (server *Server) Register(rcvr interface{}) os.Error {
195 server.Lock() 203 server.Lock()
196 defer server.Unlock() 204 defer server.Unlock()
197 if server.serviceMap == nil { 205 if server.serviceMap == nil {
198 server.serviceMap = make(map[string]*service) 206 server.serviceMap = make(map[string]*service)
199 } 207 }
200 s := new(service) 208 s := new(service)
201 s.typ = reflect.Typeof(rcvr) 209 s.typ = reflect.Typeof(rcvr)
202 s.rcvr = reflect.NewValue(rcvr) 210 s.rcvr = reflect.NewValue(rcvr)
203 sname := reflect.Indirect(s.rcvr).Type().Name() 211 sname := reflect.Indirect(s.rcvr).Type().Name()
204 if sname == "" { 212 if sname == "" {
205 log.Exit("rpc: no service name for type", s.typ.String()) 213 log.Exit("rpc: no service name for type", s.typ.String())
206 } 214 }
207 » if s.typ.PkgPath() != "" && !isPublic(sname) { 215 » if s.typ.PkgPath() != "" && !isExported(sname) {
rsc1 2010/10/24 03:47:23 i know it says public here but let's fix all these
208 » » s := "rpc Register: type " + sname + " is not public" 216 » » s := "rpc Register: type " + sname + " is not exported"
209 log.Print(s) 217 log.Print(s)
210 return os.ErrorString(s) 218 return os.ErrorString(s)
211 } 219 }
212 if _, present := server.serviceMap[sname]; present { 220 if _, present := server.serviceMap[sname]; present {
213 return os.ErrorString("rpc: service already defined: " + sname) 221 return os.ErrorString("rpc: service already defined: " + sname)
214 } 222 }
215 s.name = sname 223 s.name = sname
216 s.method = make(map[string]*methodType) 224 s.method = make(map[string]*methodType)
217 225
218 // Install the methods 226 // Install the methods
219 for m := 0; m < s.typ.NumMethod(); m++ { 227 for m := 0; m < s.typ.NumMethod(); m++ {
220 method := s.typ.Method(m) 228 method := s.typ.Method(m)
221 mtype := method.Type 229 mtype := method.Type
222 mname := method.Name 230 mname := method.Name
223 » » if mtype.PkgPath() != "" || !isPublic(mname) { 231 » » if mtype.PkgPath() != "" || !isExported(mname) {
224 continue 232 continue
225 } 233 }
226 // Method needs three ins: receiver, *args, *reply. 234 // Method needs three ins: receiver, *args, *reply.
227 if mtype.NumIn() != 3 { 235 if mtype.NumIn() != 3 {
228 log.Println("method", mname, "has wrong number of ins:", mtype.NumIn()) 236 log.Println("method", mname, "has wrong number of ins:", mtype.NumIn())
229 continue 237 continue
230 } 238 }
231 argType, ok := mtype.In(1).(*reflect.PtrType) 239 argType, ok := mtype.In(1).(*reflect.PtrType)
232 if !ok { 240 if !ok {
233 log.Println(mname, "arg type not a pointer:", mtype.In(1 )) 241 log.Println(mname, "arg type not a pointer:", mtype.In(1 ))
234 continue 242 continue
235 } 243 }
236 replyType, ok := mtype.In(2).(*reflect.PtrType) 244 replyType, ok := mtype.In(2).(*reflect.PtrType)
237 if !ok { 245 if !ok {
238 log.Println(mname, "reply type not a pointer:", mtype.In (2)) 246 log.Println(mname, "reply type not a pointer:", mtype.In (2))
239 continue 247 continue
240 } 248 }
241 » » if argType.Elem().PkgPath() != "" && !isPublic(argType.Elem().Na me()) { 249 » » if argType.Elem().PkgPath() != "" && !isExported(argType.Elem(). Name()) {
242 » » » log.Println(mname, "argument type not public:", argType) 250 » » » log.Println(mname, "argument type not exported:", argTyp e)
243 » » » continue 251 » » » continue
244 » » } 252 » » }
245 » » if replyType.Elem().PkgPath() != "" && !isPublic(replyType.Elem( ).Name()) { 253 » » if replyType.Elem().PkgPath() != "" && !isExported(replyType.Ele m().Name()) {
246 » » » log.Println(mname, "reply type not public:", replyType) 254 » » » log.Println(mname, "reply type not exported:", replyType )
247 continue 255 continue
248 } 256 }
249 if mtype.NumIn() == 4 { 257 if mtype.NumIn() == 4 {
250 t := mtype.In(3) 258 t := mtype.In(3)
251 if t != reflect.Typeof((*ClientInfo)(nil)) { 259 if t != reflect.Typeof((*ClientInfo)(nil)) {
252 log.Println(mname, "last argument not *ClientInf o") 260 log.Println(mname, "last argument not *ClientInf o")
253 continue 261 continue
254 } 262 }
255 } 263 }
256 // Method needs one out: os.Error. 264 // Method needs one out: os.Error.
257 if mtype.NumOut() != 1 { 265 if mtype.NumOut() != 1 {
258 log.Println("method", mname, "has wrong number of outs:" , mtype.NumOut()) 266 log.Println("method", mname, "has wrong number of outs:" , mtype.NumOut())
259 continue 267 continue
260 } 268 }
261 if returnType := mtype.Out(0); returnType != typeOfOsError { 269 if returnType := mtype.Out(0); returnType != typeOfOsError {
262 log.Println("method", mname, "returns", returnType.Strin g(), "not os.Error") 270 log.Println("method", mname, "returns", returnType.Strin g(), "not os.Error")
263 continue 271 continue
264 } 272 }
265 s.method[mname] = &methodType{method: method, argType: argType, replyType: replyType} 273 s.method[mname] = &methodType{method: method, argType: argType, replyType: replyType}
266 } 274 }
267 275
268 if len(s.method) == 0 { 276 if len(s.method) == 0 {
269 » » s := "rpc Register: type " + sname + " has no public methods of suitable type" 277 » » s := "rpc Register: type " + sname + " has no exported methods o f suitable type"
270 log.Print(s) 278 log.Print(s)
271 return os.ErrorString(s) 279 return os.ErrorString(s)
272 } 280 }
273 server.serviceMap[s.name] = s 281 server.serviceMap[s.name] = s
274 return nil 282 return nil
275 } 283 }
276 284
277 // A value sent as a placeholder for the response when the server receives an in valid request. 285 // A value sent as a placeholder for the response when the server receives an in valid request.
278 type InvalidRequest struct { 286 type InvalidRequest struct {
279 marker int 287 marker int
(...skipping 30 matching lines...) Expand all
310 function := mtype.method.Func 318 function := mtype.method.Func
311 // Invoke the method, providing a new value for the reply. 319 // Invoke the method, providing a new value for the reply.
312 returnValues := function.Call([]reflect.Value{s.rcvr, argv, replyv}) 320 returnValues := function.Call([]reflect.Value{s.rcvr, argv, replyv})
313 // The return value for the method is an os.Error. 321 // The return value for the method is an os.Error.
314 errInter := returnValues[0].Interface() 322 errInter := returnValues[0].Interface()
315 errmsg := "" 323 errmsg := ""
316 if errInter != nil { 324 if errInter != nil {
317 errmsg = errInter.(os.Error).String() 325 errmsg = errInter.(os.Error).String()
318 } 326 }
319 sendResponse(sending, req, replyv.Interface(), codec, errmsg) 327 sendResponse(sending, req, replyv.Interface(), codec, errmsg)
320 }
321
322 // A ServerCodec implements reading of RPC requests and writing of
rsc1 2010/10/24 03:47:23 seems like a gratuitous move, but okay
323 // RPC responses for the server side of an RPC session.
324 // The server calls ReadRequestHeader and ReadRequestBody in pairs
325 // to read requests from the connection, and it calls WriteResponse to
326 // write a response back. The server calls Close when finished with the
327 // connection.
328 type ServerCodec interface {
329 ReadRequestHeader(*Request) os.Error
330 ReadRequestBody(interface{}) os.Error
331 WriteResponse(*Response, interface{}) os.Error
332
333 Close() os.Error
334 } 328 }
335 329
336 type gobServerCodec struct { 330 type gobServerCodec struct {
337 rwc io.ReadWriteCloser 331 rwc io.ReadWriteCloser
338 dec *gob.Decoder 332 dec *gob.Decoder
339 enc *gob.Encoder 333 enc *gob.Encoder
340 } 334 }
341 335
342 func (c *gobServerCodec) ReadRequestHeader(r *Request) os.Error { 336 func (c *gobServerCodec) ReadRequestHeader(r *Request) os.Error {
343 return c.dec.Decode(r) 337 return c.dec.Decode(r)
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
430 conn, err := lis.Accept() 424 conn, err := lis.Accept()
431 if err != nil { 425 if err != nil {
432 log.Exit("rpc.Serve: accept:", err.String()) // TODO(r): exit? 426 log.Exit("rpc.Serve: accept:", err.String()) // TODO(r): exit?
433 } 427 }
434 go server.ServeConn(conn) 428 go server.ServeConn(conn)
435 } 429 }
436 } 430 }
437 431
438 // Register publishes in the DefaultServer the set of methods· 432 // Register publishes in the DefaultServer the set of methods·
439 // of the receiver value that satisfy the following conditions: 433 // of the receiver value that satisfy the following conditions:
440 //» - public method 434 //» - exported method
441 //» - two arguments, both pointers to public structs 435 //» - two arguments, both pointers to exported structs
442 //» - one return value of type os.Error 436 //» - one return value, of type os.Error
443 // It returns an error if the receiver is not public or has no 437 // It returns an error if the receiver is not an exported type or has no
444 // suitable methods. 438 // suitable methods.
445 func Register(rcvr interface{}) os.Error { return DefaultServer.Register(rcvr) } 439 func Register(rcvr interface{}) os.Error { return DefaultServer.Register(rcvr) }
440
441 // A ServerCodec implements reading of RPC requests and writing of
442 // RPC responses for the server side of an RPC session.
443 // The server calls ReadRequestHeader and ReadRequestBody in pairs
444 // to read requests from the connection, and it calls WriteResponse to
445 // write a response back. The server calls Close when finished with the
446 // connection.
447 type ServerCodec interface {
448 ReadRequestHeader(*Request) os.Error
449 ReadRequestBody(interface{}) os.Error
450 WriteResponse(*Response, interface{}) os.Error
451
452 Close() os.Error
453 }
446 454
447 // ServeConn runs the DefaultServer on a single connection. 455 // ServeConn runs the DefaultServer on a single connection.
448 // ServeConn blocks, serving the connection until the client hangs up. 456 // ServeConn blocks, serving the connection until the client hangs up.
449 // The caller typically invokes ServeConn in a go statement. 457 // The caller typically invokes ServeConn in a go statement.
450 // ServeConn uses the gob wire format (see package gob) on the 458 // ServeConn uses the gob wire format (see package gob) on the
451 // connection. To use an alternate codec, use ServeCodec. 459 // connection. To use an alternate codec, use ServeCodec.
452 func ServeConn(conn io.ReadWriteCloser) { 460 func ServeConn(conn io.ReadWriteCloser) {
453 DefaultServer.ServeConn(conn) 461 DefaultServer.ServeConn(conn)
454 } 462 }
455 463
456 // ServeCodec is like ServeConn but uses the specified codec to 464 // ServeCodec is like ServeConn but uses the specified codec to
457 // decode requests and encode responses. 465 // decode requests and encode responses.
458 func ServeCodec(codec ServerCodec) { 466 func ServeCodec(codec ServerCodec) {
459 DefaultServer.ServeCodec(codec) 467 DefaultServer.ServeCodec(codec)
460 } 468 }
461 469
462 // Accept accepts connections on the listener and serves requests 470 // Accept accepts connections on the listener and serves requests
463 // to DefaultServer for each incoming connection.·· 471 // to DefaultServer for each incoming connection.··
464 // Accept blocks; the caller typically invokes it in a go statement. 472 // Accept blocks; the caller typically invokes it in a go statement.
465 func Accept(lis net.Listener) { DefaultServer.Accept(lis) } 473 func Accept(lis net.Listener) { DefaultServer.Accept(lis) }
466 474
467 // Can connect to RPC service using HTTP CONNECT to rpcPath. 475 // Can connect to RPC service using HTTP CONNECT to rpcPath.
468 var rpcPath string = "/_goRPC_"
469 var debugPath string = "/debug/rpc"
470 var connected = "200 Connected to Go RPC" 476 var connected = "200 Connected to Go RPC"
471 477
472 // ServeHTTP implements an http.Handler that answers RPC requests. 478 // ServeHTTP implements an http.Handler that answers RPC requests.
rsc1 2010/10/24 03:47:23 Probably want to export rpcPath too? And debugPath
473 func (server *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) { 479 func (server *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
474 if req.Method != "CONNECT" { 480 if req.Method != "CONNECT" {
475 w.SetHeader("Content-Type", "text/plain; charset=utf-8") 481 w.SetHeader("Content-Type", "text/plain; charset=utf-8")
476 w.WriteHeader(http.StatusMethodNotAllowed) 482 w.WriteHeader(http.StatusMethodNotAllowed)
477 » » io.WriteString(w, "405 must CONNECT to "+rpcPath+"\n") 483 » » io.WriteString(w, "405 must CONNECT\n")
478 return 484 return
479 } 485 }
480 conn, _, err := w.Hijack() 486 conn, _, err := w.Hijack()
481 if err != nil { 487 if err != nil {
482 log.Print("rpc hijacking ", w.RemoteAddr(), ": ", err.String()) 488 log.Print("rpc hijacking ", w.RemoteAddr(), ": ", err.String())
483 return 489 return
484 } 490 }
485 io.WriteString(conn, "HTTP/1.0 "+connected+"\n\n") 491 io.WriteString(conn, "HTTP/1.0 "+connected+"\n\n")
486 server.ServeConn(conn) 492 server.ServeConn(conn)
487 } 493 }
488 494
489 // HandleHTTP registers an HTTP handler for RPC messages. 495 // HandleHTTP registers an HTTP handler for RPC messages on rpcPath,
496 // and a debugging handler on debugPath.
490 // It is still necessary to invoke http.Serve(), typically in a go statement. 497 // It is still necessary to invoke http.Serve(), typically in a go statement.
491 func (server *Server) HandleHTTP() { 498 func (server *Server) HandleHTTP(rpcPath, debugPath string) {
492 http.Handle(rpcPath, server) 499 http.Handle(rpcPath, server)
493 http.Handle(debugPath, debugHTTP{server}) 500 http.Handle(debugPath, debugHTTP{server})
494 } 501 }
495 502
496 // HandleHTTP registers an HTTP handler for RPC messages to DefaultServer. 503 // HandleHTTP registers an HTTP handler for RPC messages to DefaultServer
504 // on DefaultRPCPath and a debugging handler on DefaultDebugPath.
497 // It is still necessary to invoke http.Serve(), typically in a go statement. 505 // It is still necessary to invoke http.Serve(), typically in a go statement.
498 func HandleHTTP() { 506 func HandleHTTP() {
499 » DefaultServer.HandleHTTP() 507 » DefaultServer.HandleHTTP(DefaultRPCPath, DefaultDebugPath)
500 } 508 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b