blob: 44c58fff3910126cf4b14045d96280ae507929a6 [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
Ankure7889242014-10-20 18:37:29 -070013 vsecurity "veyron.io/veyron/veyron/security"
Jiri Simsa78b646f2014-10-08 10:23:05 -070014 "veyron.io/veyron/veyron2"
15 "veyron.io/veyron/veyron2/context"
16 "veyron.io/veyron/veyron2/ipc"
Asim Shankarf3c61a32014-10-15 17:34:11 -070017 "veyron.io/veyron/veyron2/options"
Jiri Simsa78b646f2014-10-08 10:23:05 -070018 "veyron.io/veyron/veyron2/rt"
19 "veyron.io/veyron/veyron2/security"
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -080020 "veyron.io/veyron/veyron2/vdl/vdlroot/src/signature"
Mike Burrowsb6689c22014-10-08 11:14:15 -070021 "veyron.io/veyron/veyron2/verror2"
Jiri Simsa78b646f2014-10-08 10:23:05 -070022 "veyron.io/veyron/veyron2/vlog"
Jiri Simsa78b646f2014-10-08 10:23:05 -070023 "veyron.io/wspr/veyron/services/wsprd/ipc/server"
24 "veyron.io/wspr/veyron/services/wsprd/lib"
Ali Ghassemiaa0ea242014-10-20 12:55:39 -070025 "veyron.io/wspr/veyron/services/wsprd/namespace"
Ankure7889242014-10-20 18:37:29 -070026 "veyron.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.
30const pkgPath = "veyron.io/veyron/veyron/services/wsprd/app"
31
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
64 ServerId uint64
65}
66
Ali Ghassemi1008bbe2014-11-07 16:36:08 -080067type addRemoveNameRequest struct {
68 Name string
69 ServerId uint64
70}
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 {
78 Handle int64
79 Caveats []jsonCaveatValidator
80 DurationMs int64
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
96 logger vlog.Logger
97
98 // The runtime to use to create new clients.
99 rt veyron2.Runtime
100
101 // The ipc.ListenSpec to use with server.Listen
102 listenSpec *ipc.ListenSpec
103
104 // Used to generate unique ids for requests initiated by the proxy.
105 // These ids will be even so they don't collide with the ids generated
106 // by the client.
107 lastGeneratedId int64
108
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700109 // Used to keep track of data (streams and cancellation functions) for
110 // outstanding requests.
111 outstandingRequests map[int64]*outstandingRequest
Jiri Simsa78b646f2014-10-08 10:23:05 -0700112
113 // Maps flowids to the server that owns them.
114 flowMap map[int64]*server.Server
115
116 // A manager that Handles fetching and caching signature of remote services
117 signatureManager lib.SignatureManager
118
Nicolas LaCasse4f409ce2014-11-25 11:44:03 -0800119 // We maintain multiple Veyron server per pipe for serving JavaScript
Jiri Simsa78b646f2014-10-08 10:23:05 -0700120 // services.
121 servers map[uint64]*server.Server
122
123 // Creates a client writer for a given flow. This is a member so that tests can override
124 // the default implementation.
125 writerCreator func(id int64) lib.ClientWriter
126
Ankur5b802242014-10-29 11:32:21 -0700127 // There is only one client per Controller since there is a single principal per app.
Jiri Simsa78b646f2014-10-08 10:23:05 -0700128 client ipc.Client
129
130 veyronProxyEP string
131
Ankure7889242014-10-20 18:37:29 -0700132 // Store for all the Blessings that javascript has a handle to.
133 blessingsStore *principal.JSBlessingsHandles
Jiri Simsa78b646f2014-10-08 10:23:05 -0700134}
135
136// NewController creates a new Controller. writerCreator will be used to create a new flow for rpcs to
137// 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 -0700138// opts are any options that should be passed to the rt.New().
Shyam Jayaramanae279472014-11-18 17:04:20 -0800139func NewController(writerCreator func(id int64) lib.ClientWriter, profile veyron2.Profile, listenSpec *ipc.ListenSpec, namespaceRoots []string, opts ...veyron2.ROpt) (*Controller, error) {
140 if profile != nil {
141 opts = append(opts, options.Profile{profile})
142 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700143 r, err := rt.New(opts...)
144 if err != nil {
145 return nil, err
146 }
Benjamin Prosnitz3c738502014-11-04 14:51:38 -0800147 if namespaceRoots != nil {
148 r.Namespace().SetRoots(namespaceRoots...)
149 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700150 client, err := r.NewClient()
151 if err != nil {
152 return nil, err
153 }
154
155 controller := &Controller{
Ankure7889242014-10-20 18:37:29 -0700156 rt: r,
157 logger: r.Logger(),
158 client: client,
159 writerCreator: writerCreator,
160 listenSpec: listenSpec,
Ankure7889242014-10-20 18:37:29 -0700161 blessingsStore: principal.NewJSBlessingsHandles(),
Ankure7889242014-10-20 18:37:29 -0700162 }
163
Jiri Simsa78b646f2014-10-08 10:23:05 -0700164 controller.setup()
165 return controller, nil
166}
167
168// finishCall waits for the call to finish and write out the response to w.
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800169func (c *Controller) finishCall(ctx context.T, w lib.ClientWriter, clientCall ipc.Call, msg *VeyronRPC) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700170 if msg.IsStreaming {
171 for {
172 var item interface{}
173 if err := clientCall.Recv(&item); err != nil {
174 if err == io.EOF {
175 break
176 }
177 w.Error(err) // Send streaming error as is
178 return
179 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800180 vomItem, err := lib.VomEncode(item)
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800181 if err != nil {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800182 w.Error(verror2.Make(marshallingError, ctx, item, err))
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800183 continue
184 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800185 if err := w.Send(lib.ResponseStream, vomItem); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700186 w.Error(verror2.Make(marshallingError, ctx, item))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700187 }
188 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700189 if err := w.Send(lib.ResponseStreamClose, nil); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700190 w.Error(verror2.Make(marshallingError, ctx, "ResponseStreamClose"))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700191 }
192 }
193
194 results := make([]interface{}, msg.NumOutArgs)
195 // This array will have pointers to the values in result.
196 resultptrs := make([]interface{}, msg.NumOutArgs)
197 for ax := range results {
198 resultptrs[ax] = &results[ax]
199 }
200 if err := clientCall.Finish(resultptrs...); err != nil {
201 // return the call system error as is
202 w.Error(err)
203 return
204 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800205
Jiri Simsa78b646f2014-10-08 10:23:05 -0700206 // for now we assume last out argument is always error
207 if len(results) < 1 {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700208 w.Error(verror2.Make(noResults, ctx))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700209 return
210 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700211 if err, ok := results[len(results)-1].(error); ok {
212 // return the call Application error as is
213 w.Error(err)
214 return
215 }
216
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800217 vomResults, err := lib.VomEncode(results[:len(results)-1])
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800218 if err != nil {
219 w.Error(err)
220 return
221 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800222 if err := w.Send(lib.ResponseFinal, vomResults); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700223 w.Error(verror2.Convert(marshallingError, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700224 }
225}
226
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800227func (c *Controller) startCall(ctx context.T, w lib.ClientWriter, msg *VeyronRPC) (ipc.Call, error) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700228 if c.client == nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700229 return nil, verror2.Make(verror2.BadArg, ctx, "app.Controller.client")
Jiri Simsa78b646f2014-10-08 10:23:05 -0700230 }
231 methodName := lib.UppercaseFirstCharacter(msg.Method)
Asim Shankarf3c61a32014-10-15 17:34:11 -0700232 retryTimeoutOpt := options.RetryTimeout(time.Duration(*retryTimeout) * time.Second)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700233 clientCall, err := c.client.StartCall(ctx, msg.Name, methodName, msg.InArgs, retryTimeoutOpt)
234 if err != nil {
235 return nil, fmt.Errorf("error starting call (name: %v, method: %v, args: %v): %v", msg.Name, methodName, msg.InArgs, err)
236 }
237
238 return clientCall, nil
239}
240
241// Implements the serverHelper interface
242
243// CreateNewFlow creats a new server flow that will be used to write out
244// streaming messages to Javascript.
245func (c *Controller) CreateNewFlow(s *server.Server, stream ipc.Stream) *server.Flow {
246 c.Lock()
247 defer c.Unlock()
248 id := c.lastGeneratedId
249 c.lastGeneratedId += 2
250 c.flowMap[id] = s
251 os := newStream()
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800252 os.init(stream)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700253 c.outstandingRequests[id] = &outstandingRequest{
254 stream: os,
255 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700256 return &server.Flow{ID: id, Writer: c.writerCreator(id)}
257}
258
259// CleanupFlow removes the bookkeping for a previously created flow.
260func (c *Controller) CleanupFlow(id int64) {
261 c.Lock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700262 request := c.outstandingRequests[id]
263 delete(c.outstandingRequests, id)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700264 delete(c.flowMap, id)
265 c.Unlock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700266 if request != nil && request.stream != nil {
267 request.stream.end()
268 request.stream.waitUntilDone()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700269 }
270}
271
272// GetLogger returns a Veyron logger to use.
273func (c *Controller) GetLogger() vlog.Logger {
274 return c.logger
275}
276
277// RT returns the runtime of the app.
278func (c *Controller) RT() veyron2.Runtime {
279 return c.rt
280}
281
Ankure7889242014-10-20 18:37:29 -0700282// AddBlessings adds the Blessings to the local blessings store and returns
Jiri Simsa78b646f2014-10-08 10:23:05 -0700283// the handle to it. This function exists because JS only has
Ankure7889242014-10-20 18:37:29 -0700284// a handle to the blessings to avoid shipping the certificate forest
Jiri Simsa78b646f2014-10-08 10:23:05 -0700285// to JS and back.
Ankure7889242014-10-20 18:37:29 -0700286func (c *Controller) AddBlessings(blessings security.Blessings) int64 {
287 return c.blessingsStore.Add(blessings)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700288}
289
290// Cleanup cleans up any outstanding rpcs.
291func (c *Controller) Cleanup() {
Nicolas LaCasse4f409ce2014-11-25 11:44:03 -0800292 c.logger.VI(0).Info("Cleaning up pipe")
Jiri Simsa78b646f2014-10-08 10:23:05 -0700293 c.Lock()
294 defer c.Unlock()
295
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700296 for _, request := range c.outstandingRequests {
297 if request.cancel != nil {
298 request.cancel()
299 }
300 if request.stream != nil {
301 request.stream.end()
302 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700303 }
304
305 for _, server := range c.servers {
306 server.Stop()
307 }
Benjamin Prosnitz8a51fe82014-10-16 13:05:14 -0700308
309 c.RT().Cleanup()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700310}
311
312func (c *Controller) setup() {
313 c.signatureManager = lib.NewSignatureManager()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700314 c.outstandingRequests = make(map[int64]*outstandingRequest)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700315 c.flowMap = make(map[int64]*server.Server)
316 c.servers = make(map[uint64]*server.Server)
317}
318
319// SendOnStream writes data on id's stream. The actual network write will be
320// done asynchronously. If there is an error, it will be sent to w.
321func (c *Controller) SendOnStream(id int64, data string, w lib.ClientWriter) {
322 c.Lock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700323 request := c.outstandingRequests[id]
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700324 if request == nil || request.stream == nil {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700325 vlog.Errorf("unknown stream: %d", id)
326 return
327 }
Matt Rosencrantzd608b372014-10-22 13:06:52 -0700328 stream := request.stream
329 c.Unlock()
330 stream.send(data, w)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700331}
332
333// SendVeyronRequest makes a veyron request for the given flowId. If signal is non-nil, it will receive
334// the call object after it has been constructed.
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800335func (c *Controller) sendVeyronRequest(ctx context.T, id int64, msg *VeyronRPC, w lib.ClientWriter, stream *outstandingStream) {
336 sig, err := c.getSignature(ctx, msg.Name)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700337 if err != nil {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800338 w.Error(err)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700339 return
340 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800341 methName := lib.UppercaseFirstCharacter(msg.Method)
342 methSig, ok := signature.FirstMethod(sig, methName)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700343 if !ok {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800344 w.Error(fmt.Errorf("method %q not found in signature: %#v", methName, sig))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700345 return
346 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800347 if len(methSig.InArgs) != len(msg.InArgs) {
348 w.Error(fmt.Errorf("invalid number of arguments, expected: %v, got:%v", methSig, *msg))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700349 return
350 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700351
352 // We have to make the start call synchronous so we can make sure that we populate
353 // the call map before we can Handle a recieve call.
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800354 call, err := c.startCall(ctx, w, msg)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700355 if err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700356 w.Error(verror2.Convert(verror2.Internal, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700357 return
358 }
359
360 if stream != nil {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800361 stream.init(call)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700362 }
363
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800364 c.finishCall(ctx, w, call, msg)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700365 c.Lock()
366 if request, ok := c.outstandingRequests[id]; ok {
367 delete(c.outstandingRequests, id)
368 if request.cancel != nil {
369 request.cancel()
370 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700371 }
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700372 c.Unlock()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700373}
374
375// HandleVeyronRequest starts a veyron rpc and returns before the rpc has been completed.
376func (c *Controller) HandleVeyronRequest(ctx context.T, id int64, data string, w lib.ClientWriter) {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800377 msg, err := c.parseVeyronRequest(data)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700378 if err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700379 w.Error(verror2.Convert(verror2.Internal, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700380 return
381 }
382
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700383 var cctx context.T
384 var cancel context.CancelFunc
385
386 // TODO(mattr): To be consistent with go, we should not ignore 0 timeouts.
387 // However as a rollout strategy we must, otherwise there is a circular
388 // dependency between the WSPR change and the JS change that will follow.
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800389 if msg.Timeout == lib.JSIPCNoTimeout || msg.Timeout == 0 {
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700390 cctx, cancel = ctx.WithCancel()
391 } else {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800392 cctx, cancel = ctx.WithTimeout(lib.JSToGoDuration(msg.Timeout))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700393 }
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700394
395 request := &outstandingRequest{
396 cancel: cancel,
397 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800398 if msg.IsStreaming {
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700399 // If this rpc is streaming, we would expect that the client would try to send
400 // on this stream. Since the initial handshake is done asynchronously, we have
401 // to put the outstanding stream in the map before we make the async call so that
402 // the future send know which queue to write to, even if the client call isn't
403 // actually ready yet.
404 request.stream = newStream()
405 }
406 c.Lock()
407 c.outstandingRequests[id] = request
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800408 go c.sendVeyronRequest(cctx, id, msg, w, request.stream)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700409 c.Unlock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700410}
411
412// HandleVeyronCancellation cancels the request corresponding to the
413// given id if it is still outstanding.
414func (c *Controller) HandleVeyronCancellation(id int64) {
415 c.Lock()
416 defer c.Unlock()
417 if request, ok := c.outstandingRequests[id]; ok && request.cancel != nil {
418 request.cancel()
419 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700420}
421
422// CloseStream closes the stream for a given id.
423func (c *Controller) CloseStream(id int64) {
424 c.Lock()
425 defer c.Unlock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700426 if request, ok := c.outstandingRequests[id]; ok && request.stream != nil {
427 request.stream.end()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700428 return
429 }
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700430 c.logger.Errorf("close called on non-existent call: %v", id)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700431}
432
433func (c *Controller) maybeCreateServer(serverId uint64) (*server.Server, error) {
434 c.Lock()
435 defer c.Unlock()
436 if server, ok := c.servers[serverId]; ok {
437 return server, nil
438 }
439 server, err := server.NewServer(serverId, c.listenSpec, c)
440 if err != nil {
441 return nil, err
442 }
443 c.servers[serverId] = server
444 return server, nil
445}
446
447func (c *Controller) removeServer(serverId uint64) {
448 c.Lock()
449 server := c.servers[serverId]
450 if server == nil {
451 c.Unlock()
452 return
453 }
454 delete(c.servers, serverId)
455 c.Unlock()
456
457 server.Stop()
458}
459
460func (c *Controller) serve(serveRequest serveRequest, w lib.ClientWriter) {
Nicolas LaCasse4f409ce2014-11-25 11:44:03 -0800461 // Create a server for the pipe, if it does not exist already.
Jiri Simsa78b646f2014-10-08 10:23:05 -0700462 server, err := c.maybeCreateServer(serveRequest.ServerId)
463 if err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700464 w.Error(verror2.Convert(verror2.Internal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700465 }
466
467 c.logger.VI(2).Infof("serving under name: %q", serveRequest.Name)
468
Nicolas LaCasse27b57c72014-11-19 13:40:20 -0800469 if err := server.Serve(serveRequest.Name); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700470 w.Error(verror2.Convert(verror2.Internal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700471 return
472 }
Nicolas LaCasse27b57c72014-11-19 13:40:20 -0800473 // Send true to indicate the serve has succeeded.
474 if err := w.Send(lib.ResponseFinal, true); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700475 w.Error(verror2.Convert(verror2.Internal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700476 return
477 }
478}
479
Nicolas LaCasse27b57c72014-11-19 13:40:20 -0800480// HandleServeRequest takes a request to serve a server, creates a server,
481// registers the provided services and sends true if everything succeeded.
Jiri Simsa78b646f2014-10-08 10:23:05 -0700482func (c *Controller) HandleServeRequest(data string, w lib.ClientWriter) {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800483 // Decode the serve request which includes VDL, registered services and name
Jiri Simsa78b646f2014-10-08 10:23:05 -0700484 var serveRequest serveRequest
485 if err := json.Unmarshal([]byte(data), &serveRequest); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700486 w.Error(verror2.Convert(verror2.Internal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700487 return
488 }
489 c.serve(serveRequest, w)
490}
491
492// HandleLookupResponse handles the result of a Dispatcher.Lookup call that was
493// run by the Javascript server.
494func (c *Controller) HandleLookupResponse(id int64, data string) {
495 c.Lock()
496 server := c.flowMap[id]
497 c.Unlock()
498 if server == nil {
499 c.logger.Errorf("unexpected result from JavaScript. No channel "+
500 "for MessageId: %d exists. Ignoring the results.", id)
501 //Ignore unknown responses that don't belong to any channel
502 return
503 }
504 server.HandleLookupResponse(id, data)
505}
506
507// HandleAuthResponse handles the result of a Authorizer.Authorize call that was
508// run by the Javascript server.
509func (c *Controller) HandleAuthResponse(id int64, data string) {
510 c.Lock()
511 server := c.flowMap[id]
512 c.Unlock()
513 if server == nil {
514 c.logger.Errorf("unexpected result from JavaScript. No channel "+
515 "for MessageId: %d exists. Ignoring the results.", id)
516 //Ignore unknown responses that don't belong to any channel
517 return
518 }
519 server.HandleAuthResponse(id, data)
520}
521
522// HandleStopRequest takes a request to stop a server.
523func (c *Controller) HandleStopRequest(data string, w lib.ClientWriter) {
524 var serverId uint64
525 if err := json.Unmarshal([]byte(data), &serverId); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700526 w.Error(verror2.Convert(verror2.Internal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700527 return
528 }
529
530 c.removeServer(serverId)
531
532 // Send true to indicate stop has finished
533 if err := w.Send(lib.ResponseFinal, true); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700534 w.Error(verror2.Convert(verror2.Internal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700535 return
536 }
537}
538
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800539// HandleAddNameRequest takes a request to add a new name to a server
540func (c *Controller) HandleAddNameRequest(data string, w lib.ClientWriter) {
541 var request addRemoveNameRequest
542 if err := json.Unmarshal([]byte(data), &request); err != nil {
543 w.Error(verror2.Convert(verror2.Internal, nil, err))
544 return
545 }
546
Nicolas LaCasse4f409ce2014-11-25 11:44:03 -0800547 // Create a server for the pipe, if it does not exist already
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800548 server, err := c.maybeCreateServer(request.ServerId)
549 if err != nil {
550 w.Error(verror2.Convert(verror2.Internal, nil, err))
551 return
552 }
553
554 // Add name
555 if err := server.AddName(request.Name); err != nil {
556 w.Error(verror2.Convert(verror2.Internal, nil, err))
557 return
558 }
559
560 // Send true to indicate request has finished without error
561 if err := w.Send(lib.ResponseFinal, true); err != nil {
562 w.Error(verror2.Convert(verror2.Internal, nil, err))
563 return
564 }
565}
566
567// HandleRemoveNameRequest takes a request to remove a name from a server
568func (c *Controller) HandleRemoveNameRequest(data string, w lib.ClientWriter) {
569 var request addRemoveNameRequest
570 if err := json.Unmarshal([]byte(data), &request); err != nil {
571 w.Error(verror2.Convert(verror2.Internal, nil, err))
572 return
573 }
574
Nicolas LaCasse4f409ce2014-11-25 11:44:03 -0800575 // Create a server for the pipe, if it does not exist already
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800576 server, err := c.maybeCreateServer(request.ServerId)
577 if err != nil {
578 w.Error(verror2.Convert(verror2.Internal, nil, err))
579 return
580 }
581
582 // Remove name
583 if err := server.RemoveName(request.Name); err != nil {
584 w.Error(verror2.Convert(verror2.Internal, nil, err))
585 return
586 }
587
588 // Remove name from signature cache as well
589 c.signatureManager.FlushCacheEntry(request.Name)
590
591 // Send true to indicate request has finished without error
592 if err := w.Send(lib.ResponseFinal, true); err != nil {
593 w.Error(verror2.Convert(verror2.Internal, nil, err))
594 return
595 }
596}
597
Jiri Simsa78b646f2014-10-08 10:23:05 -0700598// HandleServerResponse handles the completion of outstanding calls to JavaScript services
599// by filling the corresponding channel with the result from JavaScript.
600func (c *Controller) HandleServerResponse(id int64, data string) {
601 c.Lock()
602 server := c.flowMap[id]
603 c.Unlock()
604 if server == nil {
605 c.logger.Errorf("unexpected result from JavaScript. No channel "+
606 "for MessageId: %d exists. Ignoring the results.", id)
607 //Ignore unknown responses that don't belong to any channel
608 return
609 }
610 server.HandleServerResponse(id, data)
611}
612
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800613// parseVeyronRequest parses a json rpc request into a VeyronRPC object.
614func (c *Controller) parseVeyronRequest(data string) (*VeyronRPC, error) {
615 var msg VeyronRPC
616 if err := lib.VomDecode(data, &msg); err != nil {
617 return nil, err
Jiri Simsa78b646f2014-10-08 10:23:05 -0700618 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800619 c.logger.VI(2).Infof("VeyronRPC: %s.%s(..., streaming=%v)", msg.Name, msg.Method, msg.IsStreaming)
620 return &msg, nil
Jiri Simsa78b646f2014-10-08 10:23:05 -0700621}
622
623type signatureRequest struct {
624 Name string
625}
626
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800627func (c *Controller) getSignature(ctx context.T, name string) ([]signature.Interface, error) {
Asim Shankarf3c61a32014-10-15 17:34:11 -0700628 retryTimeoutOpt := options.RetryTimeout(time.Duration(*retryTimeout) * time.Second)
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800629 return c.signatureManager.Signature(ctx, name, c.client, retryTimeoutOpt)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700630}
631
632// HandleSignatureRequest uses signature manager to get and cache signature of a remote server
633func (c *Controller) HandleSignatureRequest(ctx context.T, data string, w lib.ClientWriter) {
634 // Decode the request
635 var request signatureRequest
636 if err := json.Unmarshal([]byte(data), &request); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700637 w.Error(verror2.Convert(verror2.Internal, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700638 return
639 }
640
641 c.logger.VI(2).Infof("requesting Signature for %q", request.Name)
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800642 sig, err := c.getSignature(ctx, request.Name)
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800643 if err != nil {
644 w.Error(err)
645 return
646 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800647 vomSig, err := lib.VomEncode(sig)
648 if err != nil {
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800649 w.Error(err)
650 return
651 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700652 // Send the signature back
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800653 if err := w.Send(lib.ResponseFinal, vomSig); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700654 w.Error(verror2.Convert(verror2.Internal, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700655 return
656 }
657}
658
Ankure7889242014-10-20 18:37:29 -0700659// HandleUnlinkJSBlessings removes the specified blessings from the JS blessings
660// store. 'data' should be a JSON encoded number (representing the blessings handle).
661func (c *Controller) HandleUnlinkJSBlessings(data string, w lib.ClientWriter) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700662 var handle int64
663 if err := json.Unmarshal([]byte(data), &handle); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700664 w.Error(verror2.Convert(verror2.Internal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700665 return
666 }
Ankure7889242014-10-20 18:37:29 -0700667 c.blessingsStore.Remove(handle)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700668}
669
670// Convert the json wire format of a caveat into the right go object
671func decodeCaveat(c jsonCaveatValidator) (security.Caveat, error) {
672 var failed security.Caveat
673 switch c.Type {
674 case "MethodCaveat":
675 var methods []string
676 if err := json.Unmarshal(c.Data, &methods); err != nil {
677 return failed, err
678 }
679 if len(methods) == 0 {
680 return failed, fmt.Errorf("must provide at least one method")
681 }
682 return security.MethodCaveat(methods[0], methods[1:]...)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700683 default:
Mike Burrowsb6689c22014-10-08 11:14:15 -0700684 return failed, verror2.Make(badCaveatType, nil, c.Type)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700685 }
686}
687
Ankure7889242014-10-20 18:37:29 -0700688func (c *Controller) getBlessingsHandle(handle int64) (*principal.BlessingsHandle, error) {
689 id := c.blessingsStore.Get(handle)
690 if id == nil {
691 return nil, verror2.Make(unknownBlessings, nil)
692 }
693 return principal.ConvertBlessingsToHandle(id, handle), nil
694}
695
696func (c *Controller) blessPublicKey(request blessingRequest) (*principal.BlessingsHandle, error) {
697 var blessee security.Blessings
Ankur697132e2014-10-22 12:12:39 -0700698 if blessee = c.blessingsStore.Get(request.Handle); blessee == nil {
Ankur5b802242014-10-29 11:32:21 -0700699 return nil, verror2.Make(invalidBlessingsHandle, nil)
Ankure7889242014-10-20 18:37:29 -0700700 }
701
702 expiryCav, err := security.ExpiryCaveat(time.Now().Add(time.Duration(request.DurationMs) * time.Millisecond))
703 if err != nil {
704 return nil, err
705 }
706 caveats := []security.Caveat{expiryCav}
707 for _, c := range request.Caveats {
708 cav, err := decodeCaveat(c)
709 if err != nil {
710 return nil, verror2.Convert(verror2.BadArg, nil, err)
711 }
712 caveats = append(caveats, cav)
713 }
714
715 // TODO(ataly, ashankar, bjornick): Currently the Bless operation is carried
716 // out using the Default blessing in this principal's blessings store. We
717 // should change this so that the JS blessing request can also specify the
718 // blessing to be used for the Bless operation.
Ankurc56b3472014-10-29 11:16:19 -0700719 blessings, err := c.rt.Principal().Bless(blessee.PublicKey(), c.rt.Principal().BlessingStore().Default(), request.Extension, caveats[0], caveats[1:]...)
Ankure7889242014-10-20 18:37:29 -0700720 if err != nil {
721 return nil, err
722 }
723
724 return principal.ConvertBlessingsToHandle(blessings, c.blessingsStore.Add(blessings)), nil
725}
726
727// HandleBlessPublicKey handles a blessing request from JS.
728func (c *Controller) HandleBlessPublicKey(data string, w lib.ClientWriter) {
729 var request blessingRequest
730 if err := json.Unmarshal([]byte(data), &request); err != nil {
731 w.Error(verror2.Convert(verror2.Internal, nil, err))
732 return
733 }
734
735 handle, err := c.blessPublicKey(request)
736 if err != nil {
737 w.Error(verror2.Convert(verror2.Internal, nil, err))
738 return
739 }
740
741 // Send the id back.
742 if err := w.Send(lib.ResponseFinal, handle); err != nil {
743 w.Error(verror2.Convert(verror2.Internal, nil, err))
744 return
745 }
746}
747
748func (c *Controller) HandleCreateBlessings(data string, w lib.ClientWriter) {
749 var extension string
750 if err := json.Unmarshal([]byte(data), &extension); err != nil {
751 w.Error(verror2.Convert(verror2.Internal, nil, err))
752 return
753 }
754 p, err := vsecurity.NewPrincipal()
755 if err != nil {
756 w.Error(verror2.Convert(verror2.Internal, nil, err))
757 return
758 }
759
760 blessings, err := p.BlessSelf(extension)
761 if err != nil {
762 w.Error(verror2.Convert(verror2.Internal, nil, err))
763 return
764 }
765 handle := principal.ConvertBlessingsToHandle(blessings, c.blessingsStore.Add(blessings))
766 if err := w.Send(lib.ResponseFinal, handle); err != nil {
767 w.Error(verror2.Convert(verror2.Internal, nil, err))
768 return
769 }
770}
771
Ali Ghassemiaa0ea242014-10-20 12:55:39 -0700772// HandleNamespaceRequest uses the namespace client to respond to namespace specific requests such as glob
773func (c *Controller) HandleNamespaceRequest(ctx context.T, data string, w lib.ClientWriter) {
774 namespace.HandleRequest(ctx, c.rt, data, w)
775}