blob: 1bb959f793377dd5db2ae0300769e780f2e9cd0b [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"
Jiri Simsa22b87ac2014-12-25 20:59:13 -080018 "v.io/core/veyron2/security"
19 "v.io/core/veyron2/vdl/vdlroot/src/signature"
20 "v.io/core/veyron2/verror2"
21 "v.io/core/veyron2/vlog"
Suharsh Sivakumar94d00662015-01-21 14:31:30 -080022 "v.io/core/veyron2/vtrace"
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 blessingRequest struct {
Benjamin Prosnitz86d52282014-12-19 15:48:38 -080073 Handle int32
Benjamin Prosnitz6e5b50a2015-01-15 10:02:41 -080074 Caveats []security.Caveat
Benjamin Prosnitz86d52282014-12-19 15:48:38 -080075 DurationMs int32
Ankurc56b3472014-10-29 11:16:19 -070076 Extension string
Jiri Simsa78b646f2014-10-08 10:23:05 -070077}
78
Matt Rosencrantz4aabe572014-10-22 09:25:50 -070079type outstandingRequest struct {
80 stream *outstandingStream
81 cancel context.CancelFunc
82}
83
Jiri Simsa78b646f2014-10-08 10:23:05 -070084// Controller represents all the state of a Veyron Web App. This is the struct
85// that is in charge performing all the veyron options.
86type Controller struct {
87 // Protects everything.
88 // TODO(bjornick): We need to split this up.
89 sync.Mutex
90
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -080091 // The context of this controller.
92 ctx *context.T
Jiri Simsa78b646f2014-10-08 10:23:05 -070093
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -080094 // The cleanup function for this controller.
95 cancel context.CancelFunc
Jiri Simsa78b646f2014-10-08 10:23:05 -070096
97 // The ipc.ListenSpec to use with server.Listen
98 listenSpec *ipc.ListenSpec
99
100 // Used to generate unique ids for requests initiated by the proxy.
101 // These ids will be even so they don't collide with the ids generated
102 // by the client.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800103 lastGeneratedId int32
Jiri Simsa78b646f2014-10-08 10:23:05 -0700104
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700105 // Used to keep track of data (streams and cancellation functions) for
106 // outstanding requests.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800107 outstandingRequests map[int32]*outstandingRequest
Jiri Simsa78b646f2014-10-08 10:23:05 -0700108
109 // Maps flowids to the server that owns them.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800110 flowMap map[int32]*server.Server
Jiri Simsa78b646f2014-10-08 10:23:05 -0700111
112 // A manager that Handles fetching and caching signature of remote services
113 signatureManager lib.SignatureManager
114
Nicolas LaCasse4f409ce2014-11-25 11:44:03 -0800115 // We maintain multiple Veyron server per pipe for serving JavaScript
Jiri Simsa78b646f2014-10-08 10:23:05 -0700116 // services.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800117 servers map[uint32]*server.Server
Jiri Simsa78b646f2014-10-08 10:23:05 -0700118
119 // Creates a client writer for a given flow. This is a member so that tests can override
120 // the default implementation.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800121 writerCreator func(id int32) lib.ClientWriter
Jiri Simsa78b646f2014-10-08 10:23:05 -0700122
Jiri Simsa78b646f2014-10-08 10:23:05 -0700123 veyronProxyEP string
124
Ankure7889242014-10-20 18:37:29 -0700125 // Store for all the Blessings that javascript has a handle to.
126 blessingsStore *principal.JSBlessingsHandles
Jiri Simsa78b646f2014-10-08 10:23:05 -0700127}
128
129// NewController creates a new Controller. writerCreator will be used to create a new flow for rpcs to
130// 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 -0800131func NewController(ctx *context.T, writerCreator func(id int32) lib.ClientWriter, listenSpec *ipc.ListenSpec, namespaceRoots []string, p security.Principal) (*Controller, error) {
132 ctx, cancel := context.WithCancel(ctx)
133
134 ctx, _ = vtrace.SetNewTrace(ctx)
Matt Rosencrantz306d9902015-01-10 17:46:07 -0800135
Benjamin Prosnitz3c738502014-11-04 14:51:38 -0800136 if namespaceRoots != nil {
Matt Rosencrantz306d9902015-01-10 17:46:07 -0800137 veyron2.GetNamespace(ctx).SetRoots(namespaceRoots...)
Benjamin Prosnitz3c738502014-11-04 14:51:38 -0800138 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700139
Suharsh Sivakumar94d00662015-01-21 14:31:30 -0800140 ctx, err := veyron2.SetPrincipal(ctx, p)
141 if err != nil {
142 return nil, err
143 }
144
Jiri Simsa78b646f2014-10-08 10:23:05 -0700145 controller := &Controller{
Matt Rosencrantz306d9902015-01-10 17:46:07 -0800146 ctx: ctx,
Suharsh Sivakumar94d00662015-01-21 14:31:30 -0800147 cancel: cancel,
Ankure7889242014-10-20 18:37:29 -0700148 writerCreator: writerCreator,
149 listenSpec: listenSpec,
Ankure7889242014-10-20 18:37:29 -0700150 blessingsStore: principal.NewJSBlessingsHandles(),
Ankure7889242014-10-20 18:37:29 -0700151 }
152
Jiri Simsa78b646f2014-10-08 10:23:05 -0700153 controller.setup()
154 return controller, nil
155}
156
157// finishCall waits for the call to finish and write out the response to w.
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800158func (c *Controller) finishCall(ctx *context.T, w lib.ClientWriter, clientCall ipc.Call, msg *VeyronRPC) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700159 if msg.IsStreaming {
160 for {
161 var item interface{}
162 if err := clientCall.Recv(&item); err != nil {
163 if err == io.EOF {
164 break
165 }
166 w.Error(err) // Send streaming error as is
167 return
168 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800169 vomItem, err := lib.VomEncode(item)
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800170 if err != nil {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800171 w.Error(verror2.Make(marshallingError, ctx, item, err))
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800172 continue
173 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800174 if err := w.Send(lib.ResponseStream, vomItem); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700175 w.Error(verror2.Make(marshallingError, ctx, item))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700176 }
177 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700178 if err := w.Send(lib.ResponseStreamClose, nil); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700179 w.Error(verror2.Make(marshallingError, ctx, "ResponseStreamClose"))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700180 }
181 }
182
Benjamin Prosnitz518af1e2015-01-20 14:20:10 -0800183 // TODO(bprosnitz) Remove this when we remove error from out args everywhere.
184 numOutArgsWithError := msg.NumOutArgs + 1
185
186 results := make([]interface{}, numOutArgsWithError)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700187 // This array will have pointers to the values in result.
Benjamin Prosnitz518af1e2015-01-20 14:20:10 -0800188 resultptrs := make([]interface{}, numOutArgsWithError)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700189 for ax := range results {
190 resultptrs[ax] = &results[ax]
191 }
192 if err := clientCall.Finish(resultptrs...); err != nil {
193 // return the call system error as is
194 w.Error(err)
195 return
196 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800197
Jiri Simsa78b646f2014-10-08 10:23:05 -0700198 // for now we assume last out argument is always error
Jiri Simsa78b646f2014-10-08 10:23:05 -0700199 if err, ok := results[len(results)-1].(error); ok {
200 // return the call Application error as is
201 w.Error(err)
202 return
203 }
204
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800205 vomResults, err := lib.VomEncode(results[:len(results)-1])
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800206 if err != nil {
207 w.Error(err)
208 return
209 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800210 if err := w.Send(lib.ResponseFinal, vomResults); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700211 w.Error(verror2.Convert(marshallingError, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700212 }
213}
214
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800215func (c *Controller) startCall(ctx *context.T, w lib.ClientWriter, msg *VeyronRPC) (ipc.Call, error) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700216 methodName := lib.UppercaseFirstCharacter(msg.Method)
Asim Shankarf3c61a32014-10-15 17:34:11 -0700217 retryTimeoutOpt := options.RetryTimeout(time.Duration(*retryTimeout) * time.Second)
Todd Wangf83dbfc2015-01-09 11:54:46 -0800218 clientCall, err := veyron2.GetClient(ctx).StartCall(ctx, msg.Name, methodName, msg.InArgs, retryTimeoutOpt)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700219 if err != nil {
220 return nil, fmt.Errorf("error starting call (name: %v, method: %v, args: %v): %v", msg.Name, methodName, msg.InArgs, err)
221 }
222
223 return clientCall, nil
224}
225
226// Implements the serverHelper interface
227
228// CreateNewFlow creats a new server flow that will be used to write out
229// streaming messages to Javascript.
230func (c *Controller) CreateNewFlow(s *server.Server, stream ipc.Stream) *server.Flow {
231 c.Lock()
232 defer c.Unlock()
233 id := c.lastGeneratedId
234 c.lastGeneratedId += 2
235 c.flowMap[id] = s
236 os := newStream()
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800237 os.init(stream)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700238 c.outstandingRequests[id] = &outstandingRequest{
239 stream: os,
240 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700241 return &server.Flow{ID: id, Writer: c.writerCreator(id)}
242}
243
244// CleanupFlow removes the bookkeping for a previously created flow.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800245func (c *Controller) CleanupFlow(id int32) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700246 c.Lock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700247 request := c.outstandingRequests[id]
248 delete(c.outstandingRequests, id)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700249 delete(c.flowMap, id)
250 c.Unlock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700251 if request != nil && request.stream != nil {
252 request.stream.end()
253 request.stream.waitUntilDone()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700254 }
255}
256
257// GetLogger returns a Veyron logger to use.
258func (c *Controller) GetLogger() vlog.Logger {
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800259 return veyron2.GetLogger(c.ctx)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700260}
261
262// RT returns the runtime of the app.
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800263func (c *Controller) Context() *context.T {
264 return c.ctx
Jiri Simsa78b646f2014-10-08 10:23:05 -0700265}
266
Ankure7889242014-10-20 18:37:29 -0700267// AddBlessings adds the Blessings to the local blessings store and returns
Jiri Simsa78b646f2014-10-08 10:23:05 -0700268// the handle to it. This function exists because JS only has
Ankure7889242014-10-20 18:37:29 -0700269// a handle to the blessings to avoid shipping the certificate forest
Jiri Simsa78b646f2014-10-08 10:23:05 -0700270// to JS and back.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800271func (c *Controller) AddBlessings(blessings security.Blessings) int32 {
Ankure7889242014-10-20 18:37:29 -0700272 return c.blessingsStore.Add(blessings)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700273}
274
275// Cleanup cleans up any outstanding rpcs.
276func (c *Controller) Cleanup() {
Nicolas LaCasse42862ba2015-01-13 12:51:12 -0800277 c.GetLogger().VI(0).Info("Cleaning up controller")
Jiri Simsa78b646f2014-10-08 10:23:05 -0700278 c.Lock()
279 defer c.Unlock()
280
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700281 for _, request := range c.outstandingRequests {
282 if request.cancel != nil {
283 request.cancel()
284 }
285 if request.stream != nil {
286 request.stream.end()
287 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700288 }
289
290 for _, server := range c.servers {
291 server.Stop()
292 }
Benjamin Prosnitz8a51fe82014-10-16 13:05:14 -0700293
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800294 c.cancel()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700295}
296
297func (c *Controller) setup() {
298 c.signatureManager = lib.NewSignatureManager()
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800299 c.outstandingRequests = make(map[int32]*outstandingRequest)
300 c.flowMap = make(map[int32]*server.Server)
301 c.servers = make(map[uint32]*server.Server)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700302}
303
304// SendOnStream writes data on id's stream. The actual network write will be
305// done asynchronously. If there is an error, it will be sent to w.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800306func (c *Controller) SendOnStream(id int32, data string, w lib.ClientWriter) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700307 c.Lock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700308 request := c.outstandingRequests[id]
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700309 if request == nil || request.stream == nil {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700310 vlog.Errorf("unknown stream: %d", id)
311 return
312 }
Matt Rosencrantzd608b372014-10-22 13:06:52 -0700313 stream := request.stream
314 c.Unlock()
315 stream.send(data, w)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700316}
317
318// SendVeyronRequest makes a veyron request for the given flowId. If signal is non-nil, it will receive
319// the call object after it has been constructed.
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800320func (c *Controller) sendVeyronRequest(ctx *context.T, id int32, msg *VeyronRPC, w lib.ClientWriter, stream *outstandingStream) {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800321 sig, err := c.getSignature(ctx, msg.Name)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700322 if err != nil {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800323 w.Error(err)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700324 return
325 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800326 methName := lib.UppercaseFirstCharacter(msg.Method)
327 methSig, ok := signature.FirstMethod(sig, methName)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700328 if !ok {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800329 w.Error(fmt.Errorf("method %q not found in signature: %#v", methName, sig))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700330 return
331 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800332 if len(methSig.InArgs) != len(msg.InArgs) {
333 w.Error(fmt.Errorf("invalid number of arguments, expected: %v, got:%v", methSig, *msg))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700334 return
335 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700336
337 // We have to make the start call synchronous so we can make sure that we populate
338 // the call map before we can Handle a recieve call.
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800339 call, err := c.startCall(ctx, w, msg)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700340 if err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700341 w.Error(verror2.Convert(verror2.Internal, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700342 return
343 }
344
345 if stream != nil {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800346 stream.init(call)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700347 }
348
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800349 c.finishCall(ctx, w, call, msg)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700350 c.Lock()
351 if request, ok := c.outstandingRequests[id]; ok {
352 delete(c.outstandingRequests, id)
353 if request.cancel != nil {
354 request.cancel()
355 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700356 }
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700357 c.Unlock()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700358}
359
360// HandleVeyronRequest starts a veyron rpc and returns before the rpc has been completed.
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800361func (c *Controller) HandleVeyronRequest(ctx *context.T, id int32, data string, w lib.ClientWriter) {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800362 msg, err := c.parseVeyronRequest(data)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700363 if err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700364 w.Error(verror2.Convert(verror2.Internal, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700365 return
366 }
367
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800368 var cctx *context.T
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700369 var cancel context.CancelFunc
370
371 // TODO(mattr): To be consistent with go, we should not ignore 0 timeouts.
372 // However as a rollout strategy we must, otherwise there is a circular
373 // dependency between the WSPR change and the JS change that will follow.
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800374 if msg.Timeout == lib.JSIPCNoTimeout || msg.Timeout == 0 {
Matt Rosencrantzb6f4b922015-01-05 13:31:55 -0800375 cctx, cancel = context.WithCancel(ctx)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700376 } else {
Matt Rosencrantzb6f4b922015-01-05 13:31:55 -0800377 cctx, cancel = context.WithTimeout(ctx, lib.JSToGoDuration(msg.Timeout))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700378 }
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700379
380 request := &outstandingRequest{
381 cancel: cancel,
382 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800383 if msg.IsStreaming {
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700384 // If this rpc is streaming, we would expect that the client would try to send
385 // on this stream. Since the initial handshake is done asynchronously, we have
386 // to put the outstanding stream in the map before we make the async call so that
387 // the future send know which queue to write to, even if the client call isn't
388 // actually ready yet.
389 request.stream = newStream()
390 }
391 c.Lock()
392 c.outstandingRequests[id] = request
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800393 go c.sendVeyronRequest(cctx, id, msg, w, request.stream)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700394 c.Unlock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700395}
396
397// HandleVeyronCancellation cancels the request corresponding to the
398// given id if it is still outstanding.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800399func (c *Controller) HandleVeyronCancellation(id int32) {
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700400 c.Lock()
401 defer c.Unlock()
402 if request, ok := c.outstandingRequests[id]; ok && request.cancel != nil {
403 request.cancel()
404 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700405}
406
407// CloseStream closes the stream for a given id.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800408func (c *Controller) CloseStream(id int32) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700409 c.Lock()
410 defer c.Unlock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700411 if request, ok := c.outstandingRequests[id]; ok && request.stream != nil {
412 request.stream.end()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700413 return
414 }
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800415 c.GetLogger().Errorf("close called on non-existent call: %v", id)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700416}
417
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800418func (c *Controller) maybeCreateServer(serverId uint32) (*server.Server, error) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700419 c.Lock()
420 defer c.Unlock()
421 if server, ok := c.servers[serverId]; ok {
422 return server, nil
423 }
424 server, err := server.NewServer(serverId, c.listenSpec, c)
425 if err != nil {
426 return nil, err
427 }
428 c.servers[serverId] = server
429 return server, nil
430}
431
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800432func (c *Controller) removeServer(serverId uint32) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700433 c.Lock()
434 server := c.servers[serverId]
435 if server == nil {
436 c.Unlock()
437 return
438 }
439 delete(c.servers, serverId)
440 c.Unlock()
441
442 server.Stop()
443}
444
445func (c *Controller) serve(serveRequest serveRequest, w lib.ClientWriter) {
Nicolas LaCasse4f409ce2014-11-25 11:44:03 -0800446 // Create a server for the pipe, if it does not exist already.
Jiri Simsa78b646f2014-10-08 10:23:05 -0700447 server, err := c.maybeCreateServer(serveRequest.ServerId)
448 if err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700449 w.Error(verror2.Convert(verror2.Internal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700450 }
451
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800452 c.GetLogger().VI(2).Infof("serving under name: %q", serveRequest.Name)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700453
Nicolas LaCasse27b57c72014-11-19 13:40:20 -0800454 if err := server.Serve(serveRequest.Name); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700455 w.Error(verror2.Convert(verror2.Internal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700456 return
457 }
Nicolas LaCasse27b57c72014-11-19 13:40:20 -0800458 // Send true to indicate the serve has succeeded.
459 if err := w.Send(lib.ResponseFinal, true); 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 }
463}
464
Nicolas LaCasse27b57c72014-11-19 13:40:20 -0800465// HandleServeRequest takes a request to serve a server, creates a server,
466// registers the provided services and sends true if everything succeeded.
Jiri Simsa78b646f2014-10-08 10:23:05 -0700467func (c *Controller) HandleServeRequest(data string, w lib.ClientWriter) {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800468 // Decode the serve request which includes VDL, registered services and name
Jiri Simsa78b646f2014-10-08 10:23:05 -0700469 var serveRequest serveRequest
470 if err := json.Unmarshal([]byte(data), &serveRequest); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700471 w.Error(verror2.Convert(verror2.Internal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700472 return
473 }
474 c.serve(serveRequest, w)
475}
476
477// HandleLookupResponse handles the result of a Dispatcher.Lookup call that was
478// run by the Javascript server.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800479func (c *Controller) HandleLookupResponse(id int32, data string) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700480 c.Lock()
481 server := c.flowMap[id]
482 c.Unlock()
483 if server == nil {
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800484 c.GetLogger().Errorf("unexpected result from JavaScript. No channel "+
Jiri Simsa78b646f2014-10-08 10:23:05 -0700485 "for MessageId: %d exists. Ignoring the results.", id)
486 //Ignore unknown responses that don't belong to any channel
487 return
488 }
489 server.HandleLookupResponse(id, data)
490}
491
492// HandleAuthResponse handles the result of a Authorizer.Authorize call that was
493// run by the Javascript server.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800494func (c *Controller) HandleAuthResponse(id int32, data string) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700495 c.Lock()
496 server := c.flowMap[id]
497 c.Unlock()
498 if server == nil {
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800499 c.GetLogger().Errorf("unexpected result from JavaScript. No channel "+
Jiri Simsa78b646f2014-10-08 10:23:05 -0700500 "for MessageId: %d exists. Ignoring the results.", id)
501 //Ignore unknown responses that don't belong to any channel
502 return
503 }
504 server.HandleAuthResponse(id, data)
505}
506
507// HandleStopRequest takes a request to stop a server.
508func (c *Controller) HandleStopRequest(data string, w lib.ClientWriter) {
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800509 var serverId uint32
Jiri Simsa78b646f2014-10-08 10:23:05 -0700510 if err := json.Unmarshal([]byte(data), &serverId); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700511 w.Error(verror2.Convert(verror2.Internal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700512 return
513 }
514
515 c.removeServer(serverId)
516
517 // Send true to indicate stop has finished
518 if err := w.Send(lib.ResponseFinal, true); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700519 w.Error(verror2.Convert(verror2.Internal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700520 return
521 }
522}
523
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800524// HandleAddNameRequest takes a request to add a new name to a server
525func (c *Controller) HandleAddNameRequest(data string, w lib.ClientWriter) {
526 var request addRemoveNameRequest
527 if err := json.Unmarshal([]byte(data), &request); err != nil {
528 w.Error(verror2.Convert(verror2.Internal, nil, err))
529 return
530 }
531
Nicolas LaCasse4f409ce2014-11-25 11:44:03 -0800532 // Create a server for the pipe, if it does not exist already
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800533 server, err := c.maybeCreateServer(request.ServerId)
534 if err != nil {
535 w.Error(verror2.Convert(verror2.Internal, nil, err))
536 return
537 }
538
539 // Add name
540 if err := server.AddName(request.Name); err != nil {
541 w.Error(verror2.Convert(verror2.Internal, nil, err))
542 return
543 }
544
545 // Send true to indicate request has finished without error
546 if err := w.Send(lib.ResponseFinal, true); err != nil {
547 w.Error(verror2.Convert(verror2.Internal, nil, err))
548 return
549 }
550}
551
552// HandleRemoveNameRequest takes a request to remove a name from a server
553func (c *Controller) HandleRemoveNameRequest(data string, w lib.ClientWriter) {
554 var request addRemoveNameRequest
555 if err := json.Unmarshal([]byte(data), &request); err != nil {
556 w.Error(verror2.Convert(verror2.Internal, nil, err))
557 return
558 }
559
Nicolas LaCasse4f409ce2014-11-25 11:44:03 -0800560 // Create a server for the pipe, if it does not exist already
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800561 server, err := c.maybeCreateServer(request.ServerId)
562 if err != nil {
563 w.Error(verror2.Convert(verror2.Internal, nil, err))
564 return
565 }
566
567 // Remove name
Cosmos Nicolaoub1a41af2015-01-25 22:13:40 -0800568 server.RemoveName(request.Name)
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800569
570 // Remove name from signature cache as well
571 c.signatureManager.FlushCacheEntry(request.Name)
572
573 // Send true to indicate request has finished without error
574 if err := w.Send(lib.ResponseFinal, true); err != nil {
575 w.Error(verror2.Convert(verror2.Internal, nil, err))
576 return
577 }
578}
579
Jiri Simsa78b646f2014-10-08 10:23:05 -0700580// HandleServerResponse handles the completion of outstanding calls to JavaScript services
581// by filling the corresponding channel with the result from JavaScript.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800582func (c *Controller) HandleServerResponse(id int32, data string) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700583 c.Lock()
584 server := c.flowMap[id]
585 c.Unlock()
586 if server == nil {
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800587 c.GetLogger().Errorf("unexpected result from JavaScript. No channel "+
Jiri Simsa78b646f2014-10-08 10:23:05 -0700588 "for MessageId: %d exists. Ignoring the results.", id)
589 //Ignore unknown responses that don't belong to any channel
590 return
591 }
592 server.HandleServerResponse(id, data)
593}
594
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800595// parseVeyronRequest parses a json rpc request into a VeyronRPC object.
596func (c *Controller) parseVeyronRequest(data string) (*VeyronRPC, error) {
597 var msg VeyronRPC
598 if err := lib.VomDecode(data, &msg); err != nil {
599 return nil, err
Jiri Simsa78b646f2014-10-08 10:23:05 -0700600 }
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800601 c.GetLogger().VI(2).Infof("VeyronRPC: %s.%s(..., streaming=%v)", msg.Name, msg.Method, msg.IsStreaming)
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800602 return &msg, nil
Jiri Simsa78b646f2014-10-08 10:23:05 -0700603}
604
605type signatureRequest struct {
606 Name string
607}
608
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800609func (c *Controller) getSignature(ctx *context.T, name string) ([]signature.Interface, error) {
Asim Shankarf3c61a32014-10-15 17:34:11 -0700610 retryTimeoutOpt := options.RetryTimeout(time.Duration(*retryTimeout) * time.Second)
Todd Wangf83dbfc2015-01-09 11:54:46 -0800611 return c.signatureManager.Signature(ctx, name, retryTimeoutOpt)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700612}
613
614// HandleSignatureRequest uses signature manager to get and cache signature of a remote server
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800615func (c *Controller) HandleSignatureRequest(ctx *context.T, data string, w lib.ClientWriter) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700616 // Decode the request
617 var request signatureRequest
618 if err := json.Unmarshal([]byte(data), &request); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700619 w.Error(verror2.Convert(verror2.Internal, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700620 return
621 }
622
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800623 c.GetLogger().VI(2).Infof("requesting Signature for %q", request.Name)
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800624 sig, err := c.getSignature(ctx, request.Name)
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800625 if err != nil {
626 w.Error(err)
627 return
628 }
Benjamin Prosnitz518af1e2015-01-20 14:20:10 -0800629
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800630 vomSig, err := lib.VomEncode(sig)
631 if err != nil {
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800632 w.Error(err)
633 return
634 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700635 // Send the signature back
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800636 if err := w.Send(lib.ResponseFinal, vomSig); 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
Ankure7889242014-10-20 18:37:29 -0700642// HandleUnlinkJSBlessings removes the specified blessings from the JS blessings
643// store. 'data' should be a JSON encoded number (representing the blessings handle).
644func (c *Controller) HandleUnlinkJSBlessings(data string, w lib.ClientWriter) {
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800645 var handle int32
Jiri Simsa78b646f2014-10-08 10:23:05 -0700646 if err := json.Unmarshal([]byte(data), &handle); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700647 w.Error(verror2.Convert(verror2.Internal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700648 return
649 }
Ankure7889242014-10-20 18:37:29 -0700650 c.blessingsStore.Remove(handle)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700651}
652
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800653func (c *Controller) getBlessingsHandle(handle int32) (*principal.BlessingsHandle, error) {
Ankure7889242014-10-20 18:37:29 -0700654 id := c.blessingsStore.Get(handle)
655 if id == nil {
656 return nil, verror2.Make(unknownBlessings, nil)
657 }
658 return principal.ConvertBlessingsToHandle(id, handle), nil
659}
660
661func (c *Controller) blessPublicKey(request blessingRequest) (*principal.BlessingsHandle, error) {
662 var blessee security.Blessings
Ankur697132e2014-10-22 12:12:39 -0700663 if blessee = c.blessingsStore.Get(request.Handle); blessee == nil {
Ankur5b802242014-10-29 11:32:21 -0700664 return nil, verror2.Make(invalidBlessingsHandle, nil)
Ankure7889242014-10-20 18:37:29 -0700665 }
666
667 expiryCav, err := security.ExpiryCaveat(time.Now().Add(time.Duration(request.DurationMs) * time.Millisecond))
668 if err != nil {
669 return nil, err
670 }
Benjamin Prosnitz6e5b50a2015-01-15 10:02:41 -0800671 caveats := append(request.Caveats, expiryCav)
Ankure7889242014-10-20 18:37:29 -0700672
673 // TODO(ataly, ashankar, bjornick): Currently the Bless operation is carried
674 // out using the Default blessing in this principal's blessings store. We
675 // should change this so that the JS blessing request can also specify the
676 // blessing to be used for the Bless operation.
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800677 p := veyron2.GetPrincipal(c.ctx)
678 blessings, err := p.Bless(blessee.PublicKey(), p.BlessingStore().Default(), request.Extension, caveats[0], caveats[1:]...)
Ankure7889242014-10-20 18:37:29 -0700679 if err != nil {
680 return nil, err
681 }
682
683 return principal.ConvertBlessingsToHandle(blessings, c.blessingsStore.Add(blessings)), nil
684}
685
686// HandleBlessPublicKey handles a blessing request from JS.
687func (c *Controller) HandleBlessPublicKey(data string, w lib.ClientWriter) {
688 var request blessingRequest
Benjamin Prosnitz6e5b50a2015-01-15 10:02:41 -0800689 if err := lib.VomDecode(data, &request); err != nil {
Ankure7889242014-10-20 18:37:29 -0700690 w.Error(verror2.Convert(verror2.Internal, nil, err))
691 return
692 }
693
694 handle, err := c.blessPublicKey(request)
695 if err != nil {
696 w.Error(verror2.Convert(verror2.Internal, nil, err))
697 return
698 }
699
700 // Send the id back.
701 if err := w.Send(lib.ResponseFinal, handle); err != nil {
702 w.Error(verror2.Convert(verror2.Internal, nil, err))
703 return
704 }
705}
706
707func (c *Controller) HandleCreateBlessings(data string, w lib.ClientWriter) {
708 var extension string
709 if err := json.Unmarshal([]byte(data), &extension); err != nil {
710 w.Error(verror2.Convert(verror2.Internal, nil, err))
711 return
712 }
713 p, err := vsecurity.NewPrincipal()
714 if err != nil {
715 w.Error(verror2.Convert(verror2.Internal, nil, err))
716 return
717 }
718
719 blessings, err := p.BlessSelf(extension)
720 if err != nil {
721 w.Error(verror2.Convert(verror2.Internal, nil, err))
722 return
723 }
724 handle := principal.ConvertBlessingsToHandle(blessings, c.blessingsStore.Add(blessings))
725 if err := w.Send(lib.ResponseFinal, handle); err != nil {
726 w.Error(verror2.Convert(verror2.Internal, nil, err))
727 return
728 }
729}
730
Ali Ghassemiaa0ea242014-10-20 12:55:39 -0700731// HandleNamespaceRequest uses the namespace client to respond to namespace specific requests such as glob
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800732func (c *Controller) HandleNamespaceRequest(ctx *context.T, data string, w lib.ClientWriter) {
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800733 namespace.HandleRequest(ctx, data, w)
Ali Ghassemiaa0ea242014-10-20 12:55:39 -0700734}