From ec0a78153866cb44606dddc4b09f03cdea597746 Mon Sep 17 00:00:00 2001 From: mappu Date: Sun, 3 Apr 2016 13:15:57 +1200 Subject: [PATCH] libnmdc: fix panic() on connection failure, owing to storing nil in an interface --- src/libnmdc/libnmdc.go | 27 +++++++++++++++++++++++---- src/nmdc-log-service/main.go | 9 ++++++--- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/libnmdc/libnmdc.go b/src/libnmdc/libnmdc.go index 7f1d65e..056adb5 100644 --- a/src/libnmdc/libnmdc.go +++ b/src/libnmdc/libnmdc.go @@ -3,9 +3,11 @@ package libnmdc import ( "crypto/tls" + "errors" "fmt" "net" "net/url" + "reflect" "regexp" "strings" "time" @@ -65,6 +67,7 @@ const ( var rx_protocolMessage *regexp.Regexp var rx_publicChat *regexp.Regexp var rx_incomingTo *regexp.Regexp +var ErrNotConnected error = errors.New("Not connected") func init() { rx_protocolMessage = regexp.MustCompile("(?ms)^[^|]*|") @@ -92,10 +95,21 @@ type HubConnection struct { OnEvent chan HubEvent // Private state - conn net.Conn + conn net.Conn // this is an interface sentOurHello bool } +func isNil(a interface{}) bool { + // Workaround to catch the potential for storing nil in an interface. + // @ref http://stackoverflow.com/q/13476349 + defer func() { recover() }() + return a == nil || reflect.ValueOf(a).IsNil() +} + +func (this *HubConnection) isConnValid() bool { + return isNil(this.conn) +} + type HubEvent struct { EventType HubEventType Nick string @@ -159,8 +173,12 @@ func (this *HubConnection) userJoined_Full(uinf *UserInfo) { // Note that protocol messages are transmitted on the caller thread, not from // any internal libnmdc thread. func (this *HubConnection) SayRaw(protocolCommand string) error { - _, err := this.conn.Write([]byte(protocolCommand)) - return err + if this.isConnValid() { + _, err := this.conn.Write([]byte(protocolCommand)) + return err + } else { + return ErrNotConnected + } } func parseLock(lock []byte) string { @@ -333,11 +351,12 @@ func (this *HubConnection) worker() { if err == nil { this.OnEvent <- HubEvent{EventType: EVENT_CONNECTION_STATE_CHANGED, StateChange: CONNECTIONSTATE_CONNECTING} + this.conn = nil // WARNING: storing nil in an interface(!) } } // Read from socket into our local buffer (blocking) - if this.conn != nil { + if this.isConnValid() { readBuff := make([]byte, 4096) nbytes, err = this.conn.Read(readBuff) if nbytes > 0 { diff --git a/src/nmdc-log-service/main.go b/src/nmdc-log-service/main.go index 5a4c1e6..1684a72 100644 --- a/src/nmdc-log-service/main.go +++ b/src/nmdc-log-service/main.go @@ -15,6 +15,7 @@ var BaseDir string = "." var PMResponse string = "" var LogConnectionState bool var DebugMode bool +var VerifyTLS bool var CharacterMatcher *regexp.Regexp func init() { @@ -53,9 +54,10 @@ func LogMessage(hub, message string) { func HubWorker(addr, nick, password string) { opts := libnmdc.HubConnectionOptions{ - Address: libnmdc.HubAddress(addr), - Self: libnmdc.UserInfo{Nick: nick}, - NickPassword: password, + Address: libnmdc.HubAddress(addr), + SkipVerifyTLS: !VerifyTLS, + Self: libnmdc.UserInfo{Nick: nick}, + NickPassword: password, } hub := opts.Connect() @@ -104,6 +106,7 @@ func main() { flag.BoolVar(&LogConnectionState, "LogConnectionState", true, "Include connection state changes in log") flag.StringVar(&PMResponse, "PMResponse", "This is an automated service. For enquiries, please contact an administrator.", "Message to respond with on PM") flag.BoolVar(&DebugMode, "Debug", false, "Print additional information on stdout") + flag.BoolVar(&VerifyTLS, "VerifyTLS", true, "Verify TLS certificates") flag.Parse() // Assert dir exists