Browse Source

socket: Very initial SendQ limit

tags/v0.7.0
Daniel Oaks 7 years ago
parent
commit
f29a5f0e70
5 changed files with 44 additions and 2 deletions
  1. 1
    1
      irc/client.go
  2. 9
    0
      irc/config.go
  3. 14
    0
      irc/server.go
  4. 17
    1
      irc/socket.go
  5. 3
    0
      oragono.yaml

+ 1
- 1
irc/client.go View File

@@ -74,7 +74,7 @@ type Client struct {
74 74
 // NewClient returns a client with all the appropriate info setup.
75 75
 func NewClient(server *Server, conn net.Conn, isTLS bool) *Client {
76 76
 	now := time.Now()
77
-	socket := NewSocket(conn)
77
+	socket := NewSocket(conn, server.MaxSendQBytes)
78 78
 	go socket.RunSocketWriter()
79 79
 	client := &Client{
80 80
 		atime:          now,

+ 9
- 0
irc/config.go View File

@@ -14,6 +14,8 @@ import (
14 14
 	"strings"
15 15
 	"time"
16 16
 
17
+	"code.cloudfoundry.org/bytefmt"
18
+
17 19
 	"github.com/DanielOaks/oragono/irc/custime"
18 20
 	"github.com/DanielOaks/oragono/irc/logger"
19 21
 	"gopkg.in/yaml.v2"
@@ -171,6 +173,8 @@ type Config struct {
171 173
 		RestAPI            RestAPIConfig `yaml:"rest-api"`
172 174
 		CheckIdent         bool          `yaml:"check-ident"`
173 175
 		MOTD               string
176
+		MaxSendQString     string `yaml:"max-sendq"`
177
+		MaxSendQBytes      uint64
174 178
 		ConnectionLimits   ConnectionLimitsConfig   `yaml:"connection-limits"`
175 179
 		ConnectionThrottle ConnectionThrottleConfig `yaml:"connection-throttling"`
176 180
 	}
@@ -433,5 +437,10 @@ func LoadConfig(filename string) (config *Config, err error) {
433 437
 	}
434 438
 	config.Logging = newLogConfigs
435 439
 
440
+	config.Server.MaxSendQBytes, err = bytefmt.ToBytes(config.Server.MaxSendQString)
441
+	if err != nil {
442
+		return nil, fmt.Errorf("Could not parse maximum SendQ size (make sure it only contains whole numbers): %s", err.Error())
443
+	}
444
+
436 445
 	return config, nil
437 446
 }

+ 14
- 0
irc/server.go View File

@@ -104,6 +104,7 @@ type Server struct {
104 104
 	listeners                    map[string]ListenerInterface
105 105
 	listenerUpdateMutex          sync.Mutex
106 106
 	logger                       *logger.Manager
107
+	MaxSendQBytes                uint64
107 108
 	monitoring                   map[string][]Client
108 109
 	motdLines                    []string
109 110
 	name                         string
@@ -211,6 +212,7 @@ func NewServer(configFilename string, config *Config, logger *logger.Manager) (*
211 212
 		},
212 213
 		listeners:      make(map[string]ListenerInterface),
213 214
 		logger:         logger,
215
+		MaxSendQBytes:  config.Server.MaxSendQBytes,
214 216
 		monitoring:     make(map[string][]Client),
215 217
 		name:           config.Server.Name,
216 218
 		nameCasefolded: casefoldedName,
@@ -1413,6 +1415,18 @@ func (server *Server) rehash() error {
1413 1415
 	accountReg := NewAccountRegistration(config.Accounts.Registration)
1414 1416
 	server.accountRegistration = &accountReg
1415 1417
 
1418
+	// set new sendqueue size
1419
+	if config.Server.MaxSendQBytes != server.MaxSendQBytes {
1420
+		server.MaxSendQBytes = config.Server.MaxSendQBytes
1421
+
1422
+		// update on all clients
1423
+		server.clients.ByNickMutex.RLock()
1424
+		for _, sClient := range server.clients.ByNick {
1425
+			sClient.socket.MaxSendQBytes = config.Server.MaxSendQBytes
1426
+		}
1427
+		server.clients.ByNickMutex.RUnlock()
1428
+	}
1429
+
1416 1430
 	// set RPL_ISUPPORT
1417 1431
 	oldISupportList := server.isupport
1418 1432
 	server.setISupport()

+ 17
- 1
irc/socket.go View File

@@ -30,16 +30,19 @@ type Socket struct {
30 30
 	conn   net.Conn
31 31
 	reader *bufio.Reader
32 32
 
33
+	MaxSendQBytes uint64
34
+
33 35
 	lineToSendExists chan bool
34 36
 	linesToSend      []string
35 37
 	linesToSendMutex sync.Mutex
36 38
 }
37 39
 
38 40
 // NewSocket returns a new Socket.
39
-func NewSocket(conn net.Conn) Socket {
41
+func NewSocket(conn net.Conn, maxSendQBytes uint64) Socket {
40 42
 	return Socket{
41 43
 		conn:             conn,
42 44
 		reader:           bufio.NewReader(conn),
45
+		MaxSendQBytes:    maxSendQBytes,
43 46
 		lineToSendExists: make(chan bool),
44 47
 	}
45 48
 }
@@ -130,6 +133,19 @@ func (socket *Socket) RunSocketWriter() {
130 133
 		case <-socket.lineToSendExists:
131 134
 			socket.linesToSendMutex.Lock()
132 135
 
136
+			// check sendq
137
+			var sendQBytes uint64
138
+			for _, line := range socket.linesToSend {
139
+				sendQBytes += uint64(len(line))
140
+				if socket.MaxSendQBytes < sendQBytes {
141
+					break
142
+				}
143
+			}
144
+			if socket.MaxSendQBytes < sendQBytes {
145
+				socket.conn.Write([]byte("\r\nERROR :SendQ Exceeded\r\n"))
146
+				break
147
+			}
148
+
133 149
 			// get data
134 150
 			data := socket.linesToSend[0]
135 151
 			if len(socket.linesToSend) > 1 {

+ 3
- 0
oragono.yaml View File

@@ -65,6 +65,9 @@ server:
65 65
     # if you change the motd, you should move it to ircd.motd
66 66
     motd: oragono.motd
67 67
 
68
+    # maximum length of clients' sendQ in bytes
69
+    max-sendq: 16k
70
+
68 71
     # maximum number of connections per subnet
69 72
     connection-limits:
70 73
         # whether to throttle limits or not

Loading…
Cancel
Save