client.go | 44 +++++++++++++++++++++++++++----------------- client_test.go | 4 ++-- daemon_test.go | 1 + room_test.go | 7 ++++--- diff --git a/client.go b/client.go index 3be53ff08846374a5f7c162572e03b9e402b42fcc8ebc80ab44f5e2de87f52b0..1a911f60664e71b8c080260bae9a1e475d1f82a03645b57ff2bd298ae46c9fb3 100644 --- a/client.go +++ b/client.go @@ -27,8 +27,11 @@ "time" ) const ( - CRLF = "\x0d\x0a" - BufSize = 1380 + BufSize = 1500 +) + +var ( + CRLF []byte = []byte{'\x0d', '\x0a'} ) type Client struct { @@ -59,34 +62,41 @@ // Client processor blockingly reads everything remote client sends, // splits messages by CRLF and send them to Daemon gorouting for processing // it futher. Also it can signalize that client is unavailable (disconnected). func (client *Client) Processor(sink chan<- ClientEvent) { - var bufNet []byte - buf := make([]byte, 0) + sink <- ClientEvent{client, EventNew, ""} log.Println(client, "New client") - sink <- ClientEvent{client, EventNew, ""} + buf := make([]byte, BufSize*2) + var n int + var prev int + var i int + var err error for { - bufNet = make([]byte, BufSize) - _, err := client.conn.Read(bufNet) + if prev == BufSize { + log.Println(client, "buffer size exceeded, kicking him") + sink <- ClientEvent{client, EventDel, ""} + client.conn.Close() + break + } + n, err = client.conn.Read(buf[prev:]) if err != nil { sink <- ClientEvent{client, EventDel, ""} break } - bufNet = bytes.TrimRight(bufNet, "\x00") - buf = append(buf, bufNet...) - if !bytes.HasSuffix(buf, []byte(CRLF)) { + prev += n + CheckMore: + i = bytes.Index(buf[:prev], CRLF) + if i == -1 { continue } - for _, msg := range bytes.Split(buf[:len(buf)-2], []byte(CRLF)) { - if len(msg) > 0 { - sink <- ClientEvent{client, EventMsg, string(msg)} - } - } - buf = []byte{} + sink <- ClientEvent{client, EventMsg, string(buf[:i])} + copy(buf, buf[i+2:prev]) + prev -= (i + 2) + goto CheckMore } } // Send message as is with CRLF appended. func (client *Client) Msg(text string) { - client.conn.Write([]byte(text + CRLF)) + client.conn.Write(append([]byte(text), CRLF...)) } // Send message from server. It has ": servername" prefix. diff --git a/client_test.go b/client_test.go index b79e589c2dcc0beb9ae5f3f2f7332d2e4a48cfb49b2a926ae1b4d9c1baf8bb64..127636dceecd120ceff732bf172d26c5c061e5eff1f021330c80fa82fe97467c 100644 --- a/client_test.go +++ b/client_test.go @@ -47,10 +47,10 @@ msg := <-conn.inbound if msg == "" { return 0, conn } - for n, bt := range []byte(msg + CRLF) { + for n, bt := range append([]byte(msg), CRLF...) { b[n] = bt } - return len(msg), nil + return len(msg)+2, nil } type MyAddr struct{} diff --git a/daemon_test.go b/daemon_test.go index 45fdab3a866395bbb5bd9454a55911db8e075aa02b37d82cb358e5c54c1de5d8..b5e75d7b6c83509415d4e7ebf17be63d6a707b5935cac22b0fe3d5bc5504f4fc 100644 --- a/daemon_test.go +++ b/daemon_test.go @@ -91,6 +91,7 @@ } conn.inbound <- "AWAY" conn.inbound <- "UNEXISTENT CMD" + <-conn.outbound if r := <-conn.outbound; r != ":foohost 421 meinick UNEXISTENT :Unknown command\r\n" { t.Fatal("reply for unexistent command", r) } diff --git a/room_test.go b/room_test.go index 1a53743785d98b35653a8725ce70fa6d7d2327b6c6256e5383c4d67e05c92405..e8e1978cc3e7b13f197fbe9515cd38bf20772f63a6128b7a4bb1ab676d70b27f 100644 --- a/room_test.go +++ b/room_test.go @@ -56,8 +56,8 @@ client2 := NewClient(&host, conn2) go client1.Processor(events) go client2.Processor(events) - conn1.inbound <- "NICK nick1\r\nUSER foo1 bar1 baz1 :Long name1\r\n" - conn2.inbound <- "NICK nick2\r\nUSER foo2 bar2 baz2 :Long name2\r\n" + conn1.inbound <- "NICK nick1\r\nUSER foo1 bar1 baz1 :Long name1" + conn2.inbound <- "NICK nick2\r\nUSER foo2 bar2 baz2 :Long name2" for i := 0; i < 6; i++ { <-conn1.outbound <-conn2.outbound @@ -105,6 +105,7 @@ } conn1.inbound <- "PRIVMSG nick2 :Hello" conn1.inbound <- "PRIVMSG #foo :world" conn1.inbound <- "NOTICE #foo :world" + <-conn2.outbound if r := <-conn2.outbound; r != ":nick1!foo1@someclient PRIVMSG nick2 :Hello\r\n" { t.Fatal("first message", r) } @@ -127,7 +128,7 @@ conn := NewTestingConn() client := NewClient(&host, conn) go client.Processor(events) - conn.inbound <- "NICK nick2\r\nUSER foo2 bar2 baz2 :Long name2\r\n" + conn.inbound <- "NICK nick2\r\nUSER foo2 bar2 baz2 :Long name2" for i := 0; i < 6; i++ { <-conn.outbound }