stream.go
changeset 72 53f15893a1a7
parent 66 4558994ab3b3
child 74 e619e18dcec3
child 98 c9cc4eda6dce
equal deleted inserted replaced
71:578c2a83dc18 72:53f15893a1a7
    45 		if cl.socket == nil {
    45 		if cl.socket == nil {
    46 			cl.waitForSocket()
    46 			cl.waitForSocket()
    47 		}
    47 		}
    48 		nr, err := cl.socket.Read(p)
    48 		nr, err := cl.socket.Read(p)
    49 		if nr == 0 {
    49 		if nr == 0 {
    50 			if errno, ok := err.(*net.OpError) ; ok {
    50 			if errno, ok := err.(*net.OpError); ok {
    51 				if errno.Timeout() {
    51 				if errno.Timeout() {
    52 					continue
    52 					continue
    53 				}
    53 				}
    54 			}
    54 			}
    55 			if Log != nil {
    55 			if Log != nil {
    87 		}
    87 		}
    88 	}
    88 	}
    89 }
    89 }
    90 
    90 
    91 func readXml(r io.Reader, ch chan<- interface{},
    91 func readXml(r io.Reader, ch chan<- interface{},
    92 	extStanza map[string] func(*xml.Name) interface{}) {
    92 extStanza map[string]func(*xml.Name) interface{}) {
    93 	if Loglevel >= syslog.LOG_DEBUG {
    93 	if Loglevel >= syslog.LOG_DEBUG {
    94 		pr, pw := io.Pipe()
    94 		pr, pw := io.Pipe()
    95 		go tee(r, pw, "S: ")
    95 		go tee(r, pw, "S: ")
    96 		r = pr
    96 		r = pr
    97 	}
    97 	}
   110 			}
   110 			}
   111 			break
   111 			break
   112 		}
   112 		}
   113 		var se xml.StartElement
   113 		var se xml.StartElement
   114 		var ok bool
   114 		var ok bool
   115 		if se, ok = t.(xml.StartElement) ; !ok {
   115 		if se, ok = t.(xml.StartElement); !ok {
   116 			continue
   116 			continue
   117 		}
   117 		}
   118 
   118 
   119 		// Allocate the appropriate structure for this token.
   119 		// Allocate the appropriate structure for this token.
   120 		var obj interface{}
   120 		var obj interface{}
   163 		}
   163 		}
   164 
   164 
   165 		// If it's a Stanza, we try to unmarshal its innerxml
   165 		// If it's a Stanza, we try to unmarshal its innerxml
   166 		// into objects of the appropriate respective
   166 		// into objects of the appropriate respective
   167 		// types. This is specified by our extensions.
   167 		// types. This is specified by our extensions.
   168 		if st, ok := obj.(Stanza) ; ok {
   168 		if st, ok := obj.(Stanza); ok {
   169 			err = parseExtended(st, extStanza)
   169 			err = parseExtended(st, extStanza)
   170 			if err != nil {
   170 			if err != nil {
   171 				if Log != nil {
   171 				if Log != nil {
   172 					Log.Err("ext unmarshal: " +
   172 					Log.Err("ext unmarshal: " +
   173 						err.String())
   173 						err.String())
   179 		// Put it on the channel.
   179 		// Put it on the channel.
   180 		ch <- obj
   180 		ch <- obj
   181 	}
   181 	}
   182 }
   182 }
   183 
   183 
   184 func parseExtended(st Stanza, extStanza map[string] func(*xml.Name) interface{}) os.Error {
   184 func parseExtended(st Stanza, extStanza map[string]func(*xml.Name) interface{}) os.Error {
   185 	// Now parse the stanza's innerxml to find the string that we
   185 	// Now parse the stanza's innerxml to find the string that we
   186 	// can unmarshal this nested element from.
   186 	// can unmarshal this nested element from.
   187 	reader := strings.NewReader(st.innerxml())
   187 	reader := strings.NewReader(st.innerxml())
   188 	p := xml.NewParser(reader)
   188 	p := xml.NewParser(reader)
   189 	for {
   189 	for {
   192 			break
   192 			break
   193 		}
   193 		}
   194 		if err != nil {
   194 		if err != nil {
   195 			return err
   195 			return err
   196 		}
   196 		}
   197 		if se, ok := t.(xml.StartElement) ; ok {
   197 		if se, ok := t.(xml.StartElement); ok {
   198 			if con, ok := extStanza[se.Name.Space] ; ok {
   198 			if con, ok := extStanza[se.Name.Space]; ok {
   199 				// Call the indicated constructor.
   199 				// Call the indicated constructor.
   200 				nested := con(&se.Name)
   200 				nested := con(&se.Name)
   201 
   201 
   202 				// Unmarshal the nested element and
   202 				// Unmarshal the nested element and
   203 				// stuff it back into the stanza.
   203 				// stuff it back into the stanza.
   218 		pr, pw := io.Pipe()
   218 		pr, pw := io.Pipe()
   219 		go tee(pr, w, "C: ")
   219 		go tee(pr, w, "C: ")
   220 		w = pw
   220 		w = pw
   221 	}
   221 	}
   222 	defer func(w io.Writer) {
   222 	defer func(w io.Writer) {
   223 		if c, ok := w.(io.Closer) ; ok {
   223 		if c, ok := w.(io.Closer); ok {
   224 			c.Close()
   224 			c.Close()
   225 		}
   225 		}
   226 	}(w)
   226 	}(w)
   227 
   227 
   228 	for obj := range ch {
   228 	for obj := range ch {
   237 }
   237 }
   238 
   238 
   239 func (cl *Client) readStream(srvIn <-chan interface{}, cliOut chan<- Stanza) {
   239 func (cl *Client) readStream(srvIn <-chan interface{}, cliOut chan<- Stanza) {
   240 	defer close(cliOut)
   240 	defer close(cliOut)
   241 
   241 
   242 	handlers := make(map[string] func(Stanza) bool)
   242 	handlers := make(map[string]func(Stanza) bool)
   243 Loop:
   243 Loop:
   244 	for {
   244 	for {
   245 		select {
   245 		select {
   246 		case h := <- cl.handlers:
   246 		case h := <-cl.handlers:
   247 			handlers[h.id] = h.f
   247 			handlers[h.id] = h.f
   248 		case x, ok := <- srvIn:
   248 		case x, ok := <-srvIn:
   249 			if !ok {
   249 			if !ok {
   250 				break Loop
   250 				break Loop
   251 			}
   251 			}
   252 			send := false
   252 			send := false
   253 			switch obj := x.(type) {
   253 			switch obj := x.(type) {
   290 // This loop is paused until resource binding is complete. Otherwise
   290 // This loop is paused until resource binding is complete. Otherwise
   291 // the app might inject something inappropriate into our negotiations
   291 // the app might inject something inappropriate into our negotiations
   292 // with the server. The control channel controls this loop's
   292 // with the server. The control channel controls this loop's
   293 // activity.
   293 // activity.
   294 func writeStream(srvOut chan<- interface{}, cliIn <-chan Stanza,
   294 func writeStream(srvOut chan<- interface{}, cliIn <-chan Stanza,
   295 	control <-chan int) {
   295 control <-chan int) {
   296 	defer close(srvOut)
   296 	defer close(srvOut)
   297 
   297 
   298 	var input <-chan Stanza
   298 	var input <-chan Stanza
   299 Loop:
   299 Loop:
   300 	for {
   300 	for {
   301 		select {
   301 		select {
   302 		case status := <- control:
   302 		case status := <-control:
   303 			switch status {
   303 			switch status {
   304 			case 0:
   304 			case 0:
   305 				input = nil
   305 				input = nil
   306 			case 1:
   306 			case 1:
   307 				input = cliIn
   307 				input = cliIn
   308 			case -1:
   308 			case -1:
   309 				break Loop
   309 				break Loop
   310 			}
   310 			}
   311 		case x, ok := <- input:
   311 		case x, ok := <-input:
   312 			if !ok {
   312 			if !ok {
   313 				break Loop
   313 				break Loop
   314 			}
   314 			}
   315 			if x == nil {
   315 			if x == nil {
   316 				if Log != nil {
   316 				if Log != nil {
   325 }
   325 }
   326 
   326 
   327 // Stanzas from the remote go up through a stack of filters to the
   327 // Stanzas from the remote go up through a stack of filters to the
   328 // app. This function manages the filters.
   328 // app. This function manages the filters.
   329 func filterTop(filterOut <-chan <-chan Stanza, filterIn chan<- <-chan Stanza,
   329 func filterTop(filterOut <-chan <-chan Stanza, filterIn chan<- <-chan Stanza,
   330 	topFilter <-chan Stanza, app chan<- Stanza) {
   330 topFilter <-chan Stanza, app chan<- Stanza) {
   331 	defer close(app)
   331 	defer close(app)
   332 Loop:
   332 Loop:
   333 	for {
   333 	for {
   334 		select {
   334 		select {
   335 		case newFilterOut := <- filterOut:
   335 		case newFilterOut := <-filterOut:
   336 			if newFilterOut == nil {
   336 			if newFilterOut == nil {
   337 				if Log != nil {
   337 				if Log != nil {
   338 					Log.Warning("Received nil filter")
   338 					Log.Warning("Received nil filter")
   339 				}
   339 				}
   340 				filterIn <- nil
   340 				filterIn <- nil
   352 	}
   352 	}
   353 }
   353 }
   354 
   354 
   355 func filterBottom(from <-chan Stanza, to chan<- Stanza) {
   355 func filterBottom(from <-chan Stanza, to chan<- Stanza) {
   356 	defer close(to)
   356 	defer close(to)
   357 	for data := range(from) {
   357 	for data := range from {
   358 		to <- data
   358 		to <- data
   359 	}
   359 	}
   360 }
   360 }
   361 
   361 
   362 func handleStream(ss *stream) {
   362 func handleStream(ss *stream) {
   441 }
   441 }
   442 
   442 
   443 // BUG(cjyar): Doesn't implement TLS/SASL EXTERNAL.
   443 // BUG(cjyar): Doesn't implement TLS/SASL EXTERNAL.
   444 func (cl *Client) chooseSasl(fe *Features) {
   444 func (cl *Client) chooseSasl(fe *Features) {
   445 	var digestMd5 bool
   445 	var digestMd5 bool
   446 	for _, m := range(fe.Mechanisms.Mechanism) {
   446 	for _, m := range fe.Mechanisms.Mechanism {
   447 		switch strings.ToLower(m) {
   447 		switch strings.ToLower(m) {
   448 		case "digest-md5":
   448 		case "digest-md5":
   449 			digestMd5 = true
   449 			digestMd5 = true
   450 		}
   450 		}
   451 	}
   451 	}
   452 
   452 
   453 	if digestMd5 {
   453 	if digestMd5 {
   454 		auth := &auth{XMLName: xml.Name{Space: NsSASL, Local:
   454 		auth := &auth{XMLName: xml.Name{Space: NsSASL, Local: "auth"}, Mechanism: "DIGEST-MD5"}
   455 				"auth"}, Mechanism: "DIGEST-MD5"}
       
   456 		cl.xmlOut <- auth
   455 		cl.xmlOut <- auth
   457 	}
   456 	}
   458 }
   457 }
   459 
   458 
   460 func (cl *Client) handleSasl(srv *auth) {
   459 func (cl *Client) handleSasl(srv *auth) {
   465 		if err != nil {
   464 		if err != nil {
   466 			if Log != nil {
   465 			if Log != nil {
   467 				Log.Err("SASL challenge decode: " +
   466 				Log.Err("SASL challenge decode: " +
   468 					err.String())
   467 					err.String())
   469 			}
   468 			}
   470 			return;
   469 			return
   471 		}
   470 		}
   472 		srvMap := parseSasl(string(str))
   471 		srvMap := parseSasl(string(str))
   473 
   472 
   474 		if cl.saslExpected == "" {
   473 		if cl.saslExpected == "" {
   475 			cl.saslDigest1(srvMap)
   474 			cl.saslDigest1(srvMap)
   488 		ss := &stream{To: cl.Jid.Domain, Version: Version}
   487 		ss := &stream{To: cl.Jid.Domain, Version: Version}
   489 		cl.xmlOut <- ss
   488 		cl.xmlOut <- ss
   490 	}
   489 	}
   491 }
   490 }
   492 
   491 
   493 func (cl *Client) saslDigest1(srvMap map[string] string) {
   492 func (cl *Client) saslDigest1(srvMap map[string]string) {
   494 	// Make sure it supports qop=auth
   493 	// Make sure it supports qop=auth
   495 	var hasAuth bool
   494 	var hasAuth bool
   496 	for _, qop := range(strings.Fields(srvMap["qop"])) {
   495 	for _, qop := range strings.Fields(srvMap["qop"]) {
   497 		if qop == "auth" {
   496 		if qop == "auth" {
   498 			hasAuth = true
   497 			hasAuth = true
   499 		}
   498 		}
   500 	}
   499 	}
   501 	if !hasAuth {
   500 	if !hasAuth {
   502 		if Log != nil {
   501 		if Log != nil {
   503 			Log.Err("Server doesn't support SASL auth")
   502 			Log.Err("Server doesn't support SASL auth")
   504 		}
   503 		}
   505 		return;
   504 		return
   506 	}
   505 	}
   507 
   506 
   508 	// Pick a realm.
   507 	// Pick a realm.
   509 	var realm string
   508 	var realm string
   510 	if srvMap["realm"] != "" {
   509 	if srvMap["realm"] != "" {
   550 	clMap := make(map[string]string)
   549 	clMap := make(map[string]string)
   551 	clMap["realm"] = `"` + realm + `"`
   550 	clMap["realm"] = `"` + realm + `"`
   552 	clMap["username"] = `"` + username + `"`
   551 	clMap["username"] = `"` + username + `"`
   553 	clMap["nonce"] = `"` + nonce + `"`
   552 	clMap["nonce"] = `"` + nonce + `"`
   554 	clMap["cnonce"] = `"` + cnonceStr + `"`
   553 	clMap["cnonce"] = `"` + cnonceStr + `"`
   555 	clMap["nc"] =  nonceCountStr
   554 	clMap["nc"] = nonceCountStr
   556 	clMap["qop"] = "auth"
   555 	clMap["qop"] = "auth"
   557 	clMap["digest-uri"] = `"` + digestUri + `"`
   556 	clMap["digest-uri"] = `"` + digestUri + `"`
   558 	clMap["response"] = response
   557 	clMap["response"] = response
   559 	if srvMap["charset"] == "utf-8" {
   558 	if srvMap["charset"] == "utf-8" {
   560 		clMap["charset"] = "utf-8"
   559 		clMap["charset"] = "utf-8"
   561 	}
   560 	}
   562 
   561 
   563 	// Encode the map and send it.
   562 	// Encode the map and send it.
   564 	clStr := packSasl(clMap)
   563 	clStr := packSasl(clMap)
   565 	b64 := base64.StdEncoding
   564 	b64 := base64.StdEncoding
   566 	clObj := &auth{XMLName: xml.Name{Space: NsSASL, Local:
   565 	clObj := &auth{XMLName: xml.Name{Space: NsSASL, Local: "response"}, Chardata: b64.EncodeToString([]byte(clStr))}
   567 			"response"}, Chardata:
       
   568 		b64.EncodeToString([]byte(clStr))}
       
   569 	cl.xmlOut <- clObj
   566 	cl.xmlOut <- clObj
   570 }
   567 }
   571 
   568 
   572 func (cl *Client) saslDigest2(srvMap map[string] string) {
   569 func (cl *Client) saslDigest2(srvMap map[string]string) {
   573 	if cl.saslExpected == srvMap["rspauth"] {
   570 	if cl.saslExpected == srvMap["rspauth"] {
   574 		clObj := &auth{XMLName: xml.Name{Space: NsSASL, Local:
   571 		clObj := &auth{XMLName: xml.Name{Space: NsSASL, Local: "response"}}
   575 				"response"}}
       
   576 		cl.xmlOut <- clObj
   572 		cl.xmlOut <- clObj
   577 	} else {
   573 	} else {
   578 		clObj := &auth{XMLName: xml.Name{Space: NsSASL, Local:
   574 		clObj := &auth{XMLName: xml.Name{Space: NsSASL, Local: "failure"}, Any: &Generic{XMLName: xml.Name{Space: NsSASL,
   579 				"failure"}, Any:
   575 			Local: "abort"}}}
   580 			&Generic{XMLName: xml.Name{Space: NsSASL,
       
   581 				Local: "abort"}}}
       
   582 		cl.xmlOut <- clObj
   576 		cl.xmlOut <- clObj
   583 	}
   577 	}
   584 }
   578 }
   585 
   579 
   586 // Takes a string like `key1=value1,key2="value2"...` and returns a
   580 // Takes a string like `key1=value1,key2="value2"...` and returns a
   587 // key/value map.
   581 // key/value map.
   588 func parseSasl(in string) map[string]string {
   582 func parseSasl(in string) map[string]string {
   589 	re := regexp.MustCompile(`([^=]+)="?([^",]+)"?,?`)
   583 	re := regexp.MustCompile(`([^=]+)="?([^",]+)"?,?`)
   590 	strs := re.FindAllStringSubmatch(in, -1)
   584 	strs := re.FindAllStringSubmatch(in, -1)
   591 	m := make(map[string]string)
   585 	m := make(map[string]string)
   592 	for _, pair := range(strs) {
   586 	for _, pair := range strs {
   593 		key := strings.ToLower(string(pair[1]))
   587 		key := strings.ToLower(string(pair[1]))
   594 		value := string(pair[2])
   588 		value := string(pair[2])
   595 		m[key] = value
   589 		m[key] = value
   596 	}
   590 	}
   597 	return m
   591 	return m
   598 }
   592 }
   599 
   593 
   600 // Inverse of parseSasl().
   594 // Inverse of parseSasl().
   601 func packSasl(m map[string]string) string {
   595 func packSasl(m map[string]string) string {
   602 	var terms []string
   596 	var terms []string
   603 	for key, value := range(m) {
   597 	for key, value := range m {
   604 		if key == "" || value == "" || value == `""` {
   598 		if key == "" || value == "" || value == `""` {
   605 			continue
   599 			continue
   606 		}
   600 		}
   607 		terms = append(terms, key + "=" + value)
   601 		terms = append(terms, key+"="+value)
   608 	}
   602 	}
   609 	return strings.Join(terms, ",")
   603 	return strings.Join(terms, ",")
   610 }
   604 }
   611 
   605 
   612 // Computes the response string for digest authentication.
   606 // Computes the response string for digest authentication.
   613 func saslDigestResponse(username, realm, passwd, nonce, cnonceStr,
   607 func saslDigestResponse(username, realm, passwd, nonce, cnonceStr,
   614 	authenticate, digestUri, nonceCountStr string) string {
   608 authenticate, digestUri, nonceCountStr string) string {
   615 	h := func(text string) []byte {
   609 	h := func(text string) []byte {
   616 		h := md5.New()
   610 		h := md5.New()
   617 		h.Write([]byte(text))
   611 		h.Write([]byte(text))
   618 		return h.Sum()
   612 		return h.Sum()
   619 	}
   613 	}
   622 	}
   616 	}
   623 	kd := func(secret, data string) []byte {
   617 	kd := func(secret, data string) []byte {
   624 		return h(secret + ":" + data)
   618 		return h(secret + ":" + data)
   625 	}
   619 	}
   626 
   620 
   627 	a1 := string(h(username + ":" + realm + ":" + passwd)) + ":" +
   621 	a1 := string(h(username+":"+realm+":"+passwd)) + ":" +
   628 		nonce + ":" + cnonceStr
   622 		nonce + ":" + cnonceStr
   629 	a2 := authenticate + ":" + digestUri
   623 	a2 := authenticate + ":" + digestUri
   630 	response := hex(kd(hex(h(a1)), nonce + ":" +
   624 	response := hex(kd(hex(h(a1)), nonce+":"+
   631 		nonceCountStr + ":" + cnonceStr + ":auth:" +
   625 		nonceCountStr+":"+cnonceStr+":auth:"+
   632 		hex(h(a2))))
   626 		hex(h(a2))))
   633 	return response
   627 	return response
   634 }
   628 }
   635 
   629 
   636 // Send a request to bind a resource. RFC 3920, section 7.
   630 // Send a request to bind a resource. RFC 3920, section 7.
   638 	res := cl.Jid.Resource
   632 	res := cl.Jid.Resource
   639 	bindReq := &bindIq{}
   633 	bindReq := &bindIq{}
   640 	if res != "" {
   634 	if res != "" {
   641 		bindReq.Resource = &res
   635 		bindReq.Resource = &res
   642 	}
   636 	}
   643 	msg := &Iq{Type: "set", Id: <- Id, Nested: []interface{}{bindReq}}
   637 	msg := &Iq{Type: "set", Id: <-Id, Nested: []interface{}{bindReq}}
   644 	f := func(st Stanza) bool {
   638 	f := func(st Stanza) bool {
   645 		if st.GetType() == "error" {
   639 		if st.GetType() == "error" {
   646 			if Log != nil {
   640 			if Log != nil {
   647 				Log.Err("Resource binding failed")
   641 				Log.Err("Resource binding failed")
   648 			}
   642 			}
   649 			return false
   643 			return false
   650 		}
   644 		}
   651 		var bindRepl *bindIq
   645 		var bindRepl *bindIq
   652 		for _, ele := range(st.GetNested()) {
   646 		for _, ele := range st.GetNested() {
   653 			if b, ok := ele.(*bindIq) ; ok {
   647 			if b, ok := ele.(*bindIq); ok {
   654 				bindRepl = b
   648 				bindRepl = b
   655 				break
   649 				break
   656 			}
   650 			}
   657 		}
   651 		}
   658 		if bindRepl == nil {
   652 		if bindRepl == nil {