@@ -60,6 +60,7 @@ import (
6060 "io"
6161 "log"
6262 "net"
63+ "sync"
6364 "time"
6465)
6566
@@ -69,6 +70,7 @@ import (
6970// The order that routes are added in matters; each is matched in the order
7071// registered.
7172type Proxy struct {
73+ mu sync.Mutex
7274 configs map [string ]* config // ip:port => config
7375
7476 lns []net.Listener
@@ -81,6 +83,14 @@ type Proxy struct {
8183 ListenFunc func (net , laddr string ) (net.Listener , error )
8284}
8385
86+ //
87+ //func (p *Proxy) Configs() map[string]*config {
88+ // p.mu.Lock()
89+ // defer p.mu.Unlock()
90+ //
91+ // return p.configs
92+ //}
93+
8494// Matcher reports whether hostname matches the Matcher's criteria.
8595type Matcher func (ctx context.Context , hostname string ) bool
8696
@@ -93,11 +103,42 @@ func equals(want string) Matcher {
93103
94104// config contains the proxying state for one listener.
95105type config struct {
106+ mu sync.Mutex
107+
96108 routes []route
97109 acmeTargets []Target // accumulates targets that should be probed for acme.
98110 stopACME bool // if true, AddSNIRoute doesn't add targets to acmeTargets.
99111}
100112
113+ func (c * config ) AddRoute (r route ) {
114+ c .mu .Lock ()
115+ defer c .mu .Unlock ()
116+
117+ c .routes = append (c .routes , r )
118+ }
119+
120+ func (c * config ) Routes () []route {
121+ c .mu .Lock ()
122+ defer c .mu .Unlock ()
123+
124+ return c .routes
125+ }
126+
127+ func (c * config ) RemoveRoute (r route ) {
128+ c .mu .Lock ()
129+ defer c .mu .Unlock ()
130+
131+ var newRoutes []route
132+
133+ for _ , i := range c .routes {
134+ if i != r {
135+ newRoutes = append (newRoutes , i )
136+ }
137+ }
138+
139+ c .routes = newRoutes
140+ }
141+
101142// A route matches a connection to a target.
102143type route interface {
103144 // match examines the initial bytes of a connection, looking for a
@@ -121,6 +162,9 @@ func (p *Proxy) netListen() func(net, laddr string) (net.Listener, error) {
121162}
122163
123164func (p * Proxy ) configFor (ipPort string ) * config {
165+ p .mu .Lock ()
166+ defer p .mu .Unlock ()
167+
124168 if p .configs == nil {
125169 p .configs = make (map [string ]* config )
126170 }
@@ -130,9 +174,20 @@ func (p *Proxy) configFor(ipPort string) *config {
130174 return p .configs [ipPort ]
131175}
132176
177+ func (p * Proxy ) configExists (ipPort string ) bool {
178+ return p .configs [ipPort ] != nil
179+ }
180+
133181func (p * Proxy ) addRoute (ipPort string , r route ) {
134182 cfg := p .configFor (ipPort )
135- cfg .routes = append (cfg .routes , r )
183+ cfg .AddRoute (r )
184+ }
185+
186+ func (p * Proxy ) removeRoute (ipPort string , r route ) {
187+ if p .configExists (ipPort ) {
188+ cfg := p .configFor (ipPort )
189+ cfg .RemoveRoute (r )
190+ }
136191}
137192
138193// AddRoute appends an always-matching route to the ipPort listener,
@@ -146,6 +201,13 @@ func (p *Proxy) AddRoute(ipPort string, dest Target) {
146201 p .addRoute (ipPort , fixedTarget {dest })
147202}
148203
204+ // RemoveRoute removes the specified target from the ipPort listener
205+ //
206+ // This method won't remove an ipPort listener if there are no routes remaining
207+ func (p * Proxy ) RemoveRoute (ipPort string , dest Target ) {
208+ p .removeRoute (ipPort , fixedTarget {dest })
209+ }
210+
149211type fixedTarget struct {
150212 t Target
151213}
@@ -200,7 +262,7 @@ func (p *Proxy) Start() error {
200262 return err
201263 }
202264 p .lns = append (p .lns , ln )
203- go p .serveListener (errc , ln , config . routes )
265+ go p .serveListener (errc , ln , config )
204266 }
205267 go p .awaitFirstError (errc )
206268 return nil
@@ -211,22 +273,22 @@ func (p *Proxy) awaitFirstError(errc <-chan error) {
211273 close (p .donec )
212274}
213275
214- func (p * Proxy ) serveListener (ret chan <- error , ln net.Listener , routes [] route ) {
276+ func (p * Proxy ) serveListener (ret chan <- error , ln net.Listener , cfg * config ) {
215277 for {
216278 c , err := ln .Accept ()
217279 if err != nil {
218280 ret <- err
219281 return
220282 }
221- go p .serveConn (c , routes )
283+ go p .serveConn (c , cfg )
222284 }
223285}
224286
225287// serveConn runs in its own goroutine and matches c against routes.
226288// It returns whether it matched purely for testing.
227- func (p * Proxy ) serveConn (c net.Conn , routes [] route ) bool {
289+ func (p * Proxy ) serveConn (c net.Conn , cfg * config ) bool {
228290 br := bufio .NewReader (c )
229- for _ , route := range routes {
291+ for _ , route := range cfg . Routes () {
230292 if target , hostName := route .match (br ); target != nil {
231293 if n := br .Buffered (); n > 0 {
232294 peeked , _ := br .Peek (br .Buffered ())
0 commit comments