blob: ae37ee95767463fb1e952b76452e0032dd71b296 [file] [log] [blame]
Suharsh Sivakumar3f0eaf92015-01-15 09:48:44 -08001// +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 Sivakumar98aa48c2015-01-14 16:11:30 -080011package roaming
12
13import (
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 LaCasse0a22b452015-01-22 09:57:15 -080020 "v.io/core/veyron2/ipc/stream"
Suharsh Sivakumard5049b72015-01-21 14:11:35 -080021 "v.io/core/veyron2/vlog"
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -080022
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 LaCasse0a22b452015-01-22 09:57:15 -080027 "v.io/core/veyron/lib/websocket"
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -080028 "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
39const (
40 SettingsStreamName = "roaming"
41)
42
Suharsh Sivakumard68949c2015-01-26 10:32:23 -080043var commonFlags *flags.Flags
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -080044
45func init() {
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -080046 veyron2.RegisterProfileInit(Init)
Nicolas LaCasse0a22b452015-01-22 09:57:15 -080047 stream.RegisterUnknownProtocol("wsh", websocket.HybridDial, websocket.HybridListener)
Suharsh Sivakumard68949c2015-01-26 10:32:23 -080048 commonFlags = flags.CreateAndRegister(flag.CommandLine, flags.Runtime, flags.Listen)
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -080049}
50
Matt Rosencrantzba470a52015-01-26 13:36:13 -080051func Init(ctx *context.T) (veyron2.Runtime, *context.T, veyron2.Shutdown, error) {
Suharsh Sivakumard68949c2015-01-26 10:32:23 -080052 if err := internal.ParseFlags(commonFlags); err != nil {
Matt Rosencrantz1b793912015-01-23 13:32:53 -080053 return nil, nil, nil, err
54 }
Suharsh Sivakumard68949c2015-01-26 10:32:23 -080055
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -080056 lf := commonFlags.ListenFlags()
57 listenSpec := ipc.ListenSpec{
58 Addrs: ipc.ListenAddrs(lf.Addrs),
59 Proxy: lf.ListenProxy,
60 }
Suharsh Sivakumard68949c2015-01-26 10:32:23 -080061 reservedDispatcher := debug.NewDispatcher(vlog.Log.LogDir(), sflag.NewAuthorizerOrDie())
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -080062
Suharsh Sivakumareb0e2962015-01-15 11:24:11 -080063 ac := appcycle.New()
Suharsh Sivakumareb0e2962015-01-15 11:24:11 -080064
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -080065 // Our address is private, so we test for running on GCE and for its
66 // 1:1 NAT configuration.
Suharsh Sivakumard68949c2015-01-26 10:32:23 -080067 if !internal.HasPublicIP(vlog.Log) {
68 if addr := internal.GCEPublicAddress(vlog.Log); addr != nil {
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -080069 listenSpec.AddressChooser = func(string, []ipc.Address) ([]ipc.Address, error) {
70 return []ipc.Address{&netstate.AddrIfc{addr, "nat", nil}}, nil
71 }
Suharsh Sivakumard68949c2015-01-26 10:32:23 -080072 runtime, ctx, shutdown, err := grt.Init(ctx, ac, nil, &listenSpec, commonFlags.RuntimeFlags(), reservedDispatcher)
Suharsh Sivakumard5049b72015-01-21 14:11:35 -080073 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 Sivakumar98aa48c2015-01-14 16:11:30 -080081 }
82 }
83
Suharsh Sivakumard5049b72015-01-21 14:11:35 -080084 publisher := config.NewPublisher()
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -080085
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 Sivakumar98aa48c2015-01-14 16:11:30 -080091 ac.Shutdown()
Suharsh Sivakumard5049b72015-01-21 14:11:35 -080092 return nil, nil, nil, err
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -080093 }
94
95 prev, err := netstate.GetAccessibleIPs()
96 if err != nil {
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -080097 ac.Shutdown()
Suharsh Sivakumard5049b72015-01-21 14:11:35 -080098 return nil, nil, nil, err
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -080099 }
100
101 // Start the dhcp watcher.
102 watcher, err := netconfig.NewNetConfigWatcher()
103 if err != nil {
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -0800104 ac.Shutdown()
Suharsh Sivakumard5049b72015-01-21 14:11:35 -0800105 return nil, nil, nil, err
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -0800106 }
107
108 cleanupCh := make(chan struct{})
109 watcherCh := make(chan struct{})
110
Matt Rosencrantz99cc06e2015-01-16 10:25:11 -0800111 listenSpec.StreamPublisher = publisher
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -0800112 listenSpec.StreamName = SettingsStreamName
113 listenSpec.AddressChooser = internal.IPAddressChooser
114
Suharsh Sivakumard68949c2015-01-26 10:32:23 -0800115 runtime, ctx, shutdown, err := grt.Init(ctx, ac, nil, &listenSpec, commonFlags.RuntimeFlags(), reservedDispatcher)
Suharsh Sivakumard5049b72015-01-21 14:11:35 -0800116 if err != nil {
117 return nil, nil, shutdown, err
118 }
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -0800119
Matt Rosencrantz99cc06e2015-01-16 10:25:11 -0800120 go monitorNetworkSettingsX(runtime, ctx, watcher, prev, stop, cleanupCh, watcherCh, ch)
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -0800121 profileShutdown := func() {
122 close(cleanupCh)
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -0800123 ac.Shutdown()
Suharsh Sivakumard5049b72015-01-21 14:11:35 -0800124 shutdown()
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -0800125 <-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 Rosencrantz99cc06e2015-01-16 10:25:11 -0800132func monitorNetworkSettingsX(
Matt Rosencrantzba470a52015-01-26 13:36:13 -0800133 runtime *grt.Runtime,
Matt Rosencrantz99cc06e2015-01-16 10:25:11 -0800134 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 Sivakumar98aa48c2015-01-14 16:11:30 -0800140 defer close(ch)
141
Matt Rosencrantz99cc06e2015-01-16 10:25:11 -0800142 listenSpec := runtime.GetListenSpec(ctx)
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -0800143
144 // TODO(cnicolaou): add support for listening on multiple network addresses.
145
146done:
147 for {
148 select {
149 case <-watcher.Channel():
150 cur, err := netstate.GetAccessibleIPs()
151 if err != nil {
Matt Rosencrantz97d67a92015-01-27 21:03:12 -0800152 vlog.Errorf("failed to read network state: %s", err)
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -0800153 continue
154 }
155 removed := netstate.FindRemoved(prev, cur)
156 added := netstate.FindAdded(prev, cur)
Matt Rosencrantz97d67a92015-01-27 21:03:12 -0800157 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 Sivakumar98aa48c2015-01-14 16:11:30 -0800161 if len(removed) == 0 && len(added) == 0 {
Matt Rosencrantz97d67a92015-01-27 21:03:12 -0800162 vlog.VI(2).Infof("Network event that lead to no address changes since our last 'baseline'")
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -0800163 continue
164 }
165 if len(removed) > 0 {
Matt Rosencrantz97d67a92015-01-27 21:03:12 -0800166 vlog.VI(2).Infof("Sending removed: %s", removed)
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -0800167 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 Nicolaou1b3594d2015-02-01 10:05:03 -0800171 vlog.VI(2).Infof("Sending added and chosen: %s", chosen)
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -0800172 ch <- ipc.NewAddAddrsSetting(chosen)
Cosmos Nicolaou1b3594d2015-02-01 10:05:03 -0800173 } else {
174 vlog.VI(2).Infof("Ignoring added %s", added)
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -0800175 }
176 prev = cur
177 case <-cleanup:
178 break done
179 case <-pubStop:
180 goto done
181 }
182 }
183 watcher.Stop()
184 close(watcherLoop)
185}