xmpp/layer3.go
changeset 150 fa7f6ff10c67
parent 149 22c96a9ab289
child 153 bbd4166df95d
equal deleted inserted replaced
149:22c96a9ab289 150:fa7f6ff10c67
    11 // Callback to handle a stanza with a particular id.
    11 // Callback to handle a stanza with a particular id.
    12 type callback struct {
    12 type callback struct {
    13 	id string
    13 	id string
    14 	// Return true means pass this to the application
    14 	// Return true means pass this to the application
    15 	f func(Stanza) bool
    15 	f func(Stanza) bool
    16 }
       
    17 
       
    18 // Receive XMLish structures, handle all the stream-related ones, and
       
    19 // send XMPP stanzas on to the client.
       
    20 func (cl *Client) recvStream(recvXml <-chan interface{}, sendXmpp chan<- Stanza) {
       
    21 	defer close(sendXmpp)
       
    22 
       
    23 	handlers := make(map[string]func(Stanza) bool)
       
    24 Loop:
       
    25 	for {
       
    26 		select {
       
    27 		case h := <-cl.handlers:
       
    28 			handlers[h.id] = h.f
       
    29 		case x, ok := <-recvXml:
       
    30 			if !ok {
       
    31 				break Loop
       
    32 			}
       
    33 			switch obj := x.(type) {
       
    34 			case *stream:
       
    35 				handleStream(obj)
       
    36 			case *streamError:
       
    37 				cl.handleStreamError(obj)
       
    38 			case *Features:
       
    39 				cl.handleFeatures(obj)
       
    40 			case *starttls:
       
    41 				cl.handleTls(obj)
       
    42 			case *auth:
       
    43 				cl.handleSasl(obj)
       
    44 			case Stanza:
       
    45 				send := true
       
    46 				id := obj.GetHeader().Id
       
    47 				if handlers[id] != nil {
       
    48 					f := handlers[id]
       
    49 					delete(handlers, id)
       
    50 					send = f(obj)
       
    51 				}
       
    52 				if send {
       
    53 					sendXmpp <- obj
       
    54 				}
       
    55 			default:
       
    56 				Warn.Logf("Unhandled non-stanza: %T %#v", x, x)
       
    57 			}
       
    58 		}
       
    59 	}
       
    60 }
    16 }
    61 
    17 
    62 // Receive XMPP stanzas from the client and send them on to the
    18 // Receive XMPP stanzas from the client and send them on to the
    63 // remote. Don't allow the client to send us any stanzas until
    19 // remote. Don't allow the client to send us any stanzas until
    64 // negotiation has completed.  This loop is paused until resource
    20 // negotiation has completed.  This loop is paused until resource
    94 			sendXml <- x
    50 			sendXml <- x
    95 		}
    51 		}
    96 	}
    52 	}
    97 }
    53 }
    98 
    54 
    99 func handleStream(ss *stream) {
    55 // Receive XMLish structures, handle all the stream-related ones, and
       
    56 // send XMPP stanzas on to the client.
       
    57 func (cl *Client) recvStream(recvXml <-chan interface{}, sendXmpp chan<- Stanza) {
       
    58 	defer close(sendXmpp)
       
    59 
       
    60 	handlers := make(map[string]func(Stanza) bool)
       
    61 	for {
       
    62 		select {
       
    63 		case h := <-cl.handlers:
       
    64 			handlers[h.id] = h.f
       
    65 		case x, ok := <-recvXml:
       
    66 			if !ok {
       
    67 				return
       
    68 			}
       
    69 			switch obj := x.(type) {
       
    70 			case *stream:
       
    71 				// Do nothing.
       
    72 			case *streamError:
       
    73 				cl.handleStreamError(obj)
       
    74 			case *Features:
       
    75 				cl.handleFeatures(obj)
       
    76 			case *starttls:
       
    77 				cl.handleTls(obj)
       
    78 			case *auth:
       
    79 				cl.handleSasl(obj)
       
    80 			case Stanza:
       
    81 				send := true
       
    82 				id := obj.GetHeader().Id
       
    83 				if handlers[id] != nil {
       
    84 					f := handlers[id]
       
    85 					delete(handlers, id)
       
    86 					send = f(obj)
       
    87 				}
       
    88 				if send {
       
    89 					sendXmpp <- obj
       
    90 				}
       
    91 			default:
       
    92 				Warn.Logf("Unhandled non-stanza: %T %#v", x, x)
       
    93 			}
       
    94 		}
       
    95 	}
   100 }
    96 }
   101 
    97 
   102 func (cl *Client) handleStreamError(se *streamError) {
    98 func (cl *Client) handleStreamError(se *streamError) {
   103 	Info.Logf("Received stream error: %v", se)
    99 	Info.Logf("Received stream error: %v", se)
   104 	cl.inputControl <- sendAbort
   100 	cl.inputControl <- sendAbort
   128 	cl.layer1.startTls(&cl.tlsConfig)
   124 	cl.layer1.startTls(&cl.tlsConfig)
   129 
   125 
   130 	// Now re-send the initial handshake message to start the new
   126 	// Now re-send the initial handshake message to start the new
   131 	// session.
   127 	// session.
   132 	cl.sendXml <- &stream{To: cl.Jid.Domain, Version: XMPPVersion}
   128 	cl.sendXml <- &stream{To: cl.Jid.Domain, Version: XMPPVersion}
   133 }
       
   134 
       
   135 // Register a callback to handle the next XMPP stanza (iq, message, or
       
   136 // presence) with a given id. The provided function will not be called
       
   137 // more than once. If it returns false, the stanza will not be made
       
   138 // available on the normal Client.Recv channel. The callback must not
       
   139 // read from that channel, as deliveries on it cannot proceed until
       
   140 // the handler returns true or false.
       
   141 func (cl *Client) SetCallback(id string, f func(Stanza) bool) {
       
   142 	h := &callback{id: id, f: f}
       
   143 	cl.handlers <- h
       
   144 }
   129 }
   145 
   130 
   146 // Send a request to bind a resource. RFC 3920, section 7.
   131 // Send a request to bind a resource. RFC 3920, section 7.
   147 func (cl *Client) bind() {
   132 func (cl *Client) bind() {
   148 	res := cl.Jid.Resource
   133 	res := cl.Jid.Resource
   188 		return false
   173 		return false
   189 	}
   174 	}
   190 	cl.SetCallback(msg.Id, f)
   175 	cl.SetCallback(msg.Id, f)
   191 	cl.sendXml <- msg
   176 	cl.sendXml <- msg
   192 }
   177 }
       
   178 
       
   179 // Register a callback to handle the next XMPP stanza (iq, message, or
       
   180 // presence) with a given id. The provided function will not be called
       
   181 // more than once. If it returns false, the stanza will not be made
       
   182 // available on the normal Client.Recv channel. The callback must not
       
   183 // read from that channel, as deliveries on it cannot proceed until
       
   184 // the handler returns true or false.
       
   185 func (cl *Client) SetCallback(id string, f func(Stanza) bool) {
       
   186 	h := &callback{id: id, f: f}
       
   187 	cl.handlers <- h
       
   188 }