Jiri Simsa | d7616c9 | 2015-03-24 23:44:30 -0700 | [diff] [blame] | 1 | // 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 | |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 5 | package rt |
| 6 | |
| 7 | import ( |
| 8 | "fmt" |
Suharsh Sivakumar | 628a8ee | 2015-01-14 11:38:56 -0800 | [diff] [blame] | 9 | "os" |
| 10 | "os/signal" |
| 11 | "path/filepath" |
| 12 | "strings" |
Suharsh Sivakumar | 628a8ee | 2015-01-14 11:38:56 -0800 | [diff] [blame] | 13 | "syscall" |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 14 | "time" |
| 15 | |
Cosmos Nicolaou | 9691e5d | 2015-06-17 12:24:35 -0700 | [diff] [blame^] | 16 | "v.io/x/lib/metadata" |
Cosmos Nicolaou | 00fe9a4 | 2015-04-24 14:18:01 -0700 | [diff] [blame] | 17 | "v.io/x/lib/pubsub" |
Cosmos Nicolaou | 0e4e392 | 2015-06-10 16:30:09 -0700 | [diff] [blame] | 18 | "v.io/x/lib/vlog" |
Cosmos Nicolaou | 00fe9a4 | 2015-04-24 14:18:01 -0700 | [diff] [blame] | 19 | |
Jiri Simsa | 6ac9522 | 2015-02-23 16:11:49 -0800 | [diff] [blame] | 20 | "v.io/v23" |
| 21 | "v.io/v23/context" |
| 22 | "v.io/v23/i18n" |
Todd Wang | 5082a55 | 2015-04-02 10:56:11 -0700 | [diff] [blame] | 23 | "v.io/v23/namespace" |
Jiri Simsa | 6ac9522 | 2015-02-23 16:11:49 -0800 | [diff] [blame] | 24 | "v.io/v23/naming" |
| 25 | "v.io/v23/options" |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 26 | "v.io/v23/rpc" |
Jiri Simsa | 6ac9522 | 2015-02-23 16:11:49 -0800 | [diff] [blame] | 27 | "v.io/v23/security" |
| 28 | "v.io/v23/verror" |
Jiri Simsa | 6ac9522 | 2015-02-23 16:11:49 -0800 | [diff] [blame] | 29 | "v.io/v23/vtrace" |
Cosmos Nicolaou | 0e4e392 | 2015-06-10 16:30:09 -0700 | [diff] [blame] | 30 | |
| 31 | "v.io/x/ref/internal/logger" |
Cosmos Nicolaou | f3c1909 | 2015-05-27 17:53:37 -0700 | [diff] [blame] | 32 | "v.io/x/ref/lib/apilog" |
Jiri Simsa | ffceefa | 2015-02-28 11:03:34 -0800 | [diff] [blame] | 33 | "v.io/x/ref/lib/flags" |
Jiri Simsa | ffceefa | 2015-02-28 11:03:34 -0800 | [diff] [blame] | 34 | "v.io/x/ref/lib/stats" |
| 35 | _ "v.io/x/ref/lib/stats/sysstats" |
Suharsh Sivakumar | dcc11d7 | 2015-05-11 12:19:20 -0700 | [diff] [blame] | 36 | "v.io/x/ref/runtime/internal/lib/dependency" |
| 37 | inaming "v.io/x/ref/runtime/internal/naming" |
| 38 | inamespace "v.io/x/ref/runtime/internal/naming/namespace" |
| 39 | irpc "v.io/x/ref/runtime/internal/rpc" |
| 40 | "v.io/x/ref/runtime/internal/rpc/stream" |
| 41 | imanager "v.io/x/ref/runtime/internal/rpc/stream/manager" |
| 42 | ivtrace "v.io/x/ref/runtime/internal/vtrace" |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 43 | ) |
| 44 | |
| 45 | type contextKey int |
| 46 | |
| 47 | const ( |
| 48 | streamManagerKey = contextKey(iota) |
| 49 | clientKey |
| 50 | namespaceKey |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 51 | principalKey |
Matt Rosencrantz | 3838c55 | 2015-01-15 13:04:53 -0800 | [diff] [blame] | 52 | backgroundKey |
Matt Rosencrantz | bf0d9d9 | 2015-04-08 12:43:14 -0700 | [diff] [blame] | 53 | reservedNameKey |
| 54 | |
| 55 | // initKey is used to store values that are only set at init time. |
| 56 | initKey |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 57 | ) |
| 58 | |
Matt Rosencrantz | bf0d9d9 | 2015-04-08 12:43:14 -0700 | [diff] [blame] | 59 | type initData struct { |
Cosmos Nicolaou | 00fe9a4 | 2015-04-24 14:18:01 -0700 | [diff] [blame] | 60 | appCycle v23.AppCycle |
| 61 | listenSpec *rpc.ListenSpec |
| 62 | protocols []string |
| 63 | settingsPublisher *pubsub.Publisher |
| 64 | settingsName string |
Matt Rosencrantz | bf0d9d9 | 2015-04-08 12:43:14 -0700 | [diff] [blame] | 65 | } |
| 66 | |
Matt Rosencrantz | fa3082c | 2015-01-22 21:39:04 -0800 | [diff] [blame] | 67 | type vtraceDependency struct{} |
| 68 | |
Jiri Simsa | 6ac9522 | 2015-02-23 16:11:49 -0800 | [diff] [blame] | 69 | // Runtime implements the v23.Runtime interface. |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 70 | // Please see the interface definition for documentation of the |
| 71 | // individiual methods. |
Matt Rosencrantz | ba470a5 | 2015-01-26 13:36:13 -0800 | [diff] [blame] | 72 | type Runtime struct { |
Matt Rosencrantz | 5dbfbef | 2015-01-26 12:40:56 -0800 | [diff] [blame] | 73 | deps *dependency.Graph |
Matt Rosencrantz | aeed5d5 | 2015-01-14 15:18:34 -0800 | [diff] [blame] | 74 | } |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 75 | |
Matt Rosencrantz | bf0d9d9 | 2015-04-08 12:43:14 -0700 | [diff] [blame] | 76 | func Init( |
| 77 | ctx *context.T, |
| 78 | appCycle v23.AppCycle, |
| 79 | protocols []string, |
| 80 | listenSpec *rpc.ListenSpec, |
Cosmos Nicolaou | 00fe9a4 | 2015-04-24 14:18:01 -0700 | [diff] [blame] | 81 | settingsPublisher *pubsub.Publisher, |
| 82 | settingsName string, |
Matt Rosencrantz | bf0d9d9 | 2015-04-08 12:43:14 -0700 | [diff] [blame] | 83 | flags flags.RuntimeFlags, |
| 84 | reservedDispatcher rpc.Dispatcher) (*Runtime, *context.T, v23.Shutdown, error) { |
Matt Rosencrantz | ba470a5 | 2015-01-26 13:36:13 -0800 | [diff] [blame] | 85 | r := &Runtime{deps: dependency.NewGraph()} |
Matt Rosencrantz | 96d952a | 2015-01-15 09:18:38 -0800 | [diff] [blame] | 86 | |
Matt Rosencrantz | bf0d9d9 | 2015-04-08 12:43:14 -0700 | [diff] [blame] | 87 | ctx = context.WithValue(ctx, initKey, &initData{ |
Cosmos Nicolaou | 00fe9a4 | 2015-04-24 14:18:01 -0700 | [diff] [blame] | 88 | protocols: protocols, |
| 89 | listenSpec: listenSpec, |
| 90 | appCycle: appCycle, |
| 91 | settingsPublisher: settingsPublisher, |
| 92 | settingsName: settingsName, |
Matt Rosencrantz | bf0d9d9 | 2015-04-08 12:43:14 -0700 | [diff] [blame] | 93 | }) |
| 94 | |
| 95 | if reservedDispatcher != nil { |
| 96 | ctx = context.WithValue(ctx, reservedNameKey, reservedDispatcher) |
| 97 | } |
| 98 | |
Cosmos Nicolaou | 0e4e392 | 2015-06-10 16:30:09 -0700 | [diff] [blame] | 99 | err := logger.Manager(logger.Global()).ConfigureFromFlags() |
Cosmos Nicolaou | 92c5748 | 2015-05-22 13:29:15 -0700 | [diff] [blame] | 100 | if err != nil && err != vlog.ErrConfigured { |
Matt Rosencrantz | 97d67a9 | 2015-01-27 21:03:12 -0800 | [diff] [blame] | 101 | return nil, nil, nil, err |
| 102 | } |
Cosmos Nicolaou | 0e4e392 | 2015-06-10 16:30:09 -0700 | [diff] [blame] | 103 | |
| 104 | // Configure the context to use the global logger. |
| 105 | ctx = context.WithLogger(ctx, logger.Global()) |
| 106 | |
Todd Wang | 3f7ceb4 | 2015-05-04 17:51:34 -0700 | [diff] [blame] | 107 | // We want to print out metadata only into the log files, to avoid |
Bogdan Caprita | 3eb7469 | 2015-03-05 09:34:18 -0800 | [diff] [blame] | 108 | // spamming stderr, see #1246. |
| 109 | // |
| 110 | // TODO(caprita): We should add it to the log file header information; |
| 111 | // since that requires changes to the llog and vlog packages, for now we |
Todd Wang | 3f7ceb4 | 2015-05-04 17:51:34 -0700 | [diff] [blame] | 112 | // condition printing of metadata on having specified an explicit |
| 113 | // log_dir for the program. It's a hack, but it gets us the metadata |
| 114 | // to device manager-run apps and avoids it for command-lines, which is |
Bogdan Caprita | 3eb7469 | 2015-03-05 09:34:18 -0800 | [diff] [blame] | 115 | // a good enough approximation. |
Cosmos Nicolaou | 9691e5d | 2015-06-17 12:24:35 -0700 | [diff] [blame^] | 116 | if logger.Manager(ctx).LogDir() != os.TempDir() { |
| 117 | ctx.Infof(metadata.ToXML()) |
| 118 | } |
Matt Rosencrantz | 96d952a | 2015-01-15 09:18:38 -0800 | [diff] [blame] | 119 | |
Matt Rosencrantz | fa3082c | 2015-01-22 21:39:04 -0800 | [diff] [blame] | 120 | // Setup the initial trace. |
| 121 | ctx, err = ivtrace.Init(ctx, flags.Vtrace) |
| 122 | if err != nil { |
| 123 | return nil, nil, nil, err |
| 124 | } |
Todd Wang | ad49204 | 2015-04-17 15:58:40 -0700 | [diff] [blame] | 125 | ctx, _ = vtrace.WithNewTrace(ctx) |
Matt Rosencrantz | fa3082c | 2015-01-22 21:39:04 -0800 | [diff] [blame] | 126 | r.addChild(ctx, vtraceDependency{}, func() { |
| 127 | vtrace.FormatTraces(os.Stderr, vtrace.GetStore(ctx).TraceRecords(), nil) |
| 128 | }) |
| 129 | |
Matt Rosencrantz | 96d952a | 2015-01-15 09:18:38 -0800 | [diff] [blame] | 130 | // Setup i18n. |
Todd Wang | ad49204 | 2015-04-17 15:58:40 -0700 | [diff] [blame] | 131 | ctx = i18n.WithLangID(ctx, i18n.LangIDFromEnv()) |
Matt Rosencrantz | 96d952a | 2015-01-15 09:18:38 -0800 | [diff] [blame] | 132 | if len(flags.I18nCatalogue) != 0 { |
| 133 | cat := i18n.Cat() |
| 134 | for _, filename := range strings.Split(flags.I18nCatalogue, ",") { |
| 135 | err := cat.MergeFromFile(filename) |
| 136 | if err != nil { |
| 137 | fmt.Fprintf(os.Stderr, "%s: i18n: error reading i18n catalogue file %q: %s\n", os.Args[0], filename, err) |
| 138 | } |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | // Setup the program name. |
Todd Wang | ad49204 | 2015-04-17 15:58:40 -0700 | [diff] [blame] | 143 | ctx = verror.WithComponentName(ctx, filepath.Base(os.Args[0])) |
Matt Rosencrantz | 96d952a | 2015-01-15 09:18:38 -0800 | [diff] [blame] | 144 | |
Matt Rosencrantz | 96d952a | 2015-01-15 09:18:38 -0800 | [diff] [blame] | 145 | // Enable signal handling. |
| 146 | r.initSignalHandling(ctx) |
| 147 | |
| 148 | // Set the initial namespace. |
| 149 | ctx, _, err = r.setNewNamespace(ctx, flags.NamespaceRoots...) |
| 150 | if err != nil { |
| 151 | return nil, nil, nil, err |
| 152 | } |
| 153 | |
Asim Shankar | e89936f | 2015-04-22 17:37:43 -0700 | [diff] [blame] | 154 | // Create and set the principal |
Matt Rosencrantz | 9837b27 | 2015-04-30 18:32:36 -0700 | [diff] [blame] | 155 | principal, deps, shutdown, err := r.initPrincipal(ctx, flags.Credentials) |
Asim Shankar | e89936f | 2015-04-22 17:37:43 -0700 | [diff] [blame] | 156 | if err != nil { |
| 157 | return nil, nil, nil, err |
| 158 | } |
Matt Rosencrantz | 9837b27 | 2015-04-30 18:32:36 -0700 | [diff] [blame] | 159 | ctx, err = r.setPrincipal(ctx, principal, shutdown, deps...) |
Matt Rosencrantz | 96d952a | 2015-01-15 09:18:38 -0800 | [diff] [blame] | 160 | if err != nil { |
| 161 | return nil, nil, nil, err |
| 162 | } |
| 163 | |
Asim Shankar | e89936f | 2015-04-22 17:37:43 -0700 | [diff] [blame] | 164 | // Setup authenticated "networking" |
| 165 | ctx, err = r.WithNewStreamManager(ctx) |
Matt Rosencrantz | 96d952a | 2015-01-15 09:18:38 -0800 | [diff] [blame] | 166 | if err != nil { |
| 167 | return nil, nil, nil, err |
| 168 | } |
| 169 | |
Asim Shankar | e89936f | 2015-04-22 17:37:43 -0700 | [diff] [blame] | 170 | return r, r.WithBackgroundContext(ctx), r.shutdown, nil |
Matt Rosencrantz | 96d952a | 2015-01-15 09:18:38 -0800 | [diff] [blame] | 171 | } |
| 172 | |
Matt Rosencrantz | ba470a5 | 2015-01-26 13:36:13 -0800 | [diff] [blame] | 173 | func (r *Runtime) addChild(ctx *context.T, me interface{}, stop func(), dependsOn ...interface{}) error { |
Matt Rosencrantz | 5dbfbef | 2015-01-26 12:40:56 -0800 | [diff] [blame] | 174 | if err := r.deps.Depend(me, dependsOn...); err != nil { |
Matt Rosencrantz | aeed5d5 | 2015-01-14 15:18:34 -0800 | [diff] [blame] | 175 | stop() |
Matt Rosencrantz | fa3082c | 2015-01-22 21:39:04 -0800 | [diff] [blame] | 176 | return err |
Matt Rosencrantz | 5dbfbef | 2015-01-26 12:40:56 -0800 | [diff] [blame] | 177 | } else if done := ctx.Done(); done != nil { |
Matt Rosencrantz | aeed5d5 | 2015-01-14 15:18:34 -0800 | [diff] [blame] | 178 | go func() { |
| 179 | <-done |
Matt Rosencrantz | 5dbfbef | 2015-01-26 12:40:56 -0800 | [diff] [blame] | 180 | finish := r.deps.CloseAndWait(me) |
Matt Rosencrantz | aeed5d5 | 2015-01-14 15:18:34 -0800 | [diff] [blame] | 181 | stop() |
Matt Rosencrantz | 5dbfbef | 2015-01-26 12:40:56 -0800 | [diff] [blame] | 182 | finish() |
Matt Rosencrantz | aeed5d5 | 2015-01-14 15:18:34 -0800 | [diff] [blame] | 183 | }() |
| 184 | } |
| 185 | return nil |
| 186 | } |
| 187 | |
Matt Rosencrantz | 3199588 | 2015-01-27 20:00:48 -0800 | [diff] [blame] | 188 | func (r *Runtime) Init(ctx *context.T) error { |
Cosmos Nicolaou | f3c1909 | 2015-05-27 17:53:37 -0700 | [diff] [blame] | 189 | defer apilog.LogCall(ctx)(ctx) // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT |
Matt Rosencrantz | 3199588 | 2015-01-27 20:00:48 -0800 | [diff] [blame] | 190 | return r.initMgmt(ctx) |
| 191 | } |
| 192 | |
Matt Rosencrantz | ba470a5 | 2015-01-26 13:36:13 -0800 | [diff] [blame] | 193 | func (r *Runtime) shutdown() { |
Matt Rosencrantz | 5dbfbef | 2015-01-26 12:40:56 -0800 | [diff] [blame] | 194 | r.deps.CloseAndWaitForAll() |
Matt Rosencrantz | aeed5d5 | 2015-01-14 15:18:34 -0800 | [diff] [blame] | 195 | vlog.FlushLog() |
| 196 | } |
| 197 | |
Matt Rosencrantz | ba470a5 | 2015-01-26 13:36:13 -0800 | [diff] [blame] | 198 | func (r *Runtime) initSignalHandling(ctx *context.T) { |
Suharsh Sivakumar | 628a8ee | 2015-01-14 11:38:56 -0800 | [diff] [blame] | 199 | // TODO(caprita): Given that our device manager implementation is to |
| 200 | // kill all child apps when the device manager dies, we should |
| 201 | // enable SIGHUP on apps by default. |
| 202 | |
| 203 | // Automatically handle SIGHUP to prevent applications started as |
| 204 | // daemons from being killed. The developer can choose to still listen |
| 205 | // on SIGHUP and take a different action if desired. |
Matt Rosencrantz | cf714c6 | 2015-01-22 16:15:56 -0800 | [diff] [blame] | 206 | signals := make(chan os.Signal, 1) |
Suharsh Sivakumar | 628a8ee | 2015-01-14 11:38:56 -0800 | [diff] [blame] | 207 | signal.Notify(signals, syscall.SIGHUP) |
| 208 | go func() { |
| 209 | for { |
Matt Rosencrantz | aeed5d5 | 2015-01-14 15:18:34 -0800 | [diff] [blame] | 210 | sig, ok := <-signals |
| 211 | if !ok { |
| 212 | break |
| 213 | } |
| 214 | vlog.Infof("Received signal %v", sig) |
Suharsh Sivakumar | 628a8ee | 2015-01-14 11:38:56 -0800 | [diff] [blame] | 215 | } |
| 216 | }() |
Matt Rosencrantz | fa3082c | 2015-01-22 21:39:04 -0800 | [diff] [blame] | 217 | r.addChild(ctx, signals, func() { |
Matt Rosencrantz | aeed5d5 | 2015-01-14 15:18:34 -0800 | [diff] [blame] | 218 | signal.Stop(signals) |
| 219 | close(signals) |
| 220 | }) |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 221 | } |
| 222 | |
Matt Rosencrantz | ba470a5 | 2015-01-26 13:36:13 -0800 | [diff] [blame] | 223 | func (*Runtime) NewEndpoint(ep string) (naming.Endpoint, error) { |
Cosmos Nicolaou | 0e4e392 | 2015-06-10 16:30:09 -0700 | [diff] [blame] | 224 | // nologcall |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 225 | return inaming.NewEndpoint(ep) |
| 226 | } |
| 227 | |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 228 | func (r *Runtime) NewServer(ctx *context.T, opts ...rpc.ServerOpt) (rpc.Server, error) { |
Cosmos Nicolaou | f3c1909 | 2015-05-27 17:53:37 -0700 | [diff] [blame] | 229 | defer apilog.LogCallf(ctx, "opts...=%v", opts)(ctx, "") // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 230 | // Create a new RoutingID (and StreamManager) for each server. |
Suharsh Sivakumar | d5049b7 | 2015-01-21 14:11:35 -0800 | [diff] [blame] | 231 | sm, err := newStreamManager() |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 232 | if err != nil { |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 233 | return nil, fmt.Errorf("failed to create rpc/stream/Manager: %v", err) |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 234 | } |
| 235 | |
Todd Wang | 5082a55 | 2015-04-02 10:56:11 -0700 | [diff] [blame] | 236 | ns, _ := ctx.Value(namespaceKey).(namespace.T) |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 237 | principal, _ := ctx.Value(principalKey).(security.Principal) |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 238 | client, _ := ctx.Value(clientKey).(rpc.Client) |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 239 | |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 240 | otherOpts := append([]rpc.ServerOpt{}, opts...) |
Matt Rosencrantz | bf0d9d9 | 2015-04-08 12:43:14 -0700 | [diff] [blame] | 241 | |
| 242 | if reservedDispatcher := r.GetReservedNameDispatcher(ctx); reservedDispatcher != nil { |
| 243 | otherOpts = append(otherOpts, irpc.ReservedNameDispatcher{ |
| 244 | Dispatcher: reservedDispatcher, |
| 245 | }) |
Matt Rosencrantz | 9db8bc3 | 2015-01-13 09:01:55 -0800 | [diff] [blame] | 246 | } |
Suharsh Sivakumar | 77357d7 | 2015-02-21 22:14:20 -0800 | [diff] [blame] | 247 | |
Matt Rosencrantz | bf0d9d9 | 2015-04-08 12:43:14 -0700 | [diff] [blame] | 248 | id, _ := ctx.Value(initKey).(*initData) |
| 249 | if id.protocols != nil { |
| 250 | otherOpts = append(otherOpts, irpc.PreferredServerResolveProtocols(id.protocols)) |
| 251 | } |
Suharsh Sivakumar | 77357d7 | 2015-02-21 22:14:20 -0800 | [diff] [blame] | 252 | if !hasServerBlessingsOpt(opts) && principal != nil { |
Matt Rosencrantz | bf0d9d9 | 2015-04-08 12:43:14 -0700 | [diff] [blame] | 253 | otherOpts = append(otherOpts, options.ServerBlessings{ |
| 254 | Blessings: principal.BlessingStore().Default(), |
| 255 | }) |
Suharsh Sivakumar | 77357d7 | 2015-02-21 22:14:20 -0800 | [diff] [blame] | 256 | } |
Cosmos Nicolaou | 00fe9a4 | 2015-04-24 14:18:01 -0700 | [diff] [blame] | 257 | server, err := irpc.InternalNewServer(ctx, sm, ns, id.settingsPublisher, id.settingsName, r.GetClient(ctx), principal, otherOpts...) |
Matt Rosencrantz | aeed5d5 | 2015-01-14 15:18:34 -0800 | [diff] [blame] | 258 | if err != nil { |
| 259 | return nil, err |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 260 | } |
Matt Rosencrantz | aeed5d5 | 2015-01-14 15:18:34 -0800 | [diff] [blame] | 261 | stop := func() { |
| 262 | if err := server.Stop(); err != nil { |
| 263 | vlog.Errorf("A server could not be stopped: %v", err) |
| 264 | } |
Suharsh Sivakumar | d5049b7 | 2015-01-21 14:11:35 -0800 | [diff] [blame] | 265 | sm.Shutdown() |
Matt Rosencrantz | aeed5d5 | 2015-01-14 15:18:34 -0800 | [diff] [blame] | 266 | } |
Matt Rosencrantz | 3dc0196 | 2015-03-16 14:16:01 -0700 | [diff] [blame] | 267 | deps := []interface{}{client, vtraceDependency{}} |
| 268 | if principal != nil { |
| 269 | deps = append(deps, principal) |
| 270 | } |
| 271 | if err = r.addChild(ctx, server, stop, deps...); err != nil { |
Matt Rosencrantz | aeed5d5 | 2015-01-14 15:18:34 -0800 | [diff] [blame] | 272 | return nil, err |
| 273 | } |
| 274 | return server, nil |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 275 | } |
| 276 | |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 277 | func hasServerBlessingsOpt(opts []rpc.ServerOpt) bool { |
Suharsh Sivakumar | 77357d7 | 2015-02-21 22:14:20 -0800 | [diff] [blame] | 278 | for _, o := range opts { |
| 279 | if _, ok := o.(options.ServerBlessings); ok { |
| 280 | return true |
| 281 | } |
| 282 | } |
| 283 | return false |
| 284 | } |
| 285 | |
Suharsh Sivakumar | af862a5 | 2015-02-04 13:50:47 -0800 | [diff] [blame] | 286 | func newStreamManager() (stream.Manager, error) { |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 287 | rid, err := naming.NewRoutingID() |
| 288 | if err != nil { |
Suharsh Sivakumar | d5049b7 | 2015-01-21 14:11:35 -0800 | [diff] [blame] | 289 | return nil, err |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 290 | } |
| 291 | sm := imanager.InternalNew(rid) |
Suharsh Sivakumar | d5049b7 | 2015-01-21 14:11:35 -0800 | [diff] [blame] | 292 | return sm, nil |
| 293 | } |
| 294 | |
Suharsh Sivakumar | af862a5 | 2015-02-04 13:50:47 -0800 | [diff] [blame] | 295 | func (r *Runtime) setNewStreamManager(ctx *context.T) (*context.T, error) { |
| 296 | sm, err := newStreamManager() |
| 297 | if err != nil { |
| 298 | return nil, err |
| 299 | } |
Matt Rosencrantz | aeed5d5 | 2015-01-14 15:18:34 -0800 | [diff] [blame] | 300 | newctx := context.WithValue(ctx, streamManagerKey, sm) |
Matt Rosencrantz | fa3082c | 2015-01-22 21:39:04 -0800 | [diff] [blame] | 301 | if err = r.addChild(ctx, sm, sm.Shutdown); err != nil { |
Suharsh Sivakumar | af862a5 | 2015-02-04 13:50:47 -0800 | [diff] [blame] | 302 | return ctx, err |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 303 | } |
Suharsh Sivakumar | af862a5 | 2015-02-04 13:50:47 -0800 | [diff] [blame] | 304 | return newctx, err |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 305 | } |
| 306 | |
Todd Wang | ad49204 | 2015-04-17 15:58:40 -0700 | [diff] [blame] | 307 | func (r *Runtime) WithNewStreamManager(ctx *context.T) (*context.T, error) { |
Cosmos Nicolaou | f3c1909 | 2015-05-27 17:53:37 -0700 | [diff] [blame] | 308 | defer apilog.LogCall(ctx)(ctx) // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT |
Suharsh Sivakumar | af862a5 | 2015-02-04 13:50:47 -0800 | [diff] [blame] | 309 | newctx, err := r.setNewStreamManager(ctx) |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 310 | if err != nil { |
Suharsh Sivakumar | af862a5 | 2015-02-04 13:50:47 -0800 | [diff] [blame] | 311 | return ctx, err |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 312 | } |
| 313 | |
| 314 | // Create a new client since it depends on the stream manager. |
Todd Wang | ad49204 | 2015-04-17 15:58:40 -0700 | [diff] [blame] | 315 | newctx, _, err = r.WithNewClient(newctx) |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 316 | if err != nil { |
Suharsh Sivakumar | af862a5 | 2015-02-04 13:50:47 -0800 | [diff] [blame] | 317 | return ctx, err |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 318 | } |
Suharsh Sivakumar | af862a5 | 2015-02-04 13:50:47 -0800 | [diff] [blame] | 319 | return newctx, nil |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 320 | } |
| 321 | |
Matt Rosencrantz | 9837b27 | 2015-04-30 18:32:36 -0700 | [diff] [blame] | 322 | func (r *Runtime) setPrincipal(ctx *context.T, principal security.Principal, shutdown func(), deps ...interface{}) (*context.T, error) { |
Suharsh Sivakumar | 2c5d810 | 2015-03-23 08:49:12 -0700 | [diff] [blame] | 323 | if principal != nil { |
| 324 | // We uniquely identify a principal with "security/principal/<publicKey>" |
| 325 | principalName := "security/principal/" + principal.PublicKey().String() |
| 326 | stats.NewStringFunc(principalName+"/blessingstore", principal.BlessingStore().DebugString) |
| 327 | stats.NewStringFunc(principalName+"/blessingroots", principal.Roots().DebugString) |
| 328 | } |
Matt Rosencrantz | 3dc0196 | 2015-03-16 14:16:01 -0700 | [diff] [blame] | 329 | ctx = context.WithValue(ctx, principalKey, principal) |
Matt Rosencrantz | 9837b27 | 2015-04-30 18:32:36 -0700 | [diff] [blame] | 330 | return ctx, r.addChild(ctx, principal, shutdown, deps...) |
Suharsh Sivakumar | 5ca4664 | 2015-01-30 10:33:38 -0800 | [diff] [blame] | 331 | } |
| 332 | |
Todd Wang | ad49204 | 2015-04-17 15:58:40 -0700 | [diff] [blame] | 333 | func (r *Runtime) WithPrincipal(ctx *context.T, principal security.Principal) (*context.T, error) { |
Cosmos Nicolaou | f3c1909 | 2015-05-27 17:53:37 -0700 | [diff] [blame] | 334 | defer apilog.LogCallf(ctx, "principal=")(ctx, "") // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 335 | var err error |
| 336 | newctx := ctx |
| 337 | |
Matt Rosencrantz | 3dc0196 | 2015-03-16 14:16:01 -0700 | [diff] [blame] | 338 | // TODO(mattr, suharshs): If there user gives us some principal that has dependencies |
| 339 | // we don't know about, we will not honour those dependencies during shutdown. |
| 340 | // For example if they create an agent principal with some client, we don't know |
| 341 | // about that, so servers based of this new principal will not prevent the client |
| 342 | // from terminating early. |
Matt Rosencrantz | 9837b27 | 2015-04-30 18:32:36 -0700 | [diff] [blame] | 343 | if newctx, err = r.setPrincipal(ctx, principal, func() {}); err != nil { |
Matt Rosencrantz | 3dc0196 | 2015-03-16 14:16:01 -0700 | [diff] [blame] | 344 | return ctx, err |
| 345 | } |
Suharsh Sivakumar | af862a5 | 2015-02-04 13:50:47 -0800 | [diff] [blame] | 346 | if newctx, err = r.setNewStreamManager(newctx); err != nil { |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 347 | return ctx, err |
| 348 | } |
Suharsh Sivakumar | 033a30e | 2015-01-07 13:54:43 -0800 | [diff] [blame] | 349 | if newctx, _, err = r.setNewNamespace(newctx, r.GetNamespace(ctx).Roots()...); err != nil { |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 350 | return ctx, err |
| 351 | } |
Todd Wang | ad49204 | 2015-04-17 15:58:40 -0700 | [diff] [blame] | 352 | if newctx, _, err = r.WithNewClient(newctx); err != nil { |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 353 | return ctx, err |
| 354 | } |
| 355 | |
| 356 | return newctx, nil |
| 357 | } |
| 358 | |
Matt Rosencrantz | ba470a5 | 2015-01-26 13:36:13 -0800 | [diff] [blame] | 359 | func (*Runtime) GetPrincipal(ctx *context.T) security.Principal { |
Cosmos Nicolaou | 0e4e392 | 2015-06-10 16:30:09 -0700 | [diff] [blame] | 360 | // nologcall |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 361 | p, _ := ctx.Value(principalKey).(security.Principal) |
| 362 | return p |
| 363 | } |
| 364 | |
Todd Wang | ad49204 | 2015-04-17 15:58:40 -0700 | [diff] [blame] | 365 | func (r *Runtime) WithNewClient(ctx *context.T, opts ...rpc.ClientOpt) (*context.T, rpc.Client, error) { |
Cosmos Nicolaou | f3c1909 | 2015-05-27 17:53:37 -0700 | [diff] [blame] | 366 | defer apilog.LogCallf(ctx, "opts...=%v", opts)(ctx, "") // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 367 | otherOpts := append([]rpc.ClientOpt{}, opts...) |
Matt Rosencrantz | 9db8bc3 | 2015-01-13 09:01:55 -0800 | [diff] [blame] | 368 | |
Suharsh Sivakumar | 2ad4e10 | 2015-03-17 21:23:37 -0700 | [diff] [blame] | 369 | p, _ := ctx.Value(principalKey).(security.Principal) |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 370 | sm, _ := ctx.Value(streamManagerKey).(stream.Manager) |
Todd Wang | 5082a55 | 2015-04-02 10:56:11 -0700 | [diff] [blame] | 371 | ns, _ := ctx.Value(namespaceKey).(namespace.T) |
Matt Rosencrantz | bf0d9d9 | 2015-04-08 12:43:14 -0700 | [diff] [blame] | 372 | otherOpts = append(otherOpts, imanager.DialTimeout(5*time.Minute)) |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 373 | |
Matt Rosencrantz | bf0d9d9 | 2015-04-08 12:43:14 -0700 | [diff] [blame] | 374 | if id, _ := ctx.Value(initKey).(*initData); id.protocols != nil { |
| 375 | otherOpts = append(otherOpts, irpc.PreferredProtocols(id.protocols)) |
Matt Rosencrantz | 9db8bc3 | 2015-01-13 09:01:55 -0800 | [diff] [blame] | 376 | } |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 377 | client, err := irpc.InternalNewClient(sm, ns, otherOpts...) |
Matt Rosencrantz | aeed5d5 | 2015-01-14 15:18:34 -0800 | [diff] [blame] | 378 | if err != nil { |
| 379 | return ctx, nil, err |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 380 | } |
Matt Rosencrantz | 1932912 | 2015-01-23 22:18:49 -0800 | [diff] [blame] | 381 | newctx := context.WithValue(ctx, clientKey, client) |
Matt Rosencrantz | 3dc0196 | 2015-03-16 14:16:01 -0700 | [diff] [blame] | 382 | deps := []interface{}{sm, vtraceDependency{}} |
| 383 | if p != nil { |
| 384 | deps = append(deps, p) |
| 385 | } |
| 386 | if err = r.addChild(ctx, client, client.Close, deps...); err != nil { |
Matt Rosencrantz | aeed5d5 | 2015-01-14 15:18:34 -0800 | [diff] [blame] | 387 | return ctx, nil, err |
| 388 | } |
| 389 | return newctx, client, err |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 390 | } |
| 391 | |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 392 | func (*Runtime) GetClient(ctx *context.T) rpc.Client { |
Cosmos Nicolaou | 0e4e392 | 2015-06-10 16:30:09 -0700 | [diff] [blame] | 393 | // nologcall |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 394 | cl, _ := ctx.Value(clientKey).(rpc.Client) |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 395 | return cl |
| 396 | } |
| 397 | |
Todd Wang | 5082a55 | 2015-04-02 10:56:11 -0700 | [diff] [blame] | 398 | func (r *Runtime) setNewNamespace(ctx *context.T, roots ...string) (*context.T, namespace.T, error) { |
| 399 | ns, err := inamespace.New(roots...) |
Asim Shankar | 263c73b | 2015-03-19 18:31:26 -0700 | [diff] [blame] | 400 | if err != nil { |
| 401 | return nil, nil, err |
| 402 | } |
Matt Rosencrantz | 001644e | 2015-01-29 14:24:48 -0800 | [diff] [blame] | 403 | |
| 404 | if oldNS := r.GetNamespace(ctx); oldNS != nil { |
| 405 | ns.CacheCtl(oldNS.CacheCtl()...) |
| 406 | } |
| 407 | |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 408 | if err == nil { |
| 409 | ctx = context.WithValue(ctx, namespaceKey, ns) |
| 410 | } |
| 411 | return ctx, ns, err |
| 412 | } |
| 413 | |
Todd Wang | ad49204 | 2015-04-17 15:58:40 -0700 | [diff] [blame] | 414 | func (r *Runtime) WithNewNamespace(ctx *context.T, roots ...string) (*context.T, namespace.T, error) { |
Cosmos Nicolaou | f3c1909 | 2015-05-27 17:53:37 -0700 | [diff] [blame] | 415 | defer apilog.LogCallf(ctx, "roots...=%v", roots)(ctx, "") // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 416 | newctx, ns, err := r.setNewNamespace(ctx, roots...) |
| 417 | if err != nil { |
| 418 | return ctx, nil, err |
| 419 | } |
| 420 | |
| 421 | // Replace the client since it depends on the namespace. |
Todd Wang | ad49204 | 2015-04-17 15:58:40 -0700 | [diff] [blame] | 422 | newctx, _, err = r.WithNewClient(newctx) |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 423 | if err != nil { |
| 424 | return ctx, nil, err |
| 425 | } |
| 426 | |
| 427 | return newctx, ns, err |
| 428 | } |
| 429 | |
Todd Wang | 5082a55 | 2015-04-02 10:56:11 -0700 | [diff] [blame] | 430 | func (*Runtime) GetNamespace(ctx *context.T) namespace.T { |
Cosmos Nicolaou | ffc646e | 2015-05-06 22:33:51 -0700 | [diff] [blame] | 431 | // nologcall |
Todd Wang | 5082a55 | 2015-04-02 10:56:11 -0700 | [diff] [blame] | 432 | ns, _ := ctx.Value(namespaceKey).(namespace.T) |
Matt Rosencrantz | 5845bf1 | 2015-01-06 13:05:21 -0800 | [diff] [blame] | 433 | return ns |
| 434 | } |
| 435 | |
Jiri Simsa | 6ac9522 | 2015-02-23 16:11:49 -0800 | [diff] [blame] | 436 | func (*Runtime) GetAppCycle(ctx *context.T) v23.AppCycle { |
Cosmos Nicolaou | ffc646e | 2015-05-06 22:33:51 -0700 | [diff] [blame] | 437 | // nologcall |
Matt Rosencrantz | bf0d9d9 | 2015-04-08 12:43:14 -0700 | [diff] [blame] | 438 | id, _ := ctx.Value(initKey).(*initData) |
| 439 | return id.appCycle |
Suharsh Sivakumar | 033a30e | 2015-01-07 13:54:43 -0800 | [diff] [blame] | 440 | } |
| 441 | |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 442 | func (*Runtime) GetListenSpec(ctx *context.T) rpc.ListenSpec { |
Cosmos Nicolaou | ffc646e | 2015-05-06 22:33:51 -0700 | [diff] [blame] | 443 | // nologcall |
Matt Rosencrantz | bf0d9d9 | 2015-04-08 12:43:14 -0700 | [diff] [blame] | 444 | if id, _ := ctx.Value(initKey).(*initData); id.listenSpec != nil { |
| 445 | return id.listenSpec.Copy() |
| 446 | } |
| 447 | return rpc.ListenSpec{} |
Suharsh Sivakumar | ac9feed | 2015-01-08 10:58:37 -0800 | [diff] [blame] | 448 | } |
Matt Rosencrantz | 3838c55 | 2015-01-15 13:04:53 -0800 | [diff] [blame] | 449 | |
Todd Wang | ad49204 | 2015-04-17 15:58:40 -0700 | [diff] [blame] | 450 | func (*Runtime) WithBackgroundContext(ctx *context.T) *context.T { |
Cosmos Nicolaou | 0e4e392 | 2015-06-10 16:30:09 -0700 | [diff] [blame] | 451 | // nologcall |
Matt Rosencrantz | 3838c55 | 2015-01-15 13:04:53 -0800 | [diff] [blame] | 452 | // Note we add an extra context with a nil value here. |
| 453 | // This prevents users from travelling back through the |
| 454 | // chain of background contexts. |
| 455 | ctx = context.WithValue(ctx, backgroundKey, nil) |
| 456 | return context.WithValue(ctx, backgroundKey, ctx) |
| 457 | } |
| 458 | |
Matt Rosencrantz | ba470a5 | 2015-01-26 13:36:13 -0800 | [diff] [blame] | 459 | func (*Runtime) GetBackgroundContext(ctx *context.T) *context.T { |
Cosmos Nicolaou | ffc646e | 2015-05-06 22:33:51 -0700 | [diff] [blame] | 460 | // nologcall |
Matt Rosencrantz | 3838c55 | 2015-01-15 13:04:53 -0800 | [diff] [blame] | 461 | bctx, _ := ctx.Value(backgroundKey).(*context.T) |
| 462 | if bctx == nil { |
| 463 | // There should always be a background context. If we don't find |
| 464 | // it, that means that the user passed us the background context |
| 465 | // in hopes of following the chain. Instead we just give them |
| 466 | // back what they sent in, which is correct. |
| 467 | return ctx |
| 468 | } |
| 469 | return bctx |
| 470 | } |
Robert Kroeger | 316442c | 2015-03-26 13:56:11 -0700 | [diff] [blame] | 471 | |
Todd Wang | ad49204 | 2015-04-17 15:58:40 -0700 | [diff] [blame] | 472 | func (*Runtime) WithReservedNameDispatcher(ctx *context.T, d rpc.Dispatcher) *context.T { |
Cosmos Nicolaou | 0e4e392 | 2015-06-10 16:30:09 -0700 | [diff] [blame] | 473 | // nologcall |
Matt Rosencrantz | bf0d9d9 | 2015-04-08 12:43:14 -0700 | [diff] [blame] | 474 | return context.WithValue(ctx, reservedNameKey, d) |
Robert Kroeger | 316442c | 2015-03-26 13:56:11 -0700 | [diff] [blame] | 475 | } |
| 476 | |
| 477 | func (*Runtime) GetReservedNameDispatcher(ctx *context.T) rpc.Dispatcher { |
Cosmos Nicolaou | ffc646e | 2015-05-06 22:33:51 -0700 | [diff] [blame] | 478 | // nologcall |
Matt Rosencrantz | bf0d9d9 | 2015-04-08 12:43:14 -0700 | [diff] [blame] | 479 | if d, ok := ctx.Value(reservedNameKey).(rpc.Dispatcher); ok { |
| 480 | return d |
Robert Kroeger | 316442c | 2015-03-26 13:56:11 -0700 | [diff] [blame] | 481 | } |
| 482 | return nil |
| 483 | } |