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