Browse Source

Recover any errors while handling tunnel connections. Fix a race condition that could cause the server to send its initial auth message out of order or even on a closed channel and crash the server

Alan Shreve 12 years ago
parent
commit
3af3e39b20
2 changed files with 14 additions and 4 deletions
  1. 6 4
      src/ngrok/server/control.go
  2. 8 0
      src/ngrok/server/main.go

+ 6 - 4
src/ngrok/server/control.go

@@ -103,11 +103,8 @@ func NewControl(ctlConn conn.Conn, authMsg *msg.Auth) {
 	// set logging prefix
 	ctlConn.SetType("ctl")
 
-	// manage the connection
-	go c.manager()
-	go c.reader()
+	// start the writer first so that the follow messages get sent
 	go c.writer()
-	go c.stopper()
 
 	// Respond to authentication
 	c.out <- &msg.AuthResp{
@@ -118,6 +115,11 @@ func NewControl(ctlConn conn.Conn, authMsg *msg.Auth) {
 
 	// As a performance optimization, ask for a proxy connection up front
 	c.out <- &msg.ReqProxy{}
+
+	// manage the connection
+	go c.manager()
+	go c.reader()
+	go c.stopper()
 }
 
 // Register a new tunnel on this control connection

+ 8 - 0
src/ngrok/server/main.go

@@ -8,6 +8,7 @@ import (
 	"ngrok/msg"
 	"ngrok/util"
 	"os"
+	"runtime/debug"
 	"time"
 )
 
@@ -64,6 +65,13 @@ func tunnelListener(addr string, tlsConfig *tls.Config) {
 	log.Info("Listening for control and proxy connections on %s", listener.Addr.String())
 	for c := range listener.Conns {
 		go func(tunnelConn conn.Conn) {
+			// don't crash on panics
+			defer func() {
+				if r := recover(); r != nil {
+					tunnelConn.Info("Control::manager failed with error %v: %s", r, debug.Stack())
+				}
+			}()
+
 			tunnelConn.SetReadDeadline(time.Now().Add(connReadTimeout))
 			var rawMsg msg.Message
 			if rawMsg, err = msg.ReadMsg(tunnelConn); err != nil {