blob: 05f30acf9865ce5a39eafe416fb53cfa98fde744 [file] [log] [blame]
Jiri Simsa78b646f2014-10-08 10:23:05 -07001// The app package contains the struct that keeps per javascript app state and handles translating
2// javascript requests to veyron requests and vice versa.
3package app
4
5import (
Matt Rosencrantz786f7272015-02-11 15:18:07 -08006 "bytes"
7 "encoding/hex"
Jiri Simsa78b646f2014-10-08 10:23:05 -07008 "encoding/json"
9 "flag"
10 "fmt"
11 "io"
12 "sync"
13 "time"
14
Jiri Simsa22b87ac2014-12-25 20:59:13 -080015 vsecurity "v.io/core/veyron/security"
16 "v.io/core/veyron2"
17 "v.io/core/veyron2/context"
18 "v.io/core/veyron2/ipc"
Matt Rosencrantz786f7272015-02-11 15:18:07 -080019 "v.io/core/veyron2/naming"
Jiri Simsa22b87ac2014-12-25 20:59:13 -080020 "v.io/core/veyron2/options"
Jiri Simsa22b87ac2014-12-25 20:59:13 -080021 "v.io/core/veyron2/security"
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -080022 "v.io/core/veyron2/vdl"
Jiri Simsa22b87ac2014-12-25 20:59:13 -080023 "v.io/core/veyron2/vdl/vdlroot/src/signature"
Todd Wangb63e9eb2015-02-10 19:57:39 -080024 "v.io/core/veyron2/verror"
Jiri Simsa22b87ac2014-12-25 20:59:13 -080025 "v.io/core/veyron2/vlog"
Matt Rosencrantz786f7272015-02-11 15:18:07 -080026 "v.io/core/veyron2/vom"
Suharsh Sivakumar94d00662015-01-21 14:31:30 -080027 "v.io/core/veyron2/vtrace"
Jiri Simsa11277162014-12-25 15:50:27 -080028 "v.io/wspr/veyron/services/wsprd/ipc/server"
29 "v.io/wspr/veyron/services/wsprd/lib"
30 "v.io/wspr/veyron/services/wsprd/namespace"
31 "v.io/wspr/veyron/services/wsprd/principal"
Jiri Simsa78b646f2014-10-08 10:23:05 -070032)
33
Mike Burrowsb6689c22014-10-08 11:14:15 -070034// pkgPath is the prefix os errors in this package.
Jiri Simsa22b87ac2014-12-25 20:59:13 -080035const pkgPath = "v.io/core/veyron/services/wsprd/app"
Mike Burrowsb6689c22014-10-08 11:14:15 -070036
37// Errors
Ankure7889242014-10-20 18:37:29 -070038var (
Todd Wangb63e9eb2015-02-10 19:57:39 -080039 marshallingError = verror.Register(pkgPath+".marshallingError", verror.NoRetry, "{1} {2} marshalling error {_}")
40 noResults = verror.Register(pkgPath+".noResults", verror.NoRetry, "{1} {2} no results from call {_}")
41 badCaveatType = verror.Register(pkgPath+".badCaveatType", verror.NoRetry, "{1} {2} bad caveat type {_}")
42 unknownBlessings = verror.Register(pkgPath+".unknownBlessings", verror.NoRetry, "{1} {2} unknown public id {_}")
43 invalidBlessingsHandle = verror.Register(pkgPath+".invalidBlessingsHandle", verror.NoRetry, "{1} {2} invalid blessings handle {_}")
Ankure7889242014-10-20 18:37:29 -070044)
Mike Burrowsb6689c22014-10-08 11:14:15 -070045
Jiri Simsa78b646f2014-10-08 10:23:05 -070046// TODO(bjornick,nlacasse): Remove the retryTimeout flag once we able
47// to pass it in from javascript. For now all RPCs have the same
48// retryTimeout, set by command line flag.
49var retryTimeout *int
50
51func init() {
52 // TODO(bjornick,nlacasse): Remove the retryTimeout flag once we able
53 // to pass it in from javascript. For now all RPCs have the same
54 // retryTimeout, set by command line flag.
Nicolas LaCasse238aeb32014-11-26 11:32:10 -080055 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 -070056}
57
Jiri Simsa78b646f2014-10-08 10:23:05 -070058type serveRequest struct {
59 Name string
Benjamin Prosnitz86d52282014-12-19 15:48:38 -080060 ServerId uint32
Jiri Simsa78b646f2014-10-08 10:23:05 -070061}
62
Ali Ghassemi1008bbe2014-11-07 16:36:08 -080063type addRemoveNameRequest struct {
64 Name string
Benjamin Prosnitz86d52282014-12-19 15:48:38 -080065 ServerId uint32
Ali Ghassemi1008bbe2014-11-07 16:36:08 -080066}
67
Matt Rosencrantz4aabe572014-10-22 09:25:50 -070068type outstandingRequest struct {
69 stream *outstandingStream
70 cancel context.CancelFunc
71}
72
Jiri Simsa78b646f2014-10-08 10:23:05 -070073// Controller represents all the state of a Veyron Web App. This is the struct
74// that is in charge performing all the veyron options.
75type Controller struct {
76 // Protects everything.
77 // TODO(bjornick): We need to split this up.
78 sync.Mutex
79
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -080080 // The context of this controller.
81 ctx *context.T
Jiri Simsa78b646f2014-10-08 10:23:05 -070082
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -080083 // The cleanup function for this controller.
84 cancel context.CancelFunc
Jiri Simsa78b646f2014-10-08 10:23:05 -070085
86 // The ipc.ListenSpec to use with server.Listen
87 listenSpec *ipc.ListenSpec
88
89 // Used to generate unique ids for requests initiated by the proxy.
90 // These ids will be even so they don't collide with the ids generated
91 // by the client.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -080092 lastGeneratedId int32
Jiri Simsa78b646f2014-10-08 10:23:05 -070093
Matt Rosencrantz4aabe572014-10-22 09:25:50 -070094 // Used to keep track of data (streams and cancellation functions) for
95 // outstanding requests.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -080096 outstandingRequests map[int32]*outstandingRequest
Jiri Simsa78b646f2014-10-08 10:23:05 -070097
98 // Maps flowids to the server that owns them.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -080099 flowMap map[int32]*server.Server
Jiri Simsa78b646f2014-10-08 10:23:05 -0700100
101 // A manager that Handles fetching and caching signature of remote services
102 signatureManager lib.SignatureManager
103
Nicolas LaCasse4f409ce2014-11-25 11:44:03 -0800104 // We maintain multiple Veyron server per pipe for serving JavaScript
Jiri Simsa78b646f2014-10-08 10:23:05 -0700105 // services.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800106 servers map[uint32]*server.Server
Jiri Simsa78b646f2014-10-08 10:23:05 -0700107
108 // Creates a client writer for a given flow. This is a member so that tests can override
109 // the default implementation.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800110 writerCreator func(id int32) lib.ClientWriter
Jiri Simsa78b646f2014-10-08 10:23:05 -0700111
Jiri Simsa78b646f2014-10-08 10:23:05 -0700112 veyronProxyEP string
113
Ankure7889242014-10-20 18:37:29 -0700114 // Store for all the Blessings that javascript has a handle to.
115 blessingsStore *principal.JSBlessingsHandles
Jiri Simsa78b646f2014-10-08 10:23:05 -0700116}
117
118// NewController creates a new Controller. writerCreator will be used to create a new flow for rpcs to
119// 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 -0800120func NewController(ctx *context.T, writerCreator func(id int32) lib.ClientWriter, listenSpec *ipc.ListenSpec, namespaceRoots []string, p security.Principal) (*Controller, error) {
121 ctx, cancel := context.WithCancel(ctx)
122
123 ctx, _ = vtrace.SetNewTrace(ctx)
Matt Rosencrantz306d9902015-01-10 17:46:07 -0800124
Benjamin Prosnitz3c738502014-11-04 14:51:38 -0800125 if namespaceRoots != nil {
Matt Rosencrantz306d9902015-01-10 17:46:07 -0800126 veyron2.GetNamespace(ctx).SetRoots(namespaceRoots...)
Benjamin Prosnitz3c738502014-11-04 14:51:38 -0800127 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700128
Suharsh Sivakumar94d00662015-01-21 14:31:30 -0800129 ctx, err := veyron2.SetPrincipal(ctx, p)
130 if err != nil {
131 return nil, err
132 }
133
Jiri Simsa78b646f2014-10-08 10:23:05 -0700134 controller := &Controller{
Matt Rosencrantz306d9902015-01-10 17:46:07 -0800135 ctx: ctx,
Suharsh Sivakumar94d00662015-01-21 14:31:30 -0800136 cancel: cancel,
Ankure7889242014-10-20 18:37:29 -0700137 writerCreator: writerCreator,
138 listenSpec: listenSpec,
Ankure7889242014-10-20 18:37:29 -0700139 blessingsStore: principal.NewJSBlessingsHandles(),
Ankure7889242014-10-20 18:37:29 -0700140 }
141
Jiri Simsa78b646f2014-10-08 10:23:05 -0700142 controller.setup()
143 return controller, nil
144}
145
146// finishCall waits for the call to finish and write out the response to w.
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800147func (c *Controller) finishCall(ctx *context.T, w lib.ClientWriter, clientCall ipc.Call, msg *VeyronRPCRequest, span vtrace.Span) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700148 if msg.IsStreaming {
149 for {
150 var item interface{}
151 if err := clientCall.Recv(&item); err != nil {
152 if err == io.EOF {
153 break
154 }
155 w.Error(err) // Send streaming error as is
156 return
157 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800158 vomItem, err := lib.VomEncode(item)
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800159 if err != nil {
Todd Wangb63e9eb2015-02-10 19:57:39 -0800160 w.Error(verror.New(marshallingError, ctx, item, err))
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800161 continue
162 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800163 if err := w.Send(lib.ResponseStream, vomItem); err != nil {
Todd Wangb63e9eb2015-02-10 19:57:39 -0800164 w.Error(verror.New(marshallingError, ctx, item))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700165 }
166 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700167 if err := w.Send(lib.ResponseStreamClose, nil); err != nil {
Todd Wangb63e9eb2015-02-10 19:57:39 -0800168 w.Error(verror.New(marshallingError, ctx, "ResponseStreamClose"))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700169 }
170 }
Todd Wangf21e1552015-02-18 13:21:52 -0800171 results := make([]interface{}, msg.NumOutArgs)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700172 // This array will have pointers to the values in result.
Todd Wangf21e1552015-02-18 13:21:52 -0800173 resultptrs := make([]interface{}, msg.NumOutArgs)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700174 for ax := range results {
175 resultptrs[ax] = &results[ax]
176 }
177 if err := clientCall.Finish(resultptrs...); err != nil {
178 // return the call system error as is
179 w.Error(err)
180 return
181 }
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800182 c.sendRPCResponse(ctx, w, span, results)
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800183}
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800184
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800185func (c *Controller) sendRPCResponse(ctx *context.T, w lib.ClientWriter, span vtrace.Span, results []interface{}) {
Todd Wangf21e1552015-02-18 13:21:52 -0800186 outargs := make([]vdl.AnyRep, len(results))
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800187 for i := range outargs {
188 outargs[i] = results[i]
189 }
190
191 span.Finish()
192 traceRecord := vtrace.GetStore(ctx).TraceRecord(span.Trace())
193
194 response := VeyronRPCResponse{
195 OutArgs: outargs,
196 TraceResponse: vtrace.Response{
Matt Rosencrantzce148612015-02-13 16:10:22 -0800197 Flags: vtrace.CollectInMemory,
198 Trace: *traceRecord,
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800199 },
200 }
201 encoded, err := lib.VomEncode(response)
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800202 if err != nil {
203 w.Error(err)
204 return
205 }
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800206 if err := w.Send(lib.ResponseFinal, encoded); err != nil {
Todd Wangb63e9eb2015-02-10 19:57:39 -0800207 w.Error(verror.Convert(marshallingError, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700208 }
209}
210
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800211func (c *Controller) startCall(ctx *context.T, w lib.ClientWriter, msg *VeyronRPCRequest, inArgs []interface{}) (ipc.Call, error) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700212 methodName := lib.UppercaseFirstCharacter(msg.Method)
Asim Shankarf3c61a32014-10-15 17:34:11 -0700213 retryTimeoutOpt := options.RetryTimeout(time.Duration(*retryTimeout) * time.Second)
Alex Fandriantoaa5af7c2015-01-29 15:20:02 -0800214 clientCall, err := veyron2.GetClient(ctx).StartCall(ctx, msg.Name, methodName, inArgs, retryTimeoutOpt)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700215 if err != nil {
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800216 return nil, fmt.Errorf("error starting call (name: %v, method: %v, args: %v): %v", msg.Name, methodName, inArgs, err)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700217 }
218
219 return clientCall, nil
220}
221
222// Implements the serverHelper interface
223
224// CreateNewFlow creats a new server flow that will be used to write out
225// streaming messages to Javascript.
226func (c *Controller) CreateNewFlow(s *server.Server, stream ipc.Stream) *server.Flow {
227 c.Lock()
228 defer c.Unlock()
229 id := c.lastGeneratedId
230 c.lastGeneratedId += 2
231 c.flowMap[id] = s
232 os := newStream()
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800233 os.init(stream)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700234 c.outstandingRequests[id] = &outstandingRequest{
235 stream: os,
236 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700237 return &server.Flow{ID: id, Writer: c.writerCreator(id)}
238}
239
240// CleanupFlow removes the bookkeping for a previously created flow.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800241func (c *Controller) CleanupFlow(id int32) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700242 c.Lock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700243 request := c.outstandingRequests[id]
244 delete(c.outstandingRequests, id)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700245 delete(c.flowMap, id)
246 c.Unlock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700247 if request != nil && request.stream != nil {
248 request.stream.end()
249 request.stream.waitUntilDone()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700250 }
251}
252
Jiri Simsa78b646f2014-10-08 10:23:05 -0700253// RT returns the runtime of the app.
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800254func (c *Controller) Context() *context.T {
255 return c.ctx
Jiri Simsa78b646f2014-10-08 10:23:05 -0700256}
257
Ankure7889242014-10-20 18:37:29 -0700258// AddBlessings adds the Blessings to the local blessings store and returns
Jiri Simsa78b646f2014-10-08 10:23:05 -0700259// the handle to it. This function exists because JS only has
Ankure7889242014-10-20 18:37:29 -0700260// a handle to the blessings to avoid shipping the certificate forest
Jiri Simsa78b646f2014-10-08 10:23:05 -0700261// to JS and back.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800262func (c *Controller) AddBlessings(blessings security.Blessings) int32 {
Ankure7889242014-10-20 18:37:29 -0700263 return c.blessingsStore.Add(blessings)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700264}
265
266// Cleanup cleans up any outstanding rpcs.
267func (c *Controller) Cleanup() {
Matt Rosencrantz99ed6782015-01-27 19:58:34 -0800268 vlog.VI(0).Info("Cleaning up controller")
Jiri Simsa78b646f2014-10-08 10:23:05 -0700269 c.Lock()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700270
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700271 for _, request := range c.outstandingRequests {
272 if request.cancel != nil {
273 request.cancel()
274 }
275 if request.stream != nil {
276 request.stream.end()
277 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700278 }
279
Nicolas LaCasse60f423e2015-02-04 17:53:14 -0800280 servers := []*server.Server{}
Jiri Simsa78b646f2014-10-08 10:23:05 -0700281 for _, server := range c.servers {
Nicolas LaCasse60f423e2015-02-04 17:53:14 -0800282 servers = append(servers, server)
283 }
284
285 c.Unlock()
286
287 // We must unlock before calling server.Stop otherwise it can deadlock.
288 for _, server := range servers {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700289 server.Stop()
290 }
Benjamin Prosnitz8a51fe82014-10-16 13:05:14 -0700291
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800292 c.cancel()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700293}
294
295func (c *Controller) setup() {
296 c.signatureManager = lib.NewSignatureManager()
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800297 c.outstandingRequests = make(map[int32]*outstandingRequest)
298 c.flowMap = make(map[int32]*server.Server)
299 c.servers = make(map[uint32]*server.Server)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700300}
301
302// SendOnStream writes data on id's stream. The actual network write will be
303// done asynchronously. If there is an error, it will be sent to w.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800304func (c *Controller) SendOnStream(id int32, data string, w lib.ClientWriter) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700305 c.Lock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700306 request := c.outstandingRequests[id]
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700307 if request == nil || request.stream == nil {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700308 vlog.Errorf("unknown stream: %d", id)
309 return
310 }
Matt Rosencrantzd608b372014-10-22 13:06:52 -0700311 stream := request.stream
312 c.Unlock()
313 stream.send(data, w)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700314}
315
316// SendVeyronRequest makes a veyron request for the given flowId. If signal is non-nil, it will receive
317// the call object after it has been constructed.
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800318func (c *Controller) sendVeyronRequest(ctx *context.T, id int32, msg *VeyronRPCRequest, inArgs []interface{}, w lib.ClientWriter, stream *outstandingStream, span vtrace.Span) {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800319 sig, err := c.getSignature(ctx, msg.Name)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700320 if err != nil {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800321 w.Error(err)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700322 return
323 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800324 methName := lib.UppercaseFirstCharacter(msg.Method)
325 methSig, ok := signature.FirstMethod(sig, methName)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700326 if !ok {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800327 w.Error(fmt.Errorf("method %q not found in signature: %#v", methName, sig))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700328 return
329 }
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800330 if len(methSig.InArgs) != len(inArgs) {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800331 w.Error(fmt.Errorf("invalid number of arguments, expected: %v, got:%v", methSig, *msg))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700332 return
333 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700334
335 // We have to make the start call synchronous so we can make sure that we populate
336 // the call map before we can Handle a recieve call.
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800337 call, err := c.startCall(ctx, w, msg, inArgs)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700338 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800339 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700340 return
341 }
342
343 if stream != nil {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800344 stream.init(call)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700345 }
346
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800347 c.finishCall(ctx, w, call, msg, span)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700348 c.Lock()
349 if request, ok := c.outstandingRequests[id]; ok {
350 delete(c.outstandingRequests, id)
351 if request.cancel != nil {
352 request.cancel()
353 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700354 }
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700355 c.Unlock()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700356}
357
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800358// TODO(mattr): This is a very limited implementation of ServerCall,
359// but currently none of the methods the controller exports require
360// any of this context information.
361type localCall struct {
362 ctx *context.T
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800363 vrpc *VeyronRPCRequest
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800364 tags []interface{}
365}
366
367func (l *localCall) Send(interface{}) error { return nil }
368func (l *localCall) Recv(interface{}) error { return nil }
369func (l *localCall) Blessings() security.Blessings { return nil }
370func (l *localCall) Server() ipc.Server { return nil }
371func (l *localCall) Context() *context.T { return l.ctx }
372func (l *localCall) Timestamp() (t time.Time) { return }
373func (l *localCall) Method() string { return l.vrpc.Method }
374func (l *localCall) MethodTags() []interface{} { return l.tags }
375func (l *localCall) Name() string { return l.vrpc.Name }
376func (l *localCall) Suffix() string { return "" }
377func (l *localCall) RemoteDischarges() map[string]security.Discharge { return nil }
378func (l *localCall) LocalPrincipal() security.Principal { return nil }
379func (l *localCall) LocalBlessings() security.Blessings { return nil }
380func (l *localCall) RemoteBlessings() security.Blessings { return nil }
381func (l *localCall) LocalEndpoint() naming.Endpoint { return nil }
382func (l *localCall) RemoteEndpoint() naming.Endpoint { return nil }
383
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800384func (c *Controller) handleInternalCall(ctx *context.T, msg *VeyronRPCRequest, decoder *vom.Decoder, w lib.ClientWriter, span vtrace.Span) {
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800385 invoker, err := ipc.ReflectInvoker(ControllerServer(c))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700386 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800387 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700388 return
389 }
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800390 argptrs, tags, err := invoker.Prepare(msg.Method, int(msg.NumInArgs))
391 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800392 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800393 return
394 }
395 for _, argptr := range argptrs {
396 if err := decoder.Decode(argptr); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800397 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800398 return
399 }
400 }
401 results, err := invoker.Invoke(msg.Method, &localCall{ctx, msg, tags}, argptrs)
402 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800403 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800404 return
405 }
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800406 c.sendRPCResponse(ctx, w, span, results)
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800407}
408
409// HandleVeyronRequest starts a veyron rpc and returns before the rpc has been completed.
410func (c *Controller) HandleVeyronRequest(ctx *context.T, id int32, data string, w lib.ClientWriter) {
411 binbytes, err := hex.DecodeString(data)
412 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800413 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800414 return
415 }
416 decoder, err := vom.NewDecoder(bytes.NewReader(binbytes))
417 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800418 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800419 return
420 }
421
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800422 var msg VeyronRPCRequest
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800423 if err := decoder.Decode(&msg); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800424 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800425 return
426 }
427 vlog.VI(2).Infof("VeyronRPC: %s.%s(..., streaming=%v)", msg.Name, msg.Method, msg.IsStreaming)
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800428 spanName := fmt.Sprintf("<wspr>%q.%s", msg.Name, msg.Method)
429 ctx, span := vtrace.SetContinuedTrace(ctx, spanName, msg.TraceRequest)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700430
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800431 var cctx *context.T
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700432 var cancel context.CancelFunc
433
434 // TODO(mattr): To be consistent with go, we should not ignore 0 timeouts.
435 // However as a rollout strategy we must, otherwise there is a circular
436 // dependency between the WSPR change and the JS change that will follow.
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800437 if msg.Timeout == lib.JSIPCNoTimeout || msg.Timeout == 0 {
Matt Rosencrantzb6f4b922015-01-05 13:31:55 -0800438 cctx, cancel = context.WithCancel(ctx)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700439 } else {
Matt Rosencrantzb6f4b922015-01-05 13:31:55 -0800440 cctx, cancel = context.WithTimeout(ctx, lib.JSToGoDuration(msg.Timeout))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700441 }
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700442
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800443 // If this message is for an internal service, do a short-circuit dispatch here.
444 if msg.Name == "controller" {
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800445 c.handleInternalCall(ctx, &msg, decoder, w, span)
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800446 return
447 }
448
449 inArgs := make([]interface{}, msg.NumInArgs)
450 for i := range inArgs {
451 if err := decoder.Decode(&inArgs[i]); err != nil {
452 w.Error(err)
453 return
454 }
455 }
456
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700457 request := &outstandingRequest{
458 cancel: cancel,
459 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800460 if msg.IsStreaming {
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700461 // If this rpc is streaming, we would expect that the client would try to send
462 // on this stream. Since the initial handshake is done asynchronously, we have
463 // to put the outstanding stream in the map before we make the async call so that
464 // the future send know which queue to write to, even if the client call isn't
465 // actually ready yet.
466 request.stream = newStream()
467 }
468 c.Lock()
469 c.outstandingRequests[id] = request
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800470 go c.sendVeyronRequest(cctx, id, &msg, inArgs, w, request.stream, span)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700471 c.Unlock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700472}
473
474// HandleVeyronCancellation cancels the request corresponding to the
475// given id if it is still outstanding.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800476func (c *Controller) HandleVeyronCancellation(id int32) {
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700477 c.Lock()
478 defer c.Unlock()
479 if request, ok := c.outstandingRequests[id]; ok && request.cancel != nil {
480 request.cancel()
481 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700482}
483
484// CloseStream closes the stream for a given id.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800485func (c *Controller) CloseStream(id int32) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700486 c.Lock()
487 defer c.Unlock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700488 if request, ok := c.outstandingRequests[id]; ok && request.stream != nil {
489 request.stream.end()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700490 return
491 }
Matt Rosencrantz99ed6782015-01-27 19:58:34 -0800492 vlog.Errorf("close called on non-existent call: %v", id)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700493}
494
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800495func (c *Controller) maybeCreateServer(serverId uint32) (*server.Server, error) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700496 c.Lock()
497 defer c.Unlock()
498 if server, ok := c.servers[serverId]; ok {
499 return server, nil
500 }
501 server, err := server.NewServer(serverId, c.listenSpec, c)
502 if err != nil {
503 return nil, err
504 }
505 c.servers[serverId] = server
506 return server, nil
507}
508
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800509func (c *Controller) removeServer(serverId uint32) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700510 c.Lock()
511 server := c.servers[serverId]
512 if server == nil {
513 c.Unlock()
514 return
515 }
516 delete(c.servers, serverId)
517 c.Unlock()
518
519 server.Stop()
520}
521
Nicolas LaCasse27b57c72014-11-19 13:40:20 -0800522// HandleServeRequest takes a request to serve a server, creates a server,
523// registers the provided services and sends true if everything succeeded.
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800524func (c *Controller) Serve(ctx ipc.ServerContext, name string, serverId uint32) error {
525 server, err := c.maybeCreateServer(serverId)
526 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800527 return verror.Convert(verror.ErrInternal, nil, err)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700528 }
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800529 vlog.VI(2).Infof("serving under name: %q", name)
530 if err := server.Serve(name); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800531 return verror.Convert(verror.ErrInternal, nil, err)
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800532 }
533 return nil
Jiri Simsa78b646f2014-10-08 10:23:05 -0700534}
535
536// HandleLookupResponse handles the result of a Dispatcher.Lookup call that was
537// run by the Javascript server.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800538func (c *Controller) HandleLookupResponse(id int32, data string) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700539 c.Lock()
540 server := c.flowMap[id]
541 c.Unlock()
542 if server == nil {
Matt Rosencrantz99ed6782015-01-27 19:58:34 -0800543 vlog.Errorf("unexpected result from JavaScript. No channel "+
Jiri Simsa78b646f2014-10-08 10:23:05 -0700544 "for MessageId: %d exists. Ignoring the results.", id)
545 //Ignore unknown responses that don't belong to any channel
546 return
547 }
548 server.HandleLookupResponse(id, data)
549}
550
551// HandleAuthResponse handles the result of a Authorizer.Authorize call that was
552// run by the Javascript server.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800553func (c *Controller) HandleAuthResponse(id int32, data string) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700554 c.Lock()
555 server := c.flowMap[id]
556 c.Unlock()
557 if server == nil {
Matt Rosencrantz99ed6782015-01-27 19:58:34 -0800558 vlog.Errorf("unexpected result from JavaScript. No channel "+
Jiri Simsa78b646f2014-10-08 10:23:05 -0700559 "for MessageId: %d exists. Ignoring the results.", id)
560 //Ignore unknown responses that don't belong to any channel
561 return
562 }
563 server.HandleAuthResponse(id, data)
564}
565
566// HandleStopRequest takes a request to stop a server.
567func (c *Controller) HandleStopRequest(data string, w lib.ClientWriter) {
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800568 var serverId uint32
Jiri Simsa78b646f2014-10-08 10:23:05 -0700569 if err := json.Unmarshal([]byte(data), &serverId); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800570 w.Error(verror.Convert(verror.ErrInternal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700571 return
572 }
573
574 c.removeServer(serverId)
575
576 // Send true to indicate stop has finished
577 if err := w.Send(lib.ResponseFinal, true); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800578 w.Error(verror.Convert(verror.ErrInternal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700579 return
580 }
581}
582
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800583// HandleAddNameRequest takes a request to add a new name to a server
584func (c *Controller) HandleAddNameRequest(data string, w lib.ClientWriter) {
585 var request addRemoveNameRequest
586 if err := json.Unmarshal([]byte(data), &request); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800587 w.Error(verror.Convert(verror.ErrInternal, nil, err))
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800588 return
589 }
590
Nicolas LaCasse4f409ce2014-11-25 11:44:03 -0800591 // Create a server for the pipe, if it does not exist already
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800592 server, err := c.maybeCreateServer(request.ServerId)
593 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800594 w.Error(verror.Convert(verror.ErrInternal, nil, err))
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800595 return
596 }
597
598 // Add name
599 if err := server.AddName(request.Name); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800600 w.Error(verror.Convert(verror.ErrInternal, nil, err))
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800601 return
602 }
603
604 // Send true to indicate request has finished without error
605 if err := w.Send(lib.ResponseFinal, true); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800606 w.Error(verror.Convert(verror.ErrInternal, nil, err))
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800607 return
608 }
609}
610
611// HandleRemoveNameRequest takes a request to remove a name from a server
612func (c *Controller) HandleRemoveNameRequest(data string, w lib.ClientWriter) {
613 var request addRemoveNameRequest
614 if err := json.Unmarshal([]byte(data), &request); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800615 w.Error(verror.Convert(verror.ErrInternal, nil, err))
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800616 return
617 }
618
Nicolas LaCasse4f409ce2014-11-25 11:44:03 -0800619 // Create a server for the pipe, if it does not exist already
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800620 server, err := c.maybeCreateServer(request.ServerId)
621 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800622 w.Error(verror.Convert(verror.ErrInternal, nil, err))
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800623 return
624 }
625
626 // Remove name
Cosmos Nicolaoub1a41af2015-01-25 22:13:40 -0800627 server.RemoveName(request.Name)
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800628
629 // Remove name from signature cache as well
630 c.signatureManager.FlushCacheEntry(request.Name)
631
632 // Send true to indicate request has finished without error
633 if err := w.Send(lib.ResponseFinal, true); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800634 w.Error(verror.Convert(verror.ErrInternal, nil, err))
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800635 return
636 }
637}
638
Jiri Simsa78b646f2014-10-08 10:23:05 -0700639// HandleServerResponse handles the completion of outstanding calls to JavaScript services
640// by filling the corresponding channel with the result from JavaScript.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800641func (c *Controller) HandleServerResponse(id int32, data string) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700642 c.Lock()
643 server := c.flowMap[id]
644 c.Unlock()
645 if server == nil {
Matt Rosencrantz99ed6782015-01-27 19:58:34 -0800646 vlog.Errorf("unexpected result from JavaScript. No channel "+
Jiri Simsa78b646f2014-10-08 10:23:05 -0700647 "for MessageId: %d exists. Ignoring the results.", id)
648 //Ignore unknown responses that don't belong to any channel
649 return
650 }
651 server.HandleServerResponse(id, data)
652}
653
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800654// parseVeyronRequest parses a json rpc request into a VeyronRPCRequest object.
655func (c *Controller) parseVeyronRequest(data string) (*VeyronRPCRequest, error) {
656 var msg VeyronRPCRequest
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800657 if err := lib.VomDecode(data, &msg); err != nil {
658 return nil, err
Jiri Simsa78b646f2014-10-08 10:23:05 -0700659 }
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800660 vlog.VI(2).Infof("VeyronRPCRequest: %s.%s(..., streaming=%v)", msg.Name, msg.Method, msg.IsStreaming)
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800661 return &msg, nil
Jiri Simsa78b646f2014-10-08 10:23:05 -0700662}
663
664type signatureRequest struct {
665 Name string
666}
667
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800668func (c *Controller) getSignature(ctx *context.T, name string) ([]signature.Interface, error) {
Asim Shankarf3c61a32014-10-15 17:34:11 -0700669 retryTimeoutOpt := options.RetryTimeout(time.Duration(*retryTimeout) * time.Second)
Todd Wangf83dbfc2015-01-09 11:54:46 -0800670 return c.signatureManager.Signature(ctx, name, retryTimeoutOpt)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700671}
672
673// HandleSignatureRequest uses signature manager to get and cache signature of a remote server
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800674func (c *Controller) HandleSignatureRequest(ctx *context.T, data string, w lib.ClientWriter) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700675 // Decode the request
676 var request signatureRequest
677 if err := json.Unmarshal([]byte(data), &request); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800678 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700679 return
680 }
681
Matt Rosencrantz99ed6782015-01-27 19:58:34 -0800682 vlog.VI(2).Infof("requesting Signature for %q", request.Name)
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800683 sig, err := c.getSignature(ctx, request.Name)
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800684 if err != nil {
685 w.Error(err)
686 return
687 }
Benjamin Prosnitz518af1e2015-01-20 14:20:10 -0800688
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800689 vomSig, err := lib.VomEncode(sig)
690 if err != nil {
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800691 w.Error(err)
692 return
693 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700694 // Send the signature back
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800695 if err := w.Send(lib.ResponseFinal, vomSig); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800696 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700697 return
698 }
699}
700
Ankure7889242014-10-20 18:37:29 -0700701// HandleUnlinkJSBlessings removes the specified blessings from the JS blessings
702// store. 'data' should be a JSON encoded number (representing the blessings handle).
703func (c *Controller) HandleUnlinkJSBlessings(data string, w lib.ClientWriter) {
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800704 var handle int32
Jiri Simsa78b646f2014-10-08 10:23:05 -0700705 if err := json.Unmarshal([]byte(data), &handle); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800706 w.Error(verror.Convert(verror.ErrInternal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700707 return
708 }
Ankure7889242014-10-20 18:37:29 -0700709 c.blessingsStore.Remove(handle)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700710}
711
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800712func (c *Controller) getBlessingsHandle(handle int32) (*principal.BlessingsHandle, error) {
Ankure7889242014-10-20 18:37:29 -0700713 id := c.blessingsStore.Get(handle)
714 if id == nil {
Todd Wangb63e9eb2015-02-10 19:57:39 -0800715 return nil, verror.New(unknownBlessings, nil)
Ankure7889242014-10-20 18:37:29 -0700716 }
717 return principal.ConvertBlessingsToHandle(id, handle), nil
718}
719
Alex Fandriantoaa5af7c2015-01-29 15:20:02 -0800720func (c *Controller) blessPublicKey(request BlessingRequest) (*principal.BlessingsHandle, error) {
Ankure7889242014-10-20 18:37:29 -0700721 var blessee security.Blessings
Ankur697132e2014-10-22 12:12:39 -0700722 if blessee = c.blessingsStore.Get(request.Handle); blessee == nil {
Todd Wangb63e9eb2015-02-10 19:57:39 -0800723 return nil, verror.New(invalidBlessingsHandle, nil)
Ankure7889242014-10-20 18:37:29 -0700724 }
725
726 expiryCav, err := security.ExpiryCaveat(time.Now().Add(time.Duration(request.DurationMs) * time.Millisecond))
727 if err != nil {
728 return nil, err
729 }
Benjamin Prosnitz6e5b50a2015-01-15 10:02:41 -0800730 caveats := append(request.Caveats, expiryCav)
Ankure7889242014-10-20 18:37:29 -0700731
732 // TODO(ataly, ashankar, bjornick): Currently the Bless operation is carried
733 // out using the Default blessing in this principal's blessings store. We
734 // should change this so that the JS blessing request can also specify the
735 // blessing to be used for the Bless operation.
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800736 p := veyron2.GetPrincipal(c.ctx)
737 blessings, err := p.Bless(blessee.PublicKey(), p.BlessingStore().Default(), request.Extension, caveats[0], caveats[1:]...)
Ankure7889242014-10-20 18:37:29 -0700738 if err != nil {
739 return nil, err
740 }
741
742 return principal.ConvertBlessingsToHandle(blessings, c.blessingsStore.Add(blessings)), nil
743}
744
745// HandleBlessPublicKey handles a blessing request from JS.
746func (c *Controller) HandleBlessPublicKey(data string, w lib.ClientWriter) {
Alex Fandriantoaa5af7c2015-01-29 15:20:02 -0800747 var request BlessingRequest
Benjamin Prosnitz6e5b50a2015-01-15 10:02:41 -0800748 if err := lib.VomDecode(data, &request); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800749 w.Error(verror.Convert(verror.ErrInternal, nil, err))
Ankure7889242014-10-20 18:37:29 -0700750 return
751 }
752
753 handle, err := c.blessPublicKey(request)
754 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800755 w.Error(verror.Convert(verror.ErrInternal, nil, err))
Ankure7889242014-10-20 18:37:29 -0700756 return
757 }
758
759 // Send the id back.
760 if err := w.Send(lib.ResponseFinal, handle); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800761 w.Error(verror.Convert(verror.ErrInternal, nil, err))
Ankure7889242014-10-20 18:37:29 -0700762 return
763 }
764}
765
766func (c *Controller) HandleCreateBlessings(data string, w lib.ClientWriter) {
767 var extension string
768 if err := json.Unmarshal([]byte(data), &extension); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800769 w.Error(verror.Convert(verror.ErrInternal, nil, err))
Ankure7889242014-10-20 18:37:29 -0700770 return
771 }
772 p, err := vsecurity.NewPrincipal()
773 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800774 w.Error(verror.Convert(verror.ErrInternal, nil, err))
Ankure7889242014-10-20 18:37:29 -0700775 return
776 }
777
778 blessings, err := p.BlessSelf(extension)
779 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800780 w.Error(verror.Convert(verror.ErrInternal, nil, err))
Ankure7889242014-10-20 18:37:29 -0700781 return
782 }
783 handle := principal.ConvertBlessingsToHandle(blessings, c.blessingsStore.Add(blessings))
784 if err := w.Send(lib.ResponseFinal, handle); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800785 w.Error(verror.Convert(verror.ErrInternal, nil, err))
Ankure7889242014-10-20 18:37:29 -0700786 return
787 }
788}
789
Nicolas LaCassee8f8ec02015-02-04 14:14:52 -0800790type remoteBlessingsRequest struct {
791 Name string
792 Method string
793}
794
795func (c *Controller) getRemoteBlessings(ctx *context.T, name, method string) ([]string, error) {
796 ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
797 defer cancel()
798
799 call, err := veyron2.GetClient(ctx).StartCall(ctx, name, method, nil)
800 if err != nil {
801 return nil, err
802 }
803
Nicolas LaCassee8f8ec02015-02-04 14:14:52 -0800804 blessings, _ := call.RemoteBlessings()
805 return blessings, nil
806}
807
808func (c *Controller) HandleRemoteBlessingsRequest(ctx *context.T, data string, w lib.ClientWriter) {
809 var request remoteBlessingsRequest
810 if err := json.Unmarshal([]byte(data), &request); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800811 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Nicolas LaCassee8f8ec02015-02-04 14:14:52 -0800812 return
813 }
814
815 vlog.VI(2).Infof("requesting remote blessings for %q", request.Name)
816 blessings, err := c.getRemoteBlessings(ctx, request.Name, request.Method)
817 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800818 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Nicolas LaCassee8f8ec02015-02-04 14:14:52 -0800819 return
820 }
821
822 vomRemoteBlessings, err := lib.VomEncode(blessings)
823 if err != nil {
824 w.Error(err)
825 return
826 }
827
828 if err := w.Send(lib.ResponseFinal, vomRemoteBlessings); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800829 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Nicolas LaCassee8f8ec02015-02-04 14:14:52 -0800830 return
831 }
832}
833
Ali Ghassemiaa0ea242014-10-20 12:55:39 -0700834// HandleNamespaceRequest uses the namespace client to respond to namespace specific requests such as glob
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800835func (c *Controller) HandleNamespaceRequest(ctx *context.T, data string, w lib.ClientWriter) {
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800836 namespace.HandleRequest(ctx, data, w)
Ali Ghassemiaa0ea242014-10-20 12:55:39 -0700837}