diff --git a/internal/shadowsocks/loop.go b/internal/shadowsocks/loop.go index a375b6a4..281dfc6f 100644 --- a/internal/shadowsocks/loop.go +++ b/internal/shadowsocks/loop.go @@ -16,20 +16,23 @@ type Looper interface { Restart() Start() Stop() + GetSettings() (settings settings.ShadowSocks) + SetSettings(settings settings.ShadowSocks) } type looper struct { - conf Configurator - firewallConf firewall.Configurator - settings settings.ShadowSocks - dnsSettings settings.DNS - logger logging.Logger - streamMerger command.StreamMerger - uid int - gid int - restart chan struct{} - start chan struct{} - stop chan struct{} + conf Configurator + firewallConf firewall.Configurator + settings settings.ShadowSocks + settingsMutex sync.RWMutex + dnsSettings settings.DNS // TODO + logger logging.Logger + streamMerger command.StreamMerger + uid int + gid int + restart chan struct{} + start chan struct{} + stop chan struct{} } func (l *looper) logAndWait(ctx context.Context, err error) { @@ -61,6 +64,30 @@ func (l *looper) Restart() { l.restart <- struct{}{} } func (l *looper) Start() { l.start <- struct{}{} } func (l *looper) Stop() { l.stop <- struct{}{} } +func (l *looper) GetSettings() (settings settings.ShadowSocks) { + l.settingsMutex.RLock() + defer l.settingsMutex.RUnlock() + return l.settings +} + +func (l *looper) SetSettings(settings settings.ShadowSocks) { + l.settingsMutex.Lock() + defer l.settingsMutex.Unlock() + l.settings = settings +} + +func (l *looper) isEnabled() bool { + l.settingsMutex.RLock() + defer l.settingsMutex.RUnlock() + return l.settings.Enabled +} + +func (l *looper) setEnabled(enabled bool) { + l.settingsMutex.Lock() + defer l.settingsMutex.Unlock() + l.settings.Enabled = enabled +} + func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) { wg.Add(1) defer wg.Done() @@ -79,19 +106,19 @@ func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) { } defer l.logger.Warn("loop exited") - l.settings.Enabled = true + l.setEnabled(true) var previousPort uint16 for ctx.Err() == nil { - for !l.settings.Enabled { + for !l.isEnabled() { // wait for a signal to re-enable select { case <-l.stop: l.logger.Info("already disabled") case <-l.restart: - l.settings.Enabled = true + l.setEnabled(true) case <-l.start: - l.settings.Enabled = true + l.setEnabled(true) case <-ctx.Done(): return } @@ -101,13 +128,8 @@ func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) { if l.dnsSettings.Enabled { nameserver = "127.0.0.1" } - err := l.conf.MakeConf( - l.settings.Port, - l.settings.Password, - l.settings.Method, - nameserver, - l.uid, - l.gid) + settings := l.GetSettings() + err := l.conf.MakeConf(settings.Port, settings.Password, settings.Method, nameserver, l.uid, l.gid) if err != nil { l.logAndWait(ctx, err) continue @@ -119,14 +141,14 @@ func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) { continue } } - if err := l.firewallConf.SetAllowedPort(ctx, l.settings.Port); err != nil { + if err := l.firewallConf.SetAllowedPort(ctx, settings.Port); err != nil { l.logger.Error(err) continue } - previousPort = l.settings.Port + previousPort = settings.Port shadowsocksCtx, shadowsocksCancel := context.WithCancel(context.Background()) - stdout, stderr, waitFn, err := l.conf.Start(shadowsocksCtx, "0.0.0.0", l.settings.Port, l.settings.Password, l.settings.Log) + stdout, stderr, waitFn, err := l.conf.Start(shadowsocksCtx, "0.0.0.0", settings.Port, settings.Password, settings.Log) if err != nil { shadowsocksCancel() l.logAndWait(ctx, err) @@ -162,7 +184,7 @@ func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) { shadowsocksCancel() <-waitError close(waitError) - l.settings.Enabled = false + l.setEnabled(false) stayHere = false case err := <-waitError: // unexpected error shadowsocksCancel()