blob: 6edb6c0010d21d03963c453e30a4eab8d9316c74 [file] [log] [blame]
Jiri Simsad7616c92015-03-24 23:44:30 -07001// 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 Simsa78b646f2014-10-08 10:23:05 -07005// The app package contains the struct that keeps per javascript app state and handles translating
Suharsh Sivakumard1cc6e02015-03-16 13:58:49 -07006// javascript requests to vanadium requests and vice versa.
Jiri Simsa78b646f2014-10-08 10:23:05 -07007package app
8
9import (
Shyam Jayaraman251f9d32015-05-29 09:27:48 -070010 "bytes"
11 "encoding/hex"
Jiri Simsa78b646f2014-10-08 10:23:05 -070012 "fmt"
13 "io"
Todd Wang5ab03662015-02-19 21:03:01 -080014 "reflect"
Jiri Simsa78b646f2014-10-08 10:23:05 -070015 "sync"
16 "time"
17
Jiri Simsa1f1302c2015-02-23 16:18:34 -080018 "v.io/v23"
19 "v.io/v23/context"
Shyam Jayaraman8e301b52015-04-27 14:12:16 -070020 "v.io/v23/i18n"
Jiri Simsa1f1302c2015-02-23 16:18:34 -080021 "v.io/v23/naming"
22 "v.io/v23/options"
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070023 "v.io/v23/rpc"
Jiri Simsa1f1302c2015-02-23 16:18:34 -080024 "v.io/v23/security"
25 "v.io/v23/vdl"
Todd Wangac9e1902015-02-25 01:58:01 -080026 "v.io/v23/vdlroot/signature"
Jiri Simsa1f1302c2015-02-23 16:18:34 -080027 "v.io/v23/verror"
Jiri Simsa1f1302c2015-02-23 16:18:34 -080028 "v.io/v23/vom"
29 "v.io/v23/vtrace"
Todd Wang5b77a342015-04-06 18:31:37 -070030 "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 Simsa78b646f2014-10-08 10:23:05 -070034)
35
Nicolas Lacasse938c4722015-03-19 14:42:18 -070036const (
37 // pkgPath is the prefix os errors in this package.
Todd Wang5b77a342015-04-06 18:31:37 -070038 pkgPath = "v.io/x/ref/services/wspr/internal/app"
Shyam Jayaraman251f9d32015-05-29 09:27:48 -070039
40 typeFlow = 0
Nicolas Lacasse938c4722015-03-19 14:42:18 -070041)
Mike Burrowsb6689c22014-10-08 11:14:15 -070042
43// Errors
Ankure7889242014-10-20 18:37:29 -070044var (
Benjamin Prosnitzae300202015-06-04 19:36:49 -070045 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 {_}")
Ankure7889242014-10-20 18:37:29 -070049)
Mike Burrowsb6689c22014-10-08 11:14:15 -070050
Matt Rosencrantz4aabe572014-10-22 09:25:50 -070051type outstandingRequest struct {
52 stream *outstandingStream
53 cancel context.CancelFunc
54}
55
Suharsh Sivakumard1cc6e02015-03-16 13:58:49 -070056// 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 Simsa78b646f2014-10-08 10:23:05 -070058type Controller struct {
59 // Protects everything.
60 // TODO(bjornick): We need to split this up.
61 sync.Mutex
62
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -080063 // The context of this controller.
64 ctx *context.T
Jiri Simsa78b646f2014-10-08 10:23:05 -070065
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -080066 // The cleanup function for this controller.
67 cancel context.CancelFunc
Jiri Simsa78b646f2014-10-08 10:23:05 -070068
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070069 // The rpc.ListenSpec to use with server.Listen
70 listenSpec *rpc.ListenSpec
Jiri Simsa78b646f2014-10-08 10:23:05 -070071
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 Prosnitz86d52282014-12-19 15:48:38 -080075 lastGeneratedId int32
Jiri Simsa78b646f2014-10-08 10:23:05 -070076
Matt Rosencrantz4aabe572014-10-22 09:25:50 -070077 // Used to keep track of data (streams and cancellation functions) for
78 // outstanding requests.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -080079 outstandingRequests map[int32]*outstandingRequest
Jiri Simsa78b646f2014-10-08 10:23:05 -070080
81 // Maps flowids to the server that owns them.
Benjamin Prosnitzbf71e962015-04-14 16:43:07 -070082 flowMap map[int32]interface{}
Jiri Simsa78b646f2014-10-08 10:23:05 -070083
84 // A manager that Handles fetching and caching signature of remote services
85 signatureManager lib.SignatureManager
86
Suharsh Sivakumard1cc6e02015-03-16 13:58:49 -070087 // We maintain multiple Vanadium server per pipe for serving JavaScript
Jiri Simsa78b646f2014-10-08 10:23:05 -070088 // services.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -080089 servers map[uint32]*server.Server
Jiri Simsa78b646f2014-10-08 10:23:05 -070090
91 // Creates a client writer for a given flow. This is a member so that tests can override
92 // the default implementation.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -080093 writerCreator func(id int32) lib.ClientWriter
Jiri Simsa78b646f2014-10-08 10:23:05 -070094
Benjamin Prosnitzc65917c2015-05-26 14:21:53 -070095 // Cache of Blessings that were sent to Javascript.
96 blessingsCache *principal.BlessingsCache
Matt Rosencrantz9d2170b2015-02-21 16:19:53 -080097
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 Rosencrantz94502cf2015-03-18 09:43:44 -0700101 reservedServices map[string]rpc.Invoker
Shyam Jayaraman5753f392015-05-05 10:29:45 -0700102
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700103 typeEncoder *vom.TypeEncoder
Shyam Jayaraman5753f392015-05-05 10:29:45 -0700104
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700105 typeDecoder *vom.TypeDecoder
106 typeReader *lib.TypeReader
Jiri Simsa78b646f2014-10-08 10:23:05 -0700107}
108
Benjamin Prosnitzc65917c2015-05-26 14:21:53 -0700109var _ ControllerServerMethods = (*Controller)(nil)
110
Jiri Simsa78b646f2014-10-08 10:23:05 -0700111// NewController creates a new Controller. writerCreator will be used to create a new flow for rpcs to
Nicolas LaCasse0e317fa2015-03-09 12:52:42 -0700112// javascript server.
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700113func NewController(ctx *context.T, writerCreator func(id int32) lib.ClientWriter, listenSpec *rpc.ListenSpec, namespaceRoots []string, p security.Principal) (*Controller, error) {
Suharsh Sivakumar94d00662015-01-21 14:31:30 -0800114 ctx, cancel := context.WithCancel(ctx)
115
Benjamin Prosnitz3c738502014-11-04 14:51:38 -0800116 if namespaceRoots != nil {
Nicolas LaCasse0e317fa2015-03-09 12:52:42 -0700117 var err error
Todd Wangad492042015-04-17 15:58:40 -0700118 ctx, _, err = v23.WithNewNamespace(ctx, namespaceRoots...)
Nicolas LaCasse0e317fa2015-03-09 12:52:42 -0700119 if err != nil {
120 return nil, err
121 }
Benjamin Prosnitz3c738502014-11-04 14:51:38 -0800122 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700123
Todd Wangad492042015-04-17 15:58:40 -0700124 ctx, _ = vtrace.WithNewTrace(ctx)
Nicolas LaCasse0e317fa2015-03-09 12:52:42 -0700125
Todd Wangad492042015-04-17 15:58:40 -0700126 ctx, err := v23.WithPrincipal(ctx, p)
Suharsh Sivakumar94d00662015-01-21 14:31:30 -0800127 if err != nil {
128 return nil, err
129 }
130
Jiri Simsa78b646f2014-10-08 10:23:05 -0700131 controller := &Controller{
Benjamin Prosnitzae300202015-06-04 19:36:49 -0700132 ctx: ctx,
133 cancel: cancel,
134 writerCreator: writerCreator,
135 listenSpec: listenSpec,
Ankure7889242014-10-20 18:37:29 -0700136 }
137
Benjamin Prosnitzc65917c2015-05-26 14:21:53 -0700138 controller.blessingsCache = principal.NewBlessingsCache(controller.SendBlessingsCacheMessages, principal.PeriodicGcPolicy(1*time.Minute))
139
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700140 controllerInvoker, err := rpc.ReflectInvoker(ControllerServer(controller))
Matt Rosencrantz9d2170b2015-02-21 16:19:53 -0800141 if err != nil {
142 return nil, err
143 }
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700144 namespaceInvoker, err := rpc.ReflectInvoker(namespace.New(ctx))
Matt Rosencrantz9d2170b2015-02-21 16:19:53 -0800145 if err != nil {
146 return nil, err
147 }
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700148 controller.reservedServices = map[string]rpc.Invoker{
Matt Rosencrantz9d2170b2015-02-21 16:19:53 -0800149 "__controller": controllerInvoker,
150 "__namespace": namespaceInvoker,
151 }
152
Jiri Simsa78b646f2014-10-08 10:23:05 -0700153 controller.setup()
154 return controller, nil
155}
156
157// finishCall waits for the call to finish and write out the response to w.
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700158func (c *Controller) finishCall(ctx *context.T, w lib.ClientWriter, clientCall rpc.ClientCall, msg *RpcRequest, span vtrace.Span) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700159 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 Jayaraman3facd242015-05-29 11:20:59 -0700169 vomItem, err := lib.HexVomEncode(item, c.typeEncoder)
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800170 if err != nil {
Todd Wangb63e9eb2015-02-10 19:57:39 -0800171 w.Error(verror.New(marshallingError, ctx, item, err))
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800172 continue
173 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800174 if err := w.Send(lib.ResponseStream, vomItem); err != nil {
Todd Wangb63e9eb2015-02-10 19:57:39 -0800175 w.Error(verror.New(marshallingError, ctx, item))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700176 }
177 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700178 if err := w.Send(lib.ResponseStreamClose, nil); err != nil {
Todd Wangb63e9eb2015-02-10 19:57:39 -0800179 w.Error(verror.New(marshallingError, ctx, "ResponseStreamClose"))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700180 }
181 }
Todd Wang5ab03662015-02-19 21:03:01 -0800182 results := make([]*vdl.Value, msg.NumOutArgs)
Shyam Jayaraman07136a72015-04-13 13:34:41 -0700183 wireBlessingsType := vdl.TypeOf(security.WireBlessings{})
Todd Wang5ab03662015-02-19 21:03:01 -0800184 // This array will have pointers to the values in results.
Todd Wangf21e1552015-02-18 13:21:52 -0800185 resultptrs := make([]interface{}, msg.NumOutArgs)
Todd Wang5ab03662015-02-19 21:03:01 -0800186 for i := range results {
187 resultptrs[i] = &results[i]
Jiri Simsa78b646f2014-10-08 10:23:05 -0700188 }
189 if err := clientCall.Finish(resultptrs...); err != nil {
190 // return the call system error as is
191 w.Error(err)
192 return
193 }
Shyam Jayaraman07136a72015-04-13 13:34:41 -0700194 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 Prosnitzae300202015-06-04 19:36:49 -0700201 results[i] = vdl.ValueOf(c.blessingsCache.Put(blessings))
Shyam Jayaraman07136a72015-04-13 13:34:41 -0700202 }
203 }
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800204 c.sendRPCResponse(ctx, w, span, results)
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800205}
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800206
Todd Wang5ab03662015-02-19 21:03:01 -0800207func (c *Controller) sendRPCResponse(ctx *context.T, w lib.ClientWriter, span vtrace.Span, results []*vdl.Value) {
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800208 span.Finish()
Todd Wangbaf16842015-03-16 14:12:29 -0700209 response := RpcResponse{
Matt Rosencrantz2803fe92015-03-09 15:26:32 -0700210 OutArgs: results,
211 TraceResponse: vtrace.GetResponse(ctx),
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800212 }
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700213 var buf bytes.Buffer
214 encoder := vom.NewEncoderWithTypeEncoder(&buf, c.typeEncoder)
215 if err := encoder.Encode(response); err != nil {
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800216 w.Error(err)
217 return
218 }
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700219 encoded := hex.EncodeToString(buf.Bytes())
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800220 if err := w.Send(lib.ResponseFinal, encoded); err != nil {
Todd Wangb63e9eb2015-02-10 19:57:39 -0800221 w.Error(verror.Convert(marshallingError, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700222 }
223}
224
Nicolas Lacasse938c4722015-03-19 14:42:18 -0700225// callOpts turns a slice of type []RpcCallOption object into an array of rpc.CallOpt.
226func (c *Controller) callOpts(opts []RpcCallOption) ([]rpc.CallOpt, error) {
227 var callOpts []rpc.CallOpt
228
Nicolas Lacasse938c4722015-03-19 14:42:18 -0700229 for _, opt := range opts {
230 switch v := opt.(type) {
231 case RpcCallOptionAllowedServersPolicy:
232 callOpts = append(callOpts, options.AllowedServersPolicy(v.Value))
233 case RpcCallOptionRetryTimeout:
Nicolas Lacasse938c4722015-03-19 14:42:18 -0700234 callOpts = append(callOpts, options.RetryTimeout(v.Value))
Nicolas Lacassef0ec4052015-04-28 13:13:13 -0700235 case RpcCallOptionGranter:
Benjamin Prosnitzbf71e962015-04-14 16:43:07 -0700236 callOpts = append(callOpts, &jsGranter{c, v.Value})
Nicolas Lacasse938c4722015-03-19 14:42:18 -0700237 default:
238 return nil, fmt.Errorf("Unknown RpcCallOption type %T", v)
239 }
240 }
241
Nicolas Lacasse938c4722015-03-19 14:42:18 -0700242 return callOpts, nil
243}
244
Ali Ghassemibac34032015-04-30 18:27:57 -0700245// serverOpts turns a slice of type []RpcServerOptions object into an array of rpc.ServerOpt.
246func (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 Rosencrantz94502cf2015-03-18 09:43:44 -0700263func (c *Controller) startCall(ctx *context.T, w lib.ClientWriter, msg *RpcRequest, inArgs []interface{}) (rpc.ClientCall, error) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700264 methodName := lib.UppercaseFirstCharacter(msg.Method)
Nicolas Lacasse938c4722015-03-19 14:42:18 -0700265 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 Simsa78b646f2014-10-08 10:23:05 -0700270 if err != nil {
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800271 return nil, fmt.Errorf("error starting call (name: %v, method: %v, args: %v): %v", msg.Name, methodName, inArgs, err)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700272 }
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 Prosnitzbf71e962015-04-14 16:43:07 -0700281func (c *Controller) CreateNewFlow(s interface{}, stream rpc.Stream) *server.Flow {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700282 c.Lock()
283 defer c.Unlock()
284 id := c.lastGeneratedId
285 c.lastGeneratedId += 2
286 c.flowMap[id] = s
Benjamin Prosnitzae300202015-06-04 19:36:49 -0700287 os := newStream(c.typeDecoder)
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800288 os.init(stream)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700289 c.outstandingRequests[id] = &outstandingRequest{
290 stream: os,
291 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700292 return &server.Flow{ID: id, Writer: c.writerCreator(id)}
293}
294
Shyam Jayaraman07136a72015-04-13 13:34:41 -0700295// CleanupFlow removes the bookkeeping for a previously created flow.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800296func (c *Controller) CleanupFlow(id int32) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700297 c.Lock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700298 request := c.outstandingRequests[id]
299 delete(c.outstandingRequests, id)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700300 delete(c.flowMap, id)
301 c.Unlock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700302 if request != nil && request.stream != nil {
303 request.stream.end()
304 request.stream.waitUntilDone()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700305 }
306}
307
Benjamin Prosnitzc65917c2015-05-26 14:21:53 -0700308// BlessingsCache gets the blessings cache used by the controller.
309func (c *Controller) BlessingsCache() *principal.BlessingsCache {
310 return c.blessingsCache
311}
312
Jiri Simsa78b646f2014-10-08 10:23:05 -0700313// RT returns the runtime of the app.
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800314func (c *Controller) Context() *context.T {
315 return c.ctx
Jiri Simsa78b646f2014-10-08 10:23:05 -0700316}
317
Jiri Simsa78b646f2014-10-08 10:23:05 -0700318// Cleanup cleans up any outstanding rpcs.
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700319func (c *Controller) Cleanup(ctx *context.T) {
320 ctx.VI(0).Info("Cleaning up controller")
Jiri Simsa78b646f2014-10-08 10:23:05 -0700321 c.Lock()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700322
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700323 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 Simsa78b646f2014-10-08 10:23:05 -0700330 }
331
Nicolas LaCasse60f423e2015-02-04 17:53:14 -0800332 servers := []*server.Server{}
Jiri Simsa78b646f2014-10-08 10:23:05 -0700333 for _, server := range c.servers {
Nicolas LaCasse60f423e2015-02-04 17:53:14 -0800334 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 Simsa78b646f2014-10-08 10:23:05 -0700341 server.Stop()
342 }
Benjamin Prosnitz8a51fe82014-10-16 13:05:14 -0700343
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700344 c.typeReader.Close()
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800345 c.cancel()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700346}
347
348func (c *Controller) setup() {
349 c.signatureManager = lib.NewSignatureManager()
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800350 c.outstandingRequests = make(map[int32]*outstandingRequest)
Benjamin Prosnitzbf71e962015-04-14 16:43:07 -0700351 c.flowMap = make(map[int32]interface{})
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800352 c.servers = make(map[uint32]*server.Server)
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700353 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 Simsa78b646f2014-10-08 10:23:05 -0700357}
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 Nicolaoud9229922015-06-24 14:12:24 -0700361func (c *Controller) SendOnStream(ctx *context.T, id int32, data string, w lib.ClientWriter) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700362 c.Lock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700363 request := c.outstandingRequests[id]
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700364 if request == nil || request.stream == nil {
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700365 ctx.Errorf("unknown stream: %d", id)
Ali Ghassemi700de8e2015-02-25 17:06:15 -0800366 c.Unlock()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700367 return
368 }
Matt Rosencrantzd608b372014-10-22 13:06:52 -0700369 stream := request.stream
370 c.Unlock()
371 stream.send(data, w)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700372}
373
Suharsh Sivakumard1cc6e02015-03-16 13:58:49 -0700374// SendVeyronRequest makes a vanadium request for the given flowId. If signal is non-nil, it will receive
Jiri Simsa78b646f2014-10-08 10:23:05 -0700375// the call object after it has been constructed.
Todd Wangbaf16842015-03-16 14:12:29 -0700376func (c *Controller) sendVeyronRequest(ctx *context.T, id int32, msg *RpcRequest, inArgs []interface{}, w lib.ClientWriter, stream *outstandingStream, span vtrace.Span) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700377 // 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 Rosencrantz786f7272015-02-11 15:18:07 -0800379 call, err := c.startCall(ctx, w, msg, inArgs)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700380 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800381 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700382 return
383 }
384
385 if stream != nil {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800386 stream.init(call)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700387 }
388
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800389 c.finishCall(ctx, w, call, msg, span)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700390 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 Simsa78b646f2014-10-08 10:23:05 -0700396 }
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700397 c.Unlock()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700398}
399
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800400// 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.
403type localCall struct {
Shyam Jayaraman3facd242015-05-29 11:20:59 -0700404 ctx *context.T
405 vrpc *RpcRequest
406 tags []*vdl.Value
407 w lib.ClientWriter
408 typeEncoder *vom.TypeEncoder
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800409}
410
Todd Wang54feabe2015-04-15 23:38:26 -0700411var (
412 _ rpc.StreamServerCall = (*localCall)(nil)
413 _ security.Call = (*localCall)(nil)
414)
415
Matt Rosencrantz9d2170b2015-02-21 16:19:53 -0800416func (l *localCall) Send(item interface{}) error {
Shyam Jayaraman3facd242015-05-29 11:20:59 -0700417 vomItem, err := lib.HexVomEncode(item, l.typeEncoder)
Matt Rosencrantz9d2170b2015-02-21 16:19:53 -0800418 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 Rosencrantz786f7272015-02-11 15:18:07 -0800430func (l *localCall) Recv(interface{}) error { return nil }
Suharsh Sivakumar380bf342015-02-27 15:38:27 -0800431func (l *localCall) GrantedBlessings() security.Blessings { return security.Blessings{} }
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700432func (l *localCall) Server() rpc.Server { return nil }
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800433func (l *localCall) Timestamp() (t time.Time) { return }
434func (l *localCall) Method() string { return l.vrpc.Method }
Todd Wang5ab03662015-02-19 21:03:01 -0800435func (l *localCall) MethodTags() []*vdl.Value { return l.tags }
Todd Wang54feabe2015-04-15 23:38:26 -0700436func (l *localCall) Suffix() string { return l.vrpc.Name }
Ankuredd74ee2015-03-04 16:38:45 -0800437func (l *localCall) LocalDischarges() map[string]security.Discharge { return nil }
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800438func (l *localCall) RemoteDischarges() map[string]security.Discharge { return nil }
439func (l *localCall) LocalPrincipal() security.Principal { return nil }
Asim Shankar2bf7b1e2015-02-27 00:45:12 -0800440func (l *localCall) LocalBlessings() security.Blessings { return security.Blessings{} }
441func (l *localCall) RemoteBlessings() security.Blessings { return security.Blessings{} }
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800442func (l *localCall) LocalEndpoint() naming.Endpoint { return nil }
443func (l *localCall) RemoteEndpoint() naming.Endpoint { return nil }
Todd Wang54feabe2015-04-15 23:38:26 -0700444func (l *localCall) Security() security.Call { return l }
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800445
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700446func (c *Controller) handleInternalCall(ctx *context.T, invoker rpc.Invoker, msg *RpcRequest, w lib.ClientWriter, span vtrace.Span, decoder *vom.Decoder) {
Cosmos Nicolaou5a3125a2015-07-10 11:19:20 -0700447 argptrs, tags, err := invoker.Prepare(ctx, msg.Method, int(msg.NumInArgs))
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800448 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800449 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800450 return
451 }
452 for _, argptr := range argptrs {
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700453 if err := decoder.Decode(argptr); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800454 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800455 return
456 }
457 }
Shyam Jayaraman3facd242015-05-29 11:20:59 -0700458 results, err := invoker.Invoke(ctx, &localCall{ctx, msg, tags, w, c.typeEncoder}, msg.Method, argptrs)
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700459 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 Wang5ab03662015-02-19 21:03:01 -0800473 if err != nil {
474 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
475 return
476 }
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700477 vresults[i] = vv
478 }
479 c.sendRPCResponse(ctx, w, span, vresults)
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800480}
481
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800482// HandleCaveatValidationResponse handles the response to caveat validation
483// requests.
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700484func (c *Controller) HandleCaveatValidationResponse(ctx *context.T, id int32, data string) {
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800485 c.Lock()
Benjamin Prosnitzbf71e962015-04-14 16:43:07 -0700486 server, ok := c.flowMap[id].(*server.Server)
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800487 c.Unlock()
Benjamin Prosnitzbf71e962015-04-14 16:43:07 -0700488 if !ok {
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700489 ctx.Errorf("unexpected result from JavaScript. No server found matching id %d.", id)
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800490 return // ignore unknown server
491 }
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700492 server.HandleCaveatValidationResponse(ctx, id, data)
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800493}
494
Suharsh Sivakumard1cc6e02015-03-16 13:58:49 -0700495// HandleVeyronRequest starts a vanadium rpc and returns before the rpc has been completed.
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800496func (c *Controller) HandleVeyronRequest(ctx *context.T, id int32, data string, w lib.ClientWriter) {
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700497 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 Rosencrantz786f7272015-02-11 15:18:07 -0800503 if err != nil {
Benjamin Prosnitzbf71e962015-04-14 16:43:07 -0700504 w.Error(verror.Convert(verror.ErrInternal, ctx, fmt.Errorf("Error decoding hex string %q: %v", data, err)))
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800505 return
506 }
Todd Wangbaf16842015-03-16 14:12:29 -0700507 var msg RpcRequest
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700508 if err := decoder.Decode(&msg); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800509 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800510 return
511 }
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700512 ctx.VI(2).Infof("Rpc: %s.%s(..., streaming=%v)", msg.Name, msg.Method, msg.IsStreaming)
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800513 spanName := fmt.Sprintf("<wspr>%q.%s", msg.Name, msg.Method)
Todd Wangad492042015-04-17 15:58:40 -0700514 ctx, span := vtrace.WithContinuedTrace(ctx, spanName, msg.TraceRequest)
Shyam Jayaraman8e301b52015-04-27 14:12:16 -0700515 ctx = i18n.WithLangID(ctx, i18n.LangID(msg.Context.Language))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700516
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800517 var cctx *context.T
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700518 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 Jayaraman7efedbe2015-03-05 12:57:18 -0800523 if msg.Deadline.IsZero() {
Matt Rosencrantzb6f4b922015-01-05 13:31:55 -0800524 cctx, cancel = context.WithCancel(ctx)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700525 } else {
Shyam Jayaraman7efedbe2015-03-05 12:57:18 -0800526 cctx, cancel = context.WithDeadline(ctx, msg.Deadline.Time)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700527 }
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700528
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800529 // If this message is for an internal service, do a short-circuit dispatch here.
Matt Rosencrantz9d2170b2015-02-21 16:19:53 -0800530 if invoker, ok := c.reservedServices[msg.Name]; ok {
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700531 go c.handleInternalCall(ctx, invoker, &msg, w, span, decoder)
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800532 return
533 }
534
535 inArgs := make([]interface{}, msg.NumInArgs)
536 for i := range inArgs {
Shyam Jayaramanb40a8ce2015-02-25 12:42:35 -0800537 var v *vdl.Value
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700538 if err := decoder.Decode(&v); err != nil {
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800539 w.Error(err)
540 return
541 }
Shyam Jayaramanb40a8ce2015-02-25 12:42:35 -0800542 inArgs[i] = v
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800543 }
544
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700545 request := &outstandingRequest{
546 cancel: cancel,
547 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800548 if msg.IsStreaming {
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700549 // 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 Prosnitzae300202015-06-04 19:36:49 -0700554 request.stream = newStream(c.typeDecoder)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700555 }
556 c.Lock()
557 c.outstandingRequests[id] = request
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800558 go c.sendVeyronRequest(cctx, id, &msg, inArgs, w, request.stream, span)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700559 c.Unlock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700560}
561
562// HandleVeyronCancellation cancels the request corresponding to the
563// given id if it is still outstanding.
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700564func (c *Controller) HandleVeyronCancellation(ctx *context.T, id int32) {
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700565 c.Lock()
566 defer c.Unlock()
567 if request, ok := c.outstandingRequests[id]; ok && request.cancel != nil {
568 request.cancel()
569 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700570}
571
572// CloseStream closes the stream for a given id.
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700573func (c *Controller) CloseStream(ctx *context.T, id int32) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700574 c.Lock()
575 defer c.Unlock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700576 if request, ok := c.outstandingRequests[id]; ok && request.stream != nil {
577 request.stream.end()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700578 return
579 }
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700580 ctx.Errorf("close called on non-existent call: %v", id)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700581}
582
Ali Ghassemibac34032015-04-30 18:27:57 -0700583func (c *Controller) maybeCreateServer(serverId uint32, opts ...rpc.ServerOpt) (*server.Server, error) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700584 c.Lock()
585 defer c.Unlock()
586 if server, ok := c.servers[serverId]; ok {
587 return server, nil
588 }
Ali Ghassemibac34032015-04-30 18:27:57 -0700589 server, err := server.NewServer(serverId, c.listenSpec, c, opts...)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700590 if err != nil {
591 return nil, err
592 }
593 c.servers[serverId] = server
594 return server, nil
595}
596
Jiri Simsa78b646f2014-10-08 10:23:05 -0700597// HandleLookupResponse handles the result of a Dispatcher.Lookup call that was
598// run by the Javascript server.
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700599func (c *Controller) HandleLookupResponse(ctx *context.T, id int32, data string) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700600 c.Lock()
Benjamin Prosnitzbf71e962015-04-14 16:43:07 -0700601 server, ok := c.flowMap[id].(*server.Server)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700602 c.Unlock()
Benjamin Prosnitzbf71e962015-04-14 16:43:07 -0700603 if !ok {
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700604 ctx.Errorf("unexpected result from JavaScript. No channel "+
Jiri Simsa78b646f2014-10-08 10:23:05 -0700605 "for MessageId: %d exists. Ignoring the results.", id)
606 //Ignore unknown responses that don't belong to any channel
607 return
608 }
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700609 server.HandleLookupResponse(ctx, id, data)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700610}
611
612// HandleAuthResponse handles the result of a Authorizer.Authorize call that was
613// run by the Javascript server.
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700614func (c *Controller) HandleAuthResponse(ctx *context.T, id int32, data string) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700615 c.Lock()
Benjamin Prosnitzbf71e962015-04-14 16:43:07 -0700616 server, ok := c.flowMap[id].(*server.Server)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700617 c.Unlock()
Benjamin Prosnitzbf71e962015-04-14 16:43:07 -0700618 if !ok {
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700619 ctx.Errorf("unexpected result from JavaScript. No channel "+
Jiri Simsa78b646f2014-10-08 10:23:05 -0700620 "for MessageId: %d exists. Ignoring the results.", id)
621 //Ignore unknown responses that don't belong to any channel
622 return
623 }
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700624 server.HandleAuthResponse(ctx, id, data)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700625}
626
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800627// Serve instructs WSPR to start listening for calls on behalf
628// of a javascript server.
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700629func (c *Controller) Serve(ctx *context.T, _ rpc.ServerCall, name string, serverId uint32, rpcServerOpts []RpcServerOption) error {
Ali Ghassemibac34032015-04-30 18:27:57 -0700630
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 Rosencrantzd4bcec62015-02-18 14:05:49 -0800636 if err != nil {
637 return verror.Convert(verror.ErrInternal, nil, err)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700638 }
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700639 ctx.VI(2).Infof("serving under name: %q", name)
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800640 if err := server.Serve(name); err != nil {
641 return verror.Convert(verror.ErrInternal, nil, err)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700642 }
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800643 return nil
Jiri Simsa78b646f2014-10-08 10:23:05 -0700644}
645
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800646// Stop instructs WSPR to stop listening for calls for the
647// given javascript server.
Todd Wang54feabe2015-04-15 23:38:26 -0700648func (c *Controller) Stop(_ *context.T, _ rpc.ServerCall, serverId uint32) error {
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800649 c.Lock()
Benjamin Prosnitzbf71e962015-04-14 16:43:07 -0700650 server, ok := c.servers[serverId]
651 if !ok {
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800652 c.Unlock()
653 return nil
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800654 }
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800655 delete(c.servers, serverId)
656 c.Unlock()
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800657
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800658 server.Stop()
659 return nil
660}
661
662// AddName adds a published name to an existing server.
Todd Wang54feabe2015-04-15 23:38:26 -0700663func (c *Controller) AddName(_ *context.T, _ rpc.ServerCall, serverId uint32, name string) error {
Nicolas LaCasse4f409ce2014-11-25 11:44:03 -0800664 // Create a server for the pipe, if it does not exist already
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800665 server, err := c.maybeCreateServer(serverId)
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800666 if err != nil {
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800667 return verror.Convert(verror.ErrInternal, nil, err)
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800668 }
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800669 // Add name
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800670 if err := server.AddName(name); err != nil {
671 return verror.Convert(verror.ErrInternal, nil, err)
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800672 }
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800673 return nil
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800674}
675
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800676// RemoveName removes a published name from an existing server.
Todd Wang54feabe2015-04-15 23:38:26 -0700677func (c *Controller) RemoveName(_ *context.T, _ rpc.ServerCall, serverId uint32, name string) error {
Nicolas LaCasse4f409ce2014-11-25 11:44:03 -0800678 // Create a server for the pipe, if it does not exist already
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800679 server, err := c.maybeCreateServer(serverId)
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800680 if err != nil {
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800681 return verror.Convert(verror.ErrInternal, nil, err)
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800682 }
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800683 // Remove name
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800684 server.RemoveName(name)
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800685 // Remove name from signature cache as well
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800686 c.signatureManager.FlushCacheEntry(name)
687 return nil
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800688}
689
Jiri Simsa78b646f2014-10-08 10:23:05 -0700690// HandleServerResponse handles the completion of outstanding calls to JavaScript services
691// by filling the corresponding channel with the result from JavaScript.
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700692func (c *Controller) HandleServerResponse(ctx *context.T, id int32, data string) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700693 c.Lock()
Benjamin Prosnitzbf71e962015-04-14 16:43:07 -0700694 server, ok := c.flowMap[id].(*server.Server)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700695 c.Unlock()
Benjamin Prosnitzbf71e962015-04-14 16:43:07 -0700696 if !ok {
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700697 ctx.Errorf("unexpected result from JavaScript. No channel "+
Jiri Simsa78b646f2014-10-08 10:23:05 -0700698 "for MessageId: %d exists. Ignoring the results.", id)
699 //Ignore unknown responses that don't belong to any channel
700 return
701 }
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700702 server.HandleServerResponse(ctx, id, data)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700703}
704
Matt Rosencrantzec3b9502015-02-19 12:53:13 -0800705// getSignature uses the signature manager to get and cache the signature of a remote server.
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800706func (c *Controller) getSignature(ctx *context.T, name string) ([]signature.Interface, error) {
Nicolas Lacassec577e9f2015-03-19 16:21:19 -0700707 return c.signatureManager.Signature(ctx, name)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700708}
709
Matt Rosencrantzec3b9502015-02-19 12:53:13 -0800710// Signature uses the signature manager to get and cache the signature of a remote server.
Todd Wang54feabe2015-04-15 23:38:26 -0700711func (c *Controller) Signature(ctx *context.T, _ rpc.ServerCall, name string) ([]signature.Interface, error) {
712 return c.getSignature(ctx, name)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700713}
714
Benjamin Prosnitz23bf1a02015-03-30 16:17:04 -0700715// Bless binds extensions of blessings held by this principal to
716// another principal (represented by its public key).
Benjamin Prosnitzae300202015-06-04 19:36:49 -0700717func (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)
Ankure7889242014-10-20 18:37:29 -0700719 if err != nil {
Benjamin Prosnitzc65917c2015-05-26 14:21:53 -0700720 return 0, err
Ankure7889242014-10-20 18:37:29 -0700721 }
Ankure7889242014-10-20 18:37:29 -0700722
Benjamin Prosnitz23bf1a02015-03-30 16:17:04 -0700723 if len(caveats) == 0 {
724 caveats = append(caveats, security.UnconstrainedUse())
725 }
726
Jiri Simsa1f1302c2015-02-23 16:18:34 -0800727 p := v23.GetPrincipal(c.ctx)
Benjamin Prosnitzae300202015-06-04 19:36:49 -0700728 blessings, err := p.Bless(key, inputBlessings, extension, caveats[0], caveats[1:]...)
Ankure7889242014-10-20 18:37:29 -0700729 if err != nil {
Benjamin Prosnitzc65917c2015-05-26 14:21:53 -0700730 return 0, err
Ankure7889242014-10-20 18:37:29 -0700731 }
Benjamin Prosnitzae300202015-06-04 19:36:49 -0700732 return c.blessingsCache.Put(blessings), nil
Ankure7889242014-10-20 18:37:29 -0700733}
734
Benjamin Prosnitz23bf1a02015-03-30 16:17:04 -0700735// BlessSelf creates a blessing with the provided name for this principal.
Benjamin Prosnitzc65917c2015-05-26 14:21:53 -0700736func (c *Controller) BlessSelf(_ *context.T, _ rpc.ServerCall, extension string, caveats []security.Caveat) (principal.BlessingsId, error) {
Benjamin Prosnitz23bf1a02015-03-30 16:17:04 -0700737 p := v23.GetPrincipal(c.ctx)
Benjamin Prosnitz70b76642015-06-05 13:54:00 +0800738 blessings, err := p.BlessSelf(extension, caveats...)
Ankure7889242014-10-20 18:37:29 -0700739 if err != nil {
Benjamin Prosnitzc65917c2015-05-26 14:21:53 -0700740 return 0, verror.Convert(verror.ErrInternal, nil, err)
Ankure7889242014-10-20 18:37:29 -0700741 }
Matt Rosencrantzfeefb772015-02-18 14:58:49 -0800742
Benjamin Prosnitzae300202015-06-04 19:36:49 -0700743 return c.blessingsCache.Put(blessings), err
Ankure7889242014-10-20 18:37:29 -0700744}
745
Benjamin Prosnitze1209d42015-05-04 15:06:42 -0700746// BlessingStoreSet puts the specified blessing in the blessing store under the
747// provided pattern.
Benjamin Prosnitzae300202015-06-04 19:36:49 -0700748func (c *Controller) BlessingStoreSet(_ *context.T, _ rpc.ServerCall, inputBlessings security.Blessings, pattern security.BlessingPattern) (principal.BlessingsId, error) {
Benjamin Prosnitz9e423992015-04-10 13:10:35 -0700749 p := v23.GetPrincipal(c.ctx)
Benjamin Prosnitz782a8a12015-04-22 15:02:38 -0700750 outBlessings, err := p.BlessingStore().Set(inputBlessings, security.BlessingPattern(pattern))
Benjamin Prosnitz9e423992015-04-10 13:10:35 -0700751 if err != nil {
Benjamin Prosnitzc65917c2015-05-26 14:21:53 -0700752 return 0, err
Benjamin Prosnitz9e423992015-04-10 13:10:35 -0700753 }
754
Benjamin Prosnitz782a8a12015-04-22 15:02:38 -0700755 if outBlessings.IsZero() {
Benjamin Prosnitzc65917c2015-05-26 14:21:53 -0700756 return 0, nil
Benjamin Prosnitz9e423992015-04-10 13:10:35 -0700757 }
758
Benjamin Prosnitzae300202015-06-04 19:36:49 -0700759 return c.blessingsCache.Put(outBlessings), nil
Benjamin Prosnitz782a8a12015-04-22 15:02:38 -0700760}
761
Benjamin Prosnitze1209d42015-05-04 15:06:42 -0700762// BlessingStoreForPeer puts the specified blessing in the blessing store under the
763// provided pattern.
Benjamin Prosnitzc65917c2015-05-26 14:21:53 -0700764func (c *Controller) BlessingStoreForPeer(_ *context.T, _ rpc.ServerCall, peerBlessings []string) (principal.BlessingsId, error) {
Benjamin Prosnitze1209d42015-05-04 15:06:42 -0700765 p := v23.GetPrincipal(c.ctx)
766 outBlessings := p.BlessingStore().ForPeer(peerBlessings...)
767
768 if outBlessings.IsZero() {
Benjamin Prosnitzc65917c2015-05-26 14:21:53 -0700769 return 0, nil
Benjamin Prosnitze1209d42015-05-04 15:06:42 -0700770 }
771
Benjamin Prosnitzae300202015-06-04 19:36:49 -0700772 return c.blessingsCache.Put(outBlessings), nil
Benjamin Prosnitze1209d42015-05-04 15:06:42 -0700773}
774
775// BlessingStoreSetDefault sets the default blessings in the blessing store.
Benjamin Prosnitzae300202015-06-04 19:36:49 -0700776func (c *Controller) BlessingStoreSetDefault(_ *context.T, _ rpc.ServerCall, inputBlessings security.Blessings) error {
Benjamin Prosnitz782a8a12015-04-22 15:02:38 -0700777 p := v23.GetPrincipal(c.ctx)
Benjamin Prosnitze1209d42015-05-04 15:06:42 -0700778 return p.BlessingStore().SetDefault(inputBlessings)
Benjamin Prosnitz9e423992015-04-10 13:10:35 -0700779}
780
Benjamin Prosnitze1209d42015-05-04 15:06:42 -0700781// BlessingStoreDefault fetches the default blessings for the principal of the controller.
Benjamin Prosnitzc65917c2015-05-26 14:21:53 -0700782func (c *Controller) BlessingStoreDefault(*context.T, rpc.ServerCall) (principal.BlessingsId, error) {
Shyam Jayaraman07136a72015-04-13 13:34:41 -0700783 p := v23.GetPrincipal(c.ctx)
784 outBlessings := p.BlessingStore().Default()
785
786 if outBlessings.IsZero() {
Benjamin Prosnitzc65917c2015-05-26 14:21:53 -0700787 return 0, nil
Shyam Jayaraman07136a72015-04-13 13:34:41 -0700788 }
789
Benjamin Prosnitzae300202015-06-04 19:36:49 -0700790 return c.blessingsCache.Put(outBlessings), nil
Shyam Jayaraman07136a72015-04-13 13:34:41 -0700791}
792
Benjamin Prosnitze1209d42015-05-04 15:06:42 -0700793// BlessingStorePublicKey fetches the public key used by the principal associated with the blessing store.
Benjamin Prosnitzae300202015-06-04 19:36:49 -0700794func (c *Controller) BlessingStorePublicKey(*context.T, rpc.ServerCall) ([]byte, error) {
Benjamin Prosnitze1209d42015-05-04 15:06:42 -0700795 p := v23.GetPrincipal(c.ctx)
Benjamin Prosnitzae300202015-06-04 19:36:49 -0700796 return p.BlessingStore().PublicKey().MarshalBinary()
Benjamin Prosnitze1209d42015-05-04 15:06:42 -0700797}
798
799// BlessingStorePeerBlessings returns all the blessings that the BlessingStore holds.
Benjamin Prosnitzc65917c2015-05-26 14:21:53 -0700800func (c *Controller) BlessingStorePeerBlessings(*context.T, rpc.ServerCall) (map[security.BlessingPattern]principal.BlessingsId, error) {
Benjamin Prosnitze1209d42015-05-04 15:06:42 -0700801 p := v23.GetPrincipal(c.ctx)
Benjamin Prosnitzc65917c2015-05-26 14:21:53 -0700802 outBlessingsMap := map[security.BlessingPattern]principal.BlessingsId{}
Benjamin Prosnitze1209d42015-05-04 15:06:42 -0700803 for pattern, blessings := range p.BlessingStore().PeerBlessings() {
Benjamin Prosnitzae300202015-06-04 19:36:49 -0700804 outBlessingsMap[pattern] = c.blessingsCache.Put(blessings)
Benjamin Prosnitze1209d42015-05-04 15:06:42 -0700805 }
806 return outBlessingsMap, nil
807}
808
809// BlessingStoreDebugString retrieves a debug string describing the state of the blessing store
810func (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 Prosnitzae300202015-06-04 19:36:49 -0700817func (c *Controller) AddToRoots(_ *context.T, _ rpc.ServerCall, inputBlessings security.Blessings) error {
Benjamin Prosnitze1209d42015-05-04 15:06:42 -0700818 p := v23.GetPrincipal(c.ctx)
819 return p.AddToRoots(inputBlessings)
820}
821
Benjamin Prosnitzbf71e962015-04-14 16:43:07 -0700822// HandleGranterResponse handles the result of a Granter request.
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700823func (c *Controller) HandleGranterResponse(ctx *context.T, id int32, data string) {
Benjamin Prosnitzbf71e962015-04-14 16:43:07 -0700824 c.Lock()
825 granterStr, ok := c.flowMap[id].(*granterStream)
826 c.Unlock()
827 if !ok {
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700828 ctx.Errorf("unexpected result from JavaScript. Flow was not a granter "+
Benjamin Prosnitzbf71e962015-04-14 16:43:07 -0700829 "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 Nicolaoud9229922015-06-24 14:12:24 -0700836func (c *Controller) HandleTypeMessage(ctx *context.T, data string) {
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700837 c.typeReader.Add(data)
838}
839
Todd Wang54feabe2015-04-15 23:38:26 -0700840func (c *Controller) RemoteBlessings(ctx *context.T, _ rpc.ServerCall, name, method string) ([]string, error) {
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700841 ctx.VI(2).Infof("requesting remote blessings for %q", name)
Nicolas LaCassee8f8ec02015-02-04 14:14:52 -0800842
Todd Wang54feabe2015-04-15 23:38:26 -0700843 cctx, cancel := context.WithTimeout(ctx, 5*time.Second)
Nicolas LaCassee8f8ec02015-02-04 14:14:52 -0800844 defer cancel()
845
Matt Rosencrantz9dce9b22015-03-02 10:48:37 -0800846 clientCall, err := v23.GetClient(cctx).StartCall(cctx, name, method, nil)
Nicolas LaCassee8f8ec02015-02-04 14:14:52 -0800847 if err != nil {
Matt Rosencrantzec3b9502015-02-19 12:53:13 -0800848 return nil, verror.Convert(verror.ErrInternal, cctx, err)
Nicolas LaCassee8f8ec02015-02-04 14:14:52 -0800849 }
850
Matt Rosencrantz9dce9b22015-03-02 10:48:37 -0800851 blessings, _ := clientCall.RemoteBlessings()
Nicolas LaCassee8f8ec02015-02-04 14:14:52 -0800852 return blessings, nil
853}
Shyam Jayaramanc17abda2015-04-06 16:49:17 -0700854
855func (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 Prosnitzc65917c2015-05-26 14:21:53 -0700865
866func (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 Nicolaoud9229922015-06-24 14:12:24 -0700872 c.ctx.Errorf("unexpected error sending blessings cache message: %v", err)
Benjamin Prosnitzc65917c2015-05-26 14:21:53 -0700873 }
874}
Shyam Jayaraman3facd242015-05-29 11:20:59 -0700875
876func (c *Controller) TypeEncoder() *vom.TypeEncoder {
877 return c.typeEncoder
878}
Shyam Jayaraman0062e272015-06-04 11:25:13 -0700879
880func (c *Controller) TypeDecoder() *vom.TypeDecoder {
881 return c.typeDecoder
882}