blob: 6205d915199553022e87723bfdc699e1d1758a20 [file] [log] [blame]
Jiri Simsad7616c92015-03-24 23:44:30 -07001// Copyright 2015 The Vanadium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Jiri Simsa78b646f2014-10-08 10:23:05 -07005// An implementation of a server for WSPR
6
7package server
8
9import (
Nicolas LaCassee3867dc2015-02-05 14:44:53 -080010 "fmt"
Jiri Simsa78b646f2014-10-08 10:23:05 -070011 "sync"
Matt Rosencrantz4aabe572014-10-22 09:25:50 -070012 "time"
Jiri Simsa78b646f2014-10-08 10:23:05 -070013
Jiri Simsa1f1302c2015-02-23 16:18:34 -080014 "v.io/v23"
15 "v.io/v23/context"
Shyam Jayaraman8e301b52015-04-27 14:12:16 -070016 "v.io/v23/i18n"
Jiri Simsa1f1302c2015-02-23 16:18:34 -080017 "v.io/v23/naming"
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070018 "v.io/v23/rpc"
Jiri Simsa1f1302c2015-02-23 16:18:34 -080019 "v.io/v23/security"
20 "v.io/v23/vdl"
Todd Wangac9e1902015-02-25 01:58:01 -080021 "v.io/v23/vdlroot/signature"
Shyam Jayaraman7efedbe2015-03-05 12:57:18 -080022 vdltime "v.io/v23/vdlroot/time"
Jiri Simsa1f1302c2015-02-23 16:18:34 -080023 "v.io/v23/verror"
Shyam Jayaraman3facd242015-05-29 11:20:59 -070024 "v.io/v23/vom"
Matt Rosencrantze7bf2bc2015-03-13 09:54:27 -070025 "v.io/v23/vtrace"
Todd Wang5b77a342015-04-06 18:31:37 -070026 "v.io/x/ref/services/wspr/internal/lib"
27 "v.io/x/ref/services/wspr/internal/principal"
Jiri Simsa78b646f2014-10-08 10:23:05 -070028)
29
30type Flow struct {
Benjamin Prosnitz86d52282014-12-19 15:48:38 -080031 ID int32
Jiri Simsa78b646f2014-10-08 10:23:05 -070032 Writer lib.ClientWriter
33}
34
Jiri Simsa78b646f2014-10-08 10:23:05 -070035type FlowHandler interface {
Benjamin Prosnitzbf71e962015-04-14 16:43:07 -070036 CreateNewFlow(server interface{}, sender rpc.Stream) *Flow
Jiri Simsa78b646f2014-10-08 10:23:05 -070037
Benjamin Prosnitz86d52282014-12-19 15:48:38 -080038 CleanupFlow(id int32)
Jiri Simsa78b646f2014-10-08 10:23:05 -070039}
40
Shyam Jayaraman0062e272015-06-04 11:25:13 -070041type VomHelper interface {
42 TypeEncoder() *vom.TypeEncoder
43
44 TypeDecoder() *vom.TypeDecoder
45}
Benjamin Prosnitzae300202015-06-04 19:36:49 -070046
Jiri Simsa78b646f2014-10-08 10:23:05 -070047type ServerHelper interface {
48 FlowHandler
Shyam Jayaraman0062e272015-06-04 11:25:13 -070049 VomHelper
Jiri Simsa78b646f2014-10-08 10:23:05 -070050
Shyam Jayaramanc17abda2015-04-06 16:49:17 -070051 SendLogMessage(level lib.LogLevel, msg string) error
Benjamin Prosnitzc65917c2015-05-26 14:21:53 -070052 BlessingsCache() *principal.BlessingsCache
Shyam Jayaramanc17abda2015-04-06 16:49:17 -070053
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -080054 Context() *context.T
Jiri Simsa78b646f2014-10-08 10:23:05 -070055}
56
Shyam Jayaraman907219d2014-11-26 12:14:37 -080057// AuthRequest is a request for a javascript authorizer to run
58// This is exported to make the app test easier.
59type AuthRequest struct {
Benjamin Prosnitz2be28dc2015-03-11 13:33:22 -070060 ServerId uint32 `json:"serverId"`
Shyam Jayaraman250aac32015-03-05 15:29:11 -080061 Handle int32 `json:"handle"`
62 Call SecurityCall `json:"call"`
Shyam Jayaraman8e301b52015-04-27 14:12:16 -070063 Context Context
Jiri Simsa78b646f2014-10-08 10:23:05 -070064}
65
66type Server struct {
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -080067 // serverStateLock should be aquired when starting or stopping the server.
68 // This should be locked before outstandingRequestLock.
69 serverStateLock sync.Mutex
Jiri Simsa78b646f2014-10-08 10:23:05 -070070
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070071 // The rpc.ListenSpec to use with server.Listen
72 listenSpec *rpc.ListenSpec
Jiri Simsa78b646f2014-10-08 10:23:05 -070073
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070074 // The server that handles the rpc layer. Listen on this server is
Jiri Simsa78b646f2014-10-08 10:23:05 -070075 // lazily started.
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070076 server rpc.Server
Jiri Simsa78b646f2014-10-08 10:23:05 -070077
78 // The saved dispatcher to reuse when serve is called multiple times.
79 dispatcher *dispatcher
80
Nicolas LaCasse27b57c72014-11-19 13:40:20 -080081 // Whether the server is listening.
82 isListening bool
Jiri Simsa78b646f2014-10-08 10:23:05 -070083
84 // The server id.
Benjamin Prosnitz86d52282014-12-19 15:48:38 -080085 id uint32
Jiri Simsa78b646f2014-10-08 10:23:05 -070086 helper ServerHelper
87
Suharsh Sivakumar4cc7c2d2015-04-09 15:21:56 -070088 // outstandingRequestLock should be acquired only to update the outstanding request maps below.
89 outstandingRequestLock sync.Mutex
90 outstandingServerRequests map[int32]chan *lib.ServerRpcReply // GUARDED_BY outstandingRequestLock
91 outstandingAuthRequests map[int32]chan error // GUARDED_BY outstandingRequestLock
92 outstandingValidationRequests map[int32]chan []error // GUARDED_BY outstandingRequestLock
Shyam Jayaramanc17abda2015-04-06 16:49:17 -070093
94 // statusClose will be closed when the server is shutting down, this will
95 // cause the status poller to exit.
96 statusClose chan struct{}
Cosmos Nicolaoud9229922015-06-24 14:12:24 -070097
98 ctx *context.T
Jiri Simsa78b646f2014-10-08 10:23:05 -070099}
100
Todd Wang555097f2015-04-21 10:49:06 -0700101type serverContextKey struct{}
102
Ali Ghassemibac34032015-04-30 18:27:57 -0700103func NewServer(id uint32, listenSpec *rpc.ListenSpec, helper ServerHelper, opts ...rpc.ServerOpt) (*Server, error) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700104 server := &Server{
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800105 id: id,
106 helper: helper,
107 listenSpec: listenSpec,
Todd Wangbaf16842015-03-16 14:12:29 -0700108 outstandingServerRequests: make(map[int32]chan *lib.ServerRpcReply),
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800109 outstandingAuthRequests: make(map[int32]chan error),
110 outstandingValidationRequests: make(map[int32]chan []error),
Jiri Simsa78b646f2014-10-08 10:23:05 -0700111 }
112 var err error
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800113 ctx := helper.Context()
Todd Wang555097f2015-04-21 10:49:06 -0700114 ctx = context.WithValue(ctx, serverContextKey{}, server)
Ali Ghassemibac34032015-04-30 18:27:57 -0700115 if server.server, err = v23.NewServer(ctx, opts...); err != nil {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700116 return nil, err
117 }
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700118 server.ctx = ctx
Jiri Simsa78b646f2014-10-08 10:23:05 -0700119 return server, nil
120}
121
122// remoteInvokeFunc is a type of function that can invoke a remote method and
123// communicate the result back via a channel to the caller
Todd Wang54feabe2015-04-15 23:38:26 -0700124type remoteInvokeFunc func(ctx *context.T, call rpc.StreamServerCall, methodName string, args []interface{}) <-chan *lib.ServerRpcReply
Jiri Simsa78b646f2014-10-08 10:23:05 -0700125
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800126func (s *Server) createRemoteInvokerFunc(handle int32) remoteInvokeFunc {
Todd Wang54feabe2015-04-15 23:38:26 -0700127 return func(ctx *context.T, call rpc.StreamServerCall, methodName string, args []interface{}) <-chan *lib.ServerRpcReply {
Todd Wang4264e4b2015-04-16 22:43:40 -0700128 securityCall := ConvertSecurityCall(s.helper, ctx, call.Security(), true)
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800129
Jiri Simsa78b646f2014-10-08 10:23:05 -0700130 flow := s.helper.CreateNewFlow(s, call)
Todd Wangbaf16842015-03-16 14:12:29 -0700131 replyChan := make(chan *lib.ServerRpcReply, 1)
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800132 s.outstandingRequestLock.Lock()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700133 s.outstandingServerRequests[flow.ID] = replyChan
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800134 s.outstandingRequestLock.Unlock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700135
Shyam Jayaraman7efedbe2015-03-05 12:57:18 -0800136 var timeout vdltime.Deadline
Todd Wang54feabe2015-04-15 23:38:26 -0700137 if deadline, ok := ctx.Deadline(); ok {
Shyam Jayaraman7efedbe2015-03-05 12:57:18 -0800138 timeout.Time = deadline
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700139 }
140
Todd Wangbaf16842015-03-16 14:12:29 -0700141 errHandler := func(err error) <-chan *lib.ServerRpcReply {
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700142 if ch := s.popServerRequest(flow.ID); ch != nil {
Todd Wang54feabe2015-04-15 23:38:26 -0700143 stdErr := verror.Convert(verror.ErrInternal, ctx, err).(verror.E)
Todd Wangbaf16842015-03-16 14:12:29 -0700144 ch <- &lib.ServerRpcReply{nil, &stdErr, vtrace.Response{}}
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700145 s.helper.CleanupFlow(flow.ID)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700146 }
147 return replyChan
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800148 }
Shyam Jayaraman907219d2014-11-26 12:14:37 -0800149
Benjamin Prosnitzc65917c2015-05-26 14:21:53 -0700150 var grantedBlessings principal.BlessingsId
Benjamin Prosnitzbf71e962015-04-14 16:43:07 -0700151 if !call.GrantedBlessings().IsZero() {
Benjamin Prosnitzae300202015-06-04 19:36:49 -0700152 grantedBlessings = s.helper.BlessingsCache().Put(call.GrantedBlessings())
Shyam Jayaraman907219d2014-11-26 12:14:37 -0800153 }
Benjamin Prosnitzbf71e962015-04-14 16:43:07 -0700154
155 rpcCall := ServerRpcRequestCall{
Shyam Jayaraman8e301b52015-04-27 14:12:16 -0700156 SecurityCall: securityCall,
157 Deadline: timeout,
158 TraceRequest: vtrace.GetRequest(ctx),
159 Context: Context{
160 Language: string(i18n.GetLangID(ctx)),
161 },
Benjamin Prosnitzbf71e962015-04-14 16:43:07 -0700162 GrantedBlessings: grantedBlessings,
163 }
164
165 var vdlValArgs []*vdl.Value = make([]*vdl.Value, len(args))
166 for i, arg := range args {
Benjamin Prosnitzbf71e962015-04-14 16:43:07 -0700167 vdlValArgs[i] = vdl.ValueOf(arg)
Shyam Jayaraman07136a72015-04-13 13:34:41 -0700168 }
Benjamin Prosnitzbf71e962015-04-14 16:43:07 -0700169
Shyam Jayaraman907219d2014-11-26 12:14:37 -0800170 // Send a invocation request to JavaScript
Benjamin Prosnitzbf71e962015-04-14 16:43:07 -0700171 message := ServerRpcRequest{
Shyam Jayaraman907219d2014-11-26 12:14:37 -0800172 ServerId: s.id,
173 Handle: handle,
174 Method: lib.LowercaseFirstCharacter(methodName),
Benjamin Prosnitzbf71e962015-04-14 16:43:07 -0700175 Args: vdlValArgs,
Shyam Jayaraman250aac32015-03-05 15:29:11 -0800176 Call: rpcCall,
Shyam Jayaraman907219d2014-11-26 12:14:37 -0800177 }
Shyam Jayaraman0062e272015-06-04 11:25:13 -0700178 vomMessage, err := lib.HexVomEncode(message, s.helper.TypeEncoder())
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800179 if err != nil {
180 return errHandler(err)
181 }
Shyam Jayaraman907219d2014-11-26 12:14:37 -0800182 if err := flow.Writer.Send(lib.ResponseServerRequest, vomMessage); err != nil {
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800183 return errHandler(err)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700184 }
185
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700186 ctx.VI(3).Infof("calling method %q with args %v, MessageID %d assigned\n", methodName, args, flow.ID)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700187
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700188 // Watch for cancellation.
189 go func() {
Todd Wang54feabe2015-04-15 23:38:26 -0700190 <-ctx.Done()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700191 ch := s.popServerRequest(flow.ID)
192 if ch == nil {
193 return
194 }
195
196 // Send a cancel message to the JS server.
197 flow.Writer.Send(lib.ResponseCancel, nil)
198 s.helper.CleanupFlow(flow.ID)
199
Todd Wang54feabe2015-04-15 23:38:26 -0700200 err := verror.Convert(verror.ErrAborted, ctx, ctx.Err()).(verror.E)
Todd Wangbaf16842015-03-16 14:12:29 -0700201 ch <- &lib.ServerRpcReply{nil, &err, vtrace.Response{}}
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700202 }()
203
Benjamin Prosnitzae300202015-06-04 19:36:49 -0700204 go s.proxyStream(call, flow, s.helper.TypeEncoder())
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700205
Jiri Simsa78b646f2014-10-08 10:23:05 -0700206 return replyChan
207 }
208}
209
Shyam Jayaramaneb10b9b2015-01-12 12:23:20 -0800210type globStream struct {
Todd Wang2331dd02015-03-17 15:38:39 -0700211 ch chan naming.GlobReply
Matt Rosencrantz99ed6782015-01-27 19:58:34 -0800212 ctx *context.T
Shyam Jayaramaneb10b9b2015-01-12 12:23:20 -0800213}
214
215func (g *globStream) Send(item interface{}) error {
Todd Wang2331dd02015-03-17 15:38:39 -0700216 if v, ok := item.(naming.GlobReply); ok {
Shyam Jayaramaneb10b9b2015-01-12 12:23:20 -0800217 g.ch <- v
218 return nil
219 }
Jiri Simsa94f68d02015-02-17 10:22:08 -0800220 return verror.New(verror.ErrBadArg, g.ctx, item)
Shyam Jayaramaneb10b9b2015-01-12 12:23:20 -0800221}
222
223func (g *globStream) Recv(itemptr interface{}) error {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800224 return verror.New(verror.ErrNoExist, g.ctx, "Can't call recieve on glob stream")
Shyam Jayaramaneb10b9b2015-01-12 12:23:20 -0800225}
226
227func (g *globStream) CloseSend() error {
228 close(g.ch)
229 return nil
230}
231
232// remoteGlobFunc is a type of function that can invoke a remote glob and
233// communicate the result back via the channel returned
Todd Wang54feabe2015-04-15 23:38:26 -0700234type remoteGlobFunc func(ctx *context.T, call rpc.ServerCall, pattern string) (<-chan naming.GlobReply, error)
Shyam Jayaramaneb10b9b2015-01-12 12:23:20 -0800235
236func (s *Server) createRemoteGlobFunc(handle int32) remoteGlobFunc {
Todd Wang54feabe2015-04-15 23:38:26 -0700237 return func(ctx *context.T, call rpc.ServerCall, pattern string) (<-chan naming.GlobReply, error) {
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800238 // Until the tests get fixed, we need to create a security context before creating the flow
239 // because creating the security context creates a flow and flow ids will be off.
Suharsh Sivakumar78b2bd82015-04-22 19:15:46 -0700240 // See https://github.com/vanadium/issues/issues/175
Todd Wang4264e4b2015-04-16 22:43:40 -0700241 securityCall := ConvertSecurityCall(s.helper, ctx, call.Security(), true)
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800242
Todd Wang2331dd02015-03-17 15:38:39 -0700243 globChan := make(chan naming.GlobReply, 1)
Shyam Jayaramaneb10b9b2015-01-12 12:23:20 -0800244 flow := s.helper.CreateNewFlow(s, &globStream{
Matt Rosencrantz99ed6782015-01-27 19:58:34 -0800245 ch: globChan,
Todd Wang54feabe2015-04-15 23:38:26 -0700246 ctx: ctx,
Shyam Jayaramaneb10b9b2015-01-12 12:23:20 -0800247 })
Todd Wangbaf16842015-03-16 14:12:29 -0700248 replyChan := make(chan *lib.ServerRpcReply, 1)
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800249 s.outstandingRequestLock.Lock()
Shyam Jayaramaneb10b9b2015-01-12 12:23:20 -0800250 s.outstandingServerRequests[flow.ID] = replyChan
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800251 s.outstandingRequestLock.Unlock()
Shyam Jayaramaneb10b9b2015-01-12 12:23:20 -0800252
Shyam Jayaraman7efedbe2015-03-05 12:57:18 -0800253 var timeout vdltime.Deadline
Todd Wang54feabe2015-04-15 23:38:26 -0700254 if deadline, ok := ctx.Deadline(); ok {
Shyam Jayaraman7efedbe2015-03-05 12:57:18 -0800255 timeout.Time = deadline
Shyam Jayaramaneb10b9b2015-01-12 12:23:20 -0800256 }
257
Todd Wang2331dd02015-03-17 15:38:39 -0700258 errHandler := func(err error) (<-chan naming.GlobReply, error) {
Shyam Jayaramaneb10b9b2015-01-12 12:23:20 -0800259 if ch := s.popServerRequest(flow.ID); ch != nil {
260 s.helper.CleanupFlow(flow.ID)
261 }
Todd Wang54feabe2015-04-15 23:38:26 -0700262 return nil, verror.Convert(verror.ErrInternal, ctx, err).(verror.E)
Shyam Jayaramaneb10b9b2015-01-12 12:23:20 -0800263 }
264
Benjamin Prosnitzbf71e962015-04-14 16:43:07 -0700265 rpcCall := ServerRpcRequestCall{
266 SecurityCall: securityCall,
267 Deadline: timeout,
Benjamin Prosnitzae300202015-06-04 19:36:49 -0700268 GrantedBlessings: s.helper.BlessingsCache().Put(call.GrantedBlessings()),
Shyam Jayaraman8e301b52015-04-27 14:12:16 -0700269 Context: Context{
270 Language: string(i18n.GetLangID(ctx)),
271 },
Shyam Jayaramaneb10b9b2015-01-12 12:23:20 -0800272 }
273
274 // Send a invocation request to JavaScript
Benjamin Prosnitzbf71e962015-04-14 16:43:07 -0700275 message := ServerRpcRequest{
Shyam Jayaramaneb10b9b2015-01-12 12:23:20 -0800276 ServerId: s.id,
277 Handle: handle,
278 Method: "Glob__",
Benjamin Prosnitzbf71e962015-04-14 16:43:07 -0700279 Args: []*vdl.Value{vdl.ValueOf(pattern)},
Shyam Jayaraman250aac32015-03-05 15:29:11 -0800280 Call: rpcCall,
Shyam Jayaramaneb10b9b2015-01-12 12:23:20 -0800281 }
Shyam Jayaraman0062e272015-06-04 11:25:13 -0700282 vomMessage, err := lib.HexVomEncode(message, s.helper.TypeEncoder())
Shyam Jayaramaneb10b9b2015-01-12 12:23:20 -0800283 if err != nil {
284 return errHandler(err)
285 }
286 if err := flow.Writer.Send(lib.ResponseServerRequest, vomMessage); err != nil {
287 return errHandler(err)
288 }
289
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700290 ctx.VI(3).Infof("calling method 'Glob__' with args %v, MessageID %d assigned\n", []interface{}{pattern}, flow.ID)
Shyam Jayaramaneb10b9b2015-01-12 12:23:20 -0800291
292 // Watch for cancellation.
293 go func() {
Todd Wang54feabe2015-04-15 23:38:26 -0700294 <-ctx.Done()
Shyam Jayaramaneb10b9b2015-01-12 12:23:20 -0800295 ch := s.popServerRequest(flow.ID)
296 if ch == nil {
297 return
298 }
299
300 // Send a cancel message to the JS server.
301 flow.Writer.Send(lib.ResponseCancel, nil)
302 s.helper.CleanupFlow(flow.ID)
303
Todd Wang54feabe2015-04-15 23:38:26 -0700304 err := verror.Convert(verror.ErrAborted, ctx, ctx.Err()).(verror.E)
Todd Wangbaf16842015-03-16 14:12:29 -0700305 ch <- &lib.ServerRpcReply{nil, &err, vtrace.Response{}}
Shyam Jayaramaneb10b9b2015-01-12 12:23:20 -0800306 }()
307
308 return globChan, nil
309 }
310}
311
Benjamin Prosnitzae300202015-06-04 19:36:49 -0700312func (s *Server) proxyStream(stream rpc.Stream, flow *Flow, typeEncoder *vom.TypeEncoder) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700313 var item interface{}
Benjamin Prosnitzc65917c2015-05-26 14:21:53 -0700314 var err error
Shyam Jayaramandc07fc52015-05-29 15:32:22 -0700315 w := flow.Writer
Benjamin Prosnitzc65917c2015-05-26 14:21:53 -0700316 for err = stream.Recv(&item); err == nil; err = stream.Recv(&item) {
Shyam Jayaraman3facd242015-05-29 11:20:59 -0700317 vomItem, err := lib.HexVomEncode(item, typeEncoder)
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800318 if err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800319 w.Error(verror.Convert(verror.ErrInternal, nil, err))
Shyam Jayaramanc96e1aa2014-11-12 16:42:39 -0800320 return
321 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800322 if err := w.Send(lib.ResponseStream, vomItem); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800323 w.Error(verror.Convert(verror.ErrInternal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700324 return
325 }
326 }
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700327 s.ctx.VI(1).Infof("Error reading from stream: %v\n", err)
Shyam Jayaramandc07fc52015-05-29 15:32:22 -0700328 s.outstandingRequestLock.Lock()
329 _, found := s.outstandingServerRequests[flow.ID]
330 s.outstandingRequestLock.Unlock()
331
332 if !found {
333 // The flow has already been closed. This is usually because we got a response
334 // from the javascript server.
335 return
336 }
Benjamin Prosnitzc65917c2015-05-26 14:21:53 -0700337
Jiri Simsa78b646f2014-10-08 10:23:05 -0700338 if err := w.Send(lib.ResponseStreamClose, nil); err != nil {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800339 w.Error(verror.Convert(verror.ErrInternal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700340 return
341 }
342}
343
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800344func makeListOfErrors(numErrors int, err error) []error {
345 errs := make([]error, numErrors)
346 for i := 0; i < numErrors; i++ {
347 errs[i] = err
Shyam Jayaramana42622c2015-01-05 16:55:53 -0800348 }
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800349 return errs
350}
351
Todd Wang555097f2015-04-21 10:49:06 -0700352// caveatValidationInGo validates caveats in Go, using the default logic.
353func caveatValidationInGo(ctx *context.T, call security.Call, sets [][]security.Caveat) []error {
354 results := make([]error, len(sets))
355 for i, set := range sets {
356 for _, cav := range set {
357 if err := cav.Validate(ctx, call); err != nil {
358 results[i] = err
359 break
360 }
361 }
362 }
363 return results
364}
365
366// caveatValidationInJavascript validates caveats in javascript. It resolves
367// each []security.Caveat in cavs to an error (or nil) and collects them in a
368// slice.
369func (s *Server) caveatValidationInJavascript(ctx *context.T, call security.Call, cavs [][]security.Caveat) []error {
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800370 flow := s.helper.CreateNewFlow(s, nil)
371 req := CaveatValidationRequest{
Todd Wang4264e4b2015-04-16 22:43:40 -0700372 Call: ConvertSecurityCall(s.helper, ctx, call, false),
Shyam Jayaraman8e301b52015-04-27 14:12:16 -0700373 Context: Context{
374 Language: string(i18n.GetLangID(ctx)),
375 },
Ankuref39ba82015-03-19 13:34:03 -0700376 Cavs: cavs,
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800377 }
378
379 replyChan := make(chan []error, 1)
380 s.outstandingRequestLock.Lock()
381 s.outstandingValidationRequests[flow.ID] = replyChan
382 s.outstandingRequestLock.Unlock()
383
384 defer func() {
385 s.outstandingRequestLock.Lock()
386 delete(s.outstandingValidationRequests, flow.ID)
387 s.outstandingRequestLock.Unlock()
388 s.cleanupFlow(flow.ID)
389 }()
390
391 if err := flow.Writer.Send(lib.ResponseValidate, req); err != nil {
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700392 ctx.VI(2).Infof("Failed to send validate response: %v", err)
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800393 replyChan <- makeListOfErrors(len(cavs), err)
394 }
395
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700396 // TODO(bprosnitz) Consider using a different timeout than the standard rpc timeout.
Todd Wangf6a06882015-02-27 17:38:01 -0800397 var timeoutChan <-chan time.Time
Matt Rosencrantz317b0c52015-03-24 20:47:01 -0700398 if deadline, ok := ctx.Deadline(); ok {
Todd Wangf6a06882015-02-27 17:38:01 -0800399 timeoutChan = time.After(deadline.Sub(time.Now()))
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800400 }
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800401
402 select {
Shyam Jayaramanf0a995c2015-04-21 17:34:38 -0700403 case <-s.statusClose:
404 return caveatValidationInGo(ctx, call, cavs)
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800405 case <-timeoutChan:
Matt Rosencrantz317b0c52015-03-24 20:47:01 -0700406 return makeListOfErrors(len(cavs), NewErrCaveatValidationTimeout(ctx))
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800407 case reply := <-replyChan:
408 if len(reply) != len(cavs) {
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700409 ctx.VI(2).Infof("Wspr caveat validator received %d results from javascript but expected %d", len(reply), len(cavs))
Matt Rosencrantz317b0c52015-03-24 20:47:01 -0700410 return makeListOfErrors(len(cavs), NewErrInvalidValidationResponseFromJavascript(ctx))
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800411 }
412
413 return reply
414 }
415}
416
Todd Wang555097f2015-04-21 10:49:06 -0700417// CaveatValidation implements a function suitable for passing to
418// security.OverrideCaveatValidation.
419//
Suharsh Sivakumar60b78e92015-04-23 21:36:49 -0700420// Certain caveats (PublicKeyThirdPartyCaveat) are intercepted and handled in
Todd Wang555097f2015-04-21 10:49:06 -0700421// go, while all other caveats are evaluated in javascript.
422func CaveatValidation(ctx *context.T, call security.Call, cavs [][]security.Caveat) []error {
423 // If the server isn't set in the context, we just perform validation in Go.
424 ctxServer := ctx.Value(serverContextKey{})
425 if ctxServer == nil {
426 return caveatValidationInGo(ctx, call, cavs)
427 }
428 // Otherwise we run our special logic.
429 server := ctxServer.(*Server)
Benjamin Prosnitz2c8c2372015-03-13 12:03:08 -0700430 type validationStatus struct {
431 err error
432 isSet bool
433 }
434 valStatus := make([]validationStatus, len(cavs))
435
436 var caveatChainsToValidate [][]security.Caveat
437nextCav:
438 for i, chainCavs := range cavs {
439 var newChainCavs []security.Caveat
440 for _, cav := range chainCavs {
Suharsh Sivakumarbc740892015-04-17 10:54:17 -0700441 // If the server is closed handle all caveats in Go, because Javascript is
442 // no longer there.
443 select {
Todd Wang555097f2015-04-21 10:49:06 -0700444 case <-server.statusClose:
Suharsh Sivakumarbc740892015-04-17 10:54:17 -0700445 res := cav.Validate(ctx, call)
446 if res != nil {
447 valStatus[i] = validationStatus{
448 err: res,
449 isSet: true,
450 }
451 continue nextCav
452 }
453 default:
454 }
Benjamin Prosnitz2c8c2372015-03-13 12:03:08 -0700455 switch cav.Id {
Suharsh Sivakumar60b78e92015-04-23 21:36:49 -0700456 case security.PublicKeyThirdPartyCaveat.Id:
Todd Wang4264e4b2015-04-16 22:43:40 -0700457 res := cav.Validate(ctx, call)
Benjamin Prosnitz2c8c2372015-03-13 12:03:08 -0700458 if res != nil {
459 valStatus[i] = validationStatus{
460 err: res,
461 isSet: true,
462 }
463 continue nextCav
464 }
465 default:
466 newChainCavs = append(newChainCavs, cav)
467 }
468 }
469 if len(newChainCavs) == 0 {
470 valStatus[i] = validationStatus{
471 err: nil,
472 isSet: true,
473 }
474 } else {
475 caveatChainsToValidate = append(caveatChainsToValidate, newChainCavs)
476 }
477 }
478
Todd Wang555097f2015-04-21 10:49:06 -0700479 jsRes := server.caveatValidationInJavascript(ctx, call, caveatChainsToValidate)
Benjamin Prosnitz2c8c2372015-03-13 12:03:08 -0700480
481 outResults := make([]error, len(cavs))
482 jsIndex := 0
483 for i, status := range valStatus {
484 if status.isSet {
485 outResults[i] = status.err
486 } else {
487 outResults[i] = jsRes[jsIndex]
488 jsIndex++
489 }
490 }
491
492 return outResults
493}
494
Todd Wang4264e4b2015-04-16 22:43:40 -0700495func ConvertSecurityCall(helper ServerHelper, ctx *context.T, call security.Call, includeBlessingStrings bool) SecurityCall {
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800496 var localEndpoint string
Matt Rosencrantz9dce9b22015-03-02 10:48:37 -0800497 if call.LocalEndpoint() != nil {
498 localEndpoint = call.LocalEndpoint().String()
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800499 }
500 var remoteEndpoint string
Matt Rosencrantz9dce9b22015-03-02 10:48:37 -0800501 if call.RemoteEndpoint() != nil {
502 remoteEndpoint = call.RemoteEndpoint().String()
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800503 }
Matt Rosencrantz9dce9b22015-03-02 10:48:37 -0800504 anymtags := make([]*vdl.Value, len(call.MethodTags()))
505 for i, mtag := range call.MethodTags() {
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800506 anymtags[i] = mtag
507 }
Matt Rosencrantz250558f2015-03-17 11:37:31 -0700508 secCall := SecurityCall{
Matt Rosencrantz9dce9b22015-03-02 10:48:37 -0800509 Method: lib.LowercaseFirstCharacter(call.Method()),
510 Suffix: call.Suffix(),
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800511 MethodTags: anymtags,
512 LocalEndpoint: localEndpoint,
513 RemoteEndpoint: remoteEndpoint,
Benjamin Prosnitzae300202015-06-04 19:36:49 -0700514 LocalBlessings: helper.BlessingsCache().Put(call.LocalBlessings()),
515 RemoteBlessings: helper.BlessingsCache().Put(call.RemoteBlessings()),
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800516 }
517 if includeBlessingStrings {
Todd Wang4264e4b2015-04-16 22:43:40 -0700518 secCall.LocalBlessingStrings = security.LocalBlessingNames(ctx, call)
519 secCall.RemoteBlessingStrings, _ = security.RemoteBlessingNames(ctx, call)
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800520 }
Matt Rosencrantz250558f2015-03-17 11:37:31 -0700521 return secCall
Shyam Jayaramana42622c2015-01-05 16:55:53 -0800522}
523
Todd Wang4264e4b2015-04-16 22:43:40 -0700524type remoteAuth struct {
525 Func func(*context.T, security.Call, int32) error
526 Handle int32
527}
Jiri Simsa78b646f2014-10-08 10:23:05 -0700528
Todd Wang4264e4b2015-04-16 22:43:40 -0700529func (r remoteAuth) Authorize(ctx *context.T, call security.Call) error {
530 return r.Func(ctx, call, r.Handle)
531}
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800532
Todd Wang4264e4b2015-04-16 22:43:40 -0700533func (s *Server) createRemoteAuthorizer(handle int32) security.Authorizer {
534 return remoteAuth{s.authorizeRemote, handle}
535}
Jiri Simsa78b646f2014-10-08 10:23:05 -0700536
Todd Wang4264e4b2015-04-16 22:43:40 -0700537func (s *Server) authorizeRemote(ctx *context.T, call security.Call, handle int32) error {
538 // Until the tests get fixed, we need to create a security context before
539 // creating the flow because creating the security context creates a flow and
540 // flow ids will be off.
541 securityCall := ConvertSecurityCall(s.helper, ctx, call, true)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700542
Todd Wang4264e4b2015-04-16 22:43:40 -0700543 flow := s.helper.CreateNewFlow(s, nil)
544 replyChan := make(chan error, 1)
545 s.outstandingRequestLock.Lock()
546 s.outstandingAuthRequests[flow.ID] = replyChan
547 s.outstandingRequestLock.Unlock()
548 message := AuthRequest{
549 ServerId: s.id,
550 Handle: handle,
551 Call: securityCall,
Shyam Jayaraman8e301b52015-04-27 14:12:16 -0700552 Context: Context{
553 Language: string(i18n.GetLangID(ctx)),
554 },
Jiri Simsa78b646f2014-10-08 10:23:05 -0700555 }
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700556 ctx.VI(0).Infof("Sending out auth request for %v, %v", flow.ID, message)
Todd Wang4264e4b2015-04-16 22:43:40 -0700557
Shyam Jayaraman0062e272015-06-04 11:25:13 -0700558 vomMessage, err := lib.HexVomEncode(message, s.helper.TypeEncoder())
Todd Wang4264e4b2015-04-16 22:43:40 -0700559 if err != nil {
560 replyChan <- verror.Convert(verror.ErrInternal, nil, err)
561 } else if err := flow.Writer.Send(lib.ResponseAuthRequest, vomMessage); err != nil {
562 replyChan <- verror.Convert(verror.ErrInternal, nil, err)
563 }
564
565 err = <-replyChan
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700566 ctx.VI(0).Infof("going to respond with %v", err)
Todd Wang4264e4b2015-04-16 22:43:40 -0700567 s.outstandingRequestLock.Lock()
568 delete(s.outstandingAuthRequests, flow.ID)
569 s.outstandingRequestLock.Unlock()
570 s.helper.CleanupFlow(flow.ID)
571 return err
Jiri Simsa78b646f2014-10-08 10:23:05 -0700572}
573
Shyam Jayaramanc17abda2015-04-06 16:49:17 -0700574func (s *Server) readStatus() {
575 // A map of names to the last error message sent.
576 lastErrors := map[string]string{}
577 for {
578 status := s.server.Status()
579 for _, mountStatus := range status.Mounts {
580 var errMsg string
581 if mountStatus.LastMountErr != nil {
582 errMsg = mountStatus.LastMountErr.Error()
583 }
584 mountName := mountStatus.Name
585 if lastMessage, ok := lastErrors[mountName]; !ok || errMsg != lastMessage {
586 if errMsg == "" {
587 s.helper.SendLogMessage(
588 lib.LogLevelInfo, "serve: "+mountName+" successfully mounted ")
589 } else {
590 s.helper.SendLogMessage(
591 lib.LogLevelError, "serve: "+mountName+" failed with: "+errMsg)
592 }
593 }
594 lastErrors[mountName] = errMsg
595 }
596 select {
597 case <-time.After(10 * time.Second):
598 continue
599 case <-s.statusClose:
600 return
601 }
602 }
603}
604
Nicolas LaCasse27b57c72014-11-19 13:40:20 -0800605func (s *Server) Serve(name string) error {
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800606 s.serverStateLock.Lock()
607 defer s.serverStateLock.Unlock()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700608
609 if s.dispatcher == nil {
Shyam Jayaraman0062e272015-06-04 11:25:13 -0700610 s.dispatcher = newDispatcher(s.id, s, s, s, s.helper)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700611 }
612
Nicolas LaCasse27b57c72014-11-19 13:40:20 -0800613 if !s.isListening {
614 _, err := s.server.Listen(*s.listenSpec)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700615 if err != nil {
Nicolas LaCasse27b57c72014-11-19 13:40:20 -0800616 return err
Jiri Simsa78b646f2014-10-08 10:23:05 -0700617 }
Nicolas LaCasse27b57c72014-11-19 13:40:20 -0800618 s.isListening = true
Jiri Simsa78b646f2014-10-08 10:23:05 -0700619 }
Cosmos Nicolaou89303d62014-11-02 12:58:11 -0800620 if err := s.server.ServeDispatcher(name, s.dispatcher); err != nil {
Nicolas LaCasse27b57c72014-11-19 13:40:20 -0800621 return err
Jiri Simsa78b646f2014-10-08 10:23:05 -0700622 }
Shyam Jayaramanc17abda2015-04-06 16:49:17 -0700623 s.statusClose = make(chan struct{}, 1)
624 go s.readStatus()
Nicolas LaCasse27b57c72014-11-19 13:40:20 -0800625 return nil
Jiri Simsa78b646f2014-10-08 10:23:05 -0700626}
627
Todd Wangbaf16842015-03-16 14:12:29 -0700628func (s *Server) popServerRequest(id int32) chan *lib.ServerRpcReply {
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800629 s.outstandingRequestLock.Lock()
630 defer s.outstandingRequestLock.Unlock()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700631 ch := s.outstandingServerRequests[id]
632 delete(s.outstandingServerRequests, id)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700633
634 return ch
635}
636
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700637func (s *Server) HandleServerResponse(ctx *context.T, id int32, data string) {
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700638 ch := s.popServerRequest(id)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700639 if ch == nil {
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700640 ctx.Errorf("unexpected result from JavaScript. No channel "+
Jiri Simsa78b646f2014-10-08 10:23:05 -0700641 "for MessageId: %d exists. Ignoring the results.", id)
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800642 // Ignore unknown responses that don't belong to any channel
Jiri Simsa78b646f2014-10-08 10:23:05 -0700643 return
644 }
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700645
Jiri Simsa78b646f2014-10-08 10:23:05 -0700646 // Decode the result and send it through the channel
Todd Wangbaf16842015-03-16 14:12:29 -0700647 var reply lib.ServerRpcReply
Shyam Jayaraman0062e272015-06-04 11:25:13 -0700648 if err := lib.HexVomDecode(data, &reply, s.helper.TypeDecoder()); err != nil {
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800649 reply.Err = err
Jiri Simsa78b646f2014-10-08 10:23:05 -0700650 }
651
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700652 ctx.VI(0).Infof("response received from JavaScript server for "+
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800653 "MessageId %d with result %v", id, reply)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700654 s.helper.CleanupFlow(id)
Shyam Jayaraman07136a72015-04-13 13:34:41 -0700655 if reply.Err != nil {
656 ch <- &reply
657 return
658 }
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800659 ch <- &reply
Jiri Simsa78b646f2014-10-08 10:23:05 -0700660}
661
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700662func (s *Server) HandleLookupResponse(ctx *context.T, id int32, data string) {
663 s.dispatcher.handleLookupResponse(ctx, id, data)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700664}
665
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700666func (s *Server) HandleAuthResponse(ctx *context.T, id int32, data string) {
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800667 s.outstandingRequestLock.Lock()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700668 ch := s.outstandingAuthRequests[id]
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800669 s.outstandingRequestLock.Unlock()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700670 if ch == nil {
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700671 ctx.Errorf("unexpected result from JavaScript. No channel "+
Shyam Jayaramane56df9a2014-11-20 17:38:54 -0800672 "for MessageId: %d exists. Ignoring the results(%s)", id, data)
Suharsh Sivakumar4cc7c2d2015-04-09 15:21:56 -0700673 // Ignore unknown responses that don't belong to any channel
Jiri Simsa78b646f2014-10-08 10:23:05 -0700674 return
675 }
676 // Decode the result and send it through the channel
Nicolas Lacassefb931a22015-05-13 16:11:29 -0700677 var reply AuthReply
Shyam Jayaraman0062e272015-06-04 11:25:13 -0700678 if err := lib.HexVomDecode(data, &reply, s.helper.TypeDecoder()); err != nil {
Nicolas Lacassefb931a22015-05-13 16:11:29 -0700679 err = verror.Convert(verror.ErrInternal, nil, err)
680 reply = AuthReply{Err: err}
Jiri Simsa78b646f2014-10-08 10:23:05 -0700681 }
682
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700683 ctx.VI(0).Infof("response received from JavaScript server for "+
Jiri Simsa78b646f2014-10-08 10:23:05 -0700684 "MessageId %d with result %v", id, reply)
685 s.helper.CleanupFlow(id)
Mike Burrows2ec2bb32015-02-26 15:14:43 -0800686 // A nil verror.E does not result in an nil error. Instead, we have create
Jiri Simsa78b646f2014-10-08 10:23:05 -0700687 // a variable for the error interface and only set it's value if the struct is non-
688 // nil.
689 var err error
690 if reply.Err != nil {
691 err = reply.Err
692 }
693 ch <- err
694}
695
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700696func (s *Server) HandleCaveatValidationResponse(ctx *context.T, id int32, data string) {
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800697 s.outstandingRequestLock.Lock()
698 ch := s.outstandingValidationRequests[id]
699 s.outstandingRequestLock.Unlock()
700 if ch == nil {
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700701 ctx.Errorf("unexpected result from JavaScript. No channel "+
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800702 "for validation response with MessageId: %d exists. Ignoring the results(%s)", id, data)
Suharsh Sivakumar4cc7c2d2015-04-09 15:21:56 -0700703 // Ignore unknown responses that don't belong to any channel
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800704 return
705 }
706
707 var reply CaveatValidationResponse
Shyam Jayaraman0062e272015-06-04 11:25:13 -0700708 if err := lib.HexVomDecode(data, &reply, s.helper.TypeDecoder()); err != nil {
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700709 ctx.Errorf("failed to decode validation response %q: error %v", data, err)
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800710 ch <- []error{}
711 return
712 }
713
714 ch <- reply.Results
715}
716
Jiri Simsa78b646f2014-10-08 10:23:05 -0700717func (s *Server) createFlow() *Flow {
718 return s.helper.CreateNewFlow(s, nil)
719}
720
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800721func (s *Server) cleanupFlow(id int32) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700722 s.helper.CleanupFlow(id)
723}
724
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700725func (s *Server) createInvoker(handle int32, sig []signature.Interface, hasGlobber bool) (rpc.Invoker, error) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700726 remoteInvokeFunc := s.createRemoteInvokerFunc(handle)
Shyam Jayaramaneb10b9b2015-01-12 12:23:20 -0800727 var globFunc remoteGlobFunc
728 if hasGlobber {
729 globFunc = s.createRemoteGlobFunc(handle)
730 }
731 return newInvoker(sig, remoteInvokeFunc, globFunc), nil
Jiri Simsa78b646f2014-10-08 10:23:05 -0700732}
733
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800734func (s *Server) createAuthorizer(handle int32, hasAuthorizer bool) (security.Authorizer, error) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700735 if hasAuthorizer {
Todd Wang4264e4b2015-04-16 22:43:40 -0700736 return s.createRemoteAuthorizer(handle), nil
Jiri Simsa78b646f2014-10-08 10:23:05 -0700737 }
Asim Shankar8572f6c2014-10-28 15:24:17 -0700738 return nil, nil
Jiri Simsa78b646f2014-10-08 10:23:05 -0700739}
740
741func (s *Server) Stop() {
Mike Burrows2ec2bb32015-02-26 15:14:43 -0800742 stdErr := verror.New(verror.ErrTimeout, nil).(verror.E)
Todd Wangbaf16842015-03-16 14:12:29 -0700743 result := lib.ServerRpcReply{
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800744 Results: nil,
Mike Burrowsb6689c22014-10-08 11:14:15 -0700745 Err: &stdErr,
Jiri Simsa78b646f2014-10-08 10:23:05 -0700746 }
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800747 s.serverStateLock.Lock()
Nicolas LaCassee3867dc2015-02-05 14:44:53 -0800748
Shyam Jayaramanc17abda2015-04-06 16:49:17 -0700749 if s.statusClose != nil {
750 close(s.statusClose)
751 }
Nicolas LaCassee3867dc2015-02-05 14:44:53 -0800752 if s.dispatcher != nil {
753 s.dispatcher.Cleanup()
754 }
755
Benjamin Prosnitzc65917c2015-05-26 14:21:53 -0700756 s.outstandingRequestLock.Lock()
Nicolas LaCassee3867dc2015-02-05 14:44:53 -0800757 for _, ch := range s.outstandingAuthRequests {
758 ch <- fmt.Errorf("Cleaning up server")
759 }
Nicolas LaCassee3867dc2015-02-05 14:44:53 -0800760
Jiri Simsa78b646f2014-10-08 10:23:05 -0700761 for _, ch := range s.outstandingServerRequests {
762 select {
763 case ch <- &result:
764 default:
765 }
766 }
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800767 s.outstandingAuthRequests = make(map[int32]chan error)
Todd Wangbaf16842015-03-16 14:12:29 -0700768 s.outstandingServerRequests = make(map[int32]chan *lib.ServerRpcReply)
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800769 s.outstandingRequestLock.Unlock()
770 s.serverStateLock.Unlock()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700771 s.server.Stop()
Matt Rosencrantz317b0c52015-03-24 20:47:01 -0700772
Suharsh Sivakumar4cc7c2d2015-04-09 15:21:56 -0700773 // Only clear the validation requests map after stopping. Clearing them before
774 // can cause the publisher to get stuck waiting for a caveat validation that
775 // will never be answered, which prevents the server from stopping.
Matt Rosencrantz317b0c52015-03-24 20:47:01 -0700776 s.serverStateLock.Lock()
777 s.outstandingRequestLock.Lock()
778 s.outstandingValidationRequests = make(map[int32]chan []error)
779 s.outstandingRequestLock.Unlock()
780 s.serverStateLock.Unlock()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700781}
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800782
783func (s *Server) AddName(name string) error {
784 return s.server.AddName(name)
785}
786
Cosmos Nicolaoub1a41af2015-01-25 22:13:40 -0800787func (s *Server) RemoveName(name string) {
788 s.server.RemoveName(name)
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800789}