blob: adbe94b897d96a19849994bebd2d8a02e1e06585 [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
Jiri Simsa6ac95222015-02-23 16:11:49 -080016 "v.io/v23"
17 "v.io/v23/config"
18 "v.io/v23/context"
19 "v.io/v23/ipc"
Jiri Simsa337af232015-02-27 14:36:46 -080020 "v.io/x/lib/vlog"
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -080021
Jiri Simsaffceefa2015-02-28 11:03:34 -080022 "v.io/x/ref/lib/flags"
23 "v.io/x/ref/lib/netconfig"
24 "v.io/x/ref/lib/netstate"
Jiri Simsaffceefa2015-02-28 11:03:34 -080025 "v.io/x/ref/profiles/internal"
Matt Rosencrantzdbc1be22015-02-28 15:15:49 -080026 _ "v.io/x/ref/profiles/internal/ipc/protocols/tcp"
27 _ "v.io/x/ref/profiles/internal/ipc/protocols/ws"
28 _ "v.io/x/ref/profiles/internal/ipc/protocols/wsh"
Matt Rosencrantz86ba1a12015-03-09 13:19:02 -070029 "v.io/x/ref/profiles/internal/lib/appcycle"
30 "v.io/x/ref/profiles/internal/lib/websocket"
Matt Rosencrantzdbc1be22015-02-28 15:15:49 -080031 grt "v.io/x/ref/profiles/internal/rt"
Jiri Simsaffceefa2015-02-28 11:03:34 -080032 "v.io/x/ref/services/mgmt/debug"
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -080033
34 // TODO(cnicolaou,ashankar): move this into flags.
Jiri Simsaffceefa2015-02-28 11:03:34 -080035 sflag "v.io/x/ref/security/flag"
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -080036)
37
38const (
39 SettingsStreamName = "roaming"
40)
41
Suharsh Sivakumard68949c2015-01-26 10:32:23 -080042var commonFlags *flags.Flags
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -080043
44func init() {
Jiri Simsa6ac95222015-02-23 16:11:49 -080045 v23.RegisterProfileInit(Init)
Suharsh Sivakumaraf862a52015-02-04 13:50:47 -080046 ipc.RegisterUnknownProtocol("wsh", websocket.HybridDial, websocket.HybridListener)
Suharsh Sivakumard68949c2015-01-26 10:32:23 -080047 commonFlags = flags.CreateAndRegister(flag.CommandLine, flags.Runtime, flags.Listen)
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -080048}
49
Jiri Simsa6ac95222015-02-23 16:11:49 -080050func Init(ctx *context.T) (v23.Runtime, *context.T, v23.Shutdown, error) {
Suharsh Sivakumard68949c2015-01-26 10:32:23 -080051 if err := internal.ParseFlags(commonFlags); err != nil {
Matt Rosencrantz1b793912015-01-23 13:32:53 -080052 return nil, nil, nil, err
53 }
Suharsh Sivakumard68949c2015-01-26 10:32:23 -080054
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -080055 lf := commonFlags.ListenFlags()
56 listenSpec := ipc.ListenSpec{
57 Addrs: ipc.ListenAddrs(lf.Addrs),
58 Proxy: lf.ListenProxy,
59 }
Robin Thellend67d95cb2015-02-13 11:02:14 -080060 reservedDispatcher := debug.NewDispatcher(vlog.Log.LogDir, sflag.NewAuthorizerOrDie())
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -080061
Suharsh Sivakumareb0e2962015-01-15 11:24:11 -080062 ac := appcycle.New()
Suharsh Sivakumareb0e2962015-01-15 11:24:11 -080063
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -080064 // Our address is private, so we test for running on GCE and for its
65 // 1:1 NAT configuration.
Suharsh Sivakumard68949c2015-01-26 10:32:23 -080066 if !internal.HasPublicIP(vlog.Log) {
67 if addr := internal.GCEPublicAddress(vlog.Log); addr != nil {
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -080068 listenSpec.AddressChooser = func(string, []ipc.Address) ([]ipc.Address, error) {
69 return []ipc.Address{&netstate.AddrIfc{addr, "nat", nil}}, nil
70 }
Suharsh Sivakumard68949c2015-01-26 10:32:23 -080071 runtime, ctx, shutdown, err := grt.Init(ctx, ac, nil, &listenSpec, commonFlags.RuntimeFlags(), reservedDispatcher)
Suharsh Sivakumard5049b72015-01-21 14:11:35 -080072 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 Sivakumar98aa48c2015-01-14 16:11:30 -080080 }
81 }
82
Suharsh Sivakumard5049b72015-01-21 14:11:35 -080083 publisher := config.NewPublisher()
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -080084
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 Sivakumar98aa48c2015-01-14 16:11:30 -080090 ac.Shutdown()
Suharsh Sivakumard5049b72015-01-21 14:11:35 -080091 return nil, nil, nil, err
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -080092 }
93
94 prev, err := netstate.GetAccessibleIPs()
95 if err != nil {
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -080096 ac.Shutdown()
Suharsh Sivakumard5049b72015-01-21 14:11:35 -080097 return nil, nil, nil, err
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -080098 }
99
100 // Start the dhcp watcher.
101 watcher, err := netconfig.NewNetConfigWatcher()
102 if err != nil {
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -0800103 ac.Shutdown()
Suharsh Sivakumard5049b72015-01-21 14:11:35 -0800104 return nil, nil, nil, err
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -0800105 }
106
107 cleanupCh := make(chan struct{})
108 watcherCh := make(chan struct{})
109
Matt Rosencrantz99cc06e2015-01-16 10:25:11 -0800110 listenSpec.StreamPublisher = publisher
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -0800111 listenSpec.StreamName = SettingsStreamName
112 listenSpec.AddressChooser = internal.IPAddressChooser
113
Suharsh Sivakumard68949c2015-01-26 10:32:23 -0800114 runtime, ctx, shutdown, err := grt.Init(ctx, ac, nil, &listenSpec, commonFlags.RuntimeFlags(), reservedDispatcher)
Suharsh Sivakumard5049b72015-01-21 14:11:35 -0800115 if err != nil {
116 return nil, nil, shutdown, err
117 }
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -0800118
Matt Rosencrantz99cc06e2015-01-16 10:25:11 -0800119 go monitorNetworkSettingsX(runtime, ctx, watcher, prev, stop, cleanupCh, watcherCh, ch)
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -0800120 profileShutdown := func() {
121 close(cleanupCh)
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -0800122 ac.Shutdown()
Suharsh Sivakumard5049b72015-01-21 14:11:35 -0800123 shutdown()
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -0800124 <-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 Rosencrantz99cc06e2015-01-16 10:25:11 -0800131func monitorNetworkSettingsX(
Matt Rosencrantzba470a52015-01-26 13:36:13 -0800132 runtime *grt.Runtime,
Matt Rosencrantz99cc06e2015-01-16 10:25:11 -0800133 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 Sivakumar98aa48c2015-01-14 16:11:30 -0800139 defer close(ch)
140
Matt Rosencrantz99cc06e2015-01-16 10:25:11 -0800141 listenSpec := runtime.GetListenSpec(ctx)
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -0800142
143 // TODO(cnicolaou): add support for listening on multiple network addresses.
144
145done:
146 for {
147 select {
148 case <-watcher.Channel():
149 cur, err := netstate.GetAccessibleIPs()
150 if err != nil {
Matt Rosencrantz97d67a92015-01-27 21:03:12 -0800151 vlog.Errorf("failed to read network state: %s", err)
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -0800152 continue
153 }
154 removed := netstate.FindRemoved(prev, cur)
155 added := netstate.FindAdded(prev, cur)
Matt Rosencrantz97d67a92015-01-27 21:03:12 -0800156 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 Sivakumar98aa48c2015-01-14 16:11:30 -0800160 if len(removed) == 0 && len(added) == 0 {
Matt Rosencrantz97d67a92015-01-27 21:03:12 -0800161 vlog.VI(2).Infof("Network event that lead to no address changes since our last 'baseline'")
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -0800162 continue
163 }
164 if len(removed) > 0 {
Matt Rosencrantz97d67a92015-01-27 21:03:12 -0800165 vlog.VI(2).Infof("Sending removed: %s", removed)
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -0800166 ch <- ipc.NewRmAddrsSetting(removed)
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 Nicolaou1b3594d2015-02-01 10:05:03 -0800170 vlog.VI(2).Infof("Sending added and chosen: %s", chosen)
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -0800171 ch <- ipc.NewAddAddrsSetting(chosen)
Cosmos Nicolaou1b3594d2015-02-01 10:05:03 -0800172 } else {
173 vlog.VI(2).Infof("Ignoring added %s", added)
Suharsh Sivakumar98aa48c2015-01-14 16:11:30 -0800174 }
175 prev = cur
176 case <-cleanup:
177 break done
178 case <-pubStop:
179 goto done
180 }
181 }
182 watcher.Stop()
183 close(watcherLoop)
184}