diff --git a/Gopkg.lock b/Gopkg.lock index 1d6ad607..ac906fb8 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1,4 +1,5 @@ -memo = "d665cbc0144a6e4c06ed8fcfbee8594a7203e47e654eeca63e11d651ae62a3a7" +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + [[projects]] name = "code.cloudfoundry.org/bytefmt" @@ -20,8 +21,12 @@ memo = "d665cbc0144a6e4c06ed8fcfbee8594a7203e47e654eeca63e11d651ae62a3a7" [[projects]] branch = "master" name = "github.com/goshuirc/irc-go" - packages = ["ircfmt","ircmatch","ircmsg"] - revision = "1cb16094f055aa5f5b49a1609aeada54d963433c" + packages = [ + "ircfmt", + "ircmatch", + "ircmsg" + ] + revision = "8d136c4f92871c1c132bf702022363add479291b" [[projects]] branch = "master" @@ -50,7 +55,11 @@ memo = "d665cbc0144a6e4c06ed8fcfbee8594a7203e47e654eeca63e11d651ae62a3a7" [[projects]] branch = "master" name = "github.com/stackimpact/stackimpact-go" - packages = [".","internal","internal/pprof/profile"] + packages = [ + ".", + "internal", + "internal/pprof/profile" + ] revision = "8b5b02c181e477dafcf505342d8a79b5c8241da7" [[projects]] @@ -86,7 +95,10 @@ memo = "d665cbc0144a6e4c06ed8fcfbee8594a7203e47e654eeca63e11d651ae62a3a7" [[projects]] branch = "master" name = "github.com/tidwall/rtree" - packages = [".","base"] + packages = [ + ".", + "base" + ] revision = "6cd427091e0e662cb4f8e2c9eb1a41e1c46ff0d3" [[projects]] @@ -98,19 +110,46 @@ memo = "d665cbc0144a6e4c06ed8fcfbee8594a7203e47e654eeca63e11d651ae62a3a7" [[projects]] branch = "master" name = "golang.org/x/crypto" - packages = ["bcrypt","blowfish","ssh/terminal"] + packages = [ + "bcrypt", + "blowfish", + "ssh/terminal" + ] revision = "5119cf507ed5294cc409c092980c7497ee5d6fd2" [[projects]] branch = "master" name = "golang.org/x/sys" - packages = ["unix","windows"] + packages = [ + "unix", + "windows" + ] revision = "37707fdb30a5b38865cfb95e5aab41707daec7fd" [[projects]] branch = "master" name = "golang.org/x/text" - packages = ["cases","collate","collate/build","internal","internal/colltab","internal/gen","internal/tag","internal/triegen","internal/ucd","language","runes","secure/bidirule","secure/precis","transform","unicode/bidi","unicode/cldr","unicode/norm","unicode/rangetable","width"] + packages = [ + "cases", + "collate", + "collate/build", + "internal", + "internal/colltab", + "internal/gen", + "internal/tag", + "internal/triegen", + "internal/ucd", + "language", + "runes", + "secure/bidirule", + "secure/precis", + "transform", + "unicode/bidi", + "unicode/cldr", + "unicode/norm", + "unicode/rangetable", + "width" + ] revision = "4e4a3210bb54bb31f6ab2cdca2edcc0b50c420c1" [[projects]] @@ -118,3 +157,10 @@ memo = "d665cbc0144a6e4c06ed8fcfbee8594a7203e47e654eeca63e11d651ae62a3a7" name = "gopkg.in/yaml.v2" packages = ["."] revision = "d670f9405373e636a5a2765eea47fac0c9bc91a4" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "1f6e6db999e9e75b04aee6f0018be1557848f8248a28cf21783188fdeb866718" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 47c02714..bd71f751 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -57,24 +57,16 @@ [[dependencies]] branch = "master" - name = "github.com/DanielOaks/girc-go" + name = "github.com/goshuirc/irc-go" [[dependencies]] branch = "master" - name = "github.com/DanielOaks/go-ident" + name = "github.com/oragono/go-ident" [[dependencies]] branch = "master" name = "github.com/docopt/docopt-go" -[[dependencies]] - branch = "master" - name = "github.com/gorilla/mux" - -[[dependencies]] - branch = "master" - name = "github.com/gorilla/websocket" - [[dependencies]] branch = "master" name = "github.com/mattn/go-colorable" diff --git a/irc/client.go b/irc/client.go index 30776416..f105f852 100644 --- a/irc/client.go +++ b/irc/client.go @@ -820,13 +820,13 @@ func (client *Client) SendRawMessage(message ircmsg.IrcMessage) error { // assemble message maxlenTags, maxlenRest := client.maxlens() - line, err := message.LineMaxLen(maxlenTags, maxlenRest) + line, err := message.LineMaxLenBytes(maxlenTags, maxlenRest) if err != nil { logline := fmt.Sprintf("Error assembling message for sending: %v\n%s", err, debug.Stack()) client.server.logger.Error("internal", logline) message = ircmsg.MakeMessage(nil, client.server.name, ERR_UNKNOWNERROR, "*", "Error assembling message for sending") - line, _ := message.Line() + line, _ := message.LineBytes() client.socket.Write(line) return err @@ -834,10 +834,14 @@ func (client *Client) SendRawMessage(message ircmsg.IrcMessage) error { // if we used the trailing hack, we need to strip the final space we appended earlier on if usedTrailingHack { - line = line[:len(line)-3] + "\r\n" + copy(line[len(line)-3:], []byte{'\r', '\n'}) + line = line[:len(line)-1] } - client.server.logger.Debug("useroutput", client.nick, " ->", strings.TrimRight(line, "\r\n")) + if client.server.logger.IsLoggingRawIO() { + logline := string(line[:len(line)-2]) // strip "\r\n" + client.server.logger.Debug("useroutput", client.nick, " ->", logline) + } client.socket.Write(line) diff --git a/irc/logger/logger.go b/irc/logger/logger.go index 2e9f2f05..48cbb097 100644 --- a/irc/logger/logger.go +++ b/irc/logger/logger.go @@ -12,6 +12,7 @@ import ( "strings" "sync" + "sync/atomic" colorable "github.com/mattn/go-colorable" "github.com/mgutz/ansi" @@ -57,7 +58,7 @@ type Manager struct { loggers []singleLogger stdoutWriteLock sync.Mutex // use one lock for both stdout and stderr fileWriteLock sync.Mutex - loggingRawIO bool + loggingRawIO uint32 } // LoggingConfig represents the configuration of a single logger. @@ -95,7 +96,7 @@ func (logger *Manager) ApplyConfig(config []LoggingConfig) error { } logger.loggers = nil - logger.loggingRawIO = false + atomic.StoreUint32(&logger.loggingRawIO, 0) // for safety, this deep-copies all mutable data in `config` // XXX let's keep it that way @@ -124,7 +125,7 @@ func (logger *Manager) ApplyConfig(config []LoggingConfig) error { fileWriteLock: &logger.fileWriteLock, } if typeMap["userinput"] || typeMap["useroutput"] || (typeMap["*"] && !(excludedTypeMap["userinput"] && excludedTypeMap["useroutput"])) { - logger.loggingRawIO = true + atomic.StoreUint32(&logger.loggingRawIO, 1) } if sLogger.MethodFile.Enabled { file, err := os.OpenFile(sLogger.MethodFile.Filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666) @@ -143,9 +144,7 @@ func (logger *Manager) ApplyConfig(config []LoggingConfig) error { // IsLoggingRawIO returns true if raw user input and output is being logged. func (logger *Manager) IsLoggingRawIO() bool { - logger.configMutex.RLock() - defer logger.configMutex.RUnlock() - return logger.loggingRawIO + return atomic.LoadUint32(&logger.loggingRawIO) == 1 } // Log logs the given message with the given details. diff --git a/irc/socket.go b/irc/socket.go index 6382e498..663377d3 100644 --- a/irc/socket.go +++ b/irc/socket.go @@ -34,7 +34,8 @@ type Socket struct { // this is a trylock enforcing that only one goroutine can write to `conn` at a time writerSemaphore Semaphore - buffer []byte + buffers [][]byte + totalLength int closed bool sendQExceeded bool finalData string // what to send when we die @@ -121,15 +122,23 @@ func (socket *Socket) Read() (string, error) { // 2. MUST NOT reorder messages // 3. MUST provide mutual exclusion for socket.conn.Write // 4. SHOULD NOT tie up additional goroutines, beyond the one blocked on socket.conn.Write -func (socket *Socket) Write(data string) (err error) { +func (socket *Socket) Write(data []byte) (err error) { + if len(data) == 0 { + return + } + socket.Lock() if socket.closed { err = io.EOF - } else if len(data)+len(socket.buffer) > socket.maxSendQBytes { - socket.sendQExceeded = true - err = errSendQExceeded } else { - socket.buffer = append(socket.buffer, data...) + prospectiveLen := socket.totalLength + len(data) + if prospectiveLen > socket.maxSendQBytes { + socket.sendQExceeded = true + err = errSendQExceeded + } else { + socket.buffers = append(socket.buffers, data) + socket.totalLength = prospectiveLen + } } socket.Unlock() @@ -165,7 +174,7 @@ func (socket *Socket) readyToWrite() bool { socket.Lock() defer socket.Unlock() // on the first time observing socket.closed, we still have to write socket.finalData - return !socket.finalized && (len(socket.buffer) > 0 || socket.closed || socket.sendQExceeded) + return !socket.finalized && (socket.totalLength > 0 || socket.closed || socket.sendQExceeded) } // send actually writes messages to socket.Conn; it may block @@ -193,11 +202,13 @@ func (socket *Socket) send() { func (socket *Socket) performWrite() { // retrieve the buffered data, clear the buffer socket.Lock() - buffer := socket.buffer - socket.buffer = nil + buffers := socket.buffers + socket.buffers = nil + socket.totalLength = 0 socket.Unlock() - _, err := socket.conn.Write(buffer) + // on Linux, the runtime will optimize this into a single writev(2) call: + _, err := (*net.Buffers)(&buffers).WriteTo(socket.conn) socket.Lock() shouldClose := (err != nil) || socket.closed || socket.sendQExceeded diff --git a/vendor b/vendor index f606564d..9dd7467d 160000 --- a/vendor +++ b/vendor @@ -1 +1 @@ -Subproject commit f606564da4732e70afeb93a0fc5d80a9f8a04c56 +Subproject commit 9dd7467d3dfc045cf5dee2f6f6951465437e2ac5