1// Copyright 2013 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Package xmpp implements the XMPP IM protocol, as specified in RFC 6120 and
6// 6121.
7package xmpp
8
9import (
10	"errors"
11	"net"
12	"strconv"
13	"strings"
14
15	ourNet "github.com/coyim/coyim/net"
16	"golang.org/x/net/proxy"
17)
18
19var (
20	// ErrServiceNotAvailable means that the service is decidedly not available at this domain
21	ErrServiceNotAvailable = errors.New("service not available")
22)
23
24// Resolve performs a DNS SRV lookup for the XMPP server that serves the given
25// domain.
26func Resolve(domain string) (hostport []string, err error) {
27	return massage(net.LookupSRV("xmpp-client", "tcp", domain))
28}
29
30// ResolveSRVWithProxy performs a DNS SRV lookup for the xmpp server that serves the given domain over the given proxy
31func ResolveSRVWithProxy(proxy proxy.Dialer, domain string) (hostport []string, err error) {
32	return massage(ourNet.LookupSRV(proxy, "xmpp-client", "tcp", domain))
33}
34
35func massage(cname string, addrs []*net.SRV, err error) ([]string, error) {
36	if err != nil {
37		return nil, err
38	}
39
40	// https://xmpp.org/rfcs/rfc6120.html#tcp-resolution-prefer
41	if len(addrs) == 1 && addrs[0].Target == "." {
42		return nil, ErrServiceNotAvailable
43	}
44
45	ret := make([]string, 0, len(addrs))
46	for _, addr := range addrs {
47		hostport := net.JoinHostPort(
48			strings.TrimSuffix(addr.Target, "."),
49			strconv.Itoa(int(addr.Port)),
50		)
51
52		ret = append(ret, hostport)
53	}
54
55	return ret, nil
56}
57