blob: e2d784c906cf25263ade1075f5b6135a0f4e0c5b [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
Matt Rosencrantz4aabe572014-10-22 09:25:50 -070058type outstandingRequest struct {
59 stream *outstandingStream
60 cancel context.CancelFunc
61}
62
Jiri Simsa78b646f2014-10-08 10:23:05 -070063// Controller represents all the state of a Veyron Web App. This is the struct
64// that is in charge performing all the veyron options.
65type Controller struct {
66 // Protects everything.
67 // TODO(bjornick): We need to split this up.
68 sync.Mutex
69
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -080070 // The context of this controller.
71 ctx *context.T
Jiri Simsa78b646f2014-10-08 10:23:05 -070072
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -080073 // The cleanup function for this controller.
74 cancel context.CancelFunc
Jiri Simsa78b646f2014-10-08 10:23:05 -070075
76 // The ipc.ListenSpec to use with server.Listen
77 listenSpec *ipc.ListenSpec
78
79 // Used to generate unique ids for requests initiated by the proxy.
80 // These ids will be even so they don't collide with the ids generated
81 // by the client.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -080082 lastGeneratedId int32
Jiri Simsa78b646f2014-10-08 10:23:05 -070083
Matt Rosencrantz4aabe572014-10-22 09:25:50 -070084 // Used to keep track of data (streams and cancellation functions) for
85 // outstanding requests.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -080086 outstandingRequests map[int32]*outstandingRequest
Jiri Simsa78b646f2014-10-08 10:23:05 -070087
88 // Maps flowids to the server that owns them.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -080089 flowMap map[int32]*server.Server
Jiri Simsa78b646f2014-10-08 10:23:05 -070090
91 // A manager that Handles fetching and caching signature of remote services
92 signatureManager lib.SignatureManager
93
Nicolas LaCasse4f409ce2014-11-25 11:44:03 -080094 // We maintain multiple Veyron server per pipe for serving JavaScript
Jiri Simsa78b646f2014-10-08 10:23:05 -070095 // services.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -080096 servers map[uint32]*server.Server
Jiri Simsa78b646f2014-10-08 10:23:05 -070097
98 // Creates a client writer for a given flow. This is a member so that tests can override
99 // the default implementation.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800100 writerCreator func(id int32) lib.ClientWriter
Jiri Simsa78b646f2014-10-08 10:23:05 -0700101
Jiri Simsa78b646f2014-10-08 10:23:05 -0700102 veyronProxyEP string
103
Ankure7889242014-10-20 18:37:29 -0700104 // Store for all the Blessings that javascript has a handle to.
105 blessingsStore *principal.JSBlessingsHandles
Jiri Simsa78b646f2014-10-08 10:23:05 -0700106}
107
108// NewController creates a new Controller. writerCreator will be used to create a new flow for rpcs to
109// 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 -0800110func NewController(ctx *context.T, writerCreator func(id int32) lib.ClientWriter, listenSpec *ipc.ListenSpec, namespaceRoots []string, p security.Principal) (*Controller, error) {
111 ctx, cancel := context.WithCancel(ctx)
112
113 ctx, _ = vtrace.SetNewTrace(ctx)
Matt Rosencrantz306d9902015-01-10 17:46:07 -0800114
Benjamin Prosnitz3c738502014-11-04 14:51:38 -0800115 if namespaceRoots != nil {
Matt Rosencrantz306d9902015-01-10 17:46:07 -0800116 veyron2.GetNamespace(ctx).SetRoots(namespaceRoots...)
Benjamin Prosnitz3c738502014-11-04 14:51:38 -0800117 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700118
Suharsh Sivakumar94d00662015-01-21 14:31:30 -0800119 ctx, err := veyron2.SetPrincipal(ctx, p)
120 if err != nil {
121 return nil, err
122 }
123
Jiri Simsa78b646f2014-10-08 10:23:05 -0700124 controller := &Controller{
Matt Rosencrantz306d9902015-01-10 17:46:07 -0800125 ctx: ctx,
Suharsh Sivakumar94d00662015-01-21 14:31:30 -0800126 cancel: cancel,
Ankure7889242014-10-20 18:37:29 -0700127 writerCreator: writerCreator,
128 listenSpec: listenSpec,
Ankure7889242014-10-20 18:37:29 -0700129 blessingsStore: principal.NewJSBlessingsHandles(),
Ankure7889242014-10-20 18:37:29 -0700130 }
131
Jiri Simsa78b646f2014-10-08 10:23:05 -0700132 controller.setup()
133 return controller, nil
134}
135
136// finishCall waits for the call to finish and write out the response to w.
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800137func (c *Controller) finishCall(ctx *context.T, w lib.ClientWriter, clientCall ipc.Call, msg *VeyronRPCRequest, span vtrace.Span) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700138 if msg.IsStreaming {
139 for {
140 var item interface{}
141 if err := clientCall.Recv(&item); err != nil {
142 if err == io.EOF {
143 break
144 }
145 w.Error(err) // Send streaming error as is
146 return
147 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800148 vomItem, err := lib.VomEncode(item)
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800149 if err != nil {
Todd Wangb63e9eb2015-02-10 19:57:39 -0800150 w.Error(verror.New(marshallingError, ctx, item, err))
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800151 continue
152 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800153 if err := w.Send(lib.ResponseStream, vomItem); err != nil {
Todd Wangb63e9eb2015-02-10 19:57:39 -0800154 w.Error(verror.New(marshallingError, ctx, item))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700155 }
156 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700157 if err := w.Send(lib.ResponseStreamClose, nil); err != nil {
Todd Wangb63e9eb2015-02-10 19:57:39 -0800158 w.Error(verror.New(marshallingError, ctx, "ResponseStreamClose"))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700159 }
160 }
Todd Wangf21e1552015-02-18 13:21:52 -0800161 results := make([]interface{}, msg.NumOutArgs)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700162 // This array will have pointers to the values in result.
Todd Wangf21e1552015-02-18 13:21:52 -0800163 resultptrs := make([]interface{}, msg.NumOutArgs)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700164 for ax := range results {
165 resultptrs[ax] = &results[ax]
166 }
167 if err := clientCall.Finish(resultptrs...); err != nil {
168 // return the call system error as is
169 w.Error(err)
170 return
171 }
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800172 c.sendRPCResponse(ctx, w, span, results)
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800173}
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800174
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800175func (c *Controller) sendRPCResponse(ctx *context.T, w lib.ClientWriter, span vtrace.Span, results []interface{}) {
Todd Wangf21e1552015-02-18 13:21:52 -0800176 outargs := make([]vdl.AnyRep, len(results))
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800177 for i := range outargs {
178 outargs[i] = results[i]
179 }
180
181 span.Finish()
182 traceRecord := vtrace.GetStore(ctx).TraceRecord(span.Trace())
183
184 response := VeyronRPCResponse{
185 OutArgs: outargs,
186 TraceResponse: vtrace.Response{
Matt Rosencrantzce148612015-02-13 16:10:22 -0800187 Flags: vtrace.CollectInMemory,
188 Trace: *traceRecord,
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800189 },
190 }
191 encoded, err := lib.VomEncode(response)
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800192 if err != nil {
193 w.Error(err)
194 return
195 }
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800196 if err := w.Send(lib.ResponseFinal, encoded); err != nil {
Todd Wangb63e9eb2015-02-10 19:57:39 -0800197 w.Error(verror.Convert(marshallingError, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700198 }
199}
200
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800201func (c *Controller) startCall(ctx *context.T, w lib.ClientWriter, msg *VeyronRPCRequest, inArgs []interface{}) (ipc.Call, error) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700202 methodName := lib.UppercaseFirstCharacter(msg.Method)
Asim Shankarf3c61a32014-10-15 17:34:11 -0700203 retryTimeoutOpt := options.RetryTimeout(time.Duration(*retryTimeout) * time.Second)
Alex Fandriantoaa5af7c2015-01-29 15:20:02 -0800204 clientCall, err := veyron2.GetClient(ctx).StartCall(ctx, msg.Name, methodName, inArgs, retryTimeoutOpt)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700205 if err != nil {
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800206 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 -0700207 }
208
209 return clientCall, nil
210}
211
212// Implements the serverHelper interface
213
214// CreateNewFlow creats a new server flow that will be used to write out
215// streaming messages to Javascript.
216func (c *Controller) CreateNewFlow(s *server.Server, stream ipc.Stream) *server.Flow {
217 c.Lock()
218 defer c.Unlock()
219 id := c.lastGeneratedId
220 c.lastGeneratedId += 2
221 c.flowMap[id] = s
222 os := newStream()
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800223 os.init(stream)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700224 c.outstandingRequests[id] = &outstandingRequest{
225 stream: os,
226 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700227 return &server.Flow{ID: id, Writer: c.writerCreator(id)}
228}
229
230// CleanupFlow removes the bookkeping for a previously created flow.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800231func (c *Controller) CleanupFlow(id int32) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700232 c.Lock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700233 request := c.outstandingRequests[id]
234 delete(c.outstandingRequests, id)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700235 delete(c.flowMap, id)
236 c.Unlock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700237 if request != nil && request.stream != nil {
238 request.stream.end()
239 request.stream.waitUntilDone()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700240 }
241}
242
Jiri Simsa78b646f2014-10-08 10:23:05 -0700243// RT returns the runtime of the app.
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800244func (c *Controller) Context() *context.T {
245 return c.ctx
Jiri Simsa78b646f2014-10-08 10:23:05 -0700246}
247
Ankure7889242014-10-20 18:37:29 -0700248// AddBlessings adds the Blessings to the local blessings store and returns
Jiri Simsa78b646f2014-10-08 10:23:05 -0700249// the handle to it. This function exists because JS only has
Ankure7889242014-10-20 18:37:29 -0700250// a handle to the blessings to avoid shipping the certificate forest
Jiri Simsa78b646f2014-10-08 10:23:05 -0700251// to JS and back.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800252func (c *Controller) AddBlessings(blessings security.Blessings) int32 {
Ankure7889242014-10-20 18:37:29 -0700253 return c.blessingsStore.Add(blessings)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700254}
255
256// Cleanup cleans up any outstanding rpcs.
257func (c *Controller) Cleanup() {
Matt Rosencrantz99ed6782015-01-27 19:58:34 -0800258 vlog.VI(0).Info("Cleaning up controller")
Jiri Simsa78b646f2014-10-08 10:23:05 -0700259 c.Lock()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700260
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700261 for _, request := range c.outstandingRequests {
262 if request.cancel != nil {
263 request.cancel()
264 }
265 if request.stream != nil {
266 request.stream.end()
267 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700268 }
269
Nicolas LaCasse60f423e2015-02-04 17:53:14 -0800270 servers := []*server.Server{}
Jiri Simsa78b646f2014-10-08 10:23:05 -0700271 for _, server := range c.servers {
Nicolas LaCasse60f423e2015-02-04 17:53:14 -0800272 servers = append(servers, server)
273 }
274
275 c.Unlock()
276
277 // We must unlock before calling server.Stop otherwise it can deadlock.
278 for _, server := range servers {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700279 server.Stop()
280 }
Benjamin Prosnitz8a51fe82014-10-16 13:05:14 -0700281
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800282 c.cancel()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700283}
284
285func (c *Controller) setup() {
286 c.signatureManager = lib.NewSignatureManager()
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800287 c.outstandingRequests = make(map[int32]*outstandingRequest)
288 c.flowMap = make(map[int32]*server.Server)
289 c.servers = make(map[uint32]*server.Server)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700290}
291
292// SendOnStream writes data on id's stream. The actual network write will be
293// done asynchronously. If there is an error, it will be sent to w.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800294func (c *Controller) SendOnStream(id int32, data string, w lib.ClientWriter) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700295 c.Lock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700296 request := c.outstandingRequests[id]
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700297 if request == nil || request.stream == nil {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700298 vlog.Errorf("unknown stream: %d", id)
299 return
300 }
Matt Rosencrantzd608b372014-10-22 13:06:52 -0700301 stream := request.stream
302 c.Unlock()
303 stream.send(data, w)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700304}
305
306// SendVeyronRequest makes a veyron request for the given flowId. If signal is non-nil, it will receive
307// the call object after it has been constructed.
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800308func (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 -0800309 sig, err := c.getSignature(ctx, msg.Name)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700310 if err != nil {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800311 w.Error(err)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700312 return
313 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800314 methName := lib.UppercaseFirstCharacter(msg.Method)
315 methSig, ok := signature.FirstMethod(sig, methName)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700316 if !ok {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800317 w.Error(fmt.Errorf("method %q not found in signature: %#v", methName, sig))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700318 return
319 }
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800320 if len(methSig.InArgs) != len(inArgs) {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800321 w.Error(fmt.Errorf("invalid number of arguments, expected: %v, got:%v", methSig, *msg))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700322 return
323 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700324
325 // We have to make the start call synchronous so we can make sure that we populate
326 // the call map before we can Handle a recieve call.
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800327 call, err := c.startCall(ctx, w, msg, inArgs)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700328 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800329 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700330 return
331 }
332
333 if stream != nil {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800334 stream.init(call)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700335 }
336
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800337 c.finishCall(ctx, w, call, msg, span)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700338 c.Lock()
339 if request, ok := c.outstandingRequests[id]; ok {
340 delete(c.outstandingRequests, id)
341 if request.cancel != nil {
342 request.cancel()
343 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700344 }
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700345 c.Unlock()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700346}
347
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800348// TODO(mattr): This is a very limited implementation of ServerCall,
349// but currently none of the methods the controller exports require
350// any of this context information.
351type localCall struct {
352 ctx *context.T
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800353 vrpc *VeyronRPCRequest
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800354 tags []interface{}
355}
356
357func (l *localCall) Send(interface{}) error { return nil }
358func (l *localCall) Recv(interface{}) error { return nil }
359func (l *localCall) Blessings() security.Blessings { return nil }
360func (l *localCall) Server() ipc.Server { return nil }
361func (l *localCall) Context() *context.T { return l.ctx }
362func (l *localCall) Timestamp() (t time.Time) { return }
363func (l *localCall) Method() string { return l.vrpc.Method }
364func (l *localCall) MethodTags() []interface{} { return l.tags }
365func (l *localCall) Name() string { return l.vrpc.Name }
366func (l *localCall) Suffix() string { return "" }
367func (l *localCall) RemoteDischarges() map[string]security.Discharge { return nil }
368func (l *localCall) LocalPrincipal() security.Principal { return nil }
369func (l *localCall) LocalBlessings() security.Blessings { return nil }
370func (l *localCall) RemoteBlessings() security.Blessings { return nil }
371func (l *localCall) LocalEndpoint() naming.Endpoint { return nil }
372func (l *localCall) RemoteEndpoint() naming.Endpoint { return nil }
373
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800374func (c *Controller) handleInternalCall(ctx *context.T, msg *VeyronRPCRequest, decoder *vom.Decoder, w lib.ClientWriter, span vtrace.Span) {
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800375 invoker, err := ipc.ReflectInvoker(ControllerServer(c))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700376 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800377 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700378 return
379 }
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800380 argptrs, tags, err := invoker.Prepare(msg.Method, int(msg.NumInArgs))
381 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800382 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800383 return
384 }
385 for _, argptr := range argptrs {
386 if err := decoder.Decode(argptr); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800387 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800388 return
389 }
390 }
391 results, err := invoker.Invoke(msg.Method, &localCall{ctx, msg, tags}, argptrs)
392 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800393 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800394 return
395 }
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800396 c.sendRPCResponse(ctx, w, span, results)
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800397}
398
399// HandleVeyronRequest starts a veyron rpc and returns before the rpc has been completed.
400func (c *Controller) HandleVeyronRequest(ctx *context.T, id int32, data string, w lib.ClientWriter) {
401 binbytes, err := hex.DecodeString(data)
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 }
406 decoder, err := vom.NewDecoder(bytes.NewReader(binbytes))
407 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800408 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800409 return
410 }
411
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800412 var msg VeyronRPCRequest
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800413 if err := decoder.Decode(&msg); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800414 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800415 return
416 }
417 vlog.VI(2).Infof("VeyronRPC: %s.%s(..., streaming=%v)", msg.Name, msg.Method, msg.IsStreaming)
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800418 spanName := fmt.Sprintf("<wspr>%q.%s", msg.Name, msg.Method)
419 ctx, span := vtrace.SetContinuedTrace(ctx, spanName, msg.TraceRequest)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700420
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800421 var cctx *context.T
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700422 var cancel context.CancelFunc
423
424 // TODO(mattr): To be consistent with go, we should not ignore 0 timeouts.
425 // However as a rollout strategy we must, otherwise there is a circular
426 // dependency between the WSPR change and the JS change that will follow.
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800427 if msg.Timeout == lib.JSIPCNoTimeout || msg.Timeout == 0 {
Matt Rosencrantzb6f4b922015-01-05 13:31:55 -0800428 cctx, cancel = context.WithCancel(ctx)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700429 } else {
Matt Rosencrantzb6f4b922015-01-05 13:31:55 -0800430 cctx, cancel = context.WithTimeout(ctx, lib.JSToGoDuration(msg.Timeout))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700431 }
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700432
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800433 // If this message is for an internal service, do a short-circuit dispatch here.
434 if msg.Name == "controller" {
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800435 go c.handleInternalCall(ctx, &msg, decoder, w, span)
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800436 return
437 }
438
439 inArgs := make([]interface{}, msg.NumInArgs)
440 for i := range inArgs {
441 if err := decoder.Decode(&inArgs[i]); err != nil {
442 w.Error(err)
443 return
444 }
445 }
446
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700447 request := &outstandingRequest{
448 cancel: cancel,
449 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800450 if msg.IsStreaming {
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700451 // If this rpc is streaming, we would expect that the client would try to send
452 // on this stream. Since the initial handshake is done asynchronously, we have
453 // to put the outstanding stream in the map before we make the async call so that
454 // the future send know which queue to write to, even if the client call isn't
455 // actually ready yet.
456 request.stream = newStream()
457 }
458 c.Lock()
459 c.outstandingRequests[id] = request
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800460 go c.sendVeyronRequest(cctx, id, &msg, inArgs, w, request.stream, span)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700461 c.Unlock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700462}
463
464// HandleVeyronCancellation cancels the request corresponding to the
465// given id if it is still outstanding.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800466func (c *Controller) HandleVeyronCancellation(id int32) {
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700467 c.Lock()
468 defer c.Unlock()
469 if request, ok := c.outstandingRequests[id]; ok && request.cancel != nil {
470 request.cancel()
471 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700472}
473
474// CloseStream closes the stream for a given id.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800475func (c *Controller) CloseStream(id int32) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700476 c.Lock()
477 defer c.Unlock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700478 if request, ok := c.outstandingRequests[id]; ok && request.stream != nil {
479 request.stream.end()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700480 return
481 }
Matt Rosencrantz99ed6782015-01-27 19:58:34 -0800482 vlog.Errorf("close called on non-existent call: %v", id)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700483}
484
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800485func (c *Controller) maybeCreateServer(serverId uint32) (*server.Server, error) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700486 c.Lock()
487 defer c.Unlock()
488 if server, ok := c.servers[serverId]; ok {
489 return server, nil
490 }
491 server, err := server.NewServer(serverId, c.listenSpec, c)
492 if err != nil {
493 return nil, err
494 }
495 c.servers[serverId] = server
496 return server, nil
497}
498
Jiri Simsa78b646f2014-10-08 10:23:05 -0700499// HandleLookupResponse handles the result of a Dispatcher.Lookup call that was
500// run by the Javascript server.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800501func (c *Controller) HandleLookupResponse(id int32, data string) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700502 c.Lock()
503 server := c.flowMap[id]
504 c.Unlock()
505 if server == nil {
Matt Rosencrantz99ed6782015-01-27 19:58:34 -0800506 vlog.Errorf("unexpected result from JavaScript. No channel "+
Jiri Simsa78b646f2014-10-08 10:23:05 -0700507 "for MessageId: %d exists. Ignoring the results.", id)
508 //Ignore unknown responses that don't belong to any channel
509 return
510 }
511 server.HandleLookupResponse(id, data)
512}
513
514// HandleAuthResponse handles the result of a Authorizer.Authorize call that was
515// run by the Javascript server.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800516func (c *Controller) HandleAuthResponse(id int32, data string) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700517 c.Lock()
518 server := c.flowMap[id]
519 c.Unlock()
520 if server == nil {
Matt Rosencrantz99ed6782015-01-27 19:58:34 -0800521 vlog.Errorf("unexpected result from JavaScript. No channel "+
Jiri Simsa78b646f2014-10-08 10:23:05 -0700522 "for MessageId: %d exists. Ignoring the results.", id)
523 //Ignore unknown responses that don't belong to any channel
524 return
525 }
526 server.HandleAuthResponse(id, data)
527}
528
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800529// Serve instructs WSPR to start listening for calls on behalf
530// of a javascript server.
531func (c *Controller) Serve(_ ipc.ServerContext, name string, serverId uint32) error {
532 server, err := c.maybeCreateServer(serverId)
533 if err != nil {
534 return verror.Convert(verror.ErrInternal, nil, err)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700535 }
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800536 vlog.VI(2).Infof("serving under name: %q", name)
537 if err := server.Serve(name); err != nil {
538 return verror.Convert(verror.ErrInternal, nil, err)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700539 }
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800540 return nil
Jiri Simsa78b646f2014-10-08 10:23:05 -0700541}
542
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800543// Stop instructs WSPR to stop listening for calls for the
544// given javascript server.
545func (c *Controller) Stop(_ ipc.ServerContext, serverId uint32) error {
546 c.Lock()
547 server := c.servers[serverId]
548 if server == nil {
549 c.Unlock()
550 return nil
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800551 }
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800552 delete(c.servers, serverId)
553 c.Unlock()
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800554
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800555 server.Stop()
556 return nil
557}
558
559// AddName adds a published name to an existing server.
560func (c *Controller) AddName(_ ipc.ServerContext, serverId uint32, name string) error {
Nicolas LaCasse4f409ce2014-11-25 11:44:03 -0800561 // Create a server for the pipe, if it does not exist already
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800562 server, err := c.maybeCreateServer(serverId)
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800563 if err != nil {
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800564 return verror.Convert(verror.ErrInternal, nil, err)
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800565 }
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800566 // Add name
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800567 if err := server.AddName(name); err != nil {
568 return verror.Convert(verror.ErrInternal, nil, err)
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800569 }
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800570 return nil
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800571}
572
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800573// RemoveName removes a published name from an existing server.
574func (c *Controller) RemoveName(_ ipc.ServerContext, serverId uint32, name string) error {
Nicolas LaCasse4f409ce2014-11-25 11:44:03 -0800575 // Create a server for the pipe, if it does not exist already
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800576 server, err := c.maybeCreateServer(serverId)
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800577 if err != nil {
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800578 return verror.Convert(verror.ErrInternal, nil, err)
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800579 }
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800580 // Remove name
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800581 server.RemoveName(name)
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800582 // Remove name from signature cache as well
Matt Rosencrantzd4bcec62015-02-18 14:05:49 -0800583 c.signatureManager.FlushCacheEntry(name)
584 return nil
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800585}
586
Jiri Simsa78b646f2014-10-08 10:23:05 -0700587// HandleServerResponse handles the completion of outstanding calls to JavaScript services
588// by filling the corresponding channel with the result from JavaScript.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800589func (c *Controller) HandleServerResponse(id int32, data string) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700590 c.Lock()
591 server := c.flowMap[id]
592 c.Unlock()
593 if server == nil {
Matt Rosencrantz99ed6782015-01-27 19:58:34 -0800594 vlog.Errorf("unexpected result from JavaScript. No channel "+
Jiri Simsa78b646f2014-10-08 10:23:05 -0700595 "for MessageId: %d exists. Ignoring the results.", id)
596 //Ignore unknown responses that don't belong to any channel
597 return
598 }
599 server.HandleServerResponse(id, data)
600}
601
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800602// parseVeyronRequest parses a json rpc request into a VeyronRPCRequest object.
603func (c *Controller) parseVeyronRequest(data string) (*VeyronRPCRequest, error) {
604 var msg VeyronRPCRequest
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800605 if err := lib.VomDecode(data, &msg); err != nil {
606 return nil, err
Jiri Simsa78b646f2014-10-08 10:23:05 -0700607 }
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800608 vlog.VI(2).Infof("VeyronRPCRequest: %s.%s(..., streaming=%v)", msg.Name, msg.Method, msg.IsStreaming)
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800609 return &msg, nil
Jiri Simsa78b646f2014-10-08 10:23:05 -0700610}
611
612type signatureRequest struct {
613 Name string
614}
615
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800616func (c *Controller) getSignature(ctx *context.T, name string) ([]signature.Interface, error) {
Asim Shankarf3c61a32014-10-15 17:34:11 -0700617 retryTimeoutOpt := options.RetryTimeout(time.Duration(*retryTimeout) * time.Second)
Todd Wangf83dbfc2015-01-09 11:54:46 -0800618 return c.signatureManager.Signature(ctx, name, retryTimeoutOpt)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700619}
620
621// HandleSignatureRequest uses signature manager to get and cache signature of a remote server
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800622func (c *Controller) HandleSignatureRequest(ctx *context.T, data string, w lib.ClientWriter) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700623 // Decode the request
624 var request signatureRequest
625 if err := json.Unmarshal([]byte(data), &request); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800626 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700627 return
628 }
629
Matt Rosencrantz99ed6782015-01-27 19:58:34 -0800630 vlog.VI(2).Infof("requesting Signature for %q", request.Name)
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800631 sig, err := c.getSignature(ctx, request.Name)
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800632 if err != nil {
633 w.Error(err)
634 return
635 }
Benjamin Prosnitz518af1e2015-01-20 14:20:10 -0800636
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800637 vomSig, err := lib.VomEncode(sig)
638 if err != nil {
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800639 w.Error(err)
640 return
641 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700642 // Send the signature back
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800643 if err := w.Send(lib.ResponseFinal, vomSig); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800644 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700645 return
646 }
647}
648
Ankure7889242014-10-20 18:37:29 -0700649// HandleUnlinkJSBlessings removes the specified blessings from the JS blessings
650// store. 'data' should be a JSON encoded number (representing the blessings handle).
651func (c *Controller) HandleUnlinkJSBlessings(data string, w lib.ClientWriter) {
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800652 var handle int32
Jiri Simsa78b646f2014-10-08 10:23:05 -0700653 if err := json.Unmarshal([]byte(data), &handle); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800654 w.Error(verror.Convert(verror.ErrInternal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700655 return
656 }
Ankure7889242014-10-20 18:37:29 -0700657 c.blessingsStore.Remove(handle)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700658}
659
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800660func (c *Controller) getBlessingsHandle(handle int32) (*principal.BlessingsHandle, error) {
Ankure7889242014-10-20 18:37:29 -0700661 id := c.blessingsStore.Get(handle)
662 if id == nil {
Todd Wangb63e9eb2015-02-10 19:57:39 -0800663 return nil, verror.New(unknownBlessings, nil)
Ankure7889242014-10-20 18:37:29 -0700664 }
665 return principal.ConvertBlessingsToHandle(id, handle), nil
666}
667
Alex Fandriantoaa5af7c2015-01-29 15:20:02 -0800668func (c *Controller) blessPublicKey(request BlessingRequest) (*principal.BlessingsHandle, error) {
Ankure7889242014-10-20 18:37:29 -0700669 var blessee security.Blessings
Ankur697132e2014-10-22 12:12:39 -0700670 if blessee = c.blessingsStore.Get(request.Handle); blessee == nil {
Todd Wangb63e9eb2015-02-10 19:57:39 -0800671 return nil, verror.New(invalidBlessingsHandle, nil)
Ankure7889242014-10-20 18:37:29 -0700672 }
673
674 expiryCav, err := security.ExpiryCaveat(time.Now().Add(time.Duration(request.DurationMs) * time.Millisecond))
675 if err != nil {
676 return nil, err
677 }
Benjamin Prosnitz6e5b50a2015-01-15 10:02:41 -0800678 caveats := append(request.Caveats, expiryCav)
Ankure7889242014-10-20 18:37:29 -0700679
680 // TODO(ataly, ashankar, bjornick): Currently the Bless operation is carried
681 // out using the Default blessing in this principal's blessings store. We
682 // should change this so that the JS blessing request can also specify the
683 // blessing to be used for the Bless operation.
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800684 p := veyron2.GetPrincipal(c.ctx)
685 blessings, err := p.Bless(blessee.PublicKey(), p.BlessingStore().Default(), request.Extension, caveats[0], caveats[1:]...)
Ankure7889242014-10-20 18:37:29 -0700686 if err != nil {
687 return nil, err
688 }
689
690 return principal.ConvertBlessingsToHandle(blessings, c.blessingsStore.Add(blessings)), nil
691}
692
693// HandleBlessPublicKey handles a blessing request from JS.
694func (c *Controller) HandleBlessPublicKey(data string, w lib.ClientWriter) {
Alex Fandriantoaa5af7c2015-01-29 15:20:02 -0800695 var request BlessingRequest
Benjamin Prosnitz6e5b50a2015-01-15 10:02:41 -0800696 if err := lib.VomDecode(data, &request); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800697 w.Error(verror.Convert(verror.ErrInternal, nil, err))
Ankure7889242014-10-20 18:37:29 -0700698 return
699 }
700
701 handle, err := c.blessPublicKey(request)
702 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800703 w.Error(verror.Convert(verror.ErrInternal, nil, err))
Ankure7889242014-10-20 18:37:29 -0700704 return
705 }
706
707 // Send the id back.
708 if err := w.Send(lib.ResponseFinal, handle); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800709 w.Error(verror.Convert(verror.ErrInternal, nil, err))
Ankure7889242014-10-20 18:37:29 -0700710 return
711 }
712}
713
714func (c *Controller) HandleCreateBlessings(data string, w lib.ClientWriter) {
715 var extension string
716 if err := json.Unmarshal([]byte(data), &extension); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800717 w.Error(verror.Convert(verror.ErrInternal, nil, err))
Ankure7889242014-10-20 18:37:29 -0700718 return
719 }
720 p, err := vsecurity.NewPrincipal()
721 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800722 w.Error(verror.Convert(verror.ErrInternal, nil, err))
Ankure7889242014-10-20 18:37:29 -0700723 return
724 }
725
726 blessings, err := p.BlessSelf(extension)
727 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800728 w.Error(verror.Convert(verror.ErrInternal, nil, err))
Ankure7889242014-10-20 18:37:29 -0700729 return
730 }
731 handle := principal.ConvertBlessingsToHandle(blessings, c.blessingsStore.Add(blessings))
732 if err := w.Send(lib.ResponseFinal, handle); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800733 w.Error(verror.Convert(verror.ErrInternal, nil, err))
Ankure7889242014-10-20 18:37:29 -0700734 return
735 }
736}
737
Nicolas LaCassee8f8ec02015-02-04 14:14:52 -0800738type remoteBlessingsRequest struct {
739 Name string
740 Method string
741}
742
743func (c *Controller) getRemoteBlessings(ctx *context.T, name, method string) ([]string, error) {
744 ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
745 defer cancel()
746
747 call, err := veyron2.GetClient(ctx).StartCall(ctx, name, method, nil)
748 if err != nil {
749 return nil, err
750 }
751
Nicolas LaCassee8f8ec02015-02-04 14:14:52 -0800752 blessings, _ := call.RemoteBlessings()
753 return blessings, nil
754}
755
756func (c *Controller) HandleRemoteBlessingsRequest(ctx *context.T, data string, w lib.ClientWriter) {
757 var request remoteBlessingsRequest
758 if err := json.Unmarshal([]byte(data), &request); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800759 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Nicolas LaCassee8f8ec02015-02-04 14:14:52 -0800760 return
761 }
762
763 vlog.VI(2).Infof("requesting remote blessings for %q", request.Name)
764 blessings, err := c.getRemoteBlessings(ctx, request.Name, request.Method)
765 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800766 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Nicolas LaCassee8f8ec02015-02-04 14:14:52 -0800767 return
768 }
769
770 vomRemoteBlessings, err := lib.VomEncode(blessings)
771 if err != nil {
772 w.Error(err)
773 return
774 }
775
776 if err := w.Send(lib.ResponseFinal, vomRemoteBlessings); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800777 w.Error(verror.Convert(verror.ErrInternal, ctx, err))
Nicolas LaCassee8f8ec02015-02-04 14:14:52 -0800778 return
779 }
780}
781
Ali Ghassemiaa0ea242014-10-20 12:55:39 -0700782// HandleNamespaceRequest uses the namespace client to respond to namespace specific requests such as glob
Matt Rosencrantzd2ecc8e2014-12-29 11:30:55 -0800783func (c *Controller) HandleNamespaceRequest(ctx *context.T, data string, w lib.ClientWriter) {
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800784 namespace.HandleRequest(ctx, data, w)
Ali Ghassemiaa0ea242014-10-20 12:55:39 -0700785}