1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
|
/*
Copyright 2013-2014 Canonical Ltd.
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License version 3, as published
by the Free Software Foundation.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranties of
MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Package protocol implements the client-daemon <-> push-server protocol.
package protocol
import (
"bytes"
"encoding/binary"
"encoding/json"
"fmt"
"io"
"net"
"time"
)
// Protocol is a connection capable of writing and reading the wire format
// of protocol messages.
type Protocol interface {
SetDeadline(t time.Time)
ReadMessage(msg interface{}) error
WriteMessage(msg interface{}) error
}
func ReadWireFormatVersion(conn net.Conn, exchangeTimeout time.Duration) (ver int, err error) {
var buf1 [1]byte
err = conn.SetReadDeadline(time.Now().Add(exchangeTimeout))
if err != nil {
panic(fmt.Errorf("can't set deadline: %v", err))
}
_, err = conn.Read(buf1[:])
ver = int(buf1[0])
return
}
const ProtocolWireVersion = 0
// protocol0 handles version 0 of the wire format
type protocol0 struct {
buffer *bytes.Buffer
enc *json.Encoder
conn net.Conn
}
// NewProtocol0 creates and initialises a protocol with wire format version 0.
func NewProtocol0(conn net.Conn) Protocol {
buf := bytes.NewBuffer(make([]byte, 5000))
return &protocol0{
buffer: buf,
enc: json.NewEncoder(buf),
conn: conn}
}
// SetDeadline sets the deadline for the subsequent WriteMessage/ReadMessage exchange.
func (c *protocol0) SetDeadline(t time.Time) {
err := c.conn.SetDeadline(t)
if err != nil {
panic(fmt.Errorf("can't set deadline: %v", err))
}
}
// ReadMessage reads from the connection one message with a JSON body
// preceded by its big-endian uint16 length.
func (c *protocol0) ReadMessage(msg interface{}) error {
c.buffer.Reset()
_, err := io.CopyN(c.buffer, c.conn, 2)
if err != nil {
return err
}
length := binary.BigEndian.Uint16(c.buffer.Bytes())
c.buffer.Reset()
_, err = io.CopyN(c.buffer, c.conn, int64(length))
if err != nil {
return err
}
return json.Unmarshal(c.buffer.Bytes(), msg)
}
// WriteMessage writes one message to the connection with a JSON body
// preceding it with its big-endian uint16 length.
func (c *protocol0) WriteMessage(msg interface{}) error {
c.buffer.Reset()
c.buffer.WriteString("\x00\x00") // placeholder for length
err := c.enc.Encode(msg)
if err != nil {
panic(fmt.Errorf("WriteMessage got: %v", err))
}
msgLen := c.buffer.Len() - 3 // length space, extra newline
toWrite := c.buffer.Bytes()
binary.BigEndian.PutUint16(toWrite[:2], uint16(msgLen))
_, err = c.conn.Write(toWrite[:msgLen+2])
return err
}
|