1package yamux 2 3import ( 4 "fmt" 5 "io" 6 "log" 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 // EnableKeepalive is used to do a period keep alive 18 // messages using a ping. 19 EnableKeepAlive bool 20 21 // KeepAliveInterval is how often to perform the keep alive 22 KeepAliveInterval time.Duration 23 24 // ConnectionWriteTimeout is meant to be a "safety valve" timeout after 25 // we which will suspect a problem with the underlying connection and 26 // close it. This is only applied to writes, where's there's generally 27 // an expectation that things will move along quickly. 28 ConnectionWriteTimeout time.Duration 29 30 // MaxStreamWindowSize is used to control the maximum 31 // window size that we allow for a stream. 32 MaxStreamWindowSize uint32 33 34 // LogOutput is used to control the log destination. Either Logger or 35 // LogOutput can be set, not both. 36 LogOutput io.Writer 37 38 // Logger is used to pass in the logger to be used. Either Logger or 39 // LogOutput can be set, not both. 40 Logger *log.Logger 41} 42 43// DefaultConfig is used to return a default configuration 44func DefaultConfig() *Config { 45 return &Config{ 46 AcceptBacklog: 256, 47 EnableKeepAlive: true, 48 KeepAliveInterval: 30 * time.Second, 49 ConnectionWriteTimeout: 10 * time.Second, 50 MaxStreamWindowSize: initialStreamWindow, 51 LogOutput: os.Stderr, 52 } 53} 54 55// VerifyConfig is used to verify the sanity of configuration 56func VerifyConfig(config *Config) error { 57 if config.AcceptBacklog <= 0 { 58 return fmt.Errorf("backlog must be positive") 59 } 60 if config.KeepAliveInterval == 0 { 61 return fmt.Errorf("keep-alive interval must be positive") 62 } 63 if config.MaxStreamWindowSize < initialStreamWindow { 64 return fmt.Errorf("MaxStreamWindowSize must be larger than %d", initialStreamWindow) 65 } 66 if config.LogOutput != nil && config.Logger != nil { 67 return fmt.Errorf("both Logger and LogOutput may not be set, select one") 68 } else if config.LogOutput == nil && config.Logger == nil { 69 return fmt.Errorf("one of Logger or LogOutput must be set, select one") 70 } 71 return nil 72} 73 74// Server is used to initialize a new server-side connection. 75// There must be at most one server-side connection. If a nil config is 76// provided, the DefaultConfiguration will be used. 77func Server(conn io.ReadWriteCloser, config *Config) (*Session, error) { 78 if config == nil { 79 config = DefaultConfig() 80 } 81 if err := VerifyConfig(config); err != nil { 82 return nil, err 83 } 84 return newSession(config, conn, false), nil 85} 86 87// Client is used to initialize a new client-side connection. 88// There must be at most one client-side connection. 89func Client(conn io.ReadWriteCloser, config *Config) (*Session, error) { 90 if config == nil { 91 config = DefaultConfig() 92 } 93 94 if err := VerifyConfig(config); err != nil { 95 return nil, err 96 } 97 return newSession(config, conn, true), nil 98} 99