xmpp.go
author Chris Jones <chris@cjones.org>
Wed, 28 Dec 2011 11:30:10 -0700
changeset 13 c9527bbe99a6
parent 12 122ab6208c3c
child 15 aa2cf77f0ed3
permissions -rw-r--r--
Added a callback handler which will handle a stanza with a particular id.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
     1
// Copyright 2011 The Go Authors.  All rights reserved.
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
     2
// Use of this source code is governed by a BSD-style
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
     3
// license that can be found in the LICENSE file.
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
     4
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
     5
// This package implements a simple XMPP client according to RFCs 3920
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
     6
// and 3921, plus the various XEPs at http://xmpp.org/protocols/.
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
     7
package xmpp
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
     8
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
     9
import (
6
8e425e340ca1 Implemented writing to the remote. Now we have bidirectional communication.
Chris Jones <christian.jones@sri.com>
parents: 5
diff changeset
    10
	"bytes"
2
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    11
	"fmt"
4
a8fbec71a194 Added an interactive test and made Client implement io.Closer.
Chris Jones <chris@cjones.org>
parents: 2
diff changeset
    12
	"io"
2
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    13
	"net"
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    14
	"os"
10
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
    15
	"sync"
2
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    16
)
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    17
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    18
const (
10
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
    19
	// Version of RFC 3920 that we implement.
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
    20
	Version = "1.0"
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
    21
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
    22
	// Various XML namespaces.
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
    23
	nsStreams = "urn:ietf:params:xml:ns:xmpp-streams"
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
    24
	nsStream = "http://etherx.jabber.org/streams"
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
    25
	nsTLS = "urn:ietf:params:xml:ns:xmpp-tls"
11
48be1ae93fd4 Added SASL digest authentication.
Chris Jones <chris@cjones.org>
parents: 10
diff changeset
    26
	nsSASL = "urn:ietf:params:xml:ns:xmpp-sasl"
12
122ab6208c3c Added resource binding and structures for <iq>, <message>, and <presence>.
Chris Jones <chris@cjones.org>
parents: 11
diff changeset
    27
	nsBind = "urn:ietf:params:xml:ns:xmpp-bind"
10
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
    28
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
    29
	// DNS SRV names
2
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    30
	serverSrv = "xmpp-server"
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    31
	clientSrv = "xmpp-client"
10
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
    32
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
    33
	debug = true
2
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    34
)
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    35
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    36
// The client in a client-server XMPP connection.
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    37
type Client struct {
10
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
    38
	Jid JID
11
48be1ae93fd4 Added SASL digest authentication.
Chris Jones <chris@cjones.org>
parents: 10
diff changeset
    39
	password string
10
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
    40
	socket net.Conn
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
    41
	socketSync sync.WaitGroup
11
48be1ae93fd4 Added SASL digest authentication.
Chris Jones <chris@cjones.org>
parents: 10
diff changeset
    42
	saslExpected string
12
122ab6208c3c Added resource binding and structures for <iq>, <message>, and <presence>.
Chris Jones <chris@cjones.org>
parents: 11
diff changeset
    43
	authDone bool
122ab6208c3c Added resource binding and structures for <iq>, <message>, and <presence>.
Chris Jones <chris@cjones.org>
parents: 11
diff changeset
    44
	idMutex sync.Mutex
122ab6208c3c Added resource binding and structures for <iq>, <message>, and <presence>.
Chris Jones <chris@cjones.org>
parents: 11
diff changeset
    45
	nextId int64
13
c9527bbe99a6 Added a callback handler which will handle a stanza with a particular id.
Chris Jones <chris@cjones.org>
parents: 12
diff changeset
    46
	handlers chan *stanzaHandler
5
faef59c8db05 Added a goroutine to read data from the remote and parse it into
Chris Jones <chris@cjones.org>
parents: 4
diff changeset
    47
	In <-chan interface{}
faef59c8db05 Added a goroutine to read data from the remote and parse it into
Chris Jones <chris@cjones.org>
parents: 4
diff changeset
    48
	Out chan<- interface{}
10
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
    49
	xmlOut chan<- interface{}
9
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
    50
	TextOut chan<- *string
2
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    51
}
4
a8fbec71a194 Added an interactive test and made Client implement io.Closer.
Chris Jones <chris@cjones.org>
parents: 2
diff changeset
    52
