Browse Source

Customize SSH channel window size for packet tunnel

- Benchmarks indicate significant performance increase.
Rod Hynes 8 years ago
parent
commit
11e4ae0670
1 changed files with 41 additions and 27 deletions
  1. 41 27
      psiphon/common/crypto/ssh/channel.go

+ 41 - 27
psiphon/common/crypto/ssh/channel.go

@@ -11,6 +11,8 @@ import (
 	"io"
 	"log"
 	"sync"
+
+	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/protocol"
 )
 
 const (
@@ -20,35 +22,47 @@ const (
 	// the minimum.
 	channelMaxPacket = 1 << 15
 
-	// We follow OpenSSH here.
-	//channelWindowSize = 64 * channelMaxPacket
-
 	// PSIPHON
 	// =======
-	// - Use a smaller initial/max channel window size.
-	// - Testing with the full Psiphon stack shows that
-	//   this smaller channel window size is more performant
-	//   for low bandwidth connections while still adequate for
-	//   higher bandwidth connections.
-	// - In Psiphon, a single SSH connection is used for all
-	//   client port forwards. Bulk data transfers with large
-	//   channel windows can immediately backlog the connection
-	//   with many large SSH packets, introducing large latency
-	//   for opening new channels. For Psiphon, we don't wish to
-	//   optimize for a single bulk transfer throughput.
-	// - TODO: can we implement some sort of adaptive max
-	//   channel window size, starting with this small initial
-	//   value and only growing based on connection properties?
-	// - channelWindowSize directly defines the local channel
-	//   window initial and max size. We also cap remote channel
-	//   window sizes via an extra customization in the
-	//   channelOpenConfirmMsg handler. Both upstream and
-	//   downstream bulk data transfers have the same latency
-	//   issue.
-
-	channelWindowSize = 4 * channelMaxPacket
+	// Use getChannelWindowSize() instead of channelWindowSize.
+	//
+	// We follow OpenSSH here.
+	//channelWindowSize = 64 * channelMaxPacket
 )
 
+// PSIPHON
+// =======
+// - Use a smaller initial/max channel window size.
+// - Testing with the full Psiphon stack shows that
+//   this smaller channel window size is more performant
+//   for low bandwidth connections while still adequate for
+//   higher bandwidth connections.
+// - In Psiphon, a single SSH connection is used for all
+//   client port forwards. Bulk data transfers with large
+//   channel windows can immediately backlog the connection
+//   with many large SSH packets, introducing large latency
+//   for opening new channels. For Psiphon, we don't wish to
+//   optimize for a single bulk transfer throughput.
+// - TODO: can we implement some sort of adaptive max
+//   channel window size, starting with this small initial
+//   value and only growing based on connection properties?
+// - channelWindowSize directly defines the local channel
+//   window initial and max size. We also cap remote channel
+//   window sizes via an extra customization in the
+//   channelOpenConfirmMsg handler. Both upstream and
+//   downstream bulk data transfers have the same latency
+//   issue.
+// - For packet tunnel, use a larger channel window size,
+//   since all tunneled traffic flows through a single
+//   channel; we still select a size smaller than the stock
+//   channelWindowSize due to client memory constraints.
+func getChannelWindowSize(chanType string) int {
+	if chanType == protocol.PACKET_TUNNEL_CHANNEL_TYPE {
+		return 16 * channelMaxPacket
+	}
+	return 4 * channelMaxPacket
+}
+
 // NewChannel represents an incoming request to a channel. It must either be
 // accepted for use by calling Accept, or rejected by calling Reject.
 type NewChannel interface {
@@ -466,7 +480,7 @@ func (c *channel) handlePacket(packet []byte) error {
 		// - See comments above channelWindowSize definition.
 
 		//c.remoteWin.add(msg.MyWindow)
-		c.remoteWin.add(min(msg.MyWindow, channelWindowSize))
+		c.remoteWin.add(min(msg.MyWindow, getChannelWindowSize(c.chanType)))
 
 		c.msg <- msg
 	case *windowAdjustMsg:
@@ -491,7 +505,7 @@ func (c *channel) handlePacket(packet []byte) error {
 func (m *mux) newChannel(chanType string, direction channelDirection, extraData []byte) *channel {
 	ch := &channel{
 		remoteWin:        window{Cond: newCond()},
-		myWindow:         channelWindowSize,
+		myWindow:         uint32(getChannelWindowSize(chanType)),
 		pending:          newBuffer(),
 		extPending:       newBuffer(),
 		direction:        direction,