# HG changeset patch # User sqwishy # Date 1392671929 28800 # Mon Feb 17 13:18:49 2014 -0800 # Node ID 2e9669d50a26f8debcc37a8e918dac79cf1cd574 # Parent ca90c50a25dc86f43d5322b749fc0a0417b1d6ce adds a fairly interesting abstraction around packets and shit ... successfully authenticates or failes to authenticate diff --git a/gorcon/client.go b/gorcon/client.go --- a/gorcon/client.go +++ b/gorcon/client.go @@ -1,9 +1,26 @@ package gorcon +import "bufio" +import "io" +import "sync" import "net" +import "log" +import "fmt" + +var _ = fmt.Println +var _ = log.Println + +//////////////////////////////////////////////////////////////////////////////// + +const ( + EXEC_ID = int32(1) + AUTH_ID = int32(2) + TERM_ID = int32(4) +) type Client struct { net.Conn + queue commQueue } func NewClient(addr string) (c *Client, err error) { @@ -11,6 +28,115 @@ if err != nil { return } - c = &Client{conn} + c = &Client{ + Conn: conn, + queue: commQueue{ + comms: make([]*comm, 0), + }, + } + go c.readLoop() return } + +func (c *Client) Auth(data string) (chan error) { + _, errch := c.writeCommand(AUTH_ID, SERVERDATA_AUTH, []byte(data)) + return errch +} + +func (c *Client) writeCommand(id int32, cmdtype CmdType, body []byte) (chan *Message, chan error) { + msgch := make(chan *Message, 1) // Keep these async + errch := make(chan error, 1) + if err := writeCommand(c, id, cmdtype, body); err != nil { + errch <- err + close(msgch) + } else { + c.queue.Push(&comm{msgch, errch}) + } + return msgch, errch +} + +func (c *Client) readLoop() { + r := bufio.NewReader(c) + for { + resp, err := readResp(r) + log.Printf("<<< %+v / %v\n", resp, err) + // TODO, implement terminal packets + comm := c.queue.Peek() + if comm == nil { + log.Panicln("u maek le bug uheuheuheh") + } + if err != nil { + if err == io.EOF { + // Retreaaaat! + log.Panicln(err) + } + comm.errch <- err + } + if (resp.Id == AUTH_ID || resp.Id == -1) && resp.Type == SERVERDATA_AUTH_RESPONSE { + // Packet two of two of response to auth request + log.Println("Received two of two of responses to auth request") + c.queue.Pop() + if resp.Id == AUTH_ID { + comm.errch <- nil + } else { + comm.errch <- fmt.Errorf("Authentication Failed") + } + close(comm.msgch) + } else if resp.Id == AUTH_ID && resp.Type == SERVERDATA_RESPONSE_VALUE { + // Packet one of two of response to auth request + log.Println("Received one of two of responses to auth request") + continue + } else if (resp.Id & EXEC_ID|TERM_ID != 0) && (resp.Type == SERVERDATA_RESPONSE_VALUE) { + log.Println("Received response to exec request") + c.queue.Pop() + comm.msgch <- &Message{[]*packet{resp}} + close(comm.errch) + } else { + log.Println("Received ... fuck if I know ... I'm likely going to crash and burn!") + c.queue.Pop() + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +type Message struct { + packets []*packet +} + +//////////////////////////////////////////////////////////////////////////////// + +type comm struct { + msgch chan *Message + errch chan error +} + +type commQueue struct { + sync.Mutex + comms []*comm +} + +func (q *commQueue) Push(c *comm) { + q.Lock() + defer q.Unlock() + q.comms = append(q.comms, c) +} + +func (q *commQueue) Peek() (c *comm) { + q.Lock() + defer q.Unlock() + if len(q.comms) > 0 { + c = q.comms[0] + } + return +} + +func (q *commQueue) Pop() (c *comm) { + q.Lock() + defer q.Unlock() + if len(q.comms) > 0 { + c = q.comms[0] + q.comms = q.comms[1:] + } + return +} diff --git a/gorcon/gorcon.go b/gorcon/gorcon.go --- a/gorcon/gorcon.go +++ b/gorcon/gorcon.go @@ -22,7 +22,7 @@ type packetHeader struct { Size int32 Id int32 - Type int32 + Type CmdType } type packet struct { @@ -34,19 +34,19 @@ return fmt.Sprintf("&{packetHeader:%+v Body:%v}", p.packetHeader, p.Body) } -func WriteCommandString(w io.Writer, cmdtype CmdType, body string) error { - return WriteCommand(w, cmdtype, []byte(body)) +func writeCommandString(w io.Writer, id int32, cmdtype CmdType, body string) error { + return writeCommand(w, id, cmdtype, []byte(body)) } -func WriteCommand(w io.Writer, cmdtype CmdType, body []byte) error { +func writeCommand(w io.Writer, id int32, cmdtype CmdType, body []byte) error { // For the size, the header is 3 fields each 4 bytes in size (but we // ignore the Size field), the length of the body, and then our two zero // bytes at the end size := 2 * 4 + len(body) + 2 p := &packetHeader{ Size: int32(size), - Id: int32(0), - Type: int32(cmdtype), + Id: id, + Type: cmdtype, } if err := binary.Write(w, binary.LittleEndian, p); err != nil { return err @@ -62,7 +62,7 @@ return nil } -func ReadResp(r io.Reader, ) (p *packet, err error) { +func readResp(r io.Reader) (p *packet, err error) { p = &packet{ packetHeader: &packetHeader{}, } diff --git a/main.go b/main.go --- a/main.go +++ b/main.go @@ -3,12 +3,9 @@ import "fmt" import "log" import "./gorcon" // Relative imports! Woo hoo! -import "io" -import "bufio" var _ = fmt.Println var _ = log.Println -var _ = io.EOF type response struct { Id int32 @@ -19,38 +16,27 @@ func main() { log.Println("Hello, world!") - client, err := gorcon.NewClient("74.91.117.120:27015") + client, err := gorcon.NewClient("74.91.117.120:27017") if err != nil { log.Panicln(err) } - done := make(chan bool) - - go func() { - r := bufio.NewReader(client) - for { - resp, err := gorcon.ReadResp(r) - if err != nil { - if err == io.EOF { - return - } - log.Panicln(err) - } - log.Printf("<<< %+v\n", resp) + errch := client.Auth("hunter2") + select { + case err := <-errch: + if err != nil { + log.Println(err) + } else { + log.Println("success?") } - defer func() { - done<-true - }() - }() - - log.Println(client) - - err = gorcon.WriteCommandString(client, gorcon.SERVERDATA_AUTH, "hunter2") - if err != nil { - log.Panicln(err) } - log.Println("waiting...") - <-done - log.Println("leaving...") + //select { + //case msg := <-msgch: + // log.Println(msg) + //case err := <-errch: + // log.Panicln(err) + //} + + log.Println("done...") }