Просмотр исходного кода

Use an explicit stop signal to gracefully stop HTTP proxy without spurious error message

Rod Hynes 11 лет назад
Родитель
Сommit
5aaeeb93ba
1 измененных файлов с 23 добавлено и 13 удалено
  1. 23 13
      psiphon/httpProxy.go

+ 23 - 13
psiphon/httpProxy.go

@@ -31,11 +31,12 @@ import (
 // HttpProxy is a HTTP server that relays HTTP requests through
 // the tunnel SSH client.
 type HttpProxy struct {
-	tunneler       Tunneler
-	listener       net.Listener
-	serveWaitGroup *sync.WaitGroup
-	httpRelay      *http.Transport
-	openConns      *Conns
+	tunneler               Tunneler
+	listener               net.Listener
+	serveWaitGroup         *sync.WaitGroup
+	httpRelay              *http.Transport
+	openConns              *Conns
+	stopListeningBroadcast chan struct{}
 }
 
 // NewHttpProxy initializes and runs a new HTTP proxy server.
@@ -56,11 +57,12 @@ func NewHttpProxy(config *Config, tunneler Tunneler) (proxy *HttpProxy, err erro
 		ResponseHeaderTimeout: HTTP_PROXY_ORIGIN_SERVER_TIMEOUT,
 	}
 	proxy = &HttpProxy{
-		tunneler:       tunneler,
-		listener:       listener,
-		serveWaitGroup: new(sync.WaitGroup),
-		httpRelay:      transport,
-		openConns:      new(Conns),
+		tunneler:               tunneler,
+		listener:               listener,
+		serveWaitGroup:         new(sync.WaitGroup),
+		httpRelay:              transport,
+		openConns:              new(Conns),
+		stopListeningBroadcast: make(chan struct{}),
 	}
 	proxy.serveWaitGroup.Add(1)
 	go proxy.serve()
@@ -70,6 +72,7 @@ func NewHttpProxy(config *Config, tunneler Tunneler) (proxy *HttpProxy, err erro
 
 // Close terminates the HTTP server.
 func (proxy *HttpProxy) Close() {
+	close(proxy.stopListeningBroadcast)
 	proxy.listener.Close()
 	proxy.serveWaitGroup.Wait()
 	// Close local->proxy persistent connections
@@ -226,9 +229,16 @@ func (proxy *HttpProxy) serve() {
 	}
 	// Note: will be interrupted by listener.Close() call made by proxy.Close()
 	err := httpServer.Serve(proxy.listener)
-	if err != nil {
-		proxy.tunneler.SignalFailure()
-		Notice(NOTICE_ALERT, "%s", ContextError(err))
+	// Can't check for the exact error that Close() will cause in Accept(),
+	// (see: https://code.google.com/p/go/issues/detail?id=4373). So using an
+	// explicit stop signal to stop gracefully.
+	select {
+	case <-proxy.stopListeningBroadcast:
+	default:
+		if err != nil {
+			proxy.tunneler.SignalFailure()
+			Notice(NOTICE_ALERT, "%s", ContextError(err))
+		}
 	}
 	Notice(NOTICE_HTTP_PROXY, "HTTP proxy stopped")
 }