var _ io.Closer = &Client{}
2
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    53
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    54
// Connect to the appropriate server and authenticate as the given JID
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    55
// with the given password.
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    56
func NewClient(jid *JID, password string) (*Client, os.Error) {
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    57
	// Resolve the domain in the JID.
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    58
	_, srvs, err := net.LookupSRV(clientSrv, "tcp", jid.Domain)
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    59
	if err != nil {
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    60
		return nil, os.NewError("LookupSrv " + jid.Domain +
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    61
			": " + err.String())
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    62
	}
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    63
9
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
    64
	var tcp *net.TCPConn
2
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    65
	for _, srv := range srvs {
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    66
		addrStr := fmt.Sprintf("%s:%d", srv.Target, srv.Port)
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    67
		addr, err := net.ResolveTCPAddr("tcp", addrStr)
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    68
		if err != nil {
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    69
			err = os.NewError(fmt.Sprintf("ResolveTCPAddr(%s): %s",
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    70
				addrStr, err.String()))
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    71
			continue
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    72
		}
9
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
    73
		tcp, err = net.DialTCP("tcp", nil, addr)
2
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    74
		if err != nil {
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    75
			err = os.NewError(fmt.Sprintf("DialTCP(%s): %s",
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    76
				addr, err.String()))
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    77
			continue
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    78
		}
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    79
	}
9
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
    80
	if tcp == nil {
2
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    81
		return nil, err
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    82
	}
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
    83
10
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
    84
	cl := new(Client)
11
48be1ae93fd4 Added SASL digest authentication.
Chris Jones <chris@cjones.org>
parents: 10
diff changeset
    85
	cl.password = password
10
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
    86
	cl.Jid = *jid
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
    87
	cl.socket = tcp
13
c9527bbe99a6 Added a callback handler which will handle a stanza with a particular id.
Chris Jones <chris@cjones.org>
parents: 12
diff changeset
    88
	cl.handlers = make(chan *stanzaHandler)
10
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
    89
9
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
    90
	// Start the transport handler, initially unencrypted.
10
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
    91
	tlsr, tlsw := cl.startTransport()
9
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
    92
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
    93
	// Start the reader and writers that convert to and from XML.
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
    94
	xmlIn := startXmlReader(tlsr)
10
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
    95
	cl.xmlOut = startXmlWriter(tlsw)
9
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
    96
	textOut := startTextWriter(tlsw)
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
    97
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
    98
	// Start the XMPP stream handler which filters stream-level
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
    99
	// events and responds to them.
10
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
   100
	clIn := cl.startStreamReader(xmlIn, cl.xmlOut)
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
   101
	clOut := startStreamWriter(cl.xmlOut)
5
faef59c8db05 Added a goroutine to read data from the remote and parse it into
Chris Jones <chris@cjones.org>
parents: 4
diff changeset
   102
8
30a7752cf8f7 Added the ability to parse <stream:features>.
Chris Jones <chris@cjones.org>
parents: 6
diff changeset
   103
	// Initial handshake.
30a7752cf8f7 Added the ability to parse <stream:features>.
Chris Jones <chris@cjones.org>
parents: 6
diff changeset
   104
	hsOut := &Stream{To: jid.Domain, Version: Version}
10
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
   105
	cl.xmlOut <- hsOut
9
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   106
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   107
	// TODO Wait for initialization to finish.
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   108
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   109
	cl.In = clIn
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   110
	cl.Out = clOut
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   111
	cl.TextOut = textOut
8
30a7752cf8f7 Added the ability to parse <stream:features>.
Chris Jones <chris@cjones.org>
parents: 6
diff changeset
   112
6
8e425e340ca1 Implemented writing to the remote. Now we have bidirectional communication.
Chris Jones <christian.jones@sri.com>
parents: 5
diff changeset
   113
	return cl, nil
2
4dabfef08c8c Forgot to add the new xmpp.go from my last commit. Also added some
Chris Jones <chris@cjones.org>
parents:
diff changeset
   114
}
4
a8fbec71a194 Added an interactive test and made Client implement io.Closer.
Chris Jones <chris@cjones.org>
parents: 2
diff changeset
   115
a8fbec71a194 Added an interactive test and made Client implement io.Closer.
Chris Jones <chris@cjones.org>
parents: 2
diff changeset
   116
func (c *Client) Close() os.Error {
9
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   117
	tryClose(c.In, c.Out, c.TextOut)
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   118
	return nil
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   119
}
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   120
10
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
   121
