Example #1
0
// NewConnection creates a SSMP connection out of a streaming netwrok connection.
//
// This method blocks until either a first message is received or a 10s timeout
// elapses.
//
// Each accepted connection spawns a goroutine continuously reading from the
// underlying network connection and triggering the Dispatcher. The caller must
// keep track of the returned Connection and call the Close method to stop the
// read goroutine and close the udnerlying netwrok connection.
//
// errInvalidLogin is returned if the first message is not a well-formed LOGIN
// request.
// errUnauthorized is returned if the authenticator doesn't accept the provided
// credentials.
func NewConnection(c net.Conn, a Authenticator, d *Dispatcher) (*Connection, error) {
	r := ssmp.NewDecoder(c)
	c.SetReadDeadline(time.Now().Add(10 * time.Second))
	verb, err := r.DecodeVerb()
	if err != nil || !ssmp.Equal(verb, ssmp.LOGIN) {
		return nil, ErrInvalidLogin
	}
	user, err := r.DecodeId()
	if err != nil {
		return nil, ErrInvalidLogin
	}
	scheme, err := r.DecodeId()
	if err != nil {
		return nil, ErrInvalidLogin
	}
	var cred []byte
	if r.AtEnd() {
		cred = []byte{}
	} else if cred, err = r.DecodePayload(); err != nil {
		return nil, ErrInvalidLogin
	}
	if !a.Auth(c, user, scheme, cred) {
		return nil, ErrUnauthorized
	}
	r.Reset()
	cc := &Connection{
		c:    c,
		r:    r,
		User: string(user),
	}
	go cc.readLoop(d)
	cc.Write(respOk)
	return cc, nil
}
Example #2
0
func (c *client) readLoop() {
	defer c.wg.Done()
	defer close(c.responses)

	idle := false
	r := ssmp.NewDecoder(c.c)
	for {
		c.c.SetReadDeadline(time.Now().Add(30 * time.Second))
		code, err := r.DecodeCode()
		if err != nil {
			if nerr, ok := err.(net.Error); ok && nerr.Timeout() && !idle {
				idle = true
				c.c.Write(ping)
				continue
			}
			// unwrap network error
			if oerr, ok := err.(*net.OpError); ok {
				err = oerr.Err
			}
			if err != io.EOF && err.Error() != "use of closed network connection" {
				fmt.Printf("Client[%p] Failed to read: %v\n", c, err)
			}
			break
		}
		idle = false
		if code == ssmp.CodeEvent {
			ev, err := parseEvent(r)
			if err != nil {
				fmt.Printf("Client[%p] Invalid event: %v\n", c, err)
				break
			}
			r.Reset()
			if ssmp.Equal(ev.Name, ssmp.PING) {
				c.c.Write(pong)
				continue
			}
			if ssmp.Equal(ev.Name, ssmp.PONG) {
				continue
			}
			h := c.EventHandler()
			if h == nil {
				continue
			}
			h.HandleEvent(ev)
			continue
		}
		var payload string
		if !r.AtEnd() {
			d, err := r.DecodePayload()
			if err != nil {
				fmt.Printf("Client[%p] Invalid response: %v\n", c, err)
				break
			}
			payload = string(d)
		}
		r.Reset()
		c.responses <- Response{
			Code:    code,
			Message: payload,
		}
	}
	c.c.Close()
}