Jiri Simsa | d7616c9 | 2015-03-24 23:44:30 -0700 | [diff] [blame] | 1 | // Copyright 2015 The Vanadium 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 | |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 5 | // The app package contains the struct that keeps per javascript app state and handles translating |
Suharsh Sivakumar | d1cc6e0 | 2015-03-16 13:58:49 -0700 | [diff] [blame] | 6 | // javascript requests to vanadium requests and vice versa. |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 7 | package app |
| 8 | |
| 9 | import ( |
Shyam Jayaraman | 251f9d3 | 2015-05-29 09:27:48 -0700 | [diff] [blame] | 10 | "bytes" |
| 11 | "encoding/hex" |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 12 | "fmt" |
| 13 | "io" |
Todd Wang | 5ab0366 | 2015-02-19 21:03:01 -0800 | [diff] [blame] | 14 | "reflect" |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 15 | "sync" |
| 16 | "time" |
| 17 | |
Jiri Simsa | 1f1302c | 2015-02-23 16:18:34 -0800 | [diff] [blame] | 18 | "v.io/v23" |
| 19 | "v.io/v23/context" |
Shyam Jayaraman | 8e301b5 | 2015-04-27 14:12:16 -0700 | [diff] [blame] | 20 | "v.io/v23/i18n" |
Jiri Simsa | 1f1302c | 2015-02-23 16:18:34 -0800 | [diff] [blame] | 21 | "v.io/v23/naming" |
| 22 | "v.io/v23/options" |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 23 | "v.io/v23/rpc" |
Jiri Simsa | 1f1302c | 2015-02-23 16:18:34 -0800 | [diff] [blame] | 24 | "v.io/v23/security" |
| 25 | "v.io/v23/vdl" |
Todd Wang | ac9e190 | 2015-02-25 01:58:01 -0800 | [diff] [blame] | 26 | "v.io/v23/vdlroot/signature" |
Jiri Simsa | 1f1302c | 2015-02-23 16:18:34 -0800 | [diff] [blame] | 27 | "v.io/v23/verror" |
Jiri Simsa | 1f1302c | 2015-02-23 16:18:34 -0800 | [diff] [blame] | 28 | "v.io/v23/vom" |
| 29 | "v.io/v23/vtrace" |
Todd Wang | 5b77a34 | 2015-04-06 18:31:37 -0700 | [diff] [blame] | 30 | "v.io/x/ref/services/wspr/internal/lib" |
| 31 | "v.io/x/ref/services/wspr/internal/namespace" |
| 32 | "v.io/x/ref/services/wspr/internal/principal" |
| 33 | "v.io/x/ref/services/wspr/internal/rpc/server" |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 34 | ) |
| 35 | |
Nicolas Lacasse | 938c472 | 2015-03-19 14:42:18 -0700 | [diff] [blame] | 36 | const ( |
| 37 | // pkgPath is the prefix os errors in this package. |
Todd Wang | 5b77a34 | 2015-04-06 18:31:37 -0700 | [diff] [blame] | 38 | pkgPath = "v.io/x/ref/services/wspr/internal/app" |
Shyam Jayaraman | 251f9d3 | 2015-05-29 09:27:48 -0700 | [diff] [blame] | 39 | |
| 40 | typeFlow = 0 |
Nicolas Lacasse | 938c472 | 2015-03-19 14:42:18 -0700 | [diff] [blame] | 41 | ) |
Mike Burrows | b6689c2 | 2014-10-08 11:14:15 -0700 | [diff] [blame] | 42 | |
| 43 | // Errors |
Ankur | e788924 | 2014-10-20 18:37:29 -0700 | [diff] [blame] | 44 | var ( |
Benjamin Prosnitz | ae30020 | 2015-06-04 19:36:49 -0700 | [diff] [blame] | 45 | marshallingError = verror.Register(pkgPath+".marshallingError", verror.NoRetry, "{1} {2} marshalling error {_}") |
| 46 | noResults = verror.Register(pkgPath+".noResults", verror.NoRetry, "{1} {2} no results from call {_}") |
| 47 | badCaveatType = verror.Register(pkgPath+".badCaveatType", verror.NoRetry, "{1} {2} bad caveat type {_}") |
| 48 | unknownBlessings = verror.Register(pkgPath+".unknownBlessings", verror.NoRetry, "{1} {2} unknown public id {_}") |
Ankur | e788924 | 2014-10-20 18:37:29 -0700 | [diff] [blame] | 49 | ) |
Mike Burrows | b6689c2 | 2014-10-08 11:14:15 -0700 | [diff] [blame] | 50 | |
Matt Rosencrantz | 4aabe57 | 2014-10-22 09:25:50 -0700 | [diff] [blame] | 51 | type outstandingRequest struct { |
| 52 | stream *outstandingStream |
| 53 | cancel context.CancelFunc |
| 54 | } |
| 55 | |
Suharsh Sivakumar | d1cc6e0 | 2015-03-16 13:58:49 -0700 | [diff] [blame] | 56 | // Controller represents all the state of a Vanadium Web App. This is the struct |
| 57 | // that is in charge performing all the vanadium options. |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 58 | type Controller struct { |
| 59 | // Protects everything. |
| 60 | // TODO(bjornick): We need to split this up. |
| 61 | sync.Mutex |
| 62 | |
Matt Rosencrantz | c90eb7b | 2015-01-09 08:32:01 -0800 | [diff] [blame] | 63 | // The context of this controller. |
| 64 | ctx *context.T |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 65 | |
Matt Rosencrantz | c90eb7b | 2015-01-09 08:32:01 -0800 | [diff] [blame] | 66 | // The cleanup function for this controller. |
| 67 | cancel context.CancelFunc |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 68 | |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 69 | // The rpc.ListenSpec to use with server.Listen |
| 70 | listenSpec *rpc.ListenSpec |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 71 | |
| 72 | // Used to generate unique ids for requests initiated by the proxy. |
| 73 | // These ids will be even so they don't collide with the ids generated |
| 74 | // by the client. |
Benjamin Prosnitz | 86d5228 | 2014-12-19 15:48:38 -0800 | [diff] [blame] | 75 | lastGeneratedId int32 |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 76 | |
Matt Rosencrantz | 4aabe57 | 2014-10-22 09:25:50 -0700 | [diff] [blame] | 77 | // Used to keep track of data (streams and cancellation functions) for |
| 78 | // outstanding requests. |
Benjamin Prosnitz | 86d5228 | 2014-12-19 15:48:38 -0800 | [diff] [blame] | 79 | outstandingRequests map[int32]*outstandingRequest |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 80 | |
| 81 | // Maps flowids to the server that owns them. |
Benjamin Prosnitz | bf71e96 | 2015-04-14 16:43:07 -0700 | [diff] [blame] | 82 | flowMap map[int32]interface{} |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 83 | |
| 84 | // A manager that Handles fetching and caching signature of remote services |
| 85 | signatureManager lib.SignatureManager |
| 86 | |
Suharsh Sivakumar | d1cc6e0 | 2015-03-16 13:58:49 -0700 | [diff] [blame] | 87 | // We maintain multiple Vanadium server per pipe for serving JavaScript |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 88 | // services. |
Benjamin Prosnitz | 86d5228 | 2014-12-19 15:48:38 -0800 | [diff] [blame] | 89 | servers map[uint32]*server.Server |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 90 | |
| 91 | // Creates a client writer for a given flow. This is a member so that tests can override |
| 92 | // the default implementation. |
Benjamin Prosnitz | 86d5228 | 2014-12-19 15:48:38 -0800 | [diff] [blame] | 93 | writerCreator func(id int32) lib.ClientWriter |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 94 | |
Benjamin Prosnitz | c65917c | 2015-05-26 14:21:53 -0700 | [diff] [blame] | 95 | // Cache of Blessings that were sent to Javascript. |
| 96 | blessingsCache *principal.BlessingsCache |
Matt Rosencrantz | 9d2170b | 2015-02-21 16:19:53 -0800 | [diff] [blame] | 97 | |
| 98 | // reservedServices contains a map of reserved service names. These |
| 99 | // are objects that serve requests in wspr without actually making |
| 100 | // an outgoing rpc call. |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 101 | reservedServices map[string]rpc.Invoker |
Shyam Jayaraman | 5753f39 | 2015-05-05 10:29:45 -0700 | [diff] [blame] | 102 | |
Shyam Jayaraman | 251f9d3 | 2015-05-29 09:27:48 -0700 | [diff] [blame] | 103 | typeEncoder *vom.TypeEncoder |
Shyam Jayaraman | 5753f39 | 2015-05-05 10:29:45 -0700 | [diff] [blame] | 104 | |
Shyam Jayaraman | 251f9d3 | 2015-05-29 09:27:48 -0700 | [diff] [blame] | 105 | typeDecoder *vom.TypeDecoder |
| 106 | typeReader *lib.TypeReader |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 107 | } |
| 108 | |
Benjamin Prosnitz | c65917c | 2015-05-26 14:21:53 -0700 | [diff] [blame] | 109 | var _ ControllerServerMethods = (*Controller)(nil) |
| 110 | |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 111 | // NewController creates a new Controller. writerCreator will be used to create a new flow for rpcs to |
Nicolas LaCasse | 0e317fa | 2015-03-09 12:52:42 -0700 | [diff] [blame] | 112 | // javascript server. |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 113 | func NewController(ctx *context.T, writerCreator func(id int32) lib.ClientWriter, listenSpec *rpc.ListenSpec, namespaceRoots []string, p security.Principal) (*Controller, error) { |
Suharsh Sivakumar | 94d0066 | 2015-01-21 14:31:30 -0800 | [diff] [blame] | 114 | ctx, cancel := context.WithCancel(ctx) |
| 115 | |
Benjamin Prosnitz | 3c73850 | 2014-11-04 14:51:38 -0800 | [diff] [blame] | 116 | if namespaceRoots != nil { |
Nicolas LaCasse | 0e317fa | 2015-03-09 12:52:42 -0700 | [diff] [blame] | 117 | var err error |
Todd Wang | ad49204 | 2015-04-17 15:58:40 -0700 | [diff] [blame] | 118 | ctx, _, err = v23.WithNewNamespace(ctx, namespaceRoots...) |
Nicolas LaCasse | 0e317fa | 2015-03-09 12:52:42 -0700 | [diff] [blame] | 119 | if err != nil { |
| 120 | return nil, err |
| 121 | } |
Benjamin Prosnitz | 3c73850 | 2014-11-04 14:51:38 -0800 | [diff] [blame] | 122 | } |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 123 | |
Todd Wang | ad49204 | 2015-04-17 15:58:40 -0700 | [diff] [blame] | 124 | ctx, _ = vtrace.WithNewTrace(ctx) |
Nicolas LaCasse | 0e317fa | 2015-03-09 12:52:42 -0700 | [diff] [blame] | 125 | |
Todd Wang | ad49204 | 2015-04-17 15:58:40 -0700 | [diff] [blame] | 126 | ctx, err := v23.WithPrincipal(ctx, p) |
Suharsh Sivakumar | 94d0066 | 2015-01-21 14:31:30 -0800 | [diff] [blame] | 127 | if err != nil { |
| 128 | return nil, err |
| 129 | } |
| 130 | |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 131 | controller := &Controller{ |
Benjamin Prosnitz | ae30020 | 2015-06-04 19:36:49 -0700 | [diff] [blame] | 132 | ctx: ctx, |
| 133 | cancel: cancel, |
| 134 | writerCreator: writerCreator, |
| 135 | listenSpec: listenSpec, |
Ankur | e788924 | 2014-10-20 18:37:29 -0700 | [diff] [blame] | 136 | } |
| 137 | |
Benjamin Prosnitz | c65917c | 2015-05-26 14:21:53 -0700 | [diff] [blame] | 138 | controller.blessingsCache = principal.NewBlessingsCache(controller.SendBlessingsCacheMessages, principal.PeriodicGcPolicy(1*time.Minute)) |
| 139 | |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 140 | controllerInvoker, err := rpc.ReflectInvoker(ControllerServer(controller)) |
Matt Rosencrantz | 9d2170b | 2015-02-21 16:19:53 -0800 | [diff] [blame] | 141 | if err != nil { |
| 142 | return nil, err |
| 143 | } |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 144 | namespaceInvoker, err := rpc.ReflectInvoker(namespace.New(ctx)) |
Matt Rosencrantz | 9d2170b | 2015-02-21 16:19:53 -0800 | [diff] [blame] | 145 | if err != nil { |
| 146 | return nil, err |
| 147 | } |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 148 | controller.reservedServices = map[string]rpc.Invoker{ |
Matt Rosencrantz | 9d2170b | 2015-02-21 16:19:53 -0800 | [diff] [blame] | 149 | "__controller": controllerInvoker, |
| 150 | "__namespace": namespaceInvoker, |
| 151 | } |
| 152 | |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 153 | controller.setup() |
| 154 | return controller, nil |
| 155 | } |
| 156 | |
| 157 | // finishCall waits for the call to finish and write out the response to w. |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 158 | func (c *Controller) finishCall(ctx *context.T, w lib.ClientWriter, clientCall rpc.ClientCall, msg *RpcRequest, span vtrace.Span) { |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 159 | if msg.IsStreaming { |
| 160 | for { |
| 161 | var item interface{} |
| 162 | if err := clientCall.Recv(&item); err != nil { |
| 163 | if err == io.EOF { |
| 164 | break |
| 165 | } |
| 166 | w.Error(err) // Send streaming error as is |
| 167 | return |
| 168 | } |
Shyam Jayaraman | 3facd24 | 2015-05-29 11:20:59 -0700 | [diff] [blame] | 169 | vomItem, err := lib.HexVomEncode(item, c.typeEncoder) |
Shyam Jayaraman | c96e1aa | 2014-11-12 16:42:39 -0800 | [diff] [blame] | 170 | if err != nil { |
Todd Wang | b63e9eb | 2015-02-10 19:57:39 -0800 | [diff] [blame] | 171 | w.Error(verror.New(marshallingError, ctx, item, err)) |
Shyam Jayaraman | c96e1aa | 2014-11-12 16:42:39 -0800 | [diff] [blame] | 172 | continue |
| 173 | } |
Benjamin Prosnitz | a2ac3b3 | 2014-12-12 11:40:31 -0800 | [diff] [blame] | 174 | if err := w.Send(lib.ResponseStream, vomItem); err != nil { |
Todd Wang | b63e9eb | 2015-02-10 19:57:39 -0800 | [diff] [blame] | 175 | w.Error(verror.New(marshallingError, ctx, item)) |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 176 | } |
| 177 | } |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 178 | if err := w.Send(lib.ResponseStreamClose, nil); err != nil { |
Todd Wang | b63e9eb | 2015-02-10 19:57:39 -0800 | [diff] [blame] | 179 | w.Error(verror.New(marshallingError, ctx, "ResponseStreamClose")) |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 180 | } |
| 181 | } |
Todd Wang | 5ab0366 | 2015-02-19 21:03:01 -0800 | [diff] [blame] | 182 | results := make([]*vdl.Value, msg.NumOutArgs) |
Shyam Jayaraman | 07136a7 | 2015-04-13 13:34:41 -0700 | [diff] [blame] | 183 | wireBlessingsType := vdl.TypeOf(security.WireBlessings{}) |
Todd Wang | 5ab0366 | 2015-02-19 21:03:01 -0800 | [diff] [blame] | 184 | // This array will have pointers to the values in results. |
Todd Wang | f21e155 | 2015-02-18 13:21:52 -0800 | [diff] [blame] | 185 | resultptrs := make([]interface{}, msg.NumOutArgs) |
Todd Wang | 5ab0366 | 2015-02-19 21:03:01 -0800 | [diff] [blame] | 186 | for i := range results { |
| 187 | resultptrs[i] = &results[i] |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 188 | } |
| 189 | if err := clientCall.Finish(resultptrs...); err != nil { |
| 190 | // return the call system error as is |
| 191 | w.Error(err) |
| 192 | return |
| 193 | } |
Shyam Jayaraman | 07136a7 | 2015-04-13 13:34:41 -0700 | [diff] [blame] | 194 | for i, val := range results { |
| 195 | if val.Type() == wireBlessingsType { |
| 196 | var blessings security.Blessings |
| 197 | if err := vdl.Convert(&blessings, val); err != nil { |
| 198 | w.Error(err) |
| 199 | return |
| 200 | } |
Benjamin Prosnitz | ae30020 | 2015-06-04 19:36:49 -0700 | [diff] [blame] | 201 | results[i] = vdl.ValueOf(c.blessingsCache.Put(blessings)) |
Shyam Jayaraman | 07136a7 | 2015-04-13 13:34:41 -0700 | [diff] [blame] | 202 | } |
| 203 | } |
Matt Rosencrantz | ac1e3a8 | 2015-02-12 16:04:28 -0800 | [diff] [blame] | 204 | c.sendRPCResponse(ctx, w, span, results) |
Matt Rosencrantz | 786f727 | 2015-02-11 15:18:07 -0800 | [diff] [blame] | 205 | } |
Benjamin Prosnitz | a2ac3b3 | 2014-12-12 11:40:31 -0800 | [diff] [blame] | 206 | |
Todd Wang | 5ab0366 | 2015-02-19 21:03:01 -0800 | [diff] [blame] | 207 | func (c *Controller) sendRPCResponse(ctx *context.T, w lib.ClientWriter, span vtrace.Span, results []*vdl.Value) { |
Matt Rosencrantz | ac1e3a8 | 2015-02-12 16:04:28 -0800 | [diff] [blame] | 208 | span.Finish() |
Todd Wang | baf1684 | 2015-03-16 14:12:29 -0700 | [diff] [blame] | 209 | response := RpcResponse{ |
Matt Rosencrantz | 2803fe9 | 2015-03-09 15:26:32 -0700 | [diff] [blame] | 210 | OutArgs: results, |
| 211 | TraceResponse: vtrace.GetResponse(ctx), |
Matt Rosencrantz | ac1e3a8 | 2015-02-12 16:04:28 -0800 | [diff] [blame] | 212 | } |
Shyam Jayaraman | 251f9d3 | 2015-05-29 09:27:48 -0700 | [diff] [blame] | 213 | var buf bytes.Buffer |
| 214 | encoder := vom.NewEncoderWithTypeEncoder(&buf, c.typeEncoder) |
| 215 | if err := encoder.Encode(response); err != nil { |
Shyam Jayaraman | c96e1aa | 2014-11-12 16:42:39 -0800 | [diff] [blame] | 216 | w.Error(err) |
| 217 | return |
| 218 | } |
Shyam Jayaraman | 251f9d3 | 2015-05-29 09:27:48 -0700 | [diff] [blame] | 219 | encoded := hex.EncodeToString(buf.Bytes()) |
Matt Rosencrantz | ac1e3a8 | 2015-02-12 16:04:28 -0800 | [diff] [blame] | 220 | if err := w.Send(lib.ResponseFinal, encoded); err != nil { |
Todd Wang | b63e9eb | 2015-02-10 19:57:39 -0800 | [diff] [blame] | 221 | w.Error(verror.Convert(marshallingError, ctx, err)) |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 222 | } |
| 223 | } |
| 224 | |
Nicolas Lacasse | 938c472 | 2015-03-19 14:42:18 -0700 | [diff] [blame] | 225 | // callOpts turns a slice of type []RpcCallOption object into an array of rpc.CallOpt. |
| 226 | func (c *Controller) callOpts(opts []RpcCallOption) ([]rpc.CallOpt, error) { |
| 227 | var callOpts []rpc.CallOpt |
| 228 | |
Nicolas Lacasse | 938c472 | 2015-03-19 14:42:18 -0700 | [diff] [blame] | 229 | for _, opt := range opts { |
| 230 | switch v := opt.(type) { |
| 231 | case RpcCallOptionAllowedServersPolicy: |
| 232 | callOpts = append(callOpts, options.AllowedServersPolicy(v.Value)) |
| 233 | case RpcCallOptionRetryTimeout: |
Nicolas Lacasse | 938c472 | 2015-03-19 14:42:18 -0700 | [diff] [blame] | 234 | callOpts = append(callOpts, options.RetryTimeout(v.Value)) |
Nicolas Lacasse | f0ec405 | 2015-04-28 13:13:13 -0700 | [diff] [blame] | 235 | case RpcCallOptionGranter: |
Benjamin Prosnitz | bf71e96 | 2015-04-14 16:43:07 -0700 | [diff] [blame] | 236 | callOpts = append(callOpts, &jsGranter{c, v.Value}) |
Nicolas Lacasse | 938c472 | 2015-03-19 14:42:18 -0700 | [diff] [blame] | 237 | default: |
| 238 | return nil, fmt.Errorf("Unknown RpcCallOption type %T", v) |
| 239 | } |
| 240 | } |
| 241 | |
Nicolas Lacasse | 938c472 | 2015-03-19 14:42:18 -0700 | [diff] [blame] | 242 | return callOpts, nil |
| 243 | } |
| 244 | |
Ali Ghassemi | bac3403 | 2015-04-30 18:27:57 -0700 | [diff] [blame] | 245 | // serverOpts turns a slice of type []RpcServerOptions object into an array of rpc.ServerOpt. |
| 246 | func (c *Controller) serverOpts(opts []RpcServerOption) ([]rpc.ServerOpt, error) { |
| 247 | var serverOpts []rpc.ServerOpt |
| 248 | |
| 249 | for _, opt := range opts { |
| 250 | switch v := opt.(type) { |
| 251 | case RpcServerOptionIsLeaf: |
| 252 | serverOpts = append(serverOpts, options.IsLeaf(v.Value)) |
| 253 | case RpcServerOptionServesMountTable: |
| 254 | serverOpts = append(serverOpts, options.ServesMountTable(v.Value)) |
| 255 | default: |
| 256 | return nil, fmt.Errorf("Unknown RpcServerOption type %T", v) |
| 257 | } |
| 258 | } |
| 259 | |
| 260 | return serverOpts, nil |
| 261 | } |
| 262 | |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 263 | func (c *Controller) startCall(ctx *context.T, w lib.ClientWriter, msg *RpcRequest, inArgs []interface{}) (rpc.ClientCall, error) { |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 264 | methodName := lib.UppercaseFirstCharacter(msg.Method) |
Nicolas Lacasse | 938c472 | 2015-03-19 14:42:18 -0700 | [diff] [blame] | 265 | callOpts, err := c.callOpts(msg.CallOptions) |
| 266 | if err != nil { |
| 267 | return nil, err |
| 268 | } |
| 269 | clientCall, err := v23.GetClient(ctx).StartCall(ctx, msg.Name, methodName, inArgs, callOpts...) |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 270 | if err != nil { |
Matt Rosencrantz | 786f727 | 2015-02-11 15:18:07 -0800 | [diff] [blame] | 271 | return nil, fmt.Errorf("error starting call (name: %v, method: %v, args: %v): %v", msg.Name, methodName, inArgs, err) |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 272 | } |
| 273 | |
| 274 | return clientCall, nil |
| 275 | } |
| 276 | |
| 277 | // Implements the serverHelper interface |
| 278 | |
| 279 | // CreateNewFlow creats a new server flow that will be used to write out |
| 280 | // streaming messages to Javascript. |
Benjamin Prosnitz | bf71e96 | 2015-04-14 16:43:07 -0700 | [diff] [blame] | 281 | func (c *Controller) CreateNewFlow(s interface{}, stream rpc.Stream) *server.Flow { |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 282 | c.Lock() |
| 283 | defer c.Unlock() |
| 284 | id := c.lastGeneratedId |
| 285 | c.lastGeneratedId += 2 |
| 286 | c.flowMap[id] = s |
Benjamin Prosnitz | ae30020 | 2015-06-04 19:36:49 -0700 | [diff] [blame] | 287 | os := newStream(c.typeDecoder) |
Benjamin Prosnitz | a2ac3b3 | 2014-12-12 11:40:31 -0800 | [diff] [blame] | 288 | os.init(stream) |
Matt Rosencrantz | 4aabe57 | 2014-10-22 09:25:50 -0700 | [diff] [blame] | 289 | c.outstandingRequests[id] = &outstandingRequest{ |
| 290 | stream: os, |
| 291 | } |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 292 | return &server.Flow{ID: id, Writer: c.writerCreator(id)} |
| 293 | } |
| 294 | |
Shyam Jayaraman | 07136a7 | 2015-04-13 13:34:41 -0700 | [diff] [blame] | 295 | // CleanupFlow removes the bookkeeping for a previously created flow. |
Benjamin Prosnitz | 86d5228 | 2014-12-19 15:48:38 -0800 | [diff] [blame] | 296 | func (c *Controller) CleanupFlow(id int32) { |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 297 | c.Lock() |
Matt Rosencrantz | 4aabe57 | 2014-10-22 09:25:50 -0700 | [diff] [blame] | 298 | request := c.outstandingRequests[id] |
| 299 | delete(c.outstandingRequests, id) |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 300 | delete(c.flowMap, id) |
| 301 | c.Unlock() |
Matt Rosencrantz | 4aabe57 | 2014-10-22 09:25:50 -0700 | [diff] [blame] | 302 | if request != nil && request.stream != nil { |
| 303 | request.stream.end() |
| 304 | request.stream.waitUntilDone() |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 305 | } |
| 306 | } |
| 307 | |
Benjamin Prosnitz | c65917c | 2015-05-26 14:21:53 -0700 | [diff] [blame] | 308 | // BlessingsCache gets the blessings cache used by the controller. |
| 309 | func (c *Controller) BlessingsCache() *principal.BlessingsCache { |
| 310 | return c.blessingsCache |
| 311 | } |
| 312 | |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 313 | // RT returns the runtime of the app. |
Matt Rosencrantz | c90eb7b | 2015-01-09 08:32:01 -0800 | [diff] [blame] | 314 | func (c *Controller) Context() *context.T { |
| 315 | return c.ctx |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 316 | } |
| 317 | |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 318 | // Cleanup cleans up any outstanding rpcs. |
Cosmos Nicolaou | d922992 | 2015-06-24 14:12:24 -0700 | [diff] [blame] | 319 | func (c *Controller) Cleanup(ctx *context.T) { |
| 320 | ctx.VI(0).Info("Cleaning up controller") |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 321 | c.Lock() |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 322 | |
Matt Rosencrantz | 4aabe57 | 2014-10-22 09:25:50 -0700 | [diff] [blame] | 323 | for _, request := range c.outstandingRequests { |
| 324 | if request.cancel != nil { |
| 325 | request.cancel() |
| 326 | } |
| 327 | if request.stream != nil { |
| 328 | request.stream.end() |
| 329 | } |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 330 | } |
| 331 | |
Nicolas LaCasse | 60f423e | 2015-02-04 17:53:14 -0800 | [diff] [blame] | 332 | servers := []*server.Server{} |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 333 | for _, server := range c.servers { |
Nicolas LaCasse | 60f423e | 2015-02-04 17:53:14 -0800 | [diff] [blame] | 334 | servers = append(servers, server) |
| 335 | } |
| 336 | |
| 337 | c.Unlock() |
| 338 | |
| 339 | // We must unlock before calling server.Stop otherwise it can deadlock. |
| 340 | for _, server := range servers { |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 341 | server.Stop() |
| 342 | } |
Benjamin Prosnitz | 8a51fe8 | 2014-10-16 13:05:14 -0700 | [diff] [blame] | 343 | |
Shyam Jayaraman | 251f9d3 | 2015-05-29 09:27:48 -0700 | [diff] [blame] | 344 | c.typeReader.Close() |
Matt Rosencrantz | c90eb7b | 2015-01-09 08:32:01 -0800 | [diff] [blame] | 345 | c.cancel() |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 346 | } |
| 347 | |
| 348 | func (c *Controller) setup() { |
| 349 | c.signatureManager = lib.NewSignatureManager() |
Benjamin Prosnitz | 86d5228 | 2014-12-19 15:48:38 -0800 | [diff] [blame] | 350 | c.outstandingRequests = make(map[int32]*outstandingRequest) |
Benjamin Prosnitz | bf71e96 | 2015-04-14 16:43:07 -0700 | [diff] [blame] | 351 | c.flowMap = make(map[int32]interface{}) |
Benjamin Prosnitz | 86d5228 | 2014-12-19 15:48:38 -0800 | [diff] [blame] | 352 | c.servers = make(map[uint32]*server.Server) |
Shyam Jayaraman | 251f9d3 | 2015-05-29 09:27:48 -0700 | [diff] [blame] | 353 | c.typeReader = lib.NewTypeReader() |
| 354 | c.typeDecoder = vom.NewTypeDecoder(c.typeReader) |
| 355 | c.typeEncoder = vom.NewTypeEncoder(lib.NewTypeWriter(c.writerCreator(typeFlow))) |
| 356 | c.lastGeneratedId += 2 |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 357 | } |
| 358 | |
| 359 | // SendOnStream writes data on id's stream. The actual network write will be |
| 360 | // done asynchronously. If there is an error, it will be sent to w. |
Cosmos Nicolaou | d922992 | 2015-06-24 14:12:24 -0700 | [diff] [blame] | 361 | func (c *Controller) SendOnStream(ctx *context.T, id int32, data string, w lib.ClientWriter) { |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 362 | c.Lock() |
Matt Rosencrantz | 4aabe57 | 2014-10-22 09:25:50 -0700 | [diff] [blame] | 363 | request := c.outstandingRequests[id] |
Matt Rosencrantz | 4aabe57 | 2014-10-22 09:25:50 -0700 | [diff] [blame] | 364 | if request == nil || request.stream == nil { |
Cosmos Nicolaou | d922992 | 2015-06-24 14:12:24 -0700 | [diff] [blame] | 365 | ctx.Errorf("unknown stream: %d", id) |
Ali Ghassemi | 700de8e | 2015-02-25 17:06:15 -0800 | [diff] [blame] | 366 | c.Unlock() |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 367 | return |
| 368 | } |
Matt Rosencrantz | d608b37 | 2014-10-22 13:06:52 -0700 | [diff] [blame] | 369 | stream := request.stream |
| 370 | c.Unlock() |
| 371 | stream.send(data, w) |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 372 | } |
| 373 | |
Suharsh Sivakumar | d1cc6e0 | 2015-03-16 13:58:49 -0700 | [diff] [blame] | 374 | // SendVeyronRequest makes a vanadium request for the given flowId. If signal is non-nil, it will receive |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 375 | // the call object after it has been constructed. |
Todd Wang | baf1684 | 2015-03-16 14:12:29 -0700 | [diff] [blame] | 376 | func (c *Controller) sendVeyronRequest(ctx *context.T, id int32, msg *RpcRequest, inArgs []interface{}, w lib.ClientWriter, stream *outstandingStream, span vtrace.Span) { |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 377 | // We have to make the start call synchronous so we can make sure that we populate |
| 378 | // the call map before we can Handle a recieve call. |
Matt Rosencrantz | 786f727 | 2015-02-11 15:18:07 -0800 | [diff] [blame] | 379 | call, err := c.startCall(ctx, w, msg, inArgs) |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 380 | if err != nil { |
Jiri Simsa | 94f68d0 | 2015-02-17 10:22:08 -0800 | [diff] [blame] | 381 | w.Error(verror.Convert(verror.ErrInternal, ctx, err)) |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 382 | return |
| 383 | } |
| 384 | |
| 385 | if stream != nil { |
Benjamin Prosnitz | a2ac3b3 | 2014-12-12 11:40:31 -0800 | [diff] [blame] | 386 | stream.init(call) |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 387 | } |
| 388 | |
Matt Rosencrantz | ac1e3a8 | 2015-02-12 16:04:28 -0800 | [diff] [blame] | 389 | c.finishCall(ctx, w, call, msg, span) |
Matt Rosencrantz | 4aabe57 | 2014-10-22 09:25:50 -0700 | [diff] [blame] | 390 | c.Lock() |
| 391 | if request, ok := c.outstandingRequests[id]; ok { |
| 392 | delete(c.outstandingRequests, id) |
| 393 | if request.cancel != nil { |
| 394 | request.cancel() |
| 395 | } |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 396 | } |
Matt Rosencrantz | 4aabe57 | 2014-10-22 09:25:50 -0700 | [diff] [blame] | 397 | c.Unlock() |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 398 | } |
| 399 | |
Matt Rosencrantz | 786f727 | 2015-02-11 15:18:07 -0800 | [diff] [blame] | 400 | // TODO(mattr): This is a very limited implementation of ServerCall, |
| 401 | // but currently none of the methods the controller exports require |
| 402 | // any of this context information. |
| 403 | type localCall struct { |
Shyam Jayaraman | 3facd24 | 2015-05-29 11:20:59 -0700 | [diff] [blame] | 404 | ctx *context.T |
| 405 | vrpc *RpcRequest |
| 406 | tags []*vdl.Value |
| 407 | w lib.ClientWriter |
| 408 | typeEncoder *vom.TypeEncoder |
Matt Rosencrantz | 786f727 | 2015-02-11 15:18:07 -0800 | [diff] [blame] | 409 | } |
| 410 | |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 411 | var ( |
| 412 | _ rpc.StreamServerCall = (*localCall)(nil) |
| 413 | _ security.Call = (*localCall)(nil) |
| 414 | ) |
| 415 | |
Matt Rosencrantz | 9d2170b | 2015-02-21 16:19:53 -0800 | [diff] [blame] | 416 | func (l *localCall) Send(item interface{}) error { |
Shyam Jayaraman | 3facd24 | 2015-05-29 11:20:59 -0700 | [diff] [blame] | 417 | vomItem, err := lib.HexVomEncode(item, l.typeEncoder) |
Matt Rosencrantz | 9d2170b | 2015-02-21 16:19:53 -0800 | [diff] [blame] | 418 | if err != nil { |
| 419 | err = verror.New(marshallingError, l.ctx, item, err) |
| 420 | l.w.Error(err) |
| 421 | return err |
| 422 | } |
| 423 | if err := l.w.Send(lib.ResponseStream, vomItem); err != nil { |
| 424 | err = verror.New(marshallingError, l.ctx, item) |
| 425 | l.w.Error(err) |
| 426 | return err |
| 427 | } |
| 428 | return nil |
| 429 | } |
Matt Rosencrantz | 786f727 | 2015-02-11 15:18:07 -0800 | [diff] [blame] | 430 | func (l *localCall) Recv(interface{}) error { return nil } |
Suharsh Sivakumar | 380bf34 | 2015-02-27 15:38:27 -0800 | [diff] [blame] | 431 | func (l *localCall) GrantedBlessings() security.Blessings { return security.Blessings{} } |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 432 | func (l *localCall) Server() rpc.Server { return nil } |
Matt Rosencrantz | 786f727 | 2015-02-11 15:18:07 -0800 | [diff] [blame] | 433 | func (l *localCall) Timestamp() (t time.Time) { return } |
| 434 | func (l *localCall) Method() string { return l.vrpc.Method } |
Todd Wang | 5ab0366 | 2015-02-19 21:03:01 -0800 | [diff] [blame] | 435 | func (l *localCall) MethodTags() []*vdl.Value { return l.tags } |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 436 | func (l *localCall) Suffix() string { return l.vrpc.Name } |
Ankur | edd74ee | 2015-03-04 16:38:45 -0800 | [diff] [blame] | 437 | func (l *localCall) LocalDischarges() map[string]security.Discharge { return nil } |
Matt Rosencrantz | 786f727 | 2015-02-11 15:18:07 -0800 | [diff] [blame] | 438 | func (l *localCall) RemoteDischarges() map[string]security.Discharge { return nil } |
| 439 | func (l *localCall) LocalPrincipal() security.Principal { return nil } |
Asim Shankar | 2bf7b1e | 2015-02-27 00:45:12 -0800 | [diff] [blame] | 440 | func (l *localCall) LocalBlessings() security.Blessings { return security.Blessings{} } |
| 441 | func (l *localCall) RemoteBlessings() security.Blessings { return security.Blessings{} } |
Matt Rosencrantz | 786f727 | 2015-02-11 15:18:07 -0800 | [diff] [blame] | 442 | func (l *localCall) LocalEndpoint() naming.Endpoint { return nil } |
| 443 | func (l *localCall) RemoteEndpoint() naming.Endpoint { return nil } |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 444 | func (l *localCall) Security() security.Call { return l } |
Matt Rosencrantz | 786f727 | 2015-02-11 15:18:07 -0800 | [diff] [blame] | 445 | |
Shyam Jayaraman | 251f9d3 | 2015-05-29 09:27:48 -0700 | [diff] [blame] | 446 | func (c *Controller) handleInternalCall(ctx *context.T, invoker rpc.Invoker, msg *RpcRequest, w lib.ClientWriter, span vtrace.Span, decoder *vom.Decoder) { |
Cosmos Nicolaou | 5a3125a | 2015-07-10 11:19:20 -0700 | [diff] [blame] | 447 | argptrs, tags, err := invoker.Prepare(ctx, msg.Method, int(msg.NumInArgs)) |
Matt Rosencrantz | 786f727 | 2015-02-11 15:18:07 -0800 | [diff] [blame] | 448 | if err != nil { |
Jiri Simsa | 94f68d0 | 2015-02-17 10:22:08 -0800 | [diff] [blame] | 449 | w.Error(verror.Convert(verror.ErrInternal, ctx, err)) |
Matt Rosencrantz | 786f727 | 2015-02-11 15:18:07 -0800 | [diff] [blame] | 450 | return |
| 451 | } |
| 452 | for _, argptr := range argptrs { |
Shyam Jayaraman | 251f9d3 | 2015-05-29 09:27:48 -0700 | [diff] [blame] | 453 | if err := decoder.Decode(argptr); err != nil { |
Jiri Simsa | 94f68d0 | 2015-02-17 10:22:08 -0800 | [diff] [blame] | 454 | w.Error(verror.Convert(verror.ErrInternal, ctx, err)) |
Matt Rosencrantz | 786f727 | 2015-02-11 15:18:07 -0800 | [diff] [blame] | 455 | return |
| 456 | } |
| 457 | } |
Shyam Jayaraman | 3facd24 | 2015-05-29 11:20:59 -0700 | [diff] [blame] | 458 | results, err := invoker.Invoke(ctx, &localCall{ctx, msg, tags, w, c.typeEncoder}, msg.Method, argptrs) |
Shyam Jayaraman | 251f9d3 | 2015-05-29 09:27:48 -0700 | [diff] [blame] | 459 | if err != nil { |
| 460 | w.Error(verror.Convert(verror.ErrInternal, ctx, err)) |
| 461 | return |
| 462 | } |
| 463 | if msg.IsStreaming { |
| 464 | if err := w.Send(lib.ResponseStreamClose, nil); err != nil { |
| 465 | w.Error(verror.New(marshallingError, ctx, "ResponseStreamClose")) |
| 466 | } |
| 467 | } |
| 468 | |
| 469 | // Convert results from []interface{} to []*vdl.Value. |
| 470 | vresults := make([]*vdl.Value, len(results)) |
| 471 | for i, res := range results { |
| 472 | vv, err := vdl.ValueFromReflect(reflect.ValueOf(res)) |
Todd Wang | 5ab0366 | 2015-02-19 21:03:01 -0800 | [diff] [blame] | 473 | if err != nil { |
| 474 | w.Error(verror.Convert(verror.ErrInternal, ctx, err)) |
| 475 | return |
| 476 | } |
Shyam Jayaraman | 251f9d3 | 2015-05-29 09:27:48 -0700 | [diff] [blame] | 477 | vresults[i] = vv |
| 478 | } |
| 479 | c.sendRPCResponse(ctx, w, span, vresults) |
Matt Rosencrantz | 786f727 | 2015-02-11 15:18:07 -0800 | [diff] [blame] | 480 | } |
| 481 | |
Benjamin Prosnitz | e8e2b9b | 2015-02-24 12:55:25 -0800 | [diff] [blame] | 482 | // HandleCaveatValidationResponse handles the response to caveat validation |
| 483 | // requests. |
Cosmos Nicolaou | d922992 | 2015-06-24 14:12:24 -0700 | [diff] [blame] | 484 | func (c *Controller) HandleCaveatValidationResponse(ctx *context.T, id int32, data string) { |
Benjamin Prosnitz | e8e2b9b | 2015-02-24 12:55:25 -0800 | [diff] [blame] | 485 | c.Lock() |
Benjamin Prosnitz | bf71e96 | 2015-04-14 16:43:07 -0700 | [diff] [blame] | 486 | server, ok := c.flowMap[id].(*server.Server) |
Benjamin Prosnitz | e8e2b9b | 2015-02-24 12:55:25 -0800 | [diff] [blame] | 487 | c.Unlock() |
Benjamin Prosnitz | bf71e96 | 2015-04-14 16:43:07 -0700 | [diff] [blame] | 488 | if !ok { |
Cosmos Nicolaou | d922992 | 2015-06-24 14:12:24 -0700 | [diff] [blame] | 489 | ctx.Errorf("unexpected result from JavaScript. No server found matching id %d.", id) |
Benjamin Prosnitz | e8e2b9b | 2015-02-24 12:55:25 -0800 | [diff] [blame] | 490 | return // ignore unknown server |
| 491 | } |
Cosmos Nicolaou | d922992 | 2015-06-24 14:12:24 -0700 | [diff] [blame] | 492 | server.HandleCaveatValidationResponse(ctx, id, data) |
Benjamin Prosnitz | e8e2b9b | 2015-02-24 12:55:25 -0800 | [diff] [blame] | 493 | } |
| 494 | |
Suharsh Sivakumar | d1cc6e0 | 2015-03-16 13:58:49 -0700 | [diff] [blame] | 495 | // HandleVeyronRequest starts a vanadium rpc and returns before the rpc has been completed. |
Matt Rosencrantz | 786f727 | 2015-02-11 15:18:07 -0800 | [diff] [blame] | 496 | func (c *Controller) HandleVeyronRequest(ctx *context.T, id int32, data string, w lib.ClientWriter) { |
Shyam Jayaraman | 251f9d3 | 2015-05-29 09:27:48 -0700 | [diff] [blame] | 497 | binBytes, err := hex.DecodeString(data) |
| 498 | if err != nil { |
| 499 | w.Error(verror.Convert(verror.ErrInternal, ctx, fmt.Errorf("Error decoding hex string %q: %v", data, err))) |
| 500 | return |
| 501 | } |
| 502 | decoder := vom.NewDecoderWithTypeDecoder(bytes.NewReader(binBytes), c.typeDecoder) |
Matt Rosencrantz | 786f727 | 2015-02-11 15:18:07 -0800 | [diff] [blame] | 503 | if err != nil { |
Benjamin Prosnitz | bf71e96 | 2015-04-14 16:43:07 -0700 | [diff] [blame] | 504 | w.Error(verror.Convert(verror.ErrInternal, ctx, fmt.Errorf("Error decoding hex string %q: %v", data, err))) |
Matt Rosencrantz | 786f727 | 2015-02-11 15:18:07 -0800 | [diff] [blame] | 505 | return |
| 506 | } |
Todd Wang | baf1684 | 2015-03-16 14:12:29 -0700 | [diff] [blame] | 507 | var msg RpcRequest |
Shyam Jayaraman | 251f9d3 | 2015-05-29 09:27:48 -0700 | [diff] [blame] | 508 | if err := decoder.Decode(&msg); err != nil { |
Jiri Simsa | 94f68d0 | 2015-02-17 10:22:08 -0800 | [diff] [blame] | 509 | w.Error(verror.Convert(verror.ErrInternal, ctx, err)) |
Matt Rosencrantz | 786f727 | 2015-02-11 15:18:07 -0800 | [diff] [blame] | 510 | return |
| 511 | } |
Cosmos Nicolaou | d922992 | 2015-06-24 14:12:24 -0700 | [diff] [blame] | 512 | ctx.VI(2).Infof("Rpc: %s.%s(..., streaming=%v)", msg.Name, msg.Method, msg.IsStreaming) |
Matt Rosencrantz | ac1e3a8 | 2015-02-12 16:04:28 -0800 | [diff] [blame] | 513 | spanName := fmt.Sprintf("<wspr>%q.%s", msg.Name, msg.Method) |
Todd Wang | ad49204 | 2015-04-17 15:58:40 -0700 | [diff] [blame] | 514 | ctx, span := vtrace.WithContinuedTrace(ctx, spanName, msg.TraceRequest) |
Shyam Jayaraman | 8e301b5 | 2015-04-27 14:12:16 -0700 | [diff] [blame] | 515 | ctx = i18n.WithLangID(ctx, i18n.LangID(msg.Context.Language)) |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 516 | |
Matt Rosencrantz | d2ecc8e | 2014-12-29 11:30:55 -0800 | [diff] [blame] | 517 | var cctx *context.T |
Matt Rosencrantz | 4aabe57 | 2014-10-22 09:25:50 -0700 | [diff] [blame] | 518 | var cancel context.CancelFunc |
| 519 | |
| 520 | // TODO(mattr): To be consistent with go, we should not ignore 0 timeouts. |
| 521 | // However as a rollout strategy we must, otherwise there is a circular |
| 522 | // dependency between the WSPR change and the JS change that will follow. |
Shyam Jayaraman | 7efedbe | 2015-03-05 12:57:18 -0800 | [diff] [blame] | 523 | if msg.Deadline.IsZero() { |
Matt Rosencrantz | b6f4b92 | 2015-01-05 13:31:55 -0800 | [diff] [blame] | 524 | cctx, cancel = context.WithCancel(ctx) |
Matt Rosencrantz | 4aabe57 | 2014-10-22 09:25:50 -0700 | [diff] [blame] | 525 | } else { |
Shyam Jayaraman | 7efedbe | 2015-03-05 12:57:18 -0800 | [diff] [blame] | 526 | cctx, cancel = context.WithDeadline(ctx, msg.Deadline.Time) |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 527 | } |
Matt Rosencrantz | 4aabe57 | 2014-10-22 09:25:50 -0700 | [diff] [blame] | 528 | |
Matt Rosencrantz | 786f727 | 2015-02-11 15:18:07 -0800 | [diff] [blame] | 529 | // If this message is for an internal service, do a short-circuit dispatch here. |
Matt Rosencrantz | 9d2170b | 2015-02-21 16:19:53 -0800 | [diff] [blame] | 530 | if invoker, ok := c.reservedServices[msg.Name]; ok { |
Shyam Jayaraman | 251f9d3 | 2015-05-29 09:27:48 -0700 | [diff] [blame] | 531 | go c.handleInternalCall(ctx, invoker, &msg, w, span, decoder) |
Matt Rosencrantz | 786f727 | 2015-02-11 15:18:07 -0800 | [diff] [blame] | 532 | return |
| 533 | } |
| 534 | |
| 535 | inArgs := make([]interface{}, msg.NumInArgs) |
| 536 | for i := range inArgs { |
Shyam Jayaraman | b40a8ce | 2015-02-25 12:42:35 -0800 | [diff] [blame] | 537 | var v *vdl.Value |
Shyam Jayaraman | 251f9d3 | 2015-05-29 09:27:48 -0700 | [diff] [blame] | 538 | if err := decoder.Decode(&v); err != nil { |
Matt Rosencrantz | 786f727 | 2015-02-11 15:18:07 -0800 | [diff] [blame] | 539 | w.Error(err) |
| 540 | return |
| 541 | } |
Shyam Jayaraman | b40a8ce | 2015-02-25 12:42:35 -0800 | [diff] [blame] | 542 | inArgs[i] = v |
Matt Rosencrantz | 786f727 | 2015-02-11 15:18:07 -0800 | [diff] [blame] | 543 | } |
| 544 | |
Matt Rosencrantz | 4aabe57 | 2014-10-22 09:25:50 -0700 | [diff] [blame] | 545 | request := &outstandingRequest{ |
| 546 | cancel: cancel, |
| 547 | } |
Benjamin Prosnitz | a2ac3b3 | 2014-12-12 11:40:31 -0800 | [diff] [blame] | 548 | if msg.IsStreaming { |
Matt Rosencrantz | 4aabe57 | 2014-10-22 09:25:50 -0700 | [diff] [blame] | 549 | // If this rpc is streaming, we would expect that the client would try to send |
| 550 | // on this stream. Since the initial handshake is done asynchronously, we have |
| 551 | // to put the outstanding stream in the map before we make the async call so that |
| 552 | // the future send know which queue to write to, even if the client call isn't |
| 553 | // actually ready yet. |
Benjamin Prosnitz | ae30020 | 2015-06-04 19:36:49 -0700 | [diff] [blame] | 554 | request.stream = newStream(c.typeDecoder) |
Matt Rosencrantz | 4aabe57 | 2014-10-22 09:25:50 -0700 | [diff] [blame] | 555 | } |
| 556 | c.Lock() |
| 557 | c.outstandingRequests[id] = request |
Matt Rosencrantz | ac1e3a8 | 2015-02-12 16:04:28 -0800 | [diff] [blame] | 558 | go c.sendVeyronRequest(cctx, id, &msg, inArgs, w, request.stream, span) |
Matt Rosencrantz | 4aabe57 | 2014-10-22 09:25:50 -0700 | [diff] [blame] | 559 | c.Unlock() |
Matt Rosencrantz | 4aabe57 | 2014-10-22 09:25:50 -0700 | [diff] [blame] | 560 | } |
| 561 | |
| 562 | // HandleVeyronCancellation cancels the request corresponding to the |
| 563 | // given id if it is still outstanding. |
Cosmos Nicolaou | d922992 | 2015-06-24 14:12:24 -0700 | [diff] [blame] | 564 | func (c *Controller) HandleVeyronCancellation(ctx *context.T, id int32) { |
Matt Rosencrantz | 4aabe57 | 2014-10-22 09:25:50 -0700 | [diff] [blame] | 565 | c.Lock() |
| 566 | defer c.Unlock() |
| 567 | if request, ok := c.outstandingRequests[id]; ok && request.cancel != nil { |
| 568 | request.cancel() |
| 569 | } |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 570 | } |
| 571 | |
| 572 | // CloseStream closes the stream for a given id. |
Cosmos Nicolaou | d922992 | 2015-06-24 14:12:24 -0700 | [diff] [blame] | 573 | func (c *Controller) CloseStream(ctx *context.T, id int32) { |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 574 | c.Lock() |
| 575 | defer c.Unlock() |
Matt Rosencrantz | 4aabe57 | 2014-10-22 09:25:50 -0700 | [diff] [blame] | 576 | if request, ok := c.outstandingRequests[id]; ok && request.stream != nil { |
| 577 | request.stream.end() |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 578 | return |
| 579 | } |
Cosmos Nicolaou | d922992 | 2015-06-24 14:12:24 -0700 | [diff] [blame] | 580 | ctx.Errorf("close called on non-existent call: %v", id) |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 581 | } |
| 582 | |
Ali Ghassemi | bac3403 | 2015-04-30 18:27:57 -0700 | [diff] [blame] | 583 | func (c *Controller) maybeCreateServer(serverId uint32, opts ...rpc.ServerOpt) (*server.Server, error) { |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 584 | c.Lock() |
| 585 | defer c.Unlock() |
| 586 | if server, ok := c.servers[serverId]; ok { |
| 587 | return server, nil |
| 588 | } |
Ali Ghassemi | bac3403 | 2015-04-30 18:27:57 -0700 | [diff] [blame] | 589 | server, err := server.NewServer(serverId, c.listenSpec, c, opts...) |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 590 | if err != nil { |
| 591 | return nil, err |
| 592 | } |
| 593 | c.servers[serverId] = server |
| 594 | return server, nil |
| 595 | } |
| 596 | |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 597 | // HandleLookupResponse handles the result of a Dispatcher.Lookup call that was |
| 598 | // run by the Javascript server. |
Cosmos Nicolaou | d922992 | 2015-06-24 14:12:24 -0700 | [diff] [blame] | 599 | func (c *Controller) HandleLookupResponse(ctx *context.T, id int32, data string) { |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 600 | c.Lock() |
Benjamin Prosnitz | bf71e96 | 2015-04-14 16:43:07 -0700 | [diff] [blame] | 601 | server, ok := c.flowMap[id].(*server.Server) |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 602 | c.Unlock() |
Benjamin Prosnitz | bf71e96 | 2015-04-14 16:43:07 -0700 | [diff] [blame] | 603 | if !ok { |
Cosmos Nicolaou | d922992 | 2015-06-24 14:12:24 -0700 | [diff] [blame] | 604 | ctx.Errorf("unexpected result from JavaScript. No channel "+ |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 605 | "for MessageId: %d exists. Ignoring the results.", id) |
| 606 | //Ignore unknown responses that don't belong to any channel |
| 607 | return |
| 608 | } |
Cosmos Nicolaou | d922992 | 2015-06-24 14:12:24 -0700 | [diff] [blame] | 609 | server.HandleLookupResponse(ctx, id, data) |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 610 | } |
| 611 | |
| 612 | // HandleAuthResponse handles the result of a Authorizer.Authorize call that was |
| 613 | // run by the Javascript server. |
Cosmos Nicolaou | d922992 | 2015-06-24 14:12:24 -0700 | [diff] [blame] | 614 | func (c *Controller) HandleAuthResponse(ctx *context.T, id int32, data string) { |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 615 | c.Lock() |
Benjamin Prosnitz | bf71e96 | 2015-04-14 16:43:07 -0700 | [diff] [blame] | 616 | server, ok := c.flowMap[id].(*server.Server) |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 617 | c.Unlock() |
Benjamin Prosnitz | bf71e96 | 2015-04-14 16:43:07 -0700 | [diff] [blame] | 618 | if !ok { |
Cosmos Nicolaou | d922992 | 2015-06-24 14:12:24 -0700 | [diff] [blame] | 619 | ctx.Errorf("unexpected result from JavaScript. No channel "+ |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 620 | "for MessageId: %d exists. Ignoring the results.", id) |
| 621 | //Ignore unknown responses that don't belong to any channel |
| 622 | return |
| 623 | } |
Cosmos Nicolaou | d922992 | 2015-06-24 14:12:24 -0700 | [diff] [blame] | 624 | server.HandleAuthResponse(ctx, id, data) |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 625 | } |
| 626 | |
Matt Rosencrantz | d4bcec6 | 2015-02-18 14:05:49 -0800 | [diff] [blame] | 627 | // Serve instructs WSPR to start listening for calls on behalf |
| 628 | // of a javascript server. |
Cosmos Nicolaou | d922992 | 2015-06-24 14:12:24 -0700 | [diff] [blame] | 629 | func (c *Controller) Serve(ctx *context.T, _ rpc.ServerCall, name string, serverId uint32, rpcServerOpts []RpcServerOption) error { |
Ali Ghassemi | bac3403 | 2015-04-30 18:27:57 -0700 | [diff] [blame] | 630 | |
| 631 | opts, err := c.serverOpts(rpcServerOpts) |
| 632 | if err != nil { |
| 633 | return verror.Convert(verror.ErrInternal, nil, err) |
| 634 | } |
| 635 | server, err := c.maybeCreateServer(serverId, opts...) |
Matt Rosencrantz | d4bcec6 | 2015-02-18 14:05:49 -0800 | [diff] [blame] | 636 | if err != nil { |
| 637 | return verror.Convert(verror.ErrInternal, nil, err) |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 638 | } |
Cosmos Nicolaou | d922992 | 2015-06-24 14:12:24 -0700 | [diff] [blame] | 639 | ctx.VI(2).Infof("serving under name: %q", name) |
Matt Rosencrantz | d4bcec6 | 2015-02-18 14:05:49 -0800 | [diff] [blame] | 640 | if err := server.Serve(name); err != nil { |
| 641 | return verror.Convert(verror.ErrInternal, nil, err) |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 642 | } |
Matt Rosencrantz | d4bcec6 | 2015-02-18 14:05:49 -0800 | [diff] [blame] | 643 | return nil |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 644 | } |
| 645 | |
Matt Rosencrantz | d4bcec6 | 2015-02-18 14:05:49 -0800 | [diff] [blame] | 646 | // Stop instructs WSPR to stop listening for calls for the |
| 647 | // given javascript server. |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 648 | func (c *Controller) Stop(_ *context.T, _ rpc.ServerCall, serverId uint32) error { |
Matt Rosencrantz | d4bcec6 | 2015-02-18 14:05:49 -0800 | [diff] [blame] | 649 | c.Lock() |
Benjamin Prosnitz | bf71e96 | 2015-04-14 16:43:07 -0700 | [diff] [blame] | 650 | server, ok := c.servers[serverId] |
| 651 | if !ok { |
Matt Rosencrantz | d4bcec6 | 2015-02-18 14:05:49 -0800 | [diff] [blame] | 652 | c.Unlock() |
| 653 | return nil |
Ali Ghassemi | 1008bbe | 2014-11-07 16:36:08 -0800 | [diff] [blame] | 654 | } |
Matt Rosencrantz | d4bcec6 | 2015-02-18 14:05:49 -0800 | [diff] [blame] | 655 | delete(c.servers, serverId) |
| 656 | c.Unlock() |
Ali Ghassemi | 1008bbe | 2014-11-07 16:36:08 -0800 | [diff] [blame] | 657 | |
Matt Rosencrantz | d4bcec6 | 2015-02-18 14:05:49 -0800 | [diff] [blame] | 658 | server.Stop() |
| 659 | return nil |
| 660 | } |
| 661 | |
| 662 | // AddName adds a published name to an existing server. |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 663 | func (c *Controller) AddName(_ *context.T, _ rpc.ServerCall, serverId uint32, name string) error { |
Nicolas LaCasse | 4f409ce | 2014-11-25 11:44:03 -0800 | [diff] [blame] | 664 | // Create a server for the pipe, if it does not exist already |
Matt Rosencrantz | d4bcec6 | 2015-02-18 14:05:49 -0800 | [diff] [blame] | 665 | server, err := c.maybeCreateServer(serverId) |
Ali Ghassemi | 1008bbe | 2014-11-07 16:36:08 -0800 | [diff] [blame] | 666 | if err != nil { |
Matt Rosencrantz | d4bcec6 | 2015-02-18 14:05:49 -0800 | [diff] [blame] | 667 | return verror.Convert(verror.ErrInternal, nil, err) |
Ali Ghassemi | 1008bbe | 2014-11-07 16:36:08 -0800 | [diff] [blame] | 668 | } |
Ali Ghassemi | 1008bbe | 2014-11-07 16:36:08 -0800 | [diff] [blame] | 669 | // Add name |
Matt Rosencrantz | d4bcec6 | 2015-02-18 14:05:49 -0800 | [diff] [blame] | 670 | if err := server.AddName(name); err != nil { |
| 671 | return verror.Convert(verror.ErrInternal, nil, err) |
Ali Ghassemi | 1008bbe | 2014-11-07 16:36:08 -0800 | [diff] [blame] | 672 | } |
Matt Rosencrantz | d4bcec6 | 2015-02-18 14:05:49 -0800 | [diff] [blame] | 673 | return nil |
Ali Ghassemi | 1008bbe | 2014-11-07 16:36:08 -0800 | [diff] [blame] | 674 | } |
| 675 | |
Matt Rosencrantz | d4bcec6 | 2015-02-18 14:05:49 -0800 | [diff] [blame] | 676 | // RemoveName removes a published name from an existing server. |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 677 | func (c *Controller) RemoveName(_ *context.T, _ rpc.ServerCall, serverId uint32, name string) error { |
Nicolas LaCasse | 4f409ce | 2014-11-25 11:44:03 -0800 | [diff] [blame] | 678 | // Create a server for the pipe, if it does not exist already |
Matt Rosencrantz | d4bcec6 | 2015-02-18 14:05:49 -0800 | [diff] [blame] | 679 | server, err := c.maybeCreateServer(serverId) |
Ali Ghassemi | 1008bbe | 2014-11-07 16:36:08 -0800 | [diff] [blame] | 680 | if err != nil { |
Matt Rosencrantz | d4bcec6 | 2015-02-18 14:05:49 -0800 | [diff] [blame] | 681 | return verror.Convert(verror.ErrInternal, nil, err) |
Ali Ghassemi | 1008bbe | 2014-11-07 16:36:08 -0800 | [diff] [blame] | 682 | } |
Ali Ghassemi | 1008bbe | 2014-11-07 16:36:08 -0800 | [diff] [blame] | 683 | // Remove name |
Matt Rosencrantz | d4bcec6 | 2015-02-18 14:05:49 -0800 | [diff] [blame] | 684 | server.RemoveName(name) |
Ali Ghassemi | 1008bbe | 2014-11-07 16:36:08 -0800 | [diff] [blame] | 685 | // Remove name from signature cache as well |
Matt Rosencrantz | d4bcec6 | 2015-02-18 14:05:49 -0800 | [diff] [blame] | 686 | c.signatureManager.FlushCacheEntry(name) |
| 687 | return nil |
Ali Ghassemi | 1008bbe | 2014-11-07 16:36:08 -0800 | [diff] [blame] | 688 | } |
| 689 | |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 690 | // HandleServerResponse handles the completion of outstanding calls to JavaScript services |
| 691 | // by filling the corresponding channel with the result from JavaScript. |
Cosmos Nicolaou | d922992 | 2015-06-24 14:12:24 -0700 | [diff] [blame] | 692 | func (c *Controller) HandleServerResponse(ctx *context.T, id int32, data string) { |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 693 | c.Lock() |
Benjamin Prosnitz | bf71e96 | 2015-04-14 16:43:07 -0700 | [diff] [blame] | 694 | server, ok := c.flowMap[id].(*server.Server) |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 695 | c.Unlock() |
Benjamin Prosnitz | bf71e96 | 2015-04-14 16:43:07 -0700 | [diff] [blame] | 696 | if !ok { |
Cosmos Nicolaou | d922992 | 2015-06-24 14:12:24 -0700 | [diff] [blame] | 697 | ctx.Errorf("unexpected result from JavaScript. No channel "+ |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 698 | "for MessageId: %d exists. Ignoring the results.", id) |
| 699 | //Ignore unknown responses that don't belong to any channel |
| 700 | return |
| 701 | } |
Cosmos Nicolaou | d922992 | 2015-06-24 14:12:24 -0700 | [diff] [blame] | 702 | server.HandleServerResponse(ctx, id, data) |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 703 | } |
| 704 | |
Matt Rosencrantz | ec3b950 | 2015-02-19 12:53:13 -0800 | [diff] [blame] | 705 | // getSignature uses the signature manager to get and cache the signature of a remote server. |
Matt Rosencrantz | d2ecc8e | 2014-12-29 11:30:55 -0800 | [diff] [blame] | 706 | func (c *Controller) getSignature(ctx *context.T, name string) ([]signature.Interface, error) { |
Nicolas Lacasse | c577e9f | 2015-03-19 16:21:19 -0700 | [diff] [blame] | 707 | return c.signatureManager.Signature(ctx, name) |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 708 | } |
| 709 | |
Matt Rosencrantz | ec3b950 | 2015-02-19 12:53:13 -0800 | [diff] [blame] | 710 | // Signature uses the signature manager to get and cache the signature of a remote server. |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 711 | func (c *Controller) Signature(ctx *context.T, _ rpc.ServerCall, name string) ([]signature.Interface, error) { |
| 712 | return c.getSignature(ctx, name) |
Jiri Simsa | 78b646f | 2014-10-08 10:23:05 -0700 | [diff] [blame] | 713 | } |
| 714 | |
Benjamin Prosnitz | 23bf1a0 | 2015-03-30 16:17:04 -0700 | [diff] [blame] | 715 | // Bless binds extensions of blessings held by this principal to |
| 716 | // another principal (represented by its public key). |
Benjamin Prosnitz | ae30020 | 2015-06-04 19:36:49 -0700 | [diff] [blame] | 717 | func (c *Controller) Bless(_ *context.T, _ rpc.ServerCall, publicKey []byte, inputBlessings security.Blessings, extension string, caveats []security.Caveat) (principal.BlessingsId, error) { |
| 718 | key, err := security.UnmarshalPublicKey(publicKey) |
Ankur | e788924 | 2014-10-20 18:37:29 -0700 | [diff] [blame] | 719 | if err != nil { |
Benjamin Prosnitz | c65917c | 2015-05-26 14:21:53 -0700 | [diff] [blame] | 720 | return 0, err |
Ankur | e788924 | 2014-10-20 18:37:29 -0700 | [diff] [blame] | 721 | } |
Ankur | e788924 | 2014-10-20 18:37:29 -0700 | [diff] [blame] | 722 | |
Benjamin Prosnitz | 23bf1a0 | 2015-03-30 16:17:04 -0700 | [diff] [blame] | 723 | if len(caveats) == 0 { |
| 724 | caveats = append(caveats, security.UnconstrainedUse()) |
| 725 | } |
| 726 | |
Jiri Simsa | 1f1302c | 2015-02-23 16:18:34 -0800 | [diff] [blame] | 727 | p := v23.GetPrincipal(c.ctx) |
Benjamin Prosnitz | ae30020 | 2015-06-04 19:36:49 -0700 | [diff] [blame] | 728 | blessings, err := p.Bless(key, inputBlessings, extension, caveats[0], caveats[1:]...) |
Ankur | e788924 | 2014-10-20 18:37:29 -0700 | [diff] [blame] | 729 | if err != nil { |
Benjamin Prosnitz | c65917c | 2015-05-26 14:21:53 -0700 | [diff] [blame] | 730 | return 0, err |
Ankur | e788924 | 2014-10-20 18:37:29 -0700 | [diff] [blame] | 731 | } |
Benjamin Prosnitz | ae30020 | 2015-06-04 19:36:49 -0700 | [diff] [blame] | 732 | return c.blessingsCache.Put(blessings), nil |
Ankur | e788924 | 2014-10-20 18:37:29 -0700 | [diff] [blame] | 733 | } |
| 734 | |
Benjamin Prosnitz | 23bf1a0 | 2015-03-30 16:17:04 -0700 | [diff] [blame] | 735 | // BlessSelf creates a blessing with the provided name for this principal. |
Benjamin Prosnitz | c65917c | 2015-05-26 14:21:53 -0700 | [diff] [blame] | 736 | func (c *Controller) BlessSelf(_ *context.T, _ rpc.ServerCall, extension string, caveats []security.Caveat) (principal.BlessingsId, error) { |
Benjamin Prosnitz | 23bf1a0 | 2015-03-30 16:17:04 -0700 | [diff] [blame] | 737 | p := v23.GetPrincipal(c.ctx) |
Benjamin Prosnitz | 70b7664 | 2015-06-05 13:54:00 +0800 | [diff] [blame] | 738 | blessings, err := p.BlessSelf(extension, caveats...) |
Ankur | e788924 | 2014-10-20 18:37:29 -0700 | [diff] [blame] | 739 | if err != nil { |
Benjamin Prosnitz | c65917c | 2015-05-26 14:21:53 -0700 | [diff] [blame] | 740 | return 0, verror.Convert(verror.ErrInternal, nil, err) |
Ankur | e788924 | 2014-10-20 18:37:29 -0700 | [diff] [blame] | 741 | } |
Matt Rosencrantz | feefb77 | 2015-02-18 14:58:49 -0800 | [diff] [blame] | 742 | |
Benjamin Prosnitz | ae30020 | 2015-06-04 19:36:49 -0700 | [diff] [blame] | 743 | return c.blessingsCache.Put(blessings), err |
Ankur | e788924 | 2014-10-20 18:37:29 -0700 | [diff] [blame] | 744 | } |
| 745 | |
Benjamin Prosnitz | e1209d4 | 2015-05-04 15:06:42 -0700 | [diff] [blame] | 746 | // BlessingStoreSet puts the specified blessing in the blessing store under the |
| 747 | // provided pattern. |
Benjamin Prosnitz | ae30020 | 2015-06-04 19:36:49 -0700 | [diff] [blame] | 748 | func (c *Controller) BlessingStoreSet(_ *context.T, _ rpc.ServerCall, inputBlessings security.Blessings, pattern security.BlessingPattern) (principal.BlessingsId, error) { |
Benjamin Prosnitz | 9e42399 | 2015-04-10 13:10:35 -0700 | [diff] [blame] | 749 | p := v23.GetPrincipal(c.ctx) |
Benjamin Prosnitz | 782a8a1 | 2015-04-22 15:02:38 -0700 | [diff] [blame] | 750 | outBlessings, err := p.BlessingStore().Set(inputBlessings, security.BlessingPattern(pattern)) |
Benjamin Prosnitz | 9e42399 | 2015-04-10 13:10:35 -0700 | [diff] [blame] | 751 | if err != nil { |
Benjamin Prosnitz | c65917c | 2015-05-26 14:21:53 -0700 | [diff] [blame] | 752 | return 0, err |
Benjamin Prosnitz | 9e42399 | 2015-04-10 13:10:35 -0700 | [diff] [blame] | 753 | } |
| 754 | |
Benjamin Prosnitz | 782a8a1 | 2015-04-22 15:02:38 -0700 | [diff] [blame] | 755 | if outBlessings.IsZero() { |
Benjamin Prosnitz | c65917c | 2015-05-26 14:21:53 -0700 | [diff] [blame] | 756 | return 0, nil |
Benjamin Prosnitz | 9e42399 | 2015-04-10 13:10:35 -0700 | [diff] [blame] | 757 | } |
| 758 | |
Benjamin Prosnitz | ae30020 | 2015-06-04 19:36:49 -0700 | [diff] [blame] | 759 | return c.blessingsCache.Put(outBlessings), nil |
Benjamin Prosnitz | 782a8a1 | 2015-04-22 15:02:38 -0700 | [diff] [blame] | 760 | } |
| 761 | |
Benjamin Prosnitz | e1209d4 | 2015-05-04 15:06:42 -0700 | [diff] [blame] | 762 | // BlessingStoreForPeer puts the specified blessing in the blessing store under the |
| 763 | // provided pattern. |
Benjamin Prosnitz | c65917c | 2015-05-26 14:21:53 -0700 | [diff] [blame] | 764 | func (c *Controller) BlessingStoreForPeer(_ *context.T, _ rpc.ServerCall, peerBlessings []string) (principal.BlessingsId, error) { |
Benjamin Prosnitz | e1209d4 | 2015-05-04 15:06:42 -0700 | [diff] [blame] | 765 | p := v23.GetPrincipal(c.ctx) |
| 766 | outBlessings := p.BlessingStore().ForPeer(peerBlessings...) |
| 767 | |
| 768 | if outBlessings.IsZero() { |
Benjamin Prosnitz | c65917c | 2015-05-26 14:21:53 -0700 | [diff] [blame] | 769 | return 0, nil |
Benjamin Prosnitz | e1209d4 | 2015-05-04 15:06:42 -0700 | [diff] [blame] | 770 | } |
| 771 | |
Benjamin Prosnitz | ae30020 | 2015-06-04 19:36:49 -0700 | [diff] [blame] | 772 | return c.blessingsCache.Put(outBlessings), nil |
Benjamin Prosnitz | e1209d4 | 2015-05-04 15:06:42 -0700 | [diff] [blame] | 773 | } |
| 774 | |
| 775 | // BlessingStoreSetDefault sets the default blessings in the blessing store. |
Benjamin Prosnitz | ae30020 | 2015-06-04 19:36:49 -0700 | [diff] [blame] | 776 | func (c *Controller) BlessingStoreSetDefault(_ *context.T, _ rpc.ServerCall, inputBlessings security.Blessings) error { |
Benjamin Prosnitz | 782a8a1 | 2015-04-22 15:02:38 -0700 | [diff] [blame] | 777 | p := v23.GetPrincipal(c.ctx) |
Benjamin Prosnitz | e1209d4 | 2015-05-04 15:06:42 -0700 | [diff] [blame] | 778 | return p.BlessingStore().SetDefault(inputBlessings) |
Benjamin Prosnitz | 9e42399 | 2015-04-10 13:10:35 -0700 | [diff] [blame] | 779 | } |
| 780 | |
Benjamin Prosnitz | e1209d4 | 2015-05-04 15:06:42 -0700 | [diff] [blame] | 781 | // BlessingStoreDefault fetches the default blessings for the principal of the controller. |
Benjamin Prosnitz | c65917c | 2015-05-26 14:21:53 -0700 | [diff] [blame] | 782 | func (c *Controller) BlessingStoreDefault(*context.T, rpc.ServerCall) (principal.BlessingsId, error) { |
Shyam Jayaraman | 07136a7 | 2015-04-13 13:34:41 -0700 | [diff] [blame] | 783 | p := v23.GetPrincipal(c.ctx) |
| 784 | outBlessings := p.BlessingStore().Default() |
| 785 | |
| 786 | if outBlessings.IsZero() { |
Benjamin Prosnitz | c65917c | 2015-05-26 14:21:53 -0700 | [diff] [blame] | 787 | return 0, nil |
Shyam Jayaraman | 07136a7 | 2015-04-13 13:34:41 -0700 | [diff] [blame] | 788 | } |
| 789 | |
Benjamin Prosnitz | ae30020 | 2015-06-04 19:36:49 -0700 | [diff] [blame] | 790 | return c.blessingsCache.Put(outBlessings), nil |
Shyam Jayaraman | 07136a7 | 2015-04-13 13:34:41 -0700 | [diff] [blame] | 791 | } |
| 792 | |
Benjamin Prosnitz | e1209d4 | 2015-05-04 15:06:42 -0700 | [diff] [blame] | 793 | // BlessingStorePublicKey fetches the public key used by the principal associated with the blessing store. |
Benjamin Prosnitz | ae30020 | 2015-06-04 19:36:49 -0700 | [diff] [blame] | 794 | func (c *Controller) BlessingStorePublicKey(*context.T, rpc.ServerCall) ([]byte, error) { |
Benjamin Prosnitz | e1209d4 | 2015-05-04 15:06:42 -0700 | [diff] [blame] | 795 | p := v23.GetPrincipal(c.ctx) |
Benjamin Prosnitz | ae30020 | 2015-06-04 19:36:49 -0700 | [diff] [blame] | 796 | return p.BlessingStore().PublicKey().MarshalBinary() |
Benjamin Prosnitz | e1209d4 | 2015-05-04 15:06:42 -0700 | [diff] [blame] | 797 | } |
| 798 | |
| 799 | // BlessingStorePeerBlessings returns all the blessings that the BlessingStore holds. |
Benjamin Prosnitz | c65917c | 2015-05-26 14:21:53 -0700 | [diff] [blame] | 800 | func (c *Controller) BlessingStorePeerBlessings(*context.T, rpc.ServerCall) (map[security.BlessingPattern]principal.BlessingsId, error) { |
Benjamin Prosnitz | e1209d4 | 2015-05-04 15:06:42 -0700 | [diff] [blame] | 801 | p := v23.GetPrincipal(c.ctx) |
Benjamin Prosnitz | c65917c | 2015-05-26 14:21:53 -0700 | [diff] [blame] | 802 | outBlessingsMap := map[security.BlessingPattern]principal.BlessingsId{} |
Benjamin Prosnitz | e1209d4 | 2015-05-04 15:06:42 -0700 | [diff] [blame] | 803 | for pattern, blessings := range p.BlessingStore().PeerBlessings() { |
Benjamin Prosnitz | ae30020 | 2015-06-04 19:36:49 -0700 | [diff] [blame] | 804 | outBlessingsMap[pattern] = c.blessingsCache.Put(blessings) |
Benjamin Prosnitz | e1209d4 | 2015-05-04 15:06:42 -0700 | [diff] [blame] | 805 | } |
| 806 | return outBlessingsMap, nil |
| 807 | } |
| 808 | |
| 809 | // BlessingStoreDebugString retrieves a debug string describing the state of the blessing store |
| 810 | func (c *Controller) BlessingStoreDebugString(*context.T, rpc.ServerCall) (string, error) { |
| 811 | p := v23.GetPrincipal(c.ctx) |
| 812 | ds := p.BlessingStore().DebugString() |
| 813 | return ds, nil |
| 814 | } |
| 815 | |
| 816 | // AddToRoots adds the provided blessing as a root. |
Benjamin Prosnitz | ae30020 | 2015-06-04 19:36:49 -0700 | [diff] [blame] | 817 | func (c *Controller) AddToRoots(_ *context.T, _ rpc.ServerCall, inputBlessings security.Blessings) error { |
Benjamin Prosnitz | e1209d4 | 2015-05-04 15:06:42 -0700 | [diff] [blame] | 818 | p := v23.GetPrincipal(c.ctx) |
| 819 | return p.AddToRoots(inputBlessings) |
| 820 | } |
| 821 | |
Benjamin Prosnitz | bf71e96 | 2015-04-14 16:43:07 -0700 | [diff] [blame] | 822 | // HandleGranterResponse handles the result of a Granter request. |
Cosmos Nicolaou | d922992 | 2015-06-24 14:12:24 -0700 | [diff] [blame] | 823 | func (c *Controller) HandleGranterResponse(ctx *context.T, id int32, data string) { |
Benjamin Prosnitz | bf71e96 | 2015-04-14 16:43:07 -0700 | [diff] [blame] | 824 | c.Lock() |
| 825 | granterStr, ok := c.flowMap[id].(*granterStream) |
| 826 | c.Unlock() |
| 827 | if !ok { |
Cosmos Nicolaou | d922992 | 2015-06-24 14:12:24 -0700 | [diff] [blame] | 828 | ctx.Errorf("unexpected result from JavaScript. Flow was not a granter "+ |
Benjamin Prosnitz | bf71e96 | 2015-04-14 16:43:07 -0700 | [diff] [blame] | 829 | "stream for MessageId: %d exists. Ignoring the results.", id) |
| 830 | //Ignore unknown responses that don't belong to any channel |
| 831 | return |
| 832 | } |
| 833 | granterStr.Send(data) |
| 834 | } |
| 835 | |
Cosmos Nicolaou | d922992 | 2015-06-24 14:12:24 -0700 | [diff] [blame] | 836 | func (c *Controller) HandleTypeMessage(ctx *context.T, data string) { |
Shyam Jayaraman | 251f9d3 | 2015-05-29 09:27:48 -0700 | [diff] [blame] | 837 | c.typeReader.Add(data) |
| 838 | } |
| 839 | |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 840 | func (c *Controller) RemoteBlessings(ctx *context.T, _ rpc.ServerCall, name, method string) ([]string, error) { |
Cosmos Nicolaou | d922992 | 2015-06-24 14:12:24 -0700 | [diff] [blame] | 841 | ctx.VI(2).Infof("requesting remote blessings for %q", name) |
Nicolas LaCasse | e8f8ec0 | 2015-02-04 14:14:52 -0800 | [diff] [blame] | 842 | |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 843 | cctx, cancel := context.WithTimeout(ctx, 5*time.Second) |
Nicolas LaCasse | e8f8ec0 | 2015-02-04 14:14:52 -0800 | [diff] [blame] | 844 | defer cancel() |
| 845 | |
Matt Rosencrantz | 9dce9b2 | 2015-03-02 10:48:37 -0800 | [diff] [blame] | 846 | clientCall, err := v23.GetClient(cctx).StartCall(cctx, name, method, nil) |
Nicolas LaCasse | e8f8ec0 | 2015-02-04 14:14:52 -0800 | [diff] [blame] | 847 | if err != nil { |
Matt Rosencrantz | ec3b950 | 2015-02-19 12:53:13 -0800 | [diff] [blame] | 848 | return nil, verror.Convert(verror.ErrInternal, cctx, err) |
Nicolas LaCasse | e8f8ec0 | 2015-02-04 14:14:52 -0800 | [diff] [blame] | 849 | } |
| 850 | |
Matt Rosencrantz | 9dce9b2 | 2015-03-02 10:48:37 -0800 | [diff] [blame] | 851 | blessings, _ := clientCall.RemoteBlessings() |
Nicolas LaCasse | e8f8ec0 | 2015-02-04 14:14:52 -0800 | [diff] [blame] | 852 | return blessings, nil |
| 853 | } |
Shyam Jayaraman | c17abda | 2015-04-06 16:49:17 -0700 | [diff] [blame] | 854 | |
| 855 | func (c *Controller) SendLogMessage(level lib.LogLevel, msg string) error { |
| 856 | c.Lock() |
| 857 | defer c.Unlock() |
| 858 | id := c.lastGeneratedId |
| 859 | c.lastGeneratedId += 2 |
| 860 | return c.writerCreator(id).Send(lib.ResponseLog, lib.LogMessage{ |
| 861 | Level: level, |
| 862 | Message: msg, |
| 863 | }) |
| 864 | } |
Benjamin Prosnitz | c65917c | 2015-05-26 14:21:53 -0700 | [diff] [blame] | 865 | |
| 866 | func (c *Controller) SendBlessingsCacheMessages(messages []principal.BlessingsCacheMessage) { |
| 867 | c.Lock() |
| 868 | defer c.Unlock() |
| 869 | id := c.lastGeneratedId |
| 870 | c.lastGeneratedId += 2 |
| 871 | if err := c.writerCreator(id).Send(lib.ResponseBlessingsCacheMessage, messages); err != nil { |
Cosmos Nicolaou | d922992 | 2015-06-24 14:12:24 -0700 | [diff] [blame] | 872 | c.ctx.Errorf("unexpected error sending blessings cache message: %v", err) |
Benjamin Prosnitz | c65917c | 2015-05-26 14:21:53 -0700 | [diff] [blame] | 873 | } |
| 874 | } |
Shyam Jayaraman | 3facd24 | 2015-05-29 11:20:59 -0700 | [diff] [blame] | 875 | |
| 876 | func (c *Controller) TypeEncoder() *vom.TypeEncoder { |
| 877 | return c.typeEncoder |
| 878 | } |
Shyam Jayaraman | 0062e27 | 2015-06-04 11:25:13 -0700 | [diff] [blame] | 879 | |
| 880 | func (c *Controller) TypeDecoder() *vom.TypeDecoder { |
| 881 | return c.typeDecoder |
| 882 | } |