func (cl *Client) startTransport() (io.Reader, io.Writer) {
9
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   122
	inr, inw := io.Pipe()
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   123
	outr, outw := io.Pipe()
10
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
   124
	go cl.readTransport(inw)
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
   125
	go cl.writeTransport(outr)
9
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   126
	return inr, outw
4
a8fbec71a194 Added an interactive test and made Client implement io.Closer.
Chris Jones <chris@cjones.org>
parents: 2
diff changeset
   127
}
5
faef59c8db05 Added a goroutine to read data from the remote and parse it into
Chris Jones <chris@cjones.org>
parents: 4
diff changeset
   128
9
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   129
func startXmlReader(r io.Reader) <-chan interface{} {
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   130
	ch := make(chan interface{})
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   131
	go readXml(r, ch)
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   132
	return ch
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   133
}
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   134
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   135
func startXmlWriter(w io.Writer) chan<- interface{} {
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   136
	ch := make(chan interface{})
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   137
	go writeXml(w, ch)
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   138
	return ch
6
8e425e340ca1 Implemented writing to the remote. Now we have bidirectional communication.
Chris Jones <christian.jones@sri.com>
parents: 5
diff changeset
   139
}
8e425e340ca1 Implemented writing to the remote. Now we have bidirectional communication.
Chris Jones <christian.jones@sri.com>
parents: 5
diff changeset
   140
9
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   141
func startTextWriter(w io.Writer) chan<- *string {
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   142
	ch := make(chan *string)
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   143
	go writeText(w, ch)
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   144
	return ch
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   145
}
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   146
10
f38b0ee7b1c1 Added TLS negotiation.
Chris Jones <chris@cjones.org>
parents: 9
diff changeset
   147
func (cl *Client) startStreamReader(xmlIn <-chan interface{}, srvOut chan<- interface{}) <-chan interface{} {
9
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   148
	ch := make(chan interface{})
11
48be1ae93fd4 Added SASL digest authentication.
Chris Jones <chris@cjones.org>
parents: 10
diff changeset
   149
	go cl.readStream(xmlIn, ch)
9
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   150
	return ch
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   151
}
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   152
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   153
func startStreamWriter(xmlOut chan<- interface{}) chan<- interface{} {
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   154
	ch := make(chan interface{})
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   155
	go writeStream(xmlOut, ch)
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   156
	return ch
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   157
}
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   158
6
8e425e340ca1 Implemented writing to the remote. Now we have bidirectional communication.
Chris Jones <christian.jones@sri.com>
parents: 5
diff changeset
   159
func tee(r io.Reader, w io.Writer, prefix string) {
9
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   160
	defer tryClose(r, w)
6
8e425e340ca1 Implemented writing to the remote. Now we have bidirectional communication.
Chris Jones <christian.jones@sri.com>
parents: 5
diff changeset
   161
8e425e340ca1 Implemented writing to the remote. Now we have bidirectional communication.
Chris Jones <christian.jones@sri.com>
parents: 5
diff changeset
   162
	buf := bytes.NewBuffer(nil)
8e425e340ca1 Implemented writing to the remote. Now we have bidirectional communication.
Chris Jones <christian.jones@sri.com>
parents: 5
diff changeset
   163
	for {
8e425e340ca1 Implemented writing to the remote. Now we have bidirectional communication.
Chris Jones <christian.jones@sri.com>
parents: 5
diff changeset
   164
		var c [1]byte
8e425e340ca1 Implemented writing to the remote. Now we have bidirectional communication.
Chris Jones <christian.jones@sri.com>
parents: 5
diff changeset
   165
		n, _ := r.Read(c[:])
8e425e340ca1 Implemented writing to the remote. Now we have bidirectional communication.
Chris Jones <christian.jones@sri.com>
parents: 5
diff changeset
   166
		if n == 0 {
8e425e340ca1 Implemented writing to the remote. Now we have bidirectional communication.
Chris Jones <christian.jones@sri.com>
parents: 5
diff changeset
   167
			break
8e425e340ca1 Implemented writing to the remote. Now we have bidirectional communication.
Chris Jones <christian.jones@sri.com>
parents: 5
diff changeset
   168
		}
9
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   169
		n, _ = w.Write(c[:n])
6
8e425e340ca1 Implemented writing to the remote. Now we have bidirectional communication.
Chris Jones <christian.jones@sri.com>
parents: 5
diff changeset
   170
		if n == 0 {
8e425e340ca1 Implemented writing to the remote. Now we have bidirectional communication.
Chris Jones <christian.jones@sri.com>
parents: 5
diff changeset
   171
			break
8e425e340ca1 Implemented writing to the remote. Now we have bidirectional communication.
Chris Jones <christian.jones@sri.com>
parents: 5
diff changeset
   172
		}
9
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   173
		buf.Write(c[:n])
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   174
		if c[0] == '\n' || c[0] == '>' {
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   175
			fmt.Printf("%s%s\n", prefix, buf.String())
6
8e425e340ca1 Implemented writing to the remote. Now we have bidirectional communication.
Chris Jones <christian.jones@sri.com>
parents: 5
diff changeset
   176
			buf.Reset()
8e425e340ca1 Implemented writing to the remote. Now we have bidirectional communication.
Chris Jones <christian.jones@sri.com>
parents: 5
diff changeset
   177
		}
8e425e340ca1 Implemented writing to the remote. Now we have bidirectional communication.
Chris Jones <christian.jones@sri.com>
parents: 5
diff changeset
   178
	}
8e425e340ca1 Implemented writing to the remote. Now we have bidirectional communication.
Chris Jones <christian.jones@sri.com>
parents: 5
diff changeset
   179
	leftover := buf.String()
8e425e340ca1 Implemented writing to the remote. Now we have bidirectional communication.
Chris Jones <christian.jones@sri.com>
parents: 5
diff changeset
   180
	if leftover != "" {
8e425e340ca1 Implemented writing to the remote. Now we have bidirectional communication.
Chris Jones <christian.jones@sri.com>
parents: 5
diff changeset
   181
		fmt.Printf("%s%s\n", prefix, leftover)
8e425e340ca1 Implemented writing to the remote. Now we have bidirectional communication.
Chris Jones <christian.jones@sri.com>
parents: 5
diff changeset
   182
	}
8e425e340ca1 Implemented writing to the remote. Now we have bidirectional communication.
Chris Jones <christian.jones@sri.com>
parents: 5
diff changeset
   183
}
9
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   184
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   185
func tryClose(xs ...interface{}) {
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   186
	f1 := func(ch chan<- interface{}) {
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   187
		defer func() {
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   188
			recover()
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   189
		}()
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   190
		close(ch)
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   191
	}
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   192
	f2 := func(ch <-chan interface{}) {
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   193
		defer func() {
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   194
			recover()
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   195
		}()
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   196
		close(ch)
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   197
	}
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   198
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   199
	for _, x := range xs {
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   200
		if c, ok := x.(io.Closer) ; ok {
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   201
			c.Close()
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   202
		} else if ch, ok := x.(chan<- interface{}) ; ok {
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   203
			f1(ch)
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   204
		} else if ch, ok := x.(<-chan interface{}) ; ok {
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   205
			f2(ch)
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   206
		}
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   207
	}
4fe926b03827 Reorganize so we have a layered approach to IO with the server.
Chris Jones <chris@cjones.org>
parents: 8
diff changeset
   208
}
12
122ab6208c3c Added resource binding and structures for <iq>, <message>, and <presence>.
Chris Jones <chris@cjones.org>
parents: 11
diff changeset
   209
122ab6208c3c Added resource binding and structures for <iq>, <message>, and <presence>.
Chris Jones <chris@cjones.org>
parents: 11
diff changeset
   210
func (cl *Client) NextId() string {
122ab6208c3c Added resource binding and structures for <iq>, <message>, and <presence>.
Chris Jones <chris@cjones.org>
parents: 11
diff changeset
   211
	cl.idMutex.Lock()
122ab6208c3c Added resource binding and structures for <iq>, <message>, and <presence>.
Chris Jones <chris@cjones.org>
parents: 11
diff changeset
   212
	defer cl.idMutex.Unlock()
122ab6208c3c Added resource binding and structures for <iq>, <message>, and <presence>.
Chris Jones <chris@cjones.org>
parents: 11
diff changeset
   213
	id := cl.nextId
122ab6208c3c Added resource binding and structures for <iq>, <message>, and <presence>.
Chris Jones <chris@cjones.org>
parents: 11
diff changeset
   214
	cl.nextId++
122ab6208c3c Added resource binding and structures for <iq>, <message>, and <presence>.
Chris Jones <chris@cjones.org>
parents: 11
diff changeset
   215
	return fmt.Sprintf("id_%d", id)
122ab6208c3c Added resource binding and structures for <iq>, <message>, and <presence>.
Chris Jones <chris@cjones.org>
parents: 11
diff changeset
   216
}