Quellcode durchsuchen

Interrupt refraction_networking_tapdance.Dialer.Dial I/O

- refraction_networking_tapdance.Dialer.Dial may block
  on network I/O, such as TLS handshake.

- Use dialManager to interrupt by closing underlying
  network connections, just as its used to interrupt
  blocking I/O calls during tapdance protocol
  reconnections.
Rod Hynes vor 7 Jahren
Ursprung
Commit
1235e3184c
1 geänderte Dateien mit 35 neuen und 6 gelöschten Zeilen
  1. 35 6
      psiphon/common/tapdance/tapdance.go

+ 35 - 6
psiphon/common/tapdance/tapdance.go

@@ -255,20 +255,49 @@ func Dial(
 
 	manager := newDialManager(netDialer.DialContext, ctx)
 
-	tapdanceDialer := &refraction_networking_tapdance.Dialer{
-		TcpDialer: manager.dial,
+	type tapdanceDialResult struct {
+		conn net.Conn
+		err  error
 	}
 
-	conn, err := tapdanceDialer.Dial("tcp", address)
-	if err != nil {
+	resultChannel := make(chan tapdanceDialResult)
+
+	go func() {
+		tapdanceDialer := &refraction_networking_tapdance.Dialer{
+			TcpDialer: manager.dial,
+		}
+
+		conn, err := tapdanceDialer.Dial("tcp", address)
+		if err != nil {
+			err = common.ContextError(err)
+		}
+
+		resultChannel <- tapdanceDialResult{
+			conn: conn,
+			err:  err,
+		}
+	}()
+
+	var result tapdanceDialResult
+
+	select {
+	case result = <-resultChannel:
+	case <-ctx.Done():
+		result.err = ctx.Err()
+		// Interrupt the goroutine
 		manager.close()
-		return nil, common.ContextError(err)
+		<-resultChannel
+	}
+
+	if result.err != nil {
+		manager.close()
+		return nil, common.ContextError(result.err)
 	}
 
 	manager.startUsingRunCtx()
 
 	return &tapdanceConn{
-		Conn:    conn,
+		Conn:    result.conn,
 		manager: manager,
 	}, nil
 }