Refactored and corrected client's network data reading

This commit is contained in:
Sergey Matveev 2015-10-06 11:27:11 +03:00
parent 63f94d18c9
commit 0b8c40aa61
4 changed files with 34 additions and 22 deletions

View File

@ -27,8 +27,11 @@ import (
) )
const ( const (
CRLF = "\x0d\x0a" BufSize = 1500
BufSize = 1380 )
var (
CRLF []byte = []byte{'\x0d', '\x0a'}
) )
type Client struct { type Client struct {
@ -59,34 +62,41 @@ func NewClient(hostname *string, conn net.Conn) *Client {
// splits messages by CRLF and send them to Daemon gorouting for processing // splits messages by CRLF and send them to Daemon gorouting for processing
// it futher. Also it can signalize that client is unavailable (disconnected). // it futher. Also it can signalize that client is unavailable (disconnected).
func (client *Client) Processor(sink chan<- ClientEvent) { func (client *Client) Processor(sink chan<- ClientEvent) {
var bufNet []byte
buf := make([]byte, 0)
log.Println(client, "New client")
sink <- ClientEvent{client, EventNew, ""} sink <- ClientEvent{client, EventNew, ""}
log.Println(client, "New client")
buf := make([]byte, BufSize*2)
var n int
var prev int
var i int
var err error
for { for {
bufNet = make([]byte, BufSize) if prev == BufSize {
_, err := client.conn.Read(bufNet) 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 { if err != nil {
sink <- ClientEvent{client, EventDel, ""} sink <- ClientEvent{client, EventDel, ""}
break break
} }
bufNet = bytes.TrimRight(bufNet, "\x00") prev += n
buf = append(buf, bufNet...) CheckMore:
if !bytes.HasSuffix(buf, []byte(CRLF)) { i = bytes.Index(buf[:prev], CRLF)
if i == -1 {
continue continue
} }
for _, msg := range bytes.Split(buf[:len(buf)-2], []byte(CRLF)) { sink <- ClientEvent{client, EventMsg, string(buf[:i])}
if len(msg) > 0 { copy(buf, buf[i+2:prev])
sink <- ClientEvent{client, EventMsg, string(msg)} prev -= (i + 2)
} goto CheckMore
}
buf = []byte{}
} }
} }
// Send message as is with CRLF appended. // Send message as is with CRLF appended.
func (client *Client) Msg(text string) { 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. // Send message from server. It has ": servername" prefix.

View File

@ -47,10 +47,10 @@ func (conn *TestingConn) Read(b []byte) (n int, err error) {
if msg == "" { if msg == "" {
return 0, conn return 0, conn
} }
for n, bt := range []byte(msg + CRLF) { for n, bt := range append([]byte(msg), CRLF...) {
b[n] = bt b[n] = bt
} }
return len(msg), nil return len(msg)+2, nil
} }
type MyAddr struct{} type MyAddr struct{}

View File

@ -91,6 +91,7 @@ func TestRegistrationWorkflow(t *testing.T) {
conn.inbound <- "AWAY" conn.inbound <- "AWAY"
conn.inbound <- "UNEXISTENT CMD" conn.inbound <- "UNEXISTENT CMD"
<-conn.outbound
if r := <-conn.outbound; r != ":foohost 421 meinick UNEXISTENT :Unknown command\r\n" { if r := <-conn.outbound; r != ":foohost 421 meinick UNEXISTENT :Unknown command\r\n" {
t.Fatal("reply for unexistent command", r) t.Fatal("reply for unexistent command", r)
} }

View File

@ -56,8 +56,8 @@ func TestTwoUsers(t *testing.T) {
go client1.Processor(events) go client1.Processor(events)
go client2.Processor(events) go client2.Processor(events)
conn1.inbound <- "NICK nick1\r\nUSER foo1 bar1 baz1 :Long name1\r\n" conn1.inbound <- "NICK nick1\r\nUSER foo1 bar1 baz1 :Long name1"
conn2.inbound <- "NICK nick2\r\nUSER foo2 bar2 baz2 :Long name2\r\n" conn2.inbound <- "NICK nick2\r\nUSER foo2 bar2 baz2 :Long name2"
for i := 0; i < 6; i++ { for i := 0; i < 6; i++ {
<-conn1.outbound <-conn1.outbound
<-conn2.outbound <-conn2.outbound
@ -105,6 +105,7 @@ func TestTwoUsers(t *testing.T) {
conn1.inbound <- "PRIVMSG nick2 :Hello" conn1.inbound <- "PRIVMSG nick2 :Hello"
conn1.inbound <- "PRIVMSG #foo :world" conn1.inbound <- "PRIVMSG #foo :world"
conn1.inbound <- "NOTICE #foo :world" conn1.inbound <- "NOTICE #foo :world"
<-conn2.outbound
if r := <-conn2.outbound; r != ":nick1!foo1@someclient PRIVMSG nick2 :Hello\r\n" { if r := <-conn2.outbound; r != ":nick1!foo1@someclient PRIVMSG nick2 :Hello\r\n" {
t.Fatal("first message", r) t.Fatal("first message", r)
} }
@ -127,7 +128,7 @@ func TestJoin(t *testing.T) {
client := NewClient(&host, conn) client := NewClient(&host, conn)
go client.Processor(events) 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++ { for i := 0; i < 6; i++ {
<-conn.outbound <-conn.outbound
} }