Browse Source

Initial commit

Armon Dadgar 10 years ago
parent
commit
4e431b9703
3 changed files with 251 additions and 3 deletions
  1. 135 3
      README.md
  2. 66 0
      const.go
  3. 50 0
      const_test.go

+ 135 - 3
README.md

@@ -1,4 +1,136 @@
-yamux
-=====
+# Yamux
+
+Yamux or Yet another Mux (Multiplexer) is another multiplexing
+library. It relies on an underlying connection to provide reliability
+and ordering (such as TCP or Unix domain sockets), and provides
+stream-oriented multiplexing. It is inspired by SPDY but is not
+interoperable with it.
+
+Yamux features include:
+* Bi-directional streams created by either client or server
+* Flow control, this prevents a single flow from starving others
+* Transparent compression
+
+# Framing
+
+Yamux uses a streaming connection underneath, but imposes a message
+framing so that it can be shared between many logical streams. Each
+frame contains a header like:
+
+<Version> (4 bits)
+<Type> (4 bits)
+<Flags> (8 bits)
+<StreamID> (32 bits)
+<Length> (32 bits)
+
+This means that each header has a 10 byte overhead. Each field
+is described below:
+
+## Version Field
+
+The version field is used for future backwards compatibily. At the
+current time, the field is always set to 0, to indicate the initial
+version.
+
+## Type Field
+
+The type field is used to switch the frame message type. The following
+message types are supported:
+* 0x0 Data - Used to transmit data. May transmit zero length payloads
+  depending on the flags.
+
+* 0x1 Window Update - Used to updated the senders receive window size.
+  This is used to implement per-session flow control.
+
+* 0x2 Ping - Used to measure RTT. It can also be used to heart-beat
+  and do keep-alives over TCP.
+
+* 0x3 Go Away - Used to close a session.
+
+## Flag Field
+
+The flags field is used to provide additional information related
+to the message type. The following flags are supported:
+
+* 0x1 SYN - Signals the start of a new stream. May be sent with a data or
+  window update message.
+
+* 0x2 ACK - Acknowledges the start of a new stream. May be sent with a data
+  or window update message.
+
+* 0x4 FIN - Performs a half-close of a new stream. May be sent with a data
+  message or window update.
+
+* 0x8 RST - Reset a stream immediately. Sent with a data message only.
+
+* 0x 16 LZW - Indicates the payload is LZW compressed. Sent with a data message
+  only.
+
+## StreamID Field
+
+The StreamID field is used to identify the logical stream the frame
+is addressing. The client side should use odd ID's, and the server even.
+This prevents any collisions. Additionally, the 0 ID is reserved to represent
+the session.
+
+Both Ping and Go Away messages should always use the 0 StreamID.
+
+A Window Update may also provide StreamID 0, meaning the window for
+the entire session is being modified.
+
+## Length Field
+
+The meaning of the length field depends on the message type:
+* Data - provides the length of bytes following the header
+* Window update - provides a delta update to the window size
+* Ping - Contains an opaque value, echoed back
+* Go Away - Contains an error code
+
+# Message Flow
+
+There is no explicit connection setup, as Yamux relies on an underlying
+transport to be provided. However, there is a distinction between client
+and server side of the connection.
+
+## Opening a stream
+
+To open a stream, an initial data or window update frame is sent
+with a new StreamID. The SYN flag should be set to signal a new stream.
+
+The receiver must then reply with either a data or window update frame
+with the StreamID along with the ACK flag to accept the stream or with
+the RST flag to reject the stream.
+
+## Closing a stream
+
+To close a stream, either side sends a data or window update frame
+along with the FIN flag. This does a half-close indicating the sender
+will send no further data.
+
+Once both sides have closed the connection, the stream is closed.
+
+Alternatively, if an error occurs, the RST flag can be used to
+hard close a stream immediately.
+
+## Flow Control
+
+When Yamux is initially started there is a 2MB window size for
+the session. Additionally, each new stream has a 256KB window size.
+
+To prevent the session or streams from stalling, window update
+frames should be sent regularly. Yamux can be configured to provide
+a limit for windows sizes.
+
+Both sides should track the number of bytes sent in Data frames
+only, as only they are tracked as part of the window size.
+
+## Session termination
+
+When a session is being terminated, the Go Away message should
+be sent. The Length should be set to one of the following to
+provide an error code:
+
+* 0x0 Normal termination
+* 0x1 Protocol error
+* 0x2 Internal error
 
-Golang connection multiplexing library

+ 66 - 0
const.go

@@ -0,0 +1,66 @@
+package yamux
+
+const (
+	// protoVersion is the only version we support
+	protoVersion = 0
+)
+
+const (
+	// Data is used for data frames. They are followed
+	// by length bytes worth of payload.
+	typeData uint8 = iota
+
+	// WindowUpdate is used to change the window of
+	// a given stream. The length indicates the delta
+	// update to the window.
+	typeWindowUpdate
+
+	// Ping is sent as a keep-alive or to measure
+	// the RTT. The StreamID and Length value are echoed
+	// back in the response.
+	typePing
+
+	// GoAway is sent to terminate a session. The StreamID
+	// should be 0 and the length is an error code.
+	typeGoAway
+)
+
+const (
+	// SYN is sent to signal a new stream. May
+	// be sent with a data payload
+	flagSYN uint8 = 1 << iota
+
+	// ACK is sent to acknowledge a new stream. May
+	// be sent with a data payload
+	flagACK
+
+	// FIN is sent to half-close the given stream.
+	// May be sent with a data payload.
+	flagFIN
+
+	// RST is used to hard close a given stream.
+	flagRST
+
+	// LZW is used to indicate that the payload is
+	// compressed with the LZW algorithm
+	flagLZW
+)
+
+const (
+	// initialSessionWindow is the initial session window size
+	initialSessionWindow = 2 * 1024 * 1024
+
+	// initialStreamWindow is the initial stream window size
+	initialStreamWindow = 256 * 1024
+)
+
+const (
+	// goAwayNormal is sent on a normal termination
+	goAwayNormal uint32 = iota
+
+	// goAwayProtoErr sent on a protocol error
+	goAwayProtoErr
+
+	// goAwayInternalErr sent on an internal error
+	goAwayInternalErr
+)

+ 50 - 0
const_test.go

@@ -0,0 +1,50 @@
+package yamux
+
+import (
+	"testing"
+)
+
+func TestConst(t *testing.T) {
+	if protoVersion != 0 {
+		t.Fatalf("bad: %v", protoVersion)
+	}
+
+	if typeData != 0 {
+		t.Fatalf("bad: %v", typeData)
+	}
+	if typeWindowUpdate != 1 {
+		t.Fatalf("bad: %v", typeWindowUpdate)
+	}
+	if typePing != 2 {
+		t.Fatalf("bad: %v", typePing)
+	}
+	if typeGoAway != 3 {
+		t.Fatalf("bad: %v", typeGoAway)
+	}
+
+	if flagSYN != 1 {
+		t.Fatalf("bad: %v", flagSYN)
+	}
+	if flagACK != 2 {
+		t.Fatalf("bad: %v", flagACK)
+	}
+	if flagFIN != 4 {
+		t.Fatalf("bad: %v", flagFIN)
+	}
+	if flagRST != 8 {
+		t.Fatalf("bad: %v", flagRST)
+	}
+	if flagLZW != 16 {
+		t.Fatalf("bad: %v", flagLZW)
+	}
+
+	if goAwayNormal != 0 {
+		t.Fatalf("bad: %v", goAwayNormal)
+	}
+	if goAwayProtoErr != 1 {
+		t.Fatalf("bad: %v", goAwayProtoErr)
+	}
+	if goAwayInternalErr != 2 {
+		t.Fatalf("bad: %v", goAwayInternalErr)
+	}
+}