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 | |
Suharsh Sivakumar | 3f0eaf9 | 2015-01-15 09:48:44 -0800 | [diff] [blame] | 5 | // +build linux darwin |
| 6 | |
| 7 | // Package roaming provides a network-aware Profile that provides appropriate |
| 8 | // options and configuration for a variety of network configurations, including |
| 9 | // being behind 1-1 NATs, using dhcp and auto-configuration for being on |
| 10 | // Google Compute Engine. |
| 11 | // |
| 12 | // The config.Publisher mechanism is used for communicating networking |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 13 | // settings to the rpc.Server implementation of the runtime and publishes |
Suharsh Sivakumar | 3f0eaf9 | 2015-01-15 09:48:44 -0800 | [diff] [blame] | 14 | // the Settings it expects. |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 15 | package roaming |
| 16 | |
| 17 | import ( |
| 18 | "flag" |
| 19 | |
Jiri Simsa | 6ac9522 | 2015-02-23 16:11:49 -0800 | [diff] [blame] | 20 | "v.io/v23" |
| 21 | "v.io/v23/config" |
| 22 | "v.io/v23/context" |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 23 | "v.io/v23/rpc" |
Jiri Simsa | 337af23 | 2015-02-27 14:36:46 -0800 | [diff] [blame] | 24 | "v.io/x/lib/vlog" |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 25 | |
Matt Rosencrantz | 9d3278a | 2015-03-11 14:58:34 -0700 | [diff] [blame] | 26 | "v.io/x/lib/netconfig" |
| 27 | "v.io/x/lib/netstate" |
Jiri Simsa | ffceefa | 2015-02-28 11:03:34 -0800 | [diff] [blame] | 28 | "v.io/x/ref/lib/flags" |
Jiri Simsa | ffceefa | 2015-02-28 11:03:34 -0800 | [diff] [blame] | 29 | "v.io/x/ref/profiles/internal" |
Matt Rosencrantz | 86ba1a1 | 2015-03-09 13:19:02 -0700 | [diff] [blame] | 30 | "v.io/x/ref/profiles/internal/lib/appcycle" |
| 31 | "v.io/x/ref/profiles/internal/lib/websocket" |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 32 | _ "v.io/x/ref/profiles/internal/rpc/protocols/tcp" |
| 33 | _ "v.io/x/ref/profiles/internal/rpc/protocols/ws" |
| 34 | _ "v.io/x/ref/profiles/internal/rpc/protocols/wsh" |
Matt Rosencrantz | dbc1be2 | 2015-02-28 15:15:49 -0800 | [diff] [blame] | 35 | grt "v.io/x/ref/profiles/internal/rt" |
Jiri Simsa | ffceefa | 2015-02-28 11:03:34 -0800 | [diff] [blame] | 36 | "v.io/x/ref/services/mgmt/debug" |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 37 | |
| 38 | // TODO(cnicolaou,ashankar): move this into flags. |
Jiri Simsa | ffceefa | 2015-02-28 11:03:34 -0800 | [diff] [blame] | 39 | sflag "v.io/x/ref/security/flag" |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 40 | ) |
| 41 | |
| 42 | const ( |
| 43 | SettingsStreamName = "roaming" |
| 44 | ) |
| 45 | |
Suharsh Sivakumar | d68949c | 2015-01-26 10:32:23 -0800 | [diff] [blame] | 46 | var commonFlags *flags.Flags |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 47 | |
| 48 | func init() { |
Suharsh Sivakumar | c6f38e9 | 2015-03-31 13:04:06 -0700 | [diff] [blame] | 49 | v23.RegisterProfile(Init) |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 50 | rpc.RegisterUnknownProtocol("wsh", websocket.HybridDial, websocket.HybridListener) |
Suharsh Sivakumar | d68949c | 2015-01-26 10:32:23 -0800 | [diff] [blame] | 51 | commonFlags = flags.CreateAndRegister(flag.CommandLine, flags.Runtime, flags.Listen) |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 52 | } |
| 53 | |
Jiri Simsa | 6ac9522 | 2015-02-23 16:11:49 -0800 | [diff] [blame] | 54 | func Init(ctx *context.T) (v23.Runtime, *context.T, v23.Shutdown, error) { |
Suharsh Sivakumar | d68949c | 2015-01-26 10:32:23 -0800 | [diff] [blame] | 55 | if err := internal.ParseFlags(commonFlags); err != nil { |
Matt Rosencrantz | 1b79391 | 2015-01-23 13:32:53 -0800 | [diff] [blame] | 56 | return nil, nil, nil, err |
| 57 | } |
Suharsh Sivakumar | d68949c | 2015-01-26 10:32:23 -0800 | [diff] [blame] | 58 | |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 59 | lf := commonFlags.ListenFlags() |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 60 | listenSpec := rpc.ListenSpec{ |
| 61 | Addrs: rpc.ListenAddrs(lf.Addrs), |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 62 | Proxy: lf.ListenProxy, |
| 63 | } |
Robin Thellend | 67d95cb | 2015-02-13 11:02:14 -0800 | [diff] [blame] | 64 | reservedDispatcher := debug.NewDispatcher(vlog.Log.LogDir, sflag.NewAuthorizerOrDie()) |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 65 | |
Suharsh Sivakumar | eb0e296 | 2015-01-15 11:24:11 -0800 | [diff] [blame] | 66 | ac := appcycle.New() |
Suharsh Sivakumar | eb0e296 | 2015-01-15 11:24:11 -0800 | [diff] [blame] | 67 | |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 68 | // Our address is private, so we test for running on GCE and for its |
| 69 | // 1:1 NAT configuration. |
Suharsh Sivakumar | d68949c | 2015-01-26 10:32:23 -0800 | [diff] [blame] | 70 | if !internal.HasPublicIP(vlog.Log) { |
| 71 | if addr := internal.GCEPublicAddress(vlog.Log); addr != nil { |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 72 | listenSpec.AddressChooser = func(string, []rpc.Address) ([]rpc.Address, error) { |
| 73 | return []rpc.Address{&netstate.AddrIfc{addr, "nat", nil}}, nil |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 74 | } |
Suharsh Sivakumar | d68949c | 2015-01-26 10:32:23 -0800 | [diff] [blame] | 75 | runtime, ctx, shutdown, err := grt.Init(ctx, ac, nil, &listenSpec, commonFlags.RuntimeFlags(), reservedDispatcher) |
Suharsh Sivakumar | d5049b7 | 2015-01-21 14:11:35 -0800 | [diff] [blame] | 76 | if err != nil { |
| 77 | return nil, nil, shutdown, err |
| 78 | } |
| 79 | profileShutdown := func() { |
| 80 | ac.Shutdown() |
| 81 | shutdown() |
| 82 | } |
| 83 | return runtime, ctx, profileShutdown, nil |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 84 | } |
| 85 | } |
| 86 | |
Suharsh Sivakumar | d5049b7 | 2015-01-21 14:11:35 -0800 | [diff] [blame] | 87 | publisher := config.NewPublisher() |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 88 | |
| 89 | // Create stream in Init function to avoid a race between any |
| 90 | // goroutines started here and consumers started after Init returns. |
| 91 | ch := make(chan config.Setting) |
| 92 | stop, err := publisher.CreateStream(SettingsStreamName, SettingsStreamName, ch) |
| 93 | if err != nil { |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 94 | ac.Shutdown() |
Suharsh Sivakumar | d5049b7 | 2015-01-21 14:11:35 -0800 | [diff] [blame] | 95 | return nil, nil, nil, err |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 96 | } |
| 97 | |
| 98 | prev, err := netstate.GetAccessibleIPs() |
| 99 | if err != nil { |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 100 | ac.Shutdown() |
Suharsh Sivakumar | d5049b7 | 2015-01-21 14:11:35 -0800 | [diff] [blame] | 101 | return nil, nil, nil, err |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 102 | } |
| 103 | |
| 104 | // Start the dhcp watcher. |
| 105 | watcher, err := netconfig.NewNetConfigWatcher() |
| 106 | if err != nil { |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 107 | ac.Shutdown() |
Suharsh Sivakumar | d5049b7 | 2015-01-21 14:11:35 -0800 | [diff] [blame] | 108 | return nil, nil, nil, err |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 109 | } |
| 110 | |
| 111 | cleanupCh := make(chan struct{}) |
| 112 | watcherCh := make(chan struct{}) |
| 113 | |
Matt Rosencrantz | 99cc06e | 2015-01-16 10:25:11 -0800 | [diff] [blame] | 114 | listenSpec.StreamPublisher = publisher |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 115 | listenSpec.StreamName = SettingsStreamName |
| 116 | listenSpec.AddressChooser = internal.IPAddressChooser |
| 117 | |
Suharsh Sivakumar | d68949c | 2015-01-26 10:32:23 -0800 | [diff] [blame] | 118 | runtime, ctx, shutdown, err := grt.Init(ctx, ac, nil, &listenSpec, commonFlags.RuntimeFlags(), reservedDispatcher) |
Suharsh Sivakumar | d5049b7 | 2015-01-21 14:11:35 -0800 | [diff] [blame] | 119 | if err != nil { |
| 120 | return nil, nil, shutdown, err |
| 121 | } |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 122 | |
Matt Rosencrantz | 99cc06e | 2015-01-16 10:25:11 -0800 | [diff] [blame] | 123 | go monitorNetworkSettingsX(runtime, ctx, watcher, prev, stop, cleanupCh, watcherCh, ch) |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 124 | profileShutdown := func() { |
| 125 | close(cleanupCh) |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 126 | ac.Shutdown() |
Suharsh Sivakumar | d5049b7 | 2015-01-21 14:11:35 -0800 | [diff] [blame] | 127 | shutdown() |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 128 | <-watcherCh |
| 129 | } |
| 130 | return runtime, ctx, profileShutdown, nil |
| 131 | } |
| 132 | |
| 133 | // monitorNetworkSettings will monitor network configuration changes and |
| 134 | // publish subsequent Settings to reflect any changes detected. |
Matt Rosencrantz | 99cc06e | 2015-01-16 10:25:11 -0800 | [diff] [blame] | 135 | func monitorNetworkSettingsX( |
Matt Rosencrantz | ba470a5 | 2015-01-26 13:36:13 -0800 | [diff] [blame] | 136 | runtime *grt.Runtime, |
Matt Rosencrantz | 99cc06e | 2015-01-16 10:25:11 -0800 | [diff] [blame] | 137 | ctx *context.T, |
| 138 | watcher netconfig.NetConfigWatcher, |
| 139 | prev netstate.AddrList, |
| 140 | pubStop, cleanup <-chan struct{}, |
| 141 | watcherLoop chan<- struct{}, |
| 142 | ch chan<- config.Setting) { |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 143 | defer close(ch) |
| 144 | |
Matt Rosencrantz | 99cc06e | 2015-01-16 10:25:11 -0800 | [diff] [blame] | 145 | listenSpec := runtime.GetListenSpec(ctx) |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 146 | |
| 147 | // TODO(cnicolaou): add support for listening on multiple network addresses. |
| 148 | |
| 149 | done: |
| 150 | for { |
| 151 | select { |
| 152 | case <-watcher.Channel(): |
| 153 | cur, err := netstate.GetAccessibleIPs() |
| 154 | if err != nil { |
Matt Rosencrantz | 97d67a9 | 2015-01-27 21:03:12 -0800 | [diff] [blame] | 155 | vlog.Errorf("failed to read network state: %s", err) |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 156 | continue |
| 157 | } |
| 158 | removed := netstate.FindRemoved(prev, cur) |
| 159 | added := netstate.FindAdded(prev, cur) |
Matt Rosencrantz | 97d67a9 | 2015-01-27 21:03:12 -0800 | [diff] [blame] | 160 | vlog.VI(2).Infof("Previous: %d: %s", len(prev), prev) |
| 161 | vlog.VI(2).Infof("Current : %d: %s", len(cur), cur) |
| 162 | vlog.VI(2).Infof("Added : %d: %s", len(added), added) |
| 163 | vlog.VI(2).Infof("Removed : %d: %s", len(removed), removed) |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 164 | if len(removed) == 0 && len(added) == 0 { |
Matt Rosencrantz | 97d67a9 | 2015-01-27 21:03:12 -0800 | [diff] [blame] | 165 | vlog.VI(2).Infof("Network event that lead to no address changes since our last 'baseline'") |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 166 | continue |
| 167 | } |
| 168 | if len(removed) > 0 { |
Matt Rosencrantz | 97d67a9 | 2015-01-27 21:03:12 -0800 | [diff] [blame] | 169 | vlog.VI(2).Infof("Sending removed: %s", removed) |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 170 | ch <- rpc.NewRmAddrsSetting(removed) |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 171 | } |
| 172 | // We will always send the best currently available address |
| 173 | if chosen, err := listenSpec.AddressChooser(listenSpec.Addrs[0].Protocol, cur); err == nil && chosen != nil { |
Cosmos Nicolaou | 1b3594d | 2015-02-01 10:05:03 -0800 | [diff] [blame] | 174 | vlog.VI(2).Infof("Sending added and chosen: %s", chosen) |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 175 | ch <- rpc.NewAddAddrsSetting(chosen) |
Cosmos Nicolaou | 1b3594d | 2015-02-01 10:05:03 -0800 | [diff] [blame] | 176 | } else { |
| 177 | vlog.VI(2).Infof("Ignoring added %s", added) |
Suharsh Sivakumar | 98aa48c | 2015-01-14 16:11:30 -0800 | [diff] [blame] | 178 | } |
| 179 | prev = cur |
| 180 | case <-cleanup: |
| 181 | break done |
| 182 | case <-pubStop: |
| 183 | goto done |
| 184 | } |
| 185 | } |
| 186 | watcher.Stop() |
| 187 | close(watcherLoop) |
| 188 | } |