blob: 400c2de8dc5cf58d923ce9a9de0b4c0d3481271a [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 (
Jiri Simsa78b646f2014-10-08 10:23:05 -07006 "encoding/json"
7 "flag"
8 "fmt"
9 "io"
10 "sync"
11 "time"
12
Jiri Simsa22b87ac2014-12-25 20:59:13 -080013 vsecurity "v.io/core/veyron/security"
14 "v.io/core/veyron2"
15 "v.io/core/veyron2/context"
16 "v.io/core/veyron2/ipc"
17 "v.io/core/veyron2/options"
18 "v.io/core/veyron2/rt"
19 "v.io/core/veyron2/security"
20 "v.io/core/veyron2/vdl/vdlroot/src/signature"
21 "v.io/core/veyron2/verror2"
22 "v.io/core/veyron2/vlog"
Jiri Simsa11277162014-12-25 15:50:27 -080023 "v.io/wspr/veyron/services/wsprd/ipc/server"
24 "v.io/wspr/veyron/services/wsprd/lib"
25 "v.io/wspr/veyron/services/wsprd/namespace"
26 "v.io/wspr/veyron/services/wsprd/principal"
Jiri Simsa78b646f2014-10-08 10:23:05 -070027)
28
Mike Burrowsb6689c22014-10-08 11:14:15 -070029// pkgPath is the prefix os errors in this package.
Jiri Simsa22b87ac2014-12-25 20:59:13 -080030const pkgPath = "v.io/core/veyron/services/wsprd/app"
Mike Burrowsb6689c22014-10-08 11:14:15 -070031
32// Errors
Ankure7889242014-10-20 18:37:29 -070033var (
34 marshallingError = verror2.Register(pkgPath+".marshallingError", verror2.NoRetry, "{1} {2} marshalling error {_}")
35 noResults = verror2.Register(pkgPath+".noResults", verror2.NoRetry, "{1} {2} no results from call {_}")
Ankure7889242014-10-20 18:37:29 -070036 badCaveatType = verror2.Register(pkgPath+".badCaveatType", verror2.NoRetry, "{1} {2} bad caveat type {_}")
Ankur5b802242014-10-29 11:32:21 -070037 unknownBlessings = verror2.Register(pkgPath+".unknownBlessings", verror2.NoRetry, "{1} {2} unknown public id {_}")
Ankure7889242014-10-20 18:37:29 -070038 invalidBlessingsHandle = verror2.Register(pkgPath+".invalidBlessingsHandle", verror2.NoRetry, "{1} {2} invalid blessings handle {_}")
Ankure7889242014-10-20 18:37:29 -070039)
Mike Burrowsb6689c22014-10-08 11:14:15 -070040
Jiri Simsa78b646f2014-10-08 10:23:05 -070041// TODO(bjornick,nlacasse): Remove the retryTimeout flag once we able
42// to pass it in from javascript. For now all RPCs have the same
43// retryTimeout, set by command line flag.
44var retryTimeout *int
45
46func init() {
47 // TODO(bjornick,nlacasse): Remove the retryTimeout flag once we able
48 // to pass it in from javascript. For now all RPCs have the same
49 // retryTimeout, set by command line flag.
Nicolas LaCasse238aeb32014-11-26 11:32:10 -080050 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 -070051}
52
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -080053type VeyronRPC struct {
Jiri Simsa78b646f2014-10-08 10:23:05 -070054 Name string
55 Method string
56 InArgs []interface{}
57 NumOutArgs int32
58 IsStreaming bool
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -080059 Timeout int64
Jiri Simsa78b646f2014-10-08 10:23:05 -070060}
61
Jiri Simsa78b646f2014-10-08 10:23:05 -070062type serveRequest struct {
63 Name string
Benjamin Prosnitz86d52282014-12-19 15:48:38 -080064 ServerId uint32
Jiri Simsa78b646f2014-10-08 10:23:05 -070065}
66
Ali Ghassemi1008bbe2014-11-07 16:36:08 -080067type addRemoveNameRequest struct {
68 Name string
Benjamin Prosnitz86d52282014-12-19 15:48:38 -080069 ServerId uint32
Ali Ghassemi1008bbe2014-11-07 16:36:08 -080070}
71
Jiri Simsa78b646f2014-10-08 10:23:05 -070072type jsonCaveatValidator struct {
73 Type string `json:"_type"`
74 Data json.RawMessage
75}
76
77type blessingRequest struct {
Benjamin Prosnitz86d52282014-12-19 15:48:38 -080078 Handle int32
Jiri Simsa78b646f2014-10-08 10:23:05 -070079 Caveats []jsonCaveatValidator
Benjamin Prosnitz86d52282014-12-19 15:48:38 -080080 DurationMs int32
Ankurc56b3472014-10-29 11:16:19 -070081 Extension string
Jiri Simsa78b646f2014-10-08 10:23:05 -070082}
83
Matt Rosencrantz4aabe572014-10-22 09:25:50 -070084type outstandingRequest struct {
85 stream *outstandingStream
86 cancel context.CancelFunc
87}
88
Jiri Simsa78b646f2014-10-08 10:23:05 -070089// Controller represents all the state of a Veyron Web App. This is the struct
90// that is in charge performing all the veyron options.
91type Controller struct {
92 // Protects everything.
93 // TODO(bjornick): We need to split this up.
94 sync.Mutex
95
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -080096 // The context of this controller.
97 ctx *context.T
Jiri Simsa78b646f2014-10-08 10:23:05 -070098
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -080099 // The cleanup function for this controller.
100 cancel context.CancelFunc
Jiri Simsa78b646f2014-10-08 10:23:05 -0700101
102 // The ipc.ListenSpec to use with server.Listen
103 listenSpec *ipc.ListenSpec
104
105 // Used to generate unique ids for requests initiated by the proxy.
106 // These ids will be even so they don't collide with the ids generated
107 // by the client.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800108 lastGeneratedId int32
Jiri Simsa78b646f2014-10-08 10:23:05 -0700109
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700110 // Used to keep track of data (streams and cancellation functions) for
111 // outstanding requests.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800112 outstandingRequests map[int32]*outstandingRequest
Jiri Simsa78b646f2014-10-08 10:23:05 -0700113
114 // Maps flowids to the server that owns them.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800115 flowMap map[int32]*server.Server
Jiri Simsa78b646f2014-10-08 10:23:05 -0700116
117 // A manager that Handles fetching and caching signature of remote services
118 signatureManager lib.SignatureManager
119
Nicolas LaCasse4f409ce2014-11-25 11:44:03 -0800120 // We maintain multiple Veyron server per pipe for serving JavaScript
Jiri Simsa78b646f2014-10-08 10:23:05 -0700121 // services.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800122 servers map[uint32]*server.Server
Jiri Simsa78b646f2014-10-08 10:23:05 -0700123
124 // Creates a client writer for a given flow. This is a member so that tests can override
125 // the default implementation.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800126 writerCreator func(id int32) lib.ClientWriter
Jiri Simsa78b646f2014-10-08 10:23:05 -0700127
Jiri Simsa78b646f2014-10-08 10:23:05 -0700128 veyronProxyEP string
129
Ankure7889242014-10-20 18:37:29 -0700130 // Store for all the Blessings that javascript has a handle to.
131 blessingsStore *principal.JSBlessingsHandles
Jiri Simsa78b646f2014-10-08 10:23:05 -0700132}
133
134// NewController creates a new Controller. writerCreator will be used to create a new flow for rpcs to
135// javascript server. veyronProxyEP is an endpoint for the veyron proxy to serve through. It can't be empty.
Cosmos Nicolaou42f75b02014-10-30 08:22:24 -0700136// opts are any options that should be passed to the rt.New().
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800137func NewController(writerCreator func(id int32) lib.ClientWriter, profile veyron2.Profile, listenSpec *ipc.ListenSpec, namespaceRoots []string, opts ...veyron2.ROpt) (*Controller, error) {
Shyam Jayaramanae279472014-11-18 17:04:20 -0800138 if profile != nil {
139 opts = append(opts, options.Profile{profile})
140 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700141 r, err := rt.New(opts...)
142 if err != nil {
143 return nil, err
144 }
Benjamin Prosnitz3c738502014-11-04 14:51:38 -0800145 if namespaceRoots != nil {
146 r.Namespace().SetRoots(namespaceRoots...)
147 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700148
149 controller := &Controller{
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800150 ctx: r.NewContext(),
151 cancel: r.Cleanup,
Ankure7889242014-10-20 18:37:29 -0700152 writerCreator: writerCreator,
153 listenSpec: listenSpec,
Ankure7889242014-10-20 18:37:29 -0700154 blessingsStore: principal.NewJSBlessingsHandles(),
Ankure7889242014-10-20 18:37:29 -0700155 }
156
Jiri Simsa78b646f2014-10-08 10:23:05 -0700157 controller.setup()
158 return controller, nil
159}
160
161// finishCall waits for the call to finish and write out the response to w.
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800162func (c *Controller) finishCall(ctx *context.T, w lib.ClientWriter, clientCall ipc.Call, msg *VeyronRPC) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700163 if msg.IsStreaming {
164 for {
165 var item interface{}
166 if err := clientCall.Recv(&item); err != nil {
167 if err == io.EOF {
168 break
169 }
170 w.Error(err) // Send streaming error as is
171 return
172 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800173 vomItem, err := lib.VomEncode(item)
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800174 if err != nil {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800175 w.Error(verror2.Make(marshallingError, ctx, item, err))
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800176 continue
177 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800178 if err := w.Send(lib.ResponseStream, vomItem); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700179 w.Error(verror2.Make(marshallingError, ctx, item))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700180 }
181 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700182 if err := w.Send(lib.ResponseStreamClose, nil); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700183 w.Error(verror2.Make(marshallingError, ctx, "ResponseStreamClose"))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700184 }
185 }
186
187 results := make([]interface{}, msg.NumOutArgs)
188 // This array will have pointers to the values in result.
189 resultptrs := make([]interface{}, msg.NumOutArgs)
190 for ax := range results {
191 resultptrs[ax] = &results[ax]
192 }
193 if err := clientCall.Finish(resultptrs...); err != nil {
194 // return the call system error as is
195 w.Error(err)
196 return
197 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800198
Jiri Simsa78b646f2014-10-08 10:23:05 -0700199 // for now we assume last out argument is always error
200 if len(results) < 1 {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700201 w.Error(verror2.Make(noResults, ctx))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700202 return
203 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700204 if err, ok := results[len(results)-1].(error); ok {
205 // return the call Application error as is
206 w.Error(err)
207 return
208 }
209
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800210 vomResults, err := lib.VomEncode(results[:len(results)-1])
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800211 if err != nil {
212 w.Error(err)
213 return
214 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800215 if err := w.Send(lib.ResponseFinal, vomResults); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700216 w.Error(verror2.Convert(marshallingError, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700217 }
218}
219
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800220func (c *Controller) startCall(ctx *context.T, w lib.ClientWriter, msg *VeyronRPC) (ipc.Call, error) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700221 methodName := lib.UppercaseFirstCharacter(msg.Method)
Asim Shankarf3c61a32014-10-15 17:34:11 -0700222 retryTimeoutOpt := options.RetryTimeout(time.Duration(*retryTimeout) * time.Second)
Todd Wangf83dbfc2015-01-09 11:54:46 -0800223 clientCall, err := veyron2.GetClient(ctx).StartCall(ctx, msg.Name, methodName, msg.InArgs, retryTimeoutOpt)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700224 if err != nil {
225 return nil, fmt.Errorf("error starting call (name: %v, method: %v, args: %v): %v", msg.Name, methodName, msg.InArgs, err)
226 }
227
228 return clientCall, nil
229}
230
231// Implements the serverHelper interface
232
233// CreateNewFlow creats a new server flow that will be used to write out
234// streaming messages to Javascript.
235func (c *Controller) CreateNewFlow(s *server.Server, stream ipc.Stream) *server.Flow {
236 c.Lock()
237 defer c.Unlock()
238 id := c.lastGeneratedId
239 c.lastGeneratedId += 2
240 c.flowMap[id] = s
241 os := newStream()
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800242 os.init(stream)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700243 c.outstandingRequests[id] = &outstandingRequest{
244 stream: os,
245 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700246 return &server.Flow{ID: id, Writer: c.writerCreator(id)}
247}
248
249// CleanupFlow removes the bookkeping for a previously created flow.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800250func (c *Controller) CleanupFlow(id int32) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700251 c.Lock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700252 request := c.outstandingRequests[id]
253 delete(c.outstandingRequests, id)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700254 delete(c.flowMap, id)
255 c.Unlock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700256 if request != nil && request.stream != nil {
257 request.stream.end()
258 request.stream.waitUntilDone()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700259 }
260}
261
262// GetLogger returns a Veyron logger to use.
263func (c *Controller) GetLogger() vlog.Logger {
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800264 return veyron2.GetLogger(c.ctx)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700265}
266
267// RT returns the runtime of the app.
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800268func (c *Controller) Context() *context.T {
269 return c.ctx
Jiri Simsa78b646f2014-10-08 10:23:05 -0700270}
271
Ankure7889242014-10-20 18:37:29 -0700272// AddBlessings adds the Blessings to the local blessings store and returns
Jiri Simsa78b646f2014-10-08 10:23:05 -0700273// the handle to it. This function exists because JS only has
Ankure7889242014-10-20 18:37:29 -0700274// a handle to the blessings to avoid shipping the certificate forest
Jiri Simsa78b646f2014-10-08 10:23:05 -0700275// to JS and back.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800276func (c *Controller) AddBlessings(blessings security.Blessings) int32 {
Ankure7889242014-10-20 18:37:29 -0700277 return c.blessingsStore.Add(blessings)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700278}
279
280// Cleanup cleans up any outstanding rpcs.
281func (c *Controller) Cleanup() {
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800282 c.GetLogger().VI(0).Info("Cleaning up pipe")
Jiri Simsa78b646f2014-10-08 10:23:05 -0700283 c.Lock()
284 defer c.Unlock()
285
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700286 for _, request := range c.outstandingRequests {
287 if request.cancel != nil {
288 request.cancel()
289 }
290 if request.stream != nil {
291 request.stream.end()
292 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700293 }
294
295 for _, server := range c.servers {
296 server.Stop()
297 }
Benjamin Prosnitz8a51fe82014-10-16 13:05:14 -0700298
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800299 c.cancel()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700300}
301
302func (c *Controller) setup() {
303 c.signatureManager = lib.NewSignatureManager()
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800304 c.outstandingRequests = make(map[int32]*outstandingRequest)
305 c.flowMap = make(map[int32]*server.Server)
306 c.servers = make(map[uint32]*server.Server)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700307}
308
309// SendOnStream writes data on id's stream. The actual network write will be
310// done asynchronously. If there is an error, it will be sent to w.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800311func (c *Controller) SendOnStream(id int32, data string, w lib.ClientWriter) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700312 c.Lock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700313 request := c.outstandingRequests[id]
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700314 if request == nil || request.stream == nil {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700315 vlog.Errorf("unknown stream: %d", id)
316 return
317 }
Matt Rosencrantzd608b372014-10-22 13:06:52 -0700318 stream := request.stream
319 c.Unlock()
320 stream.send(data, w)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700321}
322
323// SendVeyronRequest makes a veyron request for the given flowId. If signal is non-nil, it will receive
324// the call object after it has been constructed.
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800325func (c *Controller) sendVeyronRequest(ctx *context.T, id int32, msg *VeyronRPC, w lib.ClientWriter, stream *outstandingStream) {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800326 sig, err := c.getSignature(ctx, msg.Name)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700327 if err != nil {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800328 w.Error(err)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700329 return
330 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800331 methName := lib.UppercaseFirstCharacter(msg.Method)
332 methSig, ok := signature.FirstMethod(sig, methName)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700333 if !ok {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800334 w.Error(fmt.Errorf("method %q not found in signature: %#v", methName, sig))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700335 return
336 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800337 if len(methSig.InArgs) != len(msg.InArgs) {
338 w.Error(fmt.Errorf("invalid number of arguments, expected: %v, got:%v", methSig, *msg))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700339 return
340 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700341
342 // We have to make the start call synchronous so we can make sure that we populate
343 // the call map before we can Handle a recieve call.
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800344 call, err := c.startCall(ctx, w, msg)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700345 if err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700346 w.Error(verror2.Convert(verror2.Internal, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700347 return
348 }
349
350 if stream != nil {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800351 stream.init(call)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700352 }
353
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800354 c.finishCall(ctx, w, call, msg)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700355 c.Lock()
356 if request, ok := c.outstandingRequests[id]; ok {
357 delete(c.outstandingRequests, id)
358 if request.cancel != nil {
359 request.cancel()
360 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700361 }
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700362 c.Unlock()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700363}
364
365// HandleVeyronRequest starts a veyron rpc and returns before the rpc has been completed.
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800366func (c *Controller) HandleVeyronRequest(ctx *context.T, id int32, data string, w lib.ClientWriter) {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800367 msg, err := c.parseVeyronRequest(data)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700368 if err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700369 w.Error(verror2.Convert(verror2.Internal, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700370 return
371 }
372
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800373 var cctx *context.T
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700374 var cancel context.CancelFunc
375
376 // TODO(mattr): To be consistent with go, we should not ignore 0 timeouts.
377 // However as a rollout strategy we must, otherwise there is a circular
378 // dependency between the WSPR change and the JS change that will follow.
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800379 if msg.Timeout == lib.JSIPCNoTimeout || msg.Timeout == 0 {
Matt Rosencrantzb6f4b922015-01-05 13:31:55 -0800380 cctx, cancel = context.WithCancel(ctx)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700381 } else {
Matt Rosencrantzb6f4b922015-01-05 13:31:55 -0800382 cctx, cancel = context.WithTimeout(ctx, lib.JSToGoDuration(msg.Timeout))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700383 }
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700384
385 request := &outstandingRequest{
386 cancel: cancel,
387 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800388 if msg.IsStreaming {
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700389 // If this rpc is streaming, we would expect that the client would try to send
390 // on this stream. Since the initial handshake is done asynchronously, we have
391 // to put the outstanding stream in the map before we make the async call so that
392 // the future send know which queue to write to, even if the client call isn't
393 // actually ready yet.
394 request.stream = newStream()
395 }
396 c.Lock()
397 c.outstandingRequests[id] = request
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800398 go c.sendVeyronRequest(cctx, id, msg, w, request.stream)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700399 c.Unlock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700400}
401
402// HandleVeyronCancellation cancels the request corresponding to the
403// given id if it is still outstanding.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800404func (c *Controller) HandleVeyronCancellation(id int32) {
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700405 c.Lock()
406 defer c.Unlock()
407 if request, ok := c.outstandingRequests[id]; ok && request.cancel != nil {
408 request.cancel()
409 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700410}
411
412// CloseStream closes the stream for a given id.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800413func (c *Controller) CloseStream(id int32) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700414 c.Lock()
415 defer c.Unlock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700416 if request, ok := c.outstandingRequests[id]; ok && request.stream != nil {
417 request.stream.end()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700418 return
419 }
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800420 c.GetLogger().Errorf("close called on non-existent call: %v", id)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700421}
422
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800423func (c *Controller) maybeCreateServer(serverId uint32) (*server.Server, error) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700424 c.Lock()
425 defer c.Unlock()
426 if server, ok := c.servers[serverId]; ok {
427 return server, nil
428 }
429 server, err := server.NewServer(serverId, c.listenSpec, c)
430 if err != nil {
431 return nil, err
432 }
433 c.servers[serverId] = server
434 return server, nil
435}
436
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800437func (c *Controller) removeServer(serverId uint32) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700438 c.Lock()
439 server := c.servers[serverId]
440 if server == nil {
441 c.Unlock()
442 return
443 }
444 delete(c.servers, serverId)
445 c.Unlock()
446
447 server.Stop()
448}
449
450func (c *Controller) serve(serveRequest serveRequest, w lib.ClientWriter) {
Nicolas LaCasse4f409ce2014-11-25 11:44:03 -0800451 // Create a server for the pipe, if it does not exist already.
Jiri Simsa78b646f2014-10-08 10:23:05 -0700452 server, err := c.maybeCreateServer(serveRequest.ServerId)
453 if err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700454 w.Error(verror2.Convert(verror2.Internal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700455 }
456
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800457 c.GetLogger().VI(2).Infof("serving under name: %q", serveRequest.Name)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700458
Nicolas LaCasse27b57c72014-11-19 13:40:20 -0800459 if err := server.Serve(serveRequest.Name); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700460 w.Error(verror2.Convert(verror2.Internal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700461 return
462 }
Nicolas LaCasse27b57c72014-11-19 13:40:20 -0800463 // Send true to indicate the serve has succeeded.
464 if err := w.Send(lib.ResponseFinal, true); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700465 w.Error(verror2.Convert(verror2.Internal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700466 return
467 }
468}
469
Nicolas LaCasse27b57c72014-11-19 13:40:20 -0800470// HandleServeRequest takes a request to serve a server, creates a server,
471// registers the provided services and sends true if everything succeeded.
Jiri Simsa78b646f2014-10-08 10:23:05 -0700472func (c *Controller) HandleServeRequest(data string, w lib.ClientWriter) {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800473 // Decode the serve request which includes VDL, registered services and name
Jiri Simsa78b646f2014-10-08 10:23:05 -0700474 var serveRequest serveRequest
475 if err := json.Unmarshal([]byte(data), &serveRequest); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700476 w.Error(verror2.Convert(verror2.Internal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700477 return
478 }
479 c.serve(serveRequest, w)
480}
481
482// HandleLookupResponse handles the result of a Dispatcher.Lookup call that was
483// run by the Javascript server.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800484func (c *Controller) HandleLookupResponse(id int32, data string) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700485 c.Lock()
486 server := c.flowMap[id]
487 c.Unlock()
488 if server == nil {
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800489 c.GetLogger().Errorf("unexpected result from JavaScript. No channel "+
Jiri Simsa78b646f2014-10-08 10:23:05 -0700490 "for MessageId: %d exists. Ignoring the results.", id)
491 //Ignore unknown responses that don't belong to any channel
492 return
493 }
494 server.HandleLookupResponse(id, data)
495}
496
497// HandleAuthResponse handles the result of a Authorizer.Authorize call that was
498// run by the Javascript server.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800499func (c *Controller) HandleAuthResponse(id int32, data string) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700500 c.Lock()
501 server := c.flowMap[id]
502 c.Unlock()
503 if server == nil {
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800504 c.GetLogger().Errorf("unexpected result from JavaScript. No channel "+
Jiri Simsa78b646f2014-10-08 10:23:05 -0700505 "for MessageId: %d exists. Ignoring the results.", id)
506 //Ignore unknown responses that don't belong to any channel
507 return
508 }
509 server.HandleAuthResponse(id, data)
510}
511
512// HandleStopRequest takes a request to stop a server.
513func (c *Controller) HandleStopRequest(data string, w lib.ClientWriter) {
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800514 var serverId uint32
Jiri Simsa78b646f2014-10-08 10:23:05 -0700515 if err := json.Unmarshal([]byte(data), &serverId); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700516 w.Error(verror2.Convert(verror2.Internal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700517 return
518 }
519
520 c.removeServer(serverId)
521
522 // Send true to indicate stop has finished
523 if err := w.Send(lib.ResponseFinal, true); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700524 w.Error(verror2.Convert(verror2.Internal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700525 return
526 }
527}
528
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800529// HandleAddNameRequest takes a request to add a new name to a server
530func (c *Controller) HandleAddNameRequest(data string, w lib.ClientWriter) {
531 var request addRemoveNameRequest
532 if err := json.Unmarshal([]byte(data), &request); err != nil {
533 w.Error(verror2.Convert(verror2.Internal, nil, err))
534 return
535 }
536
Nicolas LaCasse4f409ce2014-11-25 11:44:03 -0800537 // Create a server for the pipe, if it does not exist already
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800538 server, err := c.maybeCreateServer(request.ServerId)
539 if err != nil {
540 w.Error(verror2.Convert(verror2.Internal, nil, err))
541 return
542 }
543
544 // Add name
545 if err := server.AddName(request.Name); err != nil {
546 w.Error(verror2.Convert(verror2.Internal, nil, err))
547 return
548 }
549
550 // Send true to indicate request has finished without error
551 if err := w.Send(lib.ResponseFinal, true); err != nil {
552 w.Error(verror2.Convert(verror2.Internal, nil, err))
553 return
554 }
555}
556
557// HandleRemoveNameRequest takes a request to remove a name from a server
558func (c *Controller) HandleRemoveNameRequest(data string, w lib.ClientWriter) {
559 var request addRemoveNameRequest
560 if err := json.Unmarshal([]byte(data), &request); err != nil {
561 w.Error(verror2.Convert(verror2.Internal, nil, err))
562 return
563 }
564
Nicolas LaCasse4f409ce2014-11-25 11:44:03 -0800565 // Create a server for the pipe, if it does not exist already
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800566 server, err := c.maybeCreateServer(request.ServerId)
567 if err != nil {
568 w.Error(verror2.Convert(verror2.Internal, nil, err))
569 return
570 }
571
572 // Remove name
573 if err := server.RemoveName(request.Name); err != nil {
574 w.Error(verror2.Convert(verror2.Internal, nil, err))
575 return
576 }
577
578 // Remove name from signature cache as well
579 c.signatureManager.FlushCacheEntry(request.Name)
580
581 // Send true to indicate request has finished without error
582 if err := w.Send(lib.ResponseFinal, true); err != nil {
583 w.Error(verror2.Convert(verror2.Internal, nil, err))
584 return
585 }
586}
587
Jiri Simsa78b646f2014-10-08 10:23:05 -0700588// HandleServerResponse handles the completion of outstanding calls to JavaScript services
589// by filling the corresponding channel with the result from JavaScript.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800590func (c *Controller) HandleServerResponse(id int32, data string) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700591 c.Lock()
592 server := c.flowMap[id]
593 c.Unlock()
594 if server == nil {
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800595 c.GetLogger().Errorf("unexpected result from JavaScript. No channel "+
Jiri Simsa78b646f2014-10-08 10:23:05 -0700596 "for MessageId: %d exists. Ignoring the results.", id)
597 //Ignore unknown responses that don't belong to any channel
598 return
599 }
600 server.HandleServerResponse(id, data)
601}
602
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800603// parseVeyronRequest parses a json rpc request into a VeyronRPC object.
604func (c *Controller) parseVeyronRequest(data string) (*VeyronRPC, error) {
605 var msg VeyronRPC
606 if err := lib.VomDecode(data, &msg); err != nil {
607 return nil, err
Jiri Simsa78b646f2014-10-08 10:23:05 -0700608 }
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800609 c.GetLogger().VI(2).Infof("VeyronRPC: %s.%s(..., streaming=%v)", msg.Name, msg.Method, msg.IsStreaming)
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800610 return &msg, nil
Jiri Simsa78b646f2014-10-08 10:23:05 -0700611}
612
613type signatureRequest struct {
614 Name string
615}
616
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800617func (c *Controller) getSignature(ctx *context.T, name string) ([]signature.Interface, error) {
Asim Shankarf3c61a32014-10-15 17:34:11 -0700618 retryTimeoutOpt := options.RetryTimeout(time.Duration(*retryTimeout) * time.Second)
Todd Wangf83dbfc2015-01-09 11:54:46 -0800619 return c.signatureManager.Signature(ctx, name, retryTimeoutOpt)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700620}
621
622// HandleSignatureRequest uses signature manager to get and cache signature of a remote server
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800623func (c *Controller) HandleSignatureRequest(ctx *context.T, data string, w lib.ClientWriter) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700624 // Decode the request
625 var request signatureRequest
626 if err := json.Unmarshal([]byte(data), &request); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700627 w.Error(verror2.Convert(verror2.Internal, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700628 return
629 }
630
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800631 c.GetLogger().VI(2).Infof("requesting Signature for %q", request.Name)
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800632 sig, err := c.getSignature(ctx, request.Name)
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800633 if err != nil {
634 w.Error(err)
635 return
636 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800637 vomSig, err := lib.VomEncode(sig)
638 if err != nil {
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800639 w.Error(err)
640 return
641 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700642 // Send the signature back
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800643 if err := w.Send(lib.ResponseFinal, vomSig); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700644 w.Error(verror2.Convert(verror2.Internal, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700645 return
646 }
647}
648
Ankure7889242014-10-20 18:37:29 -0700649// HandleUnlinkJSBlessings removes the specified blessings from the JS blessings
650// store. 'data' should be a JSON encoded number (representing the blessings handle).
651func (c *Controller) HandleUnlinkJSBlessings(data string, w lib.ClientWriter) {
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800652 var handle int32
Jiri Simsa78b646f2014-10-08 10:23:05 -0700653 if err := json.Unmarshal([]byte(data), &handle); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700654 w.Error(verror2.Convert(verror2.Internal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700655 return
656 }
Ankure7889242014-10-20 18:37:29 -0700657 c.blessingsStore.Remove(handle)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700658}
659
660// Convert the json wire format of a caveat into the right go object
661func decodeCaveat(c jsonCaveatValidator) (security.Caveat, error) {
662 var failed security.Caveat
663 switch c.Type {
664 case "MethodCaveat":
665 var methods []string
666 if err := json.Unmarshal(c.Data, &methods); err != nil {
667 return failed, err
668 }
669 if len(methods) == 0 {
670 return failed, fmt.Errorf("must provide at least one method")
671 }
672 return security.MethodCaveat(methods[0], methods[1:]...)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700673 default:
Mike Burrowsb6689c22014-10-08 11:14:15 -0700674 return failed, verror2.Make(badCaveatType, nil, c.Type)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700675 }
676}
677
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800678func (c *Controller) getBlessingsHandle(handle int32) (*principal.BlessingsHandle, error) {
Ankure7889242014-10-20 18:37:29 -0700679 id := c.blessingsStore.Get(handle)
680 if id == nil {
681 return nil, verror2.Make(unknownBlessings, nil)
682 }
683 return principal.ConvertBlessingsToHandle(id, handle), nil
684}
685
686func (c *Controller) blessPublicKey(request blessingRequest) (*principal.BlessingsHandle, error) {
687 var blessee security.Blessings
Ankur697132e2014-10-22 12:12:39 -0700688 if blessee = c.blessingsStore.Get(request.Handle); blessee == nil {
Ankur5b802242014-10-29 11:32:21 -0700689 return nil, verror2.Make(invalidBlessingsHandle, nil)
Ankure7889242014-10-20 18:37:29 -0700690 }
691
692 expiryCav, err := security.ExpiryCaveat(time.Now().Add(time.Duration(request.DurationMs) * time.Millisecond))
693 if err != nil {
694 return nil, err
695 }
696 caveats := []security.Caveat{expiryCav}
697 for _, c := range request.Caveats {
698 cav, err := decodeCaveat(c)
699 if err != nil {
700 return nil, verror2.Convert(verror2.BadArg, nil, err)
701 }
702 caveats = append(caveats, cav)
703 }
704
705 // TODO(ataly, ashankar, bjornick): Currently the Bless operation is carried
706 // out using the Default blessing in this principal's blessings store. We
707 // should change this so that the JS blessing request can also specify the
708 // blessing to be used for the Bless operation.
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800709 p := veyron2.GetPrincipal(c.ctx)
710 blessings, err := p.Bless(blessee.PublicKey(), p.BlessingStore().Default(), request.Extension, caveats[0], caveats[1:]...)
Ankure7889242014-10-20 18:37:29 -0700711 if err != nil {
712 return nil, err
713 }
714
715 return principal.ConvertBlessingsToHandle(blessings, c.blessingsStore.Add(blessings)), nil
716}
717
718// HandleBlessPublicKey handles a blessing request from JS.
719func (c *Controller) HandleBlessPublicKey(data string, w lib.ClientWriter) {
720 var request blessingRequest
721 if err := json.Unmarshal([]byte(data), &request); err != nil {
722 w.Error(verror2.Convert(verror2.Internal, nil, err))
723 return
724 }
725
726 handle, err := c.blessPublicKey(request)
727 if err != nil {
728 w.Error(verror2.Convert(verror2.Internal, nil, err))
729 return
730 }
731
732 // Send the id back.
733 if err := w.Send(lib.ResponseFinal, handle); err != nil {
734 w.Error(verror2.Convert(verror2.Internal, nil, err))
735 return
736 }
737}
738
739func (c *Controller) HandleCreateBlessings(data string, w lib.ClientWriter) {
740 var extension string
741 if err := json.Unmarshal([]byte(data), &extension); err != nil {
742 w.Error(verror2.Convert(verror2.Internal, nil, err))
743 return
744 }
745 p, err := vsecurity.NewPrincipal()
746 if err != nil {
747 w.Error(verror2.Convert(verror2.Internal, nil, err))
748 return
749 }
750
751 blessings, err := p.BlessSelf(extension)
752 if err != nil {
753 w.Error(verror2.Convert(verror2.Internal, nil, err))
754 return
755 }
756 handle := principal.ConvertBlessingsToHandle(blessings, c.blessingsStore.Add(blessings))
757 if err := w.Send(lib.ResponseFinal, handle); err != nil {
758 w.Error(verror2.Convert(verror2.Internal, nil, err))
759 return
760 }
761}
762
Ali Ghassemiaa0ea242014-10-20 12:55:39 -0700763// HandleNamespaceRequest uses the namespace client to respond to namespace specific requests such as glob
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800764func (c *Controller) HandleNamespaceRequest(ctx *context.T, data string, w lib.ClientWriter) {
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800765 namespace.HandleRequest(ctx, data, w)
Ali Ghassemiaa0ea242014-10-20 12:55:39 -0700766}