From 39a7da0a370767a27c08a1bce705eb978b160670 Mon Sep 17 00:00:00 2001 From: kyle Date: Sat, 20 Dec 2014 15:23:57 +0200 Subject: [PATCH 1/6] Added timeout to deal with connecting to slow and unreliable irc servers --- client/connection.go | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/client/connection.go b/client/connection.go index 2775933..b216ac1 100644 --- a/client/connection.go +++ b/client/connection.go @@ -79,6 +79,9 @@ type Config struct { // Split PRIVMSGs, NOTICEs and CTCPs longer than // SplitLen characters over multiple lines. SplitLen int + + // Timeout, The amount of time in seconds until a timeout is triggered. + Timeout time.Duration } func NewConfig(nick string, args ...string) *Config { @@ -88,6 +91,7 @@ func NewConfig(nick string, args ...string) *Config { NewNick: func(s string) string { return s + "_" }, Recover: (*Conn).LogPanic, // in dispatch.go SplitLen: 450, + Timeout: 60, } cfg.Me.Ident = "goirc" if len(args) > 0 && args[0] != "" { @@ -207,8 +211,14 @@ func (conn *Conn) Connect() error { if !hasPort(conn.cfg.Server) { conn.cfg.Server += ":6697" } + if &conn.cfg.Timeout != nil{ + conn.cfg.Timeout = (60 * time.Second) + } logging.Info("irc.Connect(): Connecting to %s with SSL.", conn.cfg.Server) - if s, err := tls.Dial("tcp", conn.cfg.Server, conn.cfg.SSLConfig); err == nil { + dialer := &net.Dialer{ + Timeout : conn.cfg.Timeout, + } + if s, err := tls.DialWithDialer(dialer, "tcp", conn.cfg.Server, conn.cfg.SSLConfig); err == nil { conn.sock = s } else { return err @@ -217,8 +227,11 @@ func (conn *Conn) Connect() error { if !hasPort(conn.cfg.Server) { conn.cfg.Server += ":6667" } + if &conn.cfg.Timeout != nil{ + conn.cfg.Timeout = (60 * time.Second) + } logging.Info("irc.Connect(): Connecting to %s without SSL.", conn.cfg.Server) - if s, err := net.Dial("tcp", conn.cfg.Server); err == nil { + if s, err := net.DialTimeout("tcp", conn.cfg.Server, conn.cfg.Timeout); err == nil { conn.sock = s } else { return err From c8beed09da8cffbda9264d836587372664c15e8f Mon Sep 17 00:00:00 2001 From: kyle Date: Sat, 20 Dec 2014 16:56:58 +0200 Subject: [PATCH 2/6] Fixed formatting with go fmt --- client/connection.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/client/connection.go b/client/connection.go index b216ac1..54b7435 100644 --- a/client/connection.go +++ b/client/connection.go @@ -23,8 +23,8 @@ type Conn struct { // Handlers intHandlers *hSet - fgHandlers *hSet - bgHandlers *hSet + fgHandlers *hSet + bgHandlers *hSet // State tracker for nicks and channels st state.Tracker @@ -91,7 +91,7 @@ func NewConfig(nick string, args ...string) *Config { NewNick: func(s string) string { return s + "_" }, Recover: (*Conn).LogPanic, // in dispatch.go SplitLen: 450, - Timeout: 60, + Timeout: 60, } cfg.Me.Ident = "goirc" if len(args) > 0 && args[0] != "" { @@ -211,13 +211,13 @@ func (conn *Conn) Connect() error { if !hasPort(conn.cfg.Server) { conn.cfg.Server += ":6697" } - if &conn.cfg.Timeout != nil{ + if &conn.cfg.Timeout != nil { conn.cfg.Timeout = (60 * time.Second) } logging.Info("irc.Connect(): Connecting to %s with SSL.", conn.cfg.Server) dialer := &net.Dialer{ - Timeout : conn.cfg.Timeout, - } + Timeout: conn.cfg.Timeout, + } if s, err := tls.DialWithDialer(dialer, "tcp", conn.cfg.Server, conn.cfg.SSLConfig); err == nil { conn.sock = s } else { @@ -227,7 +227,7 @@ func (conn *Conn) Connect() error { if !hasPort(conn.cfg.Server) { conn.cfg.Server += ":6667" } - if &conn.cfg.Timeout != nil{ + if &conn.cfg.Timeout != nil { conn.cfg.Timeout = (60 * time.Second) } logging.Info("irc.Connect(): Connecting to %s without SSL.", conn.cfg.Server) From dde47a6a3277c70392aebfb5d6b8f098369e3268 Mon Sep 17 00:00:00 2001 From: kyle Date: Sat, 20 Dec 2014 19:36:08 +0200 Subject: [PATCH 3/6] fixed inconsistencies --- client/connection.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/client/connection.go b/client/connection.go index e9c7708..c7ba956 100644 --- a/client/connection.go +++ b/client/connection.go @@ -227,15 +227,12 @@ func (conn *Conn) Connect() error { if conn.connected { return fmt.Errorf("irc.Connect(): Cannot connect to %s, already connected.", conn.cfg.Server) } + conn.dialer.Timeout = conn.cfg.Timeout if conn.cfg.SSL { if !hasPort(conn.cfg.Server) { conn.cfg.Server = net.JoinHostPort(conn.cfg.Server, "6697") } - if &conn.cfg.Timeout != nil { - conn.cfg.Timeout = (60 * time.Second) - } logging.Info("irc.Connect(): Connecting to %s with SSL.", conn.cfg.Server) - conn.dialer.Timeout = conn.cfg.Timeout if s, err := tls.DialWithDialer(conn.dialer, "tcp", conn.cfg.Server, conn.cfg.SSLConfig); err == nil { conn.sock = s } else { @@ -245,11 +242,8 @@ func (conn *Conn) Connect() error { if !hasPort(conn.cfg.Server) { conn.cfg.Server = net.JoinHostPort(conn.cfg.Server, "6667") } - if &conn.cfg.Timeout != nil { - conn.cfg.Timeout = (60 * time.Second) - } logging.Info("irc.Connect(): Connecting to %s without SSL.", conn.cfg.Server) - if s, err := conn.dialer.DialTimeout("tcp", conn.cfg.Server, conn.cfg.Timeout); err == nil { + if s, err := conn.dialer.Dial("tcp", conn.cfg.Server); err == nil { conn.sock = s } else { return err From 5e5f5f0253273a19dbd296ec14183e0d34a30b20 Mon Sep 17 00:00:00 2001 From: kyle Date: Sat, 20 Dec 2014 20:39:44 +0200 Subject: [PATCH 4/6] Moved timeout to Client from Connect --- client/connection.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/connection.go b/client/connection.go index c7ba956..d94f736 100644 --- a/client/connection.go +++ b/client/connection.go @@ -128,6 +128,7 @@ func Client(cfg *Config) *Conn { } dialer := new(net.Dialer) + dialer.Timeout = cfg.Timeout if cfg.LocalAddr != "" { if !hasPort(cfg.LocalAddr) { cfg.LocalAddr += ":0" @@ -227,7 +228,6 @@ func (conn *Conn) Connect() error { if conn.connected { return fmt.Errorf("irc.Connect(): Cannot connect to %s, already connected.", conn.cfg.Server) } - conn.dialer.Timeout = conn.cfg.Timeout if conn.cfg.SSL { if !hasPort(conn.cfg.Server) { conn.cfg.Server = net.JoinHostPort(conn.cfg.Server, "6697") From 2e3925035509c9a0daed9296411182fd5046f497 Mon Sep 17 00:00:00 2001 From: Alex Bramley Date: Tue, 23 Dec 2014 18:21:53 +0000 Subject: [PATCH 5/6] Allow Join command to take an optional key. --- client/commands.go | 10 ++++++++-- client/commands_test.go | 2 ++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/client/commands.go b/client/commands.go index 20e3a66..164e04e 100644 --- a/client/commands.go +++ b/client/commands.go @@ -96,8 +96,14 @@ func (conn *Conn) User(ident, name string) { conn.Raw(USER + " " + ident + " 12 * :" + name) } -// Join() sends a JOIN command to the server -func (conn *Conn) Join(channel string) { conn.Raw(JOIN + " " + channel) } +// Join() sends a JOIN command to the server with an optional key +func (conn *Conn) Join(channel string, key ...string) { + k := "" + if len(key) > 0 { + k = " " + key[0] + } + conn.Raw(JOIN + " " + channel + k) +} // Part() sends a PART command to the server with an optional part message func (conn *Conn) Part(channel string, message ...string) { diff --git a/client/commands_test.go b/client/commands_test.go index dabaf61..a4d457e 100644 --- a/client/commands_test.go +++ b/client/commands_test.go @@ -97,6 +97,8 @@ func TestClientCommands(t *testing.T) { c.Join("#foo") s.nc.Expect("JOIN #foo") + c.Join("#foo bar") + s.nc.Expect("JOIN #foo bar") c.Part("#foo") s.nc.Expect("PART #foo") From 36e4aeb603cd3aaa6e77a4f220e6bf1fad5caccf Mon Sep 17 00:00:00 2001 From: Alex Bramley Date: Wed, 31 Dec 2014 17:31:50 +0000 Subject: [PATCH 6/6] An attempt to trigger data races in the state tracker. --- state/tracker_test.go | 58 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/state/tracker_test.go b/state/tracker_test.go index 9ae2c19..78521dc 100644 --- a/state/tracker_test.go +++ b/state/tracker_test.go @@ -1,6 +1,9 @@ package state -import "testing" +import ( + "sync" + "testing" +) func TestSTNewTracker(t *testing.T) { st := NewTracker("mynick") @@ -413,3 +416,56 @@ func TestSTWipe(t *testing.T) { t.Errorf("Nick chan lists wrong length after wipe.") } } + +func TestSTRaces(t *testing.T) { + st := NewTracker("mynick") + wg := sync.WaitGroup{} + + for i := 'a'; i < 'g'; i++ { + wg.Add(2) + go func(s string) { + st.NewNick("nick-" + s) + c := st.NewChannel("#chan-" + s) + st.Associate(c, st.me) + wg.Done() + }(string(i)) + go func(s string) { + n := st.GetNick("nick-" + s) + c := st.GetChannel("#chan-" + s) + st.Associate(c, n) + wg.Done() + }(string(i)) + } + wg.Wait() + + wg = sync.WaitGroup{} + race := func(ns, cs string) { + wg.Add(5) + go func() { + st.Associate(st.GetChannel("#chan-"+cs), st.GetNick("nick-"+ns)) + wg.Done() + }() + go func() { + st.GetNick("nick-"+ns).Channels() + wg.Done() + }() + go func() { + st.GetChannel("#chan-"+cs).Nicks() + wg.Done() + }() + go func() { + st.Dissociate(st.GetChannel("#chan-"+cs), st.GetNick("nick-"+ns)) + wg.Done() + }() + go func() { + st.ReNick("nick-"+ns, "nick2-"+ns) + wg.Done() + }() + } + for n := 'a'; n < 'g'; n++ { + for c := 'a'; c < 'g'; c++ { + race(string(n), string(c)) + } + } + wg.Wait() +}