xmpp.go
changeset 29 a456133ed0ac
parent 28 78961db80bae
child 30 a77fc342e013
equal deleted inserted replaced
28:78961db80bae 29:a456133ed0ac
    43 	debug = true
    43 	debug = true
    44 )
    44 )
    45 
    45 
    46 // The client in a client-server XMPP connection.
    46 // The client in a client-server XMPP connection.
    47 type Client struct {
    47 type Client struct {
    48 	// This client's JID. This will be updated asynchronously when
    48 	// This client's JID. This will be updated asynchronously by
    49 	// resource binding completes; at that time an iq stanza will
    49 	// the time StartSession() returns.
    50 	// be published on the In channel:
       
    51 	// <iq><bind><jid>jid</jid></bind></iq>
       
    52 	Jid JID
    50 	Jid JID
    53 	password string
    51 	password string
    54 	socket net.Conn
    52 	socket net.Conn
    55 	socketSync sync.WaitGroup
    53 	socketSync sync.WaitGroup
    56 	saslExpected string
    54 	saslExpected string
    57 	authDone bool
    55 	authDone bool
    58 	idMutex sync.Mutex
    56 	idMutex sync.Mutex
    59 	nextId int64
    57 	nextId int64
    60 	handlers chan *stanzaHandler
    58 	handlers chan *stanzaHandler
       
    59 	inputControl chan int
    61 	// Incoming XMPP stanzas from the server will be published on
    60 	// Incoming XMPP stanzas from the server will be published on
    62 	// this channel. Information which is only used by this
    61 	// this channel. Information which is only used by this
    63 	// library to set up the XMPP stream will not appear here.
    62 	// library to set up the XMPP stream will not appear here.
    64 	In <-chan Stanza
    63 	In <-chan Stanza
    65 	// Outgoing XMPP stanzas to the server should be sent to this
    64 	// Outgoing XMPP stanzas to the server should be sent to this
   106 	cl := new(Client)
   105 	cl := new(Client)
   107 	cl.password = password
   106 	cl.password = password
   108 	cl.Jid = *jid
   107 	cl.Jid = *jid
   109 	cl.socket = tcp
   108 	cl.socket = tcp
   110 	cl.handlers = make(chan *stanzaHandler, 1)
   109 	cl.handlers = make(chan *stanzaHandler, 1)
       
   110 	cl.inputControl = make(chan int)
   111 
   111 
   112 	// Start the transport handler, initially unencrypted.
   112 	// Start the transport handler, initially unencrypted.
   113 	tlsr, tlsw := cl.startTransport()
   113 	tlsr, tlsw := cl.startTransport()
   114 
   114 
   115 	// Start the reader and writers that convert to and from XML.
   115 	// Start the reader and writers that convert to and from XML.
   117 	cl.xmlOut = startXmlWriter(tlsw)
   117 	cl.xmlOut = startXmlWriter(tlsw)
   118 
   118 
   119 	// Start the XMPP stream handler which filters stream-level
   119 	// Start the XMPP stream handler which filters stream-level
   120 	// events and responds to them.
   120 	// events and responds to them.
   121 	clIn := cl.startStreamReader(xmlIn, cl.xmlOut)
   121 	clIn := cl.startStreamReader(xmlIn, cl.xmlOut)
   122 	clOut := startStreamWriter(cl.xmlOut)
   122 	clOut := cl.startStreamWriter(cl.xmlOut)
   123 
   123 
   124 	// Initial handshake.
   124 	// Initial handshake.
   125 	hsOut := &stream{To: jid.Domain, Version: Version}
   125 	hsOut := &stream{To: jid.Domain, Version: Version}
   126 	cl.xmlOut <- hsOut
   126 	cl.xmlOut <- hsOut
   127 
   127 
   160 	ch := make(chan Stanza)
   160 	ch := make(chan Stanza)
   161 	go cl.readStream(xmlIn, ch)
   161 	go cl.readStream(xmlIn, ch)
   162 	return ch
   162 	return ch
   163 }
   163 }
   164 
   164 
   165 func startStreamWriter(xmlOut chan<- interface{}) chan<- Stanza {
   165 func (cl *Client) startStreamWriter(xmlOut chan<- interface{}) chan<- Stanza {
   166 	ch := make(chan Stanza)
   166 	ch := make(chan Stanza)
   167 	go writeStream(xmlOut, ch)
   167 	go writeStream(xmlOut, ch, cl.inputControl)
   168 	return ch
   168 	return ch
   169 }
   169 }
   170 
   170 
   171 func tee(r io.Reader, w io.Writer, prefix string) {
   171 func tee(r io.Reader, w io.Writer, prefix string) {
   172 	defer tryClose(r, w)
   172 	defer tryClose(r, w)
   227 	cl.idMutex.Lock()
   227 	cl.idMutex.Lock()
   228 	defer cl.idMutex.Unlock()
   228 	defer cl.idMutex.Unlock()
   229 	id := cl.nextId
   229 	id := cl.nextId
   230 	cl.nextId++
   230 	cl.nextId++
   231 	return fmt.Sprintf("id_%d", id)
   231 	return fmt.Sprintf("id_%d", id)
       
   232 }
       
   233 
       
   234 // bindDone is called when we've finished resource binding (and all
       
   235 // the negotiations that precede it). Now we can start accepting
       
   236 // traffic from the app.
       
   237 func (cl *Client) bindDone() {
       
   238 	cl.inputControl <- 1
   232 }
   239 }
   233 
   240 
   234 // Start an XMPP session. This should typically be done immediately
   241 // Start an XMPP session. This should typically be done immediately
   235 // after creating the new Client. Once the session has been
   242 // after creating the new Client. Once the session has been
   236 // established, pr will be sent as an initial presence; nil means
   243 // established, pr will be sent as an initial presence; nil means