adds a fairly interesting abstraction around packets and shit ... successfully authenticates or failes to authenticate
3 files changed, 150 insertions(+), 38 deletions(-)

M gorcon/client.go
M gorcon/gorcon.go
M main.go
M gorcon/client.go +127 -1
@@ 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 @@ func NewClient(addr string) (c *Client, 
     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
+}

          
M gorcon/gorcon.go +7 -7
@@ 22,7 22,7 @@ type CmdType int32
 type packetHeader struct {
     Size int32
     Id int32
-    Type int32
+    Type CmdType
 }
 
 type packet struct {

          
@@ 34,19 34,19 @@ func (p *packet) String() string {
     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 @@ func WriteCommand(w io.Writer, cmdtype C
     return nil
 }
 
-func ReadResp(r io.Reader, ) (p *packet, err error) {
+func readResp(r io.Reader) (p *packet, err error) {
     p = &packet{
         packetHeader: &packetHeader{},
     }

          
M main.go +16 -30
@@ 3,12 3,9 @@ package main
 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 @@ type response struct {
 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...")
 }