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