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