~trn/gfsmux

ref: 2106.0.0 gfsmux/mux.go -rw-r--r-- 3.1 KiB
753dd037 — Jeffrey H. Johnson Update dependencies 3 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Package gfsmux is a multiplexing library for Golang.
//
// It relies on an underlying connection to provide reliability and ordering,
// such as GFCP, and provides stream-oriented multiplexing over a single channel.
package gfsmux

import (
	"errors"
	"fmt"
	"io"
	"math"
	"time"
)

// Config is used to tune the Smux session
type Config struct {
	// SMUX Protocol version, support 1,2
	Version int

	// Disabled keepalive
	KeepAliveDisabled bool

	// KeepAliveInterval is how often to send a NOP command to the remote
	KeepAliveInterval time.Duration

	// KeepAliveTimeout is how long the session
	// will be closed if no data has arrived
	KeepAliveTimeout time.Duration

	// MaxFrameSize is used to control the maximum
	// frame size to sent to the remote
	MaxFrameSize int

	// MaxReceiveBuffer is used to control the maximum
	// number of data in the buffer pool
	MaxReceiveBuffer int

	// MaxStreamBuffer is used to control the maximum
	// number of data per stream
	MaxStreamBuffer int
}

// DefaultConfig is used to return a default Configuration
func DefaultConfig() *Config {
	return &Config{
		Version:           1,
		KeepAliveInterval: 10 * time.Second,
		KeepAliveTimeout:  30 * time.Second,
		MaxFrameSize:      32768,
		MaxReceiveBuffer:  4194304,
		MaxStreamBuffer:   65536,
	}
}

// VerifyConfig is used to verify the sanity of Configuration
func VerifyConfig(
	Config *Config,
) error {
	if !(Config.Version == 1 || Config.Version == 2) {
		return errors.New(
			"unsupported protocol version",
		)
	}
	if !Config.KeepAliveDisabled {
		if Config.KeepAliveInterval == 0 {
			return errors.New(
				"keep-alive interval must be positive",
			)
		}
		if Config.KeepAliveTimeout < Config.KeepAliveInterval {
			return fmt.Errorf(
				"keep-alive timeout must be larger than keep-alive interval",
			)
		}
	}
	if Config.MaxFrameSize <= 0 {
		return errors.New(
			"max frame size must be positive",
		)
	}
	if Config.MaxFrameSize > 65535 {
		return errors.New(
			"max frame size must not be larger than 65535",
		)
	}
	if Config.MaxReceiveBuffer <= 0 {
		return errors.New(
			"max receive buffer must be positive",
		)
	}
	if Config.MaxStreamBuffer <= 0 {
		return errors.New(
			"max stream buffer must be positive",
		)
	}
	if Config.MaxStreamBuffer > Config.MaxReceiveBuffer {
		return errors.New(
			"max stream buffer must not be larger than max receive buffer",
		)
	}
	if Config.MaxStreamBuffer > math.MaxInt32 {
		return errors.New(
			"max stream buffer cannot be larger than 2147483647",
		)
	}
	return nil
}

// Server is used to initialize a new server-side Connection.
func Server(
	Conn io.ReadWriteCloser,
	Config *Config,
) (
	*Session,
	error,
) {
	if Config == nil {
		Config = DefaultConfig()
	}
	if err := VerifyConfig(
		Config,
	); err != nil {
		return nil, err
	}
	return newSession(
		Config,
		Conn,
		false,
	), nil
}

// Client is used to initialize a new client-side Connection.
func Client(
	Conn io.ReadWriteCloser,
	Config *Config,
) (
	*Session,
	error,
) {
	if Config == nil {
		Config = DefaultConfig()
	}

	if err := VerifyConfig(
		Config,
	); err != nil {
		return nil, err
	}
	return newSession(
		Config,
		Conn,
		true,
	), nil
}