blob: 9a1a33c08f5e34a5516ccf9d98fe334790c36466 [file] [log] [blame]
Jiri Simsa78b646f2014-10-08 10:23:05 -07001// The app package contains the struct that keeps per javascript app state and handles translating
2// javascript requests to veyron requests and vice versa.
3package app
4
5import (
Matt Rosencrantz786f7272015-02-11 15:18:07 -08006 "bytes"
7 "encoding/hex"
Jiri Simsa78b646f2014-10-08 10:23:05 -07008 "flag"
9 "fmt"
10 "io"
11 "sync"
12 "time"
13
Jiri Simsa22b87ac2014-12-25 20:59:13 -080014 vsecurity "v.io/core/veyron/security"
15 "v.io/core/veyron2"
16 "v.io/core/veyron2/context"
17 "v.io/core/veyron2/ipc"
Matt Rosencrantz786f7272015-02-11 15:18:07 -080018 "v.io/core/veyron2/naming"
Jiri Simsa22b87ac2014-12-25 20:59:13 -080019 "v.io/core/veyron2/options"
Jiri Simsa22b87ac2014-12-25 20:59:13 -080020 "v.io/core/veyron2/security"
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -080021 "v.io/core/veyron2/vdl"
Jiri Simsa22b87ac2014-12-25 20:59:13 -080022 "v.io/core/veyron2/vdl/vdlroot/src/signature"
Todd Wangb63e9eb2015-02-10 19:57:39 -080023 "v.io/core/veyron2/verror"
Jiri Simsa22b87ac2014-12-25 20:59:13 -080024 "v.io/core/veyron2/vlog"
Matt Rosencrantz786f7272015-02-11 15:18:07 -080025 "v.io/core/veyron2/vom"
Suharsh Sivakumar94d00662015-01-21 14:31:30 -080026 "v.io/core/veyron2/vtrace"
Jiri Simsa11277162014-12-25 15:50:27 -080027 "v.io/wspr/veyron/services/wsprd/ipc/server"
28 "v.io/wspr/veyron/services/wsprd/lib"
29 "v.io/wspr/veyron/services/wsprd/namespace"
30 "v.io/wspr/veyron/services/wsprd/principal"
Jiri Simsa78b646f2014-10-08 10:23:05 -070031)
32
Mike Burrowsb6689c22014-10-08 11:14:15 -070033// pkgPath is the prefix os errors in this package.
Jiri Simsa22b87ac2014-12-25 20:59:13 -080034const pkgPath = "v.io/core/veyron/services/wsprd/app"
Mike Burrowsb6689c22014-10-08 11:14:15 -070035
36// Errors
Ankure7889242014-10-20 18:37:29 -070037var (
Todd Wangb63e9eb2015-02-10 19:57:39 -080038 marshallingError = verror.Register(pkgPath+".marshallingError", verror.NoRetry, "{1} {2} marshalling error {_}")
39 noResults = verror.Register(pkgPath+".noResults", verror.NoRetry, "{1} {2} no results from call {_}")
40 badCaveatType = verror.Register(pkgPath+".badCaveatType", verror.NoRetry, "{1} {2} bad caveat type {_}")
41 unknownBlessings = verror.Register(pkgPath+".unknownBlessings", verror.NoRetry, "{1} {2} unknown public id {_}")
42 invalidBlessingsHandle = verror.Register(pkgPath+".invalidBlessingsHandle", verror.NoRetry, "{1} {2} invalid blessings handle {_}")
Ankure7889242014-10-20 18:37:29 -070043)
Mike Burrowsb6689c22014-10-08 11:14:15 -070044
Jiri Simsa78b646f2014-10-08 10:23:05 -070045// TODO(bjornick,nlacasse): Remove the retryTimeout flag once we able
46// to pass it in from javascript. For now all RPCs have the same
47// retryTimeout, set by command line flag.
48var retryTimeout *int
49
50func init() {
51 // TODO(bjornick,nlacasse): Remove the retryTimeout flag once we able
52 // to pass it in from javascript. For now all RPCs have the same
53 // retryTimeout, set by command line flag.
Nicolas LaCasse238aeb32014-11-26 11:32:10 -080054 retryTimeout = flag.Int("retry-timeout", 2, "Duration in seconds to retry starting an RPC call. 0 means never retry.")
Jiri Simsa78b646f2014-10-08 10:23:05 -070055}
56
Matt Rosencrantz4aabe572014-10-22 09:25:50 -070057type outstandingRequest struct {
58 stream *outstandingStream
59 cancel context.CancelFunc
60}
61
Jiri Simsa78b646f2014-10-08 10:23:05 -070062// Controller represents all the state of a Veyron Web App. This is the struct
63// that is in charge performing all the veyron options.
64type Controller struct {
65 // Protects everything.
66 // TODO(bjornick): We need to split this up.
67 sync.Mutex
68
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -080069 // The context of this controller.
70 ctx *context.T
Jiri Simsa78b646f2014-10-08 10:23:05 -070071
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -080072 // The cleanup function for this controller.
73 cancel context.CancelFunc
Jiri Simsa78b646f2014-10-08 10:23:05 -070074
75 // The ipc.ListenSpec to use with server.Listen
76 listenSpec *ipc.ListenSpec
77
78 // Used to generate unique ids for requests initiated by the proxy.
79 // These ids will be even so they don't collide with the ids generated
80 // by the client.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -080081 lastGeneratedId int32
Jiri Simsa78b646f2014-10-08 10:23:05 -070082
Matt Rosencrantz4aabe572014-10-22 09:25:50 -070083 // Used to keep track of data (streams and cancellation functions) for
84 // outstanding requests.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -080085 outstandingRequests map[int32]*outstandingRequest
Jiri Simsa78b646f2014-10-08 10:23:05 -070086
87 // Maps flowids to the server that owns them.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -080088 flowMap map[int32]*server.Server
Jiri Simsa78b646f2014-10-08 10:23:05 -070089
90 // A manager that Handles fetching and caching signature of remote services
91 signatureManager lib.SignatureManager
92
Nicolas LaCasse4f409ce2014-11-25 11:44:03 -080093 // We maintain multiple Veyron server per pipe for serving JavaScript
Jiri Simsa78b646f2014-10-08 10:23:05 -070094 // services.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -080095 servers map[uint32]*server.Server
Jiri Simsa78b646f2014-10-08 10:23:05 -070096
97 // Creates a client writer for a given flow. This is a member so that tests can override
98 // the default implementation.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -080099 writerCreator func(id int32) lib.ClientWriter
Jiri Simsa78b646f2014-10-08 10:23:05 -0700100
Jiri Simsa78b646f2014-10-08 10:23:05 -0700101 veyronProxyEP string
102
Ankure7889242014-10-20 18:37:29 -0700103 // Store for all the Blessings that javascript has a handle to.
104 blessingsStore *principal.JSBlessingsHandles
Jiri Simsa78b646f2014-10-08 10:23:05 -0700105}
106
107// NewController creates a new Controller. writerCreator will be used to create a new flow for rpcs to
108// javascript server. veyronProxyEP is an endpoint for the veyron proxy to serve through. It can't be empty.
Suharsh Sivakumar94d00662015-01-21 14:31:30 -0800109func NewController(ctx *context.T, writerCreator func(id int32) lib.ClientWriter, listenSpec *ipc.ListenSpec, namespaceRoots []string, p security.Principal) (*Controller, error) {
110 ctx, cancel := context.WithCancel(ctx)
111
112 ctx, _ = vtrace.SetNewTrace(ctx)
Matt Rosencrantz306d9902015-01-10 17:46:07 -0800113
Benjamin Prosnitz3c738502014-11-04 14:51:38 -0800114 if namespaceRoots != nil {
Matt Rosencrantz306d9902015-01-10 17:46:07 -0800115 veyron2.GetNamespace(ctx).SetRoots(namespaceRoots...)
Benjamin Prosnitz3c738502014-11-04 14:51:38 -0800116 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700117
Suharsh Sivakumar94d00662015-01-21 14:31:30 -0800118 ctx, err := veyron2.SetPrincipal(ctx, p)
119 if err != nil {
120 return nil, err
121 }
122
Jiri Simsa78b646f2014-10-08 10:23:05 -0700123 controller := &Controller{
Matt Rosencrantz306d9902015-01-10 17:46:07 -0800124 ctx: ctx,
Suharsh Sivakumar94d00662015-01-21 14:31:30 -0800125 cancel: cancel,
Ankure7889242014-10-20 18:37:29 -0700126 writerCreator: writerCreator,
127 listenSpec: listenSpec,
Ankure7889242014-10-20 18:37:29 -0700128 blessingsStore: principal.NewJSBlessingsHandles(),
Ankure7889242014-10-20 18:37:29 -0700129 }
130
Jiri Simsa78b646f2014-10-08 10:23:05 -0700131 controller.setup()
132 return controller, nil
133}
134
135// finishCall waits for the call to finish and write out the response to w.
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800136func (c *Controller) finishCall(ctx *context.T, w lib.ClientWriter, clientCall ipc.Call, msg *VeyronRPCRequest, span vtrace.Span) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700137 if msg.IsStreaming {
138 for {
139 var item interface{}
140 if err := clientCall.Recv(&item); err != nil {
141 if err == io.EOF {
142 break
143 }
144 w.Error(err) // Send streaming error as is
145 return
146 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800147 vomItem, err := lib.VomEncode(item)
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800148 if err != nil {
Todd Wangb63e9eb2015-02-10 19:57:39 -0800149 w.Error(verror.New(marshallingError, ctx, item, err))
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800150 continue
151 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800152 if err := w.Send(lib.ResponseStream, vomItem); err != nil {
Todd Wangb63e9eb2015-02-10 19:57:39 -0800153 w.Error(verror.New(marshallingError, ctx, item))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700154 }
155 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700156 if err := w.Send(lib.ResponseStreamClose, nil); err != nil {
Todd Wangb63e9eb2015-02-10 19:57:39 -0800157 w.Error(verror.New(marshallingError, ctx, "ResponseStreamClose"))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700158 }
159 }
Todd Wangf21e1552015-02-18 13:21:52 -0800160 results := make([]interface{}, msg.NumOutArgs)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700161 // This array will have pointers to the values in result.
Todd Wangf21e1552015-02-18 13:21:52 -0800162 resultptrs := make([]interface{}, msg.NumOutArgs)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700163 for ax := range results {
164 resultptrs[ax] = &results[ax]
165 }
166 if err := clientCall.Finish(resultptrs...); err != nil {
167 // return the call system error as is
168 w.Error(err)
169 return
170 }
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800171 c.sendRPCResponse(ctx, w, span, results)
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800172}
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800173
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800174func (c *Controller) sendRPCResponse(ctx *context.T, w lib.ClientWriter, span vtrace.Span, results []interface{}) {
Todd Wangf21e1552015-02-18 13:21:52 -0800175 outargs := make([]vdl.AnyRep, len(results))
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800176 for i := range outargs {
177 outargs[i] = results[i]
178 }
179
180 span.Finish()
181 traceRecord := vtrace.GetStore(ctx).TraceRecord(span.Trace())
182
183 response := VeyronRPCResponse{
184 OutArgs: outargs,
185 TraceResponse: vtrace.Response{
Matt Rosencrantzce148612015-02-13 16:10:22 -0800186 Flags: vtrace.CollectInMemory,
187 Trace: *traceRecord,
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800188 },
189 }
190 encoded, err := lib.VomEncode(response)
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800191 if err != nil {
192 w.Error(err)
193 return
194 }
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800195 if err := w.Send(lib.ResponseFinal, encoded); err != nil {
Todd Wangb63e9eb2015-02-10 19:57:39 -0800196 w.Error(verror.Convert(marshallingError, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700197 }
198}
199
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800200func (c *Controller) startCall(ctx *context.T, w lib.ClientWriter, msg *VeyronRPCRequest, inArgs []interface{}) (ipc.Call, error) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700201 methodName := lib.UppercaseFirstCharacter(msg.Method)
Asim Shankarf3c61a32014-10-15 17:34:11 -0700202 retryTimeoutOpt := options.RetryTimeout(time.Duration(*retryTimeout) * time.Second)
Alex Fandriantoaa5af7c2015-01-29 15:20:02 -0800203 clientCall, err := veyron2.GetClient(ctx).StartCall(ctx, msg.Name, methodName, inArgs, retryTimeoutOpt)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700204 if err != nil {
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800205 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 -0700206 }
207
208 return clientCall, nil
209}
210
211// Implements the serverHelper interface
212
213// CreateNewFlow creats a new server flow that will be used to write out
214// streaming messages to Javascript.
215func (c *Controller) CreateNewFlow(s *server.Server, stream ipc.Stream) *server.Flow {
216 c.Lock()
217 defer c.Unlock()
218 id := c.lastGeneratedId
219 c.lastGeneratedId += 2
220 c.flowMap[id] = s
221 os := newStream()
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800222 os.init(stream)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700223 c.outstandingRequests[id] = &outstandingRequest{
224 stream: os,
225 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700226 return &server.Flow{ID: id, Writer: c.writerCreator(id)}
227}
228
229// CleanupFlow removes the bookkeping for a previously created flow.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800230func (c *Controller) CleanupFlow(id int32) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700231 c.Lock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700232 request := c.outstandingRequests[id]
233 delete(c.outstandingRequests, id)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700234 delete(c.flowMap, id)
235 c.Unlock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700236 if request != nil && request.stream != nil {
237 request.stream.end()
238 request.stream.waitUntilDone()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700239 }
240}
241
Jiri Simsa78b646f2014-10-08 10:23:05 -0700242// RT returns the runtime of the app.
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800243func (c *Controller) Context() *context.T {
244 return c.ctx
Jiri Simsa78b646f2014-10-08 10:23:05 -0700245}
246
Ankure7889242014-10-20 18:37:29 -0700247// AddBlessings adds the Blessings to the local blessings store and returns
Jiri Simsa78b646f2014-10-08 10:23:05 -0700248// the handle to it. This function exists because JS only has
Ankure7889242014-10-20 18:37:29 -0700249// a handle to the blessings to avoid shipping the certificate forest
Jiri Simsa78b646f2014-10-08 10:23:05 -0700250// to JS and back.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800251func (c *Controller) AddBlessings(blessings security.Blessings) int32 {
Ankure7889242014-10-20 18:37:29 -0700252 return c.blessingsStore.Add(blessings)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700253}
254
255// Cleanup cleans up any outstanding rpcs.
256func (c *Controller) Cleanup() {
Matt Rosencrantz99ed6782015-01-27 19:58:34 -0800257 vlog.VI(0).Info("Cleaning up controller")
Jiri Simsa78b646f2014-10-08 10:23:05 -0700258 c.Lock()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700259
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700260 for _, request := range c.outstandingRequests {
261 if request.cancel != nil {
262 request.cancel()
263 }
264 if request.stream != nil {
265 request.stream.end()
266 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700267 }
268
Nicolas LaCasse60f423e2015-02-04 17:53:14 -0800269 servers := []*server.Server{}
Jiri Simsa78b646f2014-10-08 10:23:05 -0700270 for _, server := range c.servers {
Nicolas LaCasse60f423e2015-02-04 17:53:14 -0800271 servers = append(servers, server)
272 }
273
274 c.Unlock()
275
276 // We must unlock before calling server.Stop otherwise it can deadlock.
277 for _, server := range servers {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700278 server.Stop()
279 }
Benjamin Prosnitz8a51fe82014-10-16 13:05:14 -0700280
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800281 c.cancel()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700282}
283
284func (c *Controller) setup() {
285 c.signatureManager = lib.NewSignatureManager()
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800286 c.outstandingRequests = make(map[int32]*outstandingRequest)
287 c.flowMap = make(map[int32]*server.Server)
288 c.servers = make(map[uint32]*server.Server)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700289}
290
291// SendOnStream writes data on id's stream. The actual network write will be
292// done asynchronously. If there is an error, it will be sent to w.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800293func (c *Controller) SendOnStream(id int32, data string, w lib.ClientWriter) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700294 c.Lock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700295 request := c.outstandingRequests[id]
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700296 if request == nil || request.stream == nil {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700297 vlog.Errorf("unknown stream: %d", id)
298 return
299 }
Matt Rosencrantzd608b372014-10-22 13:06:52 -0700300 stream := request.stream
301 c.Unlock()
302 stream.send(data, w)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700303}
304
305// SendVeyronRequest makes a veyron request for the given flowId. If signal is non-nil, it will receive
306// the call object after it has been constructed.
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800307func (c *Controller) sendVeyronRequest(ctx *context.T, id int32, msg *VeyronRPCRequest, inArgs []interface{}, w lib.ClientWriter, stream *outstandingStream, span vtrace.Span) {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800308 sig, err := c.getSignature(ctx, msg.Name)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700309 if err != nil {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800310 w.Error(err)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700311 return
312 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800313 methName := lib.UppercaseFirstCharacter(msg.Method)
314 methSig, ok := signature.FirstMethod(sig, methName)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700315 if !ok {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800316 w.Error(fmt.Errorf("method %q not found in signature: %#v", methName, sig))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700317 return
318 }
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800319 if len(methSig.InArgs) != len(inArgs) {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800320 w.Error(fmt.Errorf("invalid number of arguments, expected: %v, got:%v", methSig, *msg))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700321 return
322 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700323
324 // We have to make the start call synchronous so we can make sure that we populate
325 // the call map before we can Handle a recieve call.
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800326 call, err := c.startCall(ctx, w, msg, inArgs)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700327 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800328 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700329 return
330 }
331
332 if stream != nil {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800333 stream.init(call)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700334 }
335
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800336 c.finishCall(ctx, w, call, msg, span)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700337 c.Lock()
338 if request, ok := c.outstandingRequests[id]; ok {
339 delete(c.outstandingRequests, id)
340 if request.cancel != nil {
341 request.cancel()
342 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700343 }
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700344 c.Unlock()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700345}
346
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800347// TODO(mattr): This is a very limited implementation of ServerCall,
348// but currently none of the methods the controller exports require
349// any of this context information.
350type localCall struct {
351 ctx *context.T
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800352 vrpc *VeyronRPCRequest
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800353 tags []interface{}
354}
355
356func (l *localCall) Send(interface{}) error { return nil }
357func (l *localCall) Recv(interface{}) error { return nil }
358func (l *localCall) Blessings() security.Blessings { return nil }
359func (l *localCall) Server() ipc.Server { return nil }
360func (l *localCall) Context() *context.T { return l.ctx }
361func (l *localCall) Timestamp() (t time.Time) { return }
362func (l *localCall) Method() string { return l.vrpc.Method }
363func (l *localCall) MethodTags() []interface{} { return l.tags }
364func (l *localCall) Name() string { return l.vrpc.Name }
365func (l *localCall) Suffix() string { return "" }
366func (l *localCall) RemoteDischarges() map[string]security.Discharge { return nil }
367func (l *localCall) LocalPrincipal() security.Principal { return nil }
368func (l *localCall) LocalBlessings() security.Blessings { return nil }
369func (l *localCall) RemoteBlessings() security.Blessings { return nil }
370func (l *localCall) LocalEndpoint() naming.Endpoint { return nil }
371func (l *localCall) RemoteEndpoint() naming.Endpoint { return nil }
372
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800373func (c *Controller) handleInternalCall(ctx *context.T, msg *VeyronRPCRequest, decoder *vom.Decoder, w lib.ClientWriter, span vtrace.Span) {
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800374 invoker, err := ipc.ReflectInvoker(ControllerServer(c))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700375 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800376 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700377 return
378 }
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800379 argptrs, tags, err := invoker.Prepare(msg.Method, int(msg.NumInArgs))
380 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800381 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800382 return
383 }
384 for _, argptr := range argptrs {
385 if err := decoder.Decode(argptr); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800386 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800387 return
388 }
389 }
390 results, err := invoker.Invoke(msg.Method, &localCall{ctx, msg, tags}, argptrs)
391 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800392 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800393 return
394 }
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800395 c.sendRPCResponse(ctx, w, span, results)
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800396}
397
398// HandleVeyronRequest starts a veyron rpc and returns before the rpc has been completed.
399func (c *Controller) HandleVeyronRequest(ctx *context.T, id int32, data string, w lib.ClientWriter) {
400 binbytes, err := hex.DecodeString(data)
401 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800402 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800403 return
404 }
405 decoder, err := vom.NewDecoder(bytes.NewReader(binbytes))
406 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800407 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800408 return
409 }
410
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800411 var msg VeyronRPCRequest
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800412 if err := decoder.Decode(&msg); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800413 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800414 return
415 }
416 vlog.VI(2).Infof("VeyronRPC: %s.%s(..., streaming=%v)", msg.Name, msg.Method, msg.IsStreaming)
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800417 spanName := fmt.Sprintf("<wspr>%q.%s", msg.Name, msg.Method)
418 ctx, span := vtrace.SetContinuedTrace(ctx, spanName, msg.TraceRequest)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700419
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800420 var cctx *context.T
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700421 var cancel context.CancelFunc
422
423 // TODO(mattr): To be consistent with go, we should not ignore 0 timeouts.
424 // However as a rollout strategy we must, otherwise there is a circular
425 // dependency between the WSPR change and the JS change that will follow.
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800426 if msg.Timeout == lib.JSIPCNoTimeout || msg.Timeout == 0 {
Matt Rosencrantzb6f4b922015-01-05 13:31:55 -0800427 cctx, cancel = context.WithCancel(ctx)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700428 } else {
Matt Rosencrantzb6f4b922015-01-05 13:31:55 -0800429 cctx, cancel = context.WithTimeout(ctx, lib.JSToGoDuration(msg.Timeout))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700430 }
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700431
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800432 // If this message is for an internal service, do a short-circuit dispatch here.
433 if msg.Name == "controller" {
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800434 go c.handleInternalCall(ctx, &msg, decoder, w, span)
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800435 return
436 }
437
438 inArgs := make([]interface{}, msg.NumInArgs)
439 for i := range inArgs {
440 if err := decoder.Decode(&inArgs[i]); err != nil {
441 w.Error(err)
442 return
443 }
444 }
445
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700446 request := &outstandingRequest{
447 cancel: cancel,
448 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800449 if msg.IsStreaming {
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700450 // If this rpc is streaming, we would expect that the client would try to send
451 // on this stream. Since the initial handshake is done asynchronously, we have
452 // to put the outstanding stream in the map before we make the async call so that
453 // the future send know which queue to write to, even if the client call isn't
454 // actually ready yet.
455 request.stream = newStream()
456 }
457 c.Lock()
458 c.outstandingRequests[id] = request
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800459 go c.sendVeyronRequest(cctx, id, &msg, inArgs, w, request.stream, span)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700460 c.Unlock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700461}
462
463// HandleVeyronCancellation cancels the request corresponding to the
464// given id if it is still outstanding.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800465func (c *Controller) HandleVeyronCancellation(id int32) {
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700466 c.Lock()
467 defer c.Unlock()
468 if request, ok := c.outstandingRequests[id]; ok && request.cancel != nil {
469 request.cancel()
470 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700471}
472
473// CloseStream closes the stream for a given id.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800474func (c *Controller) CloseStream(id int32) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700475 c.Lock()
476 defer c.Unlock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700477 if request, ok := c.outstandingRequests[id]; ok && request.stream != nil {
478 request.stream.end()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700479 return
480 }
Matt Rosencrantz99ed6782015-01-27 19:58:34 -0800481 vlog.Errorf("close called on non-existent call: %v", id)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700482}
483
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800484func (c *Controller) maybeCreateServer(serverId uint32) (*server.Server, error) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700485 c.Lock()
486 defer c.Unlock()
487 if server, ok := c.servers[serverId]; ok {
488 return server, nil
489 }
490 server, err := server.NewServer(serverId, c.listenSpec, c)
491 if err != nil {
492 return nil, err
493 }
494 c.servers[serverId] = server
495 return server, nil
496}
497
Jiri Simsa78b646f2014-10-08 10:23:05 -0700498// HandleLookupResponse handles the result of a Dispatcher.Lookup call that was
499// run by the Javascript server.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800500func (c *Controller) HandleLookupResponse(id int32, data string) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700501 c.Lock()
502 server := c.flowMap[id]
503 c.Unlock()
504 if server == nil {
Matt Rosencrantz99ed6782015-01-27 19:58:34 -0800505 vlog.Errorf("unexpected result from JavaScript. No channel "+
Jiri Simsa78b646f2014-10-08 10:23:05 -0700506 "for MessageId: %d exists. Ignoring the results.", id)
507 //Ignore unknown responses that don't belong to any channel
508 return
509 }
510 server.HandleLookupResponse(id, data)
511}
512
513// HandleAuthResponse handles the result of a Authorizer.Authorize call that was
514// run by the Javascript server.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800515func (c *Controller) HandleAuthResponse(id int32, data string) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700516 c.Lock()
517 server := c.flowMap[id]
518 c.Unlock()
519 if server == nil {
Matt Rosencrantz99ed6782015-01-27 19:58:34 -0800520 vlog.Errorf("unexpected result from JavaScript. No channel "+
Jiri Simsa78b646f2014-10-08 10:23:05 -0700521 "for MessageId: %d exists. Ignoring the results.", id)
522 //Ignore unknown responses that don't belong to any channel
523 return
524 }
525 server.HandleAuthResponse(id, data)
526}
527
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800528// Serve instructs WSPR to start listening for calls on behalf
529// of a javascript server.
530func (c *Controller) Serve(_ ipc.ServerContext, name string, serverId uint32) error {
531 server, err := c.maybeCreateServer(serverId)
532 if err != nil {
533 return verror.Convert(verror.ErrInternal, nil, err)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700534 }
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800535 vlog.VI(2).Infof("serving under name: %q", name)
536 if err := server.Serve(name); err != nil {
537 return verror.Convert(verror.ErrInternal, nil, err)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700538 }
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800539 return nil
Jiri Simsa78b646f2014-10-08 10:23:05 -0700540}
541
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800542// Stop instructs WSPR to stop listening for calls for the
543// given javascript server.
544func (c *Controller) Stop(_ ipc.ServerContext, serverId uint32) error {
545 c.Lock()
546 server := c.servers[serverId]
547 if server == nil {
548 c.Unlock()
549 return nil
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800550 }
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800551 delete(c.servers, serverId)
552 c.Unlock()
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800553
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800554 server.Stop()
555 return nil
556}
557
558// AddName adds a published name to an existing server.
559func (c *Controller) AddName(_ ipc.ServerContext, serverId uint32, name string) error {
Nicolas LaCasse4f409ce2014-11-25 11:44:03 -0800560 // Create a server for the pipe, if it does not exist already
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800561 server, err := c.maybeCreateServer(serverId)
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800562 if err != nil {
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800563 return verror.Convert(verror.ErrInternal, nil, err)
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800564 }
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800565 // Add name
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800566 if err := server.AddName(name); err != nil {
567 return verror.Convert(verror.ErrInternal, nil, err)
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800568 }
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800569 return nil
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800570}
571
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800572// RemoveName removes a published name from an existing server.
573func (c *Controller) RemoveName(_ ipc.ServerContext, serverId uint32, name string) error {
Nicolas LaCasse4f409ce2014-11-25 11:44:03 -0800574 // Create a server for the pipe, if it does not exist already
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800575 server, err := c.maybeCreateServer(serverId)
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800576 if err != nil {
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800577 return verror.Convert(verror.ErrInternal, nil, err)
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800578 }
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800579 // Remove name
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800580 server.RemoveName(name)
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800581 // Remove name from signature cache as well
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800582 c.signatureManager.FlushCacheEntry(name)
583 return nil
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800584}
585
Jiri Simsa78b646f2014-10-08 10:23:05 -0700586// HandleServerResponse handles the completion of outstanding calls to JavaScript services
587// by filling the corresponding channel with the result from JavaScript.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800588func (c *Controller) HandleServerResponse(id int32, data string) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700589 c.Lock()
590 server := c.flowMap[id]
591 c.Unlock()
592 if server == nil {
Matt Rosencrantz99ed6782015-01-27 19:58:34 -0800593 vlog.Errorf("unexpected result from JavaScript. No channel "+
Jiri Simsa78b646f2014-10-08 10:23:05 -0700594 "for MessageId: %d exists. Ignoring the results.", id)
595 //Ignore unknown responses that don't belong to any channel
596 return
597 }
598 server.HandleServerResponse(id, data)
599}
600
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800601// parseVeyronRequest parses a json rpc request into a VeyronRPCRequest object.
602func (c *Controller) parseVeyronRequest(data string) (*VeyronRPCRequest, error) {
603 var msg VeyronRPCRequest
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800604 if err := lib.VomDecode(data, &msg); err != nil {
605 return nil, err
Jiri Simsa78b646f2014-10-08 10:23:05 -0700606 }
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800607 vlog.VI(2).Infof("VeyronRPCRequest: %s.%s(..., streaming=%v)", msg.Name, msg.Method, msg.IsStreaming)
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800608 return &msg, nil
Jiri Simsa78b646f2014-10-08 10:23:05 -0700609}
610
Matt Rosencrantzec3b9502015-02-19 12:53:13 -0800611// getSignature uses the signature manager to get and cache the signature of a remote server.
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800612func (c *Controller) getSignature(ctx *context.T, name string) ([]signature.Interface, error) {
Asim Shankarf3c61a32014-10-15 17:34:11 -0700613 retryTimeoutOpt := options.RetryTimeout(time.Duration(*retryTimeout) * time.Second)
Todd Wangf83dbfc2015-01-09 11:54:46 -0800614 return c.signatureManager.Signature(ctx, name, retryTimeoutOpt)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700615}
616
Matt Rosencrantzec3b9502015-02-19 12:53:13 -0800617// Signature uses the signature manager to get and cache the signature of a remote server.
618func (c *Controller) Signature(ctx ipc.ServerContext, name string) ([]signature.Interface, error) {
619 return c.getSignature(ctx.Context(), name)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700620}
621
Matt Rosencrantzfeefb772015-02-18 14:58:49 -0800622// UnlinkJSBlessings removes the given blessings from the blessings store.
623func (c *Controller) UnlinkJSBlessings(_ ipc.ServerContext, handle int32) error {
Ankure7889242014-10-20 18:37:29 -0700624 c.blessingsStore.Remove(handle)
Matt Rosencrantzfeefb772015-02-18 14:58:49 -0800625 return nil
Jiri Simsa78b646f2014-10-08 10:23:05 -0700626}
627
Matt Rosencrantzfeefb772015-02-18 14:58:49 -0800628// BlessPublicKey creates a new blessing.
629func (c *Controller) BlessPublicKey(_ ipc.ServerContext,
630 handle int32,
631 caveats []security.Caveat,
632 duration time.Duration,
633 extension string) (int32, string, error) {
Ankure7889242014-10-20 18:37:29 -0700634 var blessee security.Blessings
Matt Rosencrantzfeefb772015-02-18 14:58:49 -0800635 if blessee = c.blessingsStore.Get(handle); blessee == nil {
636 return 0, "", verror.New(invalidBlessingsHandle, nil)
Ankure7889242014-10-20 18:37:29 -0700637 }
638
Matt Rosencrantzfeefb772015-02-18 14:58:49 -0800639 expiryCav, err := security.ExpiryCaveat(time.Now().Add(duration))
Ankure7889242014-10-20 18:37:29 -0700640 if err != nil {
Matt Rosencrantzfeefb772015-02-18 14:58:49 -0800641 return 0, "", err
Ankure7889242014-10-20 18:37:29 -0700642 }
Matt Rosencrantzfeefb772015-02-18 14:58:49 -0800643 caveats = append(caveats, expiryCav)
Ankure7889242014-10-20 18:37:29 -0700644
645 // TODO(ataly, ashankar, bjornick): Currently the Bless operation is carried
646 // out using the Default blessing in this principal's blessings store. We
647 // should change this so that the JS blessing request can also specify the
648 // blessing to be used for the Bless operation.
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800649 p := veyron2.GetPrincipal(c.ctx)
Matt Rosencrantzfeefb772015-02-18 14:58:49 -0800650 key := blessee.PublicKey()
651 blessing := p.BlessingStore().Default()
652 blessings, err := p.Bless(key, blessing, extension, caveats[0], caveats[1:]...)
Ankure7889242014-10-20 18:37:29 -0700653 if err != nil {
Matt Rosencrantzfeefb772015-02-18 14:58:49 -0800654 return 0, "", err
Ankure7889242014-10-20 18:37:29 -0700655 }
Matt Rosencrantzfeefb772015-02-18 14:58:49 -0800656 handle = c.blessingsStore.Add(blessings)
657 encodedKey, err := principal.EncodePublicKey(blessings.PublicKey())
658 if err != nil {
659 return 0, "", err
660 }
661 return handle, encodedKey, nil
Ankure7889242014-10-20 18:37:29 -0700662}
663
Matt Rosencrantzfeefb772015-02-18 14:58:49 -0800664// CreateBlessings creates a new principal self-blessed with the given extension.
665func (c *Controller) CreateBlessings(_ ipc.ServerContext,
666 extension string) (int32, string, error) {
Ankure7889242014-10-20 18:37:29 -0700667 p, err := vsecurity.NewPrincipal()
668 if err != nil {
Matt Rosencrantzfeefb772015-02-18 14:58:49 -0800669 return 0, "", verror.Convert(verror.ErrInternal, nil, err)
Ankure7889242014-10-20 18:37:29 -0700670 }
Ankure7889242014-10-20 18:37:29 -0700671 blessings, err := p.BlessSelf(extension)
672 if err != nil {
Matt Rosencrantzfeefb772015-02-18 14:58:49 -0800673 return 0, "", verror.Convert(verror.ErrInternal, nil, err)
Ankure7889242014-10-20 18:37:29 -0700674 }
Matt Rosencrantzfeefb772015-02-18 14:58:49 -0800675
676 handle := c.blessingsStore.Add(blessings)
677 encodedKey, err := principal.EncodePublicKey(blessings.PublicKey())
678 if err != nil {
679 return 0, "", err
Ankure7889242014-10-20 18:37:29 -0700680 }
Matt Rosencrantzfeefb772015-02-18 14:58:49 -0800681 return handle, encodedKey, nil
Ankure7889242014-10-20 18:37:29 -0700682}
683
Matt Rosencrantzec3b9502015-02-19 12:53:13 -0800684func (c *Controller) RemoteBlessings(ctx ipc.ServerContext, name, method string) ([]string, error) {
685 vlog.VI(2).Infof("requesting remote blessings for %q", name)
Nicolas LaCassee8f8ec02015-02-04 14:14:52 -0800686
Matt Rosencrantzec3b9502015-02-19 12:53:13 -0800687 cctx, cancel := context.WithTimeout(ctx.Context(), 5*time.Second)
Nicolas LaCassee8f8ec02015-02-04 14:14:52 -0800688 defer cancel()
689
Matt Rosencrantzec3b9502015-02-19 12:53:13 -0800690 call, err := veyron2.GetClient(cctx).StartCall(cctx, name, method, nil)
Nicolas LaCassee8f8ec02015-02-04 14:14:52 -0800691 if err != nil {
Matt Rosencrantzec3b9502015-02-19 12:53:13 -0800692 return nil, verror.Convert(verror.ErrInternal, cctx, err)
Nicolas LaCassee8f8ec02015-02-04 14:14:52 -0800693 }
694
Nicolas LaCassee8f8ec02015-02-04 14:14:52 -0800695 blessings, _ := call.RemoteBlessings()
696 return blessings, nil
697}
698
Ali Ghassemiaa0ea242014-10-20 12:55:39 -0700699// HandleNamespaceRequest uses the namespace client to respond to namespace specific requests such as glob
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800700func (c *Controller) HandleNamespaceRequest(ctx *context.T, data string, w lib.ClientWriter) {
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800701 namespace.HandleRequest(ctx, data, w)
Ali Ghassemiaa0ea242014-10-20 12:55:39 -0700702}