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