diff options
Diffstat (limited to 'src/pkg/rpc/server.go')
-rw-r--r-- | src/pkg/rpc/server.go | 274 |
1 files changed, 137 insertions, 137 deletions
diff --git a/src/pkg/rpc/server.go b/src/pkg/rpc/server.go index 3e01a9d41..2fdae0b46 100644 --- a/src/pkg/rpc/server.go +++ b/src/pkg/rpc/server.go @@ -108,17 +108,17 @@ package rpc import ( - "gob"; - "http"; - "log"; - "io"; - "net"; - "os"; - "reflect"; - "strings"; - "sync"; - "unicode"; - "utf8"; + "gob" + "http" + "log" + "io" + "net" + "os" + "reflect" + "strings" + "sync" + "unicode" + "utf8" ) // Precompute the reflect type for os.Error. Can't use os.Error directly @@ -127,40 +127,40 @@ var unusedError *os.Error var typeOfOsError = reflect.Typeof(unusedError).(*reflect.PtrType).Elem() type methodType struct { - sync.Mutex; // protects counters - method reflect.Method; - argType *reflect.PtrType; - replyType *reflect.PtrType; - numCalls uint; + sync.Mutex // protects counters + method reflect.Method + argType *reflect.PtrType + replyType *reflect.PtrType + numCalls uint } type service struct { - name string; // name of service - rcvr reflect.Value; // receiver of methods for the service - typ reflect.Type; // type of the receiver - method map[string]*methodType; // registered methods + name string // name of service + rcvr reflect.Value // receiver of methods for the service + typ reflect.Type // type of the receiver + method map[string]*methodType // registered methods } // Request is a header written before every RPC call. It is used internally // but documented here as an aid to debugging, such as when analyzing // network traffic. type Request struct { - ServiceMethod string; // format: "Service.Method" - Seq uint64; // sequence number chosen by client + ServiceMethod string // format: "Service.Method" + Seq uint64 // sequence number chosen by client } // Response is a header written before every RPC return. It is used internally // but documented here as an aid to debugging, such as when analyzing // network traffic. type Response struct { - ServiceMethod string; // echoes that of the Request - Seq uint64; // echoes that of the request - Error string; // error, if any. + ServiceMethod string // echoes that of the Request + Seq uint64 // echoes that of the request + Error string // error, if any. } type serverType struct { - sync.Mutex; // protects the serviceMap - serviceMap map[string]*service; + sync.Mutex // protects the serviceMap + serviceMap map[string]*service } // This variable is a global whose "public" methods are really private methods @@ -170,198 +170,198 @@ var server = &serverType{serviceMap: make(map[string]*service)} // Is this a publicly visible - upper case - name? func isPublic(name string) bool { - rune, _ := utf8.DecodeRuneInString(name); - return unicode.IsUpper(rune); + rune, _ := utf8.DecodeRuneInString(name) + return unicode.IsUpper(rune) } func (server *serverType) register(rcvr interface{}) os.Error { - server.Lock(); - defer server.Unlock(); + server.Lock() + defer server.Unlock() if server.serviceMap == nil { server.serviceMap = make(map[string]*service) } - s := new(service); - s.typ = reflect.Typeof(rcvr); - s.rcvr = reflect.NewValue(rcvr); - sname := reflect.Indirect(s.rcvr).Type().Name(); + s := new(service) + s.typ = reflect.Typeof(rcvr) + s.rcvr = reflect.NewValue(rcvr) + sname := reflect.Indirect(s.rcvr).Type().Name() if sname == "" { log.Exit("rpc: no service name for type", s.typ.String()) } if !isPublic(sname) { - s := "rpc Register: type " + sname + " is not public"; - log.Stderr(s); - return os.ErrorString(s); + s := "rpc Register: type " + sname + " is not public" + log.Stderr(s) + return os.ErrorString(s) } if _, present := server.serviceMap[sname]; present { return os.ErrorString("rpc: service already defined: " + sname) } - s.name = sname; - s.method = make(map[string]*methodType); + s.name = sname + s.method = make(map[string]*methodType) // Install the methods for m := 0; m < s.typ.NumMethod(); m++ { - method := s.typ.Method(m); - mtype := method.Type; - mname := method.Name; + method := s.typ.Method(m) + mtype := method.Type + mname := method.Name if !isPublic(mname) { continue } // Method needs three ins: receiver, *args, *reply. // The args and reply must be structs until gobs are more general. if mtype.NumIn() != 3 { - log.Stderr("method", mname, "has wrong number of ins:", mtype.NumIn()); - continue; + log.Stderr("method", mname, "has wrong number of ins:", mtype.NumIn()) + continue } - argType, ok := mtype.In(1).(*reflect.PtrType); + argType, ok := mtype.In(1).(*reflect.PtrType) if !ok { - log.Stderr(mname, "arg type not a pointer:", mtype.In(1)); - continue; + log.Stderr(mname, "arg type not a pointer:", mtype.In(1)) + continue } if _, ok := argType.Elem().(*reflect.StructType); !ok { - log.Stderr(mname, "arg type not a pointer to a struct:", argType); - continue; + log.Stderr(mname, "arg type not a pointer to a struct:", argType) + continue } - replyType, ok := mtype.In(2).(*reflect.PtrType); + replyType, ok := mtype.In(2).(*reflect.PtrType) if !ok { - log.Stderr(mname, "reply type not a pointer:", mtype.In(2)); - continue; + log.Stderr(mname, "reply type not a pointer:", mtype.In(2)) + continue } if _, ok := replyType.Elem().(*reflect.StructType); !ok { - log.Stderr(mname, "reply type not a pointer to a struct:", replyType); - continue; + log.Stderr(mname, "reply type not a pointer to a struct:", replyType) + continue } if !isPublic(argType.Elem().Name()) { - log.Stderr(mname, "argument type not public:", argType); - continue; + log.Stderr(mname, "argument type not public:", argType) + continue } if !isPublic(replyType.Elem().Name()) { - log.Stderr(mname, "reply type not public:", replyType); - continue; + log.Stderr(mname, "reply type not public:", replyType) + continue } // Method needs one out: os.Error. if mtype.NumOut() != 1 { - log.Stderr("method", mname, "has wrong number of outs:", mtype.NumOut()); - continue; + log.Stderr("method", mname, "has wrong number of outs:", mtype.NumOut()) + continue } if returnType := mtype.Out(0); returnType != typeOfOsError { - log.Stderr("method", mname, "returns", returnType.String(), "not os.Error"); - continue; + log.Stderr("method", mname, "returns", returnType.String(), "not os.Error") + continue } - s.method[mname] = &methodType{method: method, argType: argType, replyType: replyType}; + s.method[mname] = &methodType{method: method, argType: argType, replyType: replyType} } if len(s.method) == 0 { - s := "rpc Register: type " + sname + " has no public methods of suitable type"; - log.Stderr(s); - return os.ErrorString(s); + s := "rpc Register: type " + sname + " has no public methods of suitable type" + log.Stderr(s) + return os.ErrorString(s) } - server.serviceMap[s.name] = s; - return nil; + server.serviceMap[s.name] = s + return nil } // A value sent as a placeholder for the response when the server receives an invalid request. type InvalidRequest struct { - marker int; + marker int } var invalidRequest = InvalidRequest{1} func _new(t *reflect.PtrType) *reflect.PtrValue { - v := reflect.MakeZero(t).(*reflect.PtrValue); - v.PointTo(reflect.MakeZero(t.Elem())); - return v; + v := reflect.MakeZero(t).(*reflect.PtrValue) + v.PointTo(reflect.MakeZero(t.Elem())) + return v } func sendResponse(sending *sync.Mutex, req *Request, reply interface{}, enc *gob.Encoder, errmsg string) { - resp := new(Response); + resp := new(Response) // Encode the response header - resp.ServiceMethod = req.ServiceMethod; + resp.ServiceMethod = req.ServiceMethod if errmsg != "" { resp.Error = errmsg } - resp.Seq = req.Seq; - sending.Lock(); - enc.Encode(resp); + resp.Seq = req.Seq + sending.Lock() + enc.Encode(resp) // Encode the reply value. - enc.Encode(reply); - sending.Unlock(); + enc.Encode(reply) + sending.Unlock() } func (s *service) call(sending *sync.Mutex, mtype *methodType, req *Request, argv, replyv reflect.Value, enc *gob.Encoder) { - mtype.Lock(); - mtype.numCalls++; - mtype.Unlock(); - function := mtype.method.Func; + mtype.Lock() + mtype.numCalls++ + mtype.Unlock() + function := mtype.method.Func // Invoke the method, providing a new value for the reply. - returnValues := function.Call([]reflect.Value{s.rcvr, argv, replyv}); + returnValues := function.Call([]reflect.Value{s.rcvr, argv, replyv}) // The return value for the method is an os.Error. - errInter := returnValues[0].Interface(); - errmsg := ""; + errInter := returnValues[0].Interface() + errmsg := "" if errInter != nil { errmsg = errInter.(os.Error).String() } - sendResponse(sending, req, replyv.Interface(), enc, errmsg); + sendResponse(sending, req, replyv.Interface(), enc, errmsg) } func (server *serverType) input(conn io.ReadWriteCloser) { - dec := gob.NewDecoder(conn); - enc := gob.NewEncoder(conn); - sending := new(sync.Mutex); + dec := gob.NewDecoder(conn) + enc := gob.NewEncoder(conn) + sending := new(sync.Mutex) for { // Grab the request header. - req := new(Request); - err := dec.Decode(req); + req := new(Request) + err := dec.Decode(req) if err != nil { if err == os.EOF || err == io.ErrUnexpectedEOF { - log.Stderr("rpc: ", err); - break; + log.Stderr("rpc: ", err) + break } - s := "rpc: server cannot decode request: " + err.String(); - sendResponse(sending, req, invalidRequest, enc, s); - continue; + s := "rpc: server cannot decode request: " + err.String() + sendResponse(sending, req, invalidRequest, enc, s) + continue } - serviceMethod := strings.Split(req.ServiceMethod, ".", 0); + serviceMethod := strings.Split(req.ServiceMethod, ".", 0) if len(serviceMethod) != 2 { - s := "rpc: service/method request ill:formed: " + req.ServiceMethod; - sendResponse(sending, req, invalidRequest, enc, s); - continue; + s := "rpc: service/method request ill:formed: " + req.ServiceMethod + sendResponse(sending, req, invalidRequest, enc, s) + continue } // Look up the request. - server.Lock(); - service, ok := server.serviceMap[serviceMethod[0]]; - server.Unlock(); + server.Lock() + service, ok := server.serviceMap[serviceMethod[0]] + server.Unlock() if !ok { - s := "rpc: can't find service " + req.ServiceMethod; - sendResponse(sending, req, invalidRequest, enc, s); - continue; + s := "rpc: can't find service " + req.ServiceMethod + sendResponse(sending, req, invalidRequest, enc, s) + continue } - mtype, ok := service.method[serviceMethod[1]]; + mtype, ok := service.method[serviceMethod[1]] if !ok { - s := "rpc: can't find method " + req.ServiceMethod; - sendResponse(sending, req, invalidRequest, enc, s); - continue; + s := "rpc: can't find method " + req.ServiceMethod + sendResponse(sending, req, invalidRequest, enc, s) + continue } // Decode the argument value. - argv := _new(mtype.argType); - replyv := _new(mtype.replyType); - err = dec.Decode(argv.Interface()); + argv := _new(mtype.argType) + replyv := _new(mtype.replyType) + err = dec.Decode(argv.Interface()) if err != nil { - log.Stderr("rpc: tearing down", serviceMethod[0], "connection:", err); - sendResponse(sending, req, replyv.Interface(), enc, err.String()); - continue; + log.Stderr("rpc: tearing down", serviceMethod[0], "connection:", err) + sendResponse(sending, req, replyv.Interface(), enc, err.String()) + continue } - go service.call(sending, mtype, req, argv, replyv, enc); + go service.call(sending, mtype, req, argv, replyv, enc) } - conn.Close(); + conn.Close() } func (server *serverType) accept(lis net.Listener) { for { - conn, err := lis.Accept(); + conn, err := lis.Accept() if err != nil { - log.Exit("rpc.Serve: accept:", err.String()) // TODO(r): exit? + log.Exit("rpc.Serve: accept:", err.String()) // TODO(r): exit? } - go server.input(conn); + go server.input(conn) } } @@ -372,17 +372,17 @@ func (server *serverType) accept(lis net.Listener) { // - one return value of type os.Error // It returns an error if the receiver is not public or has no // suitable methods. -func Register(rcvr interface{}) os.Error { return server.register(rcvr) } +func Register(rcvr interface{}) os.Error { return server.register(rcvr) } // ServeConn runs the server on a single connection. When the connection // completes, service terminates. ServeConn blocks; the caller typically // invokes it in a go statement. -func ServeConn(conn io.ReadWriteCloser) { go server.input(conn) } +func ServeConn(conn io.ReadWriteCloser) { go server.input(conn) } // Accept accepts connections on the listener and serves requests // for each incoming connection. Accept blocks; the caller typically // invokes it in a go statement. -func Accept(lis net.Listener) { server.accept(lis) } +func Accept(lis net.Listener) { server.accept(lis) } // Can connect to RPC service using HTTP CONNECT to rpcPath. var rpcPath string = "/_goRPC_" @@ -391,23 +391,23 @@ var connected = "200 Connected to Go RPC" func serveHTTP(c *http.Conn, req *http.Request) { if req.Method != "CONNECT" { - c.SetHeader("Content-Type", "text/plain; charset=utf-8"); - c.WriteHeader(http.StatusMethodNotAllowed); - io.WriteString(c, "405 must CONNECT to "+rpcPath+"\n"); - return; + c.SetHeader("Content-Type", "text/plain; charset=utf-8") + c.WriteHeader(http.StatusMethodNotAllowed) + io.WriteString(c, "405 must CONNECT to "+rpcPath+"\n") + return } - conn, _, err := c.Hijack(); + conn, _, err := c.Hijack() if err != nil { - log.Stderr("rpc hijacking ", c.RemoteAddr, ": ", err.String()); - return; + log.Stderr("rpc hijacking ", c.RemoteAddr, ": ", err.String()) + return } - io.WriteString(conn, "HTTP/1.0 "+connected+"\n\n"); - server.input(conn); + io.WriteString(conn, "HTTP/1.0 "+connected+"\n\n") + server.input(conn) } // HandleHTTP registers an HTTP handler for RPC messages. // It is still necessary to invoke http.Serve(), typically in a go statement. func HandleHTTP() { - http.Handle(rpcPath, http.HandlerFunc(serveHTTP)); - http.Handle(debugPath, http.HandlerFunc(debugHTTP)); + http.Handle(rpcPath, http.HandlerFunc(serveHTTP)) + http.Handle(debugPath, http.HandlerFunc(debugHTTP)) } |