1package yamux
2
3import (
4	"fmt"
5	"io"
6	"net"
7	"os"
8	"time"
9)
10
11// Config is used to tune the Yamux session
12type Config struct {
13	// AcceptBacklog is used to limit how many streams may be
14	// waiting an accept.
15	AcceptBacklog int
16
17	// PingBacklog is used to limit how many ping acks we can queue.
18	PingBacklog int
19
20	// EnableKeepalive is used to do a period keep alive
21	// messages using a ping.
22	EnableKeepAlive bool
23
24	// KeepAliveInterval is how often to perform the keep alive
25	KeepAliveInterval time.Duration
26
27	// ConnectionWriteTimeout is meant to be a "safety valve" timeout after
28	// we which will suspect a problem with the underlying connection and
29	// close it. This is only applied to writes, where's there's generally
30	// an expectation that things will move along quickly.
31	ConnectionWriteTimeout time.Duration
32
33	// MaxStreamWindowSize is used to control the maximum
34	// window size that we allow for a stream.
35	MaxStreamWindowSize uint32
36
37	// LogOutput is used to control the log destination
38	LogOutput io.Writer
39
40	// ReadBufSize controls the size of the read buffer.
41	//
42	// Set to 0 to disable it.
43	ReadBufSize int
44
45	// WriteCoalesceDelay is the maximum amount of time we'll delay
46	// coalescing a packet before sending it. This should be on the order of
47	// micro-milliseconds.
48	WriteCoalesceDelay time.Duration
49
50	// MaxMessageSize is the maximum size of a message that we'll send on a
51	// stream. This ensures that a single stream doesn't hog a connection.
52	MaxMessageSize uint32
53}
54
55// DefaultConfig is used to return a default configuration
56func DefaultConfig() *Config {
57	return &Config{
58		AcceptBacklog:          256,
59		PingBacklog:            32,
60		EnableKeepAlive:        true,
61		KeepAliveInterval:      30 * time.Second,
62		ConnectionWriteTimeout: 10 * time.Second,
63		MaxStreamWindowSize:    initialStreamWindow,
64		LogOutput:              os.Stderr,
65		ReadBufSize:            4096,
66		MaxMessageSize:         64 * 1024, // Means 64KiB/10s = 52kbps minimum speed.
67		WriteCoalesceDelay:     100 * time.Microsecond,
68	}
69}
70
71// VerifyConfig is used to verify the sanity of configuration
72func VerifyConfig(config *Config) error {
73	if config.AcceptBacklog <= 0 {
74		return fmt.Errorf("backlog must be positive")
75	}
76	if config.KeepAliveInterval == 0 {
77		return fmt.Errorf("keep-alive interval must be positive")
78	}
79	if config.MaxStreamWindowSize < initialStreamWindow {
80		return fmt.Errorf("MaxStreamWindowSize must be larger than %d", initialStreamWindow)
81	}
82	if config.MaxMessageSize < 1024 {
83		return fmt.Errorf("MaxMessageSize must be greater than a kilobyte")
84	}
85	if config.WriteCoalesceDelay < 0 {
86		return fmt.Errorf("WriteCoalesceDelay must be >= 0")
87	}
88	if config.PingBacklog < 1 {
89		return fmt.Errorf("PingBacklog must be > 0")
90	}
91	return nil
92}
93
94// Server is used to initialize a new server-side connection.
95// There must be at most one server-side connection. If a nil config is
96// provided, the DefaultConfiguration will be used.
97func Server(conn net.Conn, config *Config) (*Session, error) {
98	if config == nil {
99		config = DefaultConfig()
100	}
101	if err := VerifyConfig(config); err != nil {
102		return nil, err
103	}
104	return newSession(config, conn, false, config.ReadBufSize), nil
105}
106
107// Client is used to initialize a new client-side connection.
108// There must be at most one client-side connection.
109func Client(conn net.Conn, config *Config) (*Session, error) {
110	if config == nil {
111		config = DefaultConfig()
112	}
113
114	if err := VerifyConfig(config); err != nil {
115		return nil, err
116	}
117	return newSession(config, conn, true, config.ReadBufSize), nil
118}
119