mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-10 22:19:31 +01:00
Merge master
This commit is contained in:
commit
6842d2ead6
@ -19,8 +19,9 @@ New release of Oragono!
|
|||||||
* Added draft IRCv3 capability [draft/sts](http://ircv3.net/specs/core/sts-3.3.html).
|
* Added draft IRCv3 capability [draft/sts](http://ircv3.net/specs/core/sts-3.3.html).
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
* Logging is now much better and useful.
|
* `DLINE` and `KLINE` now let you specify years, months and days (e.g. `1y12m30d`) in durations.
|
||||||
* Can now specify years, months and days (e.g. `1y12m30d`) with DLINE and KLINE.
|
* Logging is now much more useful, displays colours and can log to disk.
|
||||||
|
* Socket handling has been rewritten, which means we should support more connections more effectively (thanks dp- for the suggestion!).
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
|
@ -74,7 +74,8 @@ type Client struct {
|
|||||||
// NewClient returns a client with all the appropriate info setup.
|
// NewClient returns a client with all the appropriate info setup.
|
||||||
func NewClient(server *Server, conn net.Conn, isTLS bool) *Client {
|
func NewClient(server *Server, conn net.Conn, isTLS bool) *Client {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
socket := NewSocket(conn)
|
socket := NewSocket(conn, server.MaxSendQBytes)
|
||||||
|
go socket.RunSocketWriter()
|
||||||
client := &Client{
|
client := &Client{
|
||||||
atime: now,
|
atime: now,
|
||||||
authorized: server.password == nil,
|
authorized: server.password == nil,
|
||||||
|
@ -14,6 +14,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"code.cloudfoundry.org/bytefmt"
|
||||||
|
|
||||||
"github.com/DanielOaks/oragono/irc/custime"
|
"github.com/DanielOaks/oragono/irc/custime"
|
||||||
"github.com/DanielOaks/oragono/irc/logger"
|
"github.com/DanielOaks/oragono/irc/logger"
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
@ -171,6 +173,8 @@ type Config struct {
|
|||||||
RestAPI RestAPIConfig `yaml:"rest-api"`
|
RestAPI RestAPIConfig `yaml:"rest-api"`
|
||||||
CheckIdent bool `yaml:"check-ident"`
|
CheckIdent bool `yaml:"check-ident"`
|
||||||
MOTD string
|
MOTD string
|
||||||
|
MaxSendQString string `yaml:"max-sendq"`
|
||||||
|
MaxSendQBytes uint64
|
||||||
ConnectionLimits ConnectionLimitsConfig `yaml:"connection-limits"`
|
ConnectionLimits ConnectionLimitsConfig `yaml:"connection-limits"`
|
||||||
ConnectionThrottle ConnectionThrottleConfig `yaml:"connection-throttling"`
|
ConnectionThrottle ConnectionThrottleConfig `yaml:"connection-throttling"`
|
||||||
}
|
}
|
||||||
@ -433,5 +437,10 @@ func LoadConfig(filename string) (config *Config, err error) {
|
|||||||
}
|
}
|
||||||
config.Logging = newLogConfigs
|
config.Logging = newLogConfigs
|
||||||
|
|
||||||
|
config.Server.MaxSendQBytes, err = bytefmt.ToBytes(config.Server.MaxSendQString)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Could not parse maximum SendQ size (make sure it only contains whole numbers): %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
@ -212,7 +212,7 @@ func (logger *singleLogger) Log(level Level, logType string, messageParts ...str
|
|||||||
|
|
||||||
sep := grey(":")
|
sep := grey(":")
|
||||||
fullStringFormatted := fmt.Sprintf("%s %s %s %s %s %s ", timeGrey(time.Now().UTC().Format("2006-01-02T15:04:05Z")), sep, levelDisplay, sep, section(logType), sep)
|
fullStringFormatted := fmt.Sprintf("%s %s %s %s %s %s ", timeGrey(time.Now().UTC().Format("2006-01-02T15:04:05Z")), sep, levelDisplay, sep, section(logType), sep)
|
||||||
fullStringRaw := fmt.Sprintf("%s : %s : %s : ", time.Now().UTC().Format("2006-01-02T15:04:05Z"), LogLevelDisplayNames[level], section(logType))
|
fullStringRaw := fmt.Sprintf("%s : %s : %s : ", time.Now().UTC().Format("2006-01-02T15:04:05Z"), LogLevelDisplayNames[level], logType)
|
||||||
for i, p := range messageParts {
|
for i, p := range messageParts {
|
||||||
fullStringFormatted += p
|
fullStringFormatted += p
|
||||||
fullStringRaw += p
|
fullStringRaw += p
|
||||||
|
@ -104,6 +104,7 @@ type Server struct {
|
|||||||
listeners map[string]ListenerInterface
|
listeners map[string]ListenerInterface
|
||||||
listenerUpdateMutex sync.Mutex
|
listenerUpdateMutex sync.Mutex
|
||||||
logger *logger.Manager
|
logger *logger.Manager
|
||||||
|
MaxSendQBytes uint64
|
||||||
monitoring map[string][]Client
|
monitoring map[string][]Client
|
||||||
motdLines []string
|
motdLines []string
|
||||||
name string
|
name string
|
||||||
@ -214,6 +215,7 @@ func NewServer(configFilename string, config *Config, logger *logger.Manager) (*
|
|||||||
},
|
},
|
||||||
listeners: make(map[string]ListenerInterface),
|
listeners: make(map[string]ListenerInterface),
|
||||||
logger: logger,
|
logger: logger,
|
||||||
|
MaxSendQBytes: config.Server.MaxSendQBytes,
|
||||||
monitoring: make(map[string][]Client),
|
monitoring: make(map[string][]Client),
|
||||||
name: config.Server.Name,
|
name: config.Server.Name,
|
||||||
nameCasefolded: casefoldedName,
|
nameCasefolded: casefoldedName,
|
||||||
@ -1423,6 +1425,18 @@ func (server *Server) rehash() error {
|
|||||||
accountReg := NewAccountRegistration(config.Accounts.Registration)
|
accountReg := NewAccountRegistration(config.Accounts.Registration)
|
||||||
server.accountRegistration = &accountReg
|
server.accountRegistration = &accountReg
|
||||||
|
|
||||||
|
// set new sendqueue size
|
||||||
|
if config.Server.MaxSendQBytes != server.MaxSendQBytes {
|
||||||
|
server.MaxSendQBytes = config.Server.MaxSendQBytes
|
||||||
|
|
||||||
|
// update on all clients
|
||||||
|
server.clients.ByNickMutex.RLock()
|
||||||
|
for _, sClient := range server.clients.ByNick {
|
||||||
|
sClient.socket.MaxSendQBytes = config.Server.MaxSendQBytes
|
||||||
|
}
|
||||||
|
server.clients.ByNickMutex.RUnlock()
|
||||||
|
}
|
||||||
|
|
||||||
// set RPL_ISUPPORT
|
// set RPL_ISUPPORT
|
||||||
oldISupportList := server.isupport
|
oldISupportList := server.isupport
|
||||||
server.setISupport()
|
server.setISupport()
|
||||||
|
@ -10,9 +10,11 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -27,23 +29,33 @@ type Socket struct {
|
|||||||
Closed bool
|
Closed bool
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
reader *bufio.Reader
|
reader *bufio.Reader
|
||||||
|
|
||||||
|
MaxSendQBytes uint64
|
||||||
|
|
||||||
|
lineToSendExists chan bool
|
||||||
|
linesToSend []string
|
||||||
|
linesToSendMutex sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSocket returns a new Socket.
|
// NewSocket returns a new Socket.
|
||||||
func NewSocket(conn net.Conn) Socket {
|
func NewSocket(conn net.Conn, maxSendQBytes uint64) Socket {
|
||||||
return Socket{
|
return Socket{
|
||||||
conn: conn,
|
conn: conn,
|
||||||
reader: bufio.NewReader(conn),
|
reader: bufio.NewReader(conn),
|
||||||
|
MaxSendQBytes: maxSendQBytes,
|
||||||
|
lineToSendExists: make(chan bool),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close stops a Socket from being able to send/receive any more data.
|
// Close stops a Socket from being able to send/receive any more data.
|
||||||
func (socket *Socket) Close() {
|
func (socket *Socket) Close() {
|
||||||
if socket.Closed {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
socket.Closed = true
|
socket.Closed = true
|
||||||
socket.conn.Close()
|
|
||||||
|
// 'send data' to force close loop to happen
|
||||||
|
socket.linesToSendMutex.Lock()
|
||||||
|
socket.linesToSend = append(socket.linesToSend, "")
|
||||||
|
socket.linesToSendMutex.Unlock()
|
||||||
|
go socket.fillLineToSendExists()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CertFP returns the fingerprint of the certificate provided by the client.
|
// CertFP returns the fingerprint of the certificate provided by the client.
|
||||||
@ -104,13 +116,78 @@ func (socket *Socket) Write(data string) error {
|
|||||||
return io.EOF
|
return io.EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
socket.linesToSendMutex.Lock()
|
||||||
|
socket.linesToSend = append(socket.linesToSend, data)
|
||||||
|
socket.linesToSendMutex.Unlock()
|
||||||
|
go socket.fillLineToSendExists()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// fillLineToSendExists only exists because you can't goroutine single statements.
|
||||||
|
func (socket *Socket) fillLineToSendExists() {
|
||||||
|
socket.lineToSendExists <- true
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunSocketWriter starts writing messages to the outgoing socket.
|
||||||
|
func (socket *Socket) RunSocketWriter() {
|
||||||
|
var errOut bool
|
||||||
|
for {
|
||||||
|
// wait for new lines
|
||||||
|
select {
|
||||||
|
case <-socket.lineToSendExists:
|
||||||
|
socket.linesToSendMutex.Lock()
|
||||||
|
|
||||||
|
// check sendq
|
||||||
|
var sendQBytes uint64
|
||||||
|
for _, line := range socket.linesToSend {
|
||||||
|
sendQBytes += uint64(len(line))
|
||||||
|
if socket.MaxSendQBytes < sendQBytes {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if socket.MaxSendQBytes < sendQBytes {
|
||||||
|
socket.conn.Write([]byte("\r\nERROR :SendQ Exceeded\r\n"))
|
||||||
|
fmt.Println("SendQ exceeded, disconnected client")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// get data
|
||||||
|
data := socket.linesToSend[0]
|
||||||
|
if len(socket.linesToSend) > 1 {
|
||||||
|
socket.linesToSend = socket.linesToSend[1:]
|
||||||
|
} else {
|
||||||
|
socket.linesToSend = []string{}
|
||||||
|
}
|
||||||
|
|
||||||
// write data
|
// write data
|
||||||
|
if 0 < len(data) {
|
||||||
_, err := socket.conn.Write([]byte(data))
|
_, err := socket.conn.Write([]byte(data))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
socket.Close()
|
errOut = true
|
||||||
return err
|
fmt.Println(err.Error())
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if we're closed
|
||||||
|
if socket.Closed {
|
||||||
|
socket.linesToSendMutex.Unlock()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.linesToSendMutex.Unlock()
|
||||||
|
}
|
||||||
|
if errOut {
|
||||||
|
// error out, bad stuff happened
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//TODO(dan): empty socket.lineToSendExists queue
|
||||||
|
socket.conn.Close()
|
||||||
|
if !socket.Closed {
|
||||||
|
socket.Closed = true
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteLine writes the given line out of Socket.
|
// WriteLine writes the given line out of Socket.
|
||||||
|
@ -65,6 +65,10 @@ server:
|
|||||||
# if you change the motd, you should move it to ircd.motd
|
# if you change the motd, you should move it to ircd.motd
|
||||||
motd: oragono.motd
|
motd: oragono.motd
|
||||||
|
|
||||||
|
# maximum length of clients' sendQ in bytes
|
||||||
|
# this should be big enough to hold /LIST and HELP replies
|
||||||
|
max-sendq: 16k
|
||||||
|
|
||||||
# maximum number of connections per subnet
|
# maximum number of connections per subnet
|
||||||
connection-limits:
|
connection-limits:
|
||||||
# whether to throttle limits or not
|
# whether to throttle limits or not
|
||||||
|
Loading…
Reference in New Issue
Block a user