87 // may be specified. The initial presence will be broadcast. If status |
87 // may be specified. The initial presence will be broadcast. If status |
88 // is non-nil, connection progress information will be sent on it. |
88 // is non-nil, connection progress information will be sent on it. |
89 func NewClient(jid *JID, password string, tlsconf tls.Config, exts []Extension, |
89 func NewClient(jid *JID, password string, tlsconf tls.Config, exts []Extension, |
90 pr Presence, status chan<- Status) (*Client, error) { |
90 pr Presence, status chan<- Status) (*Client, error) { |
91 |
91 |
|
92 // Resolve the domain in the JID. |
|
93 _, srvs, err := net.LookupSRV(clientSrv, "tcp", jid.Domain) |
|
94 if err != nil { |
|
95 return nil, fmt.Errorf("LookupSrv %s: %v", jid.Domain, err) |
|
96 } |
|
97 if len(srvs) == 0 { |
|
98 return nil, fmt.Errorf("LookupSrv %s: no results", jid.Domain) |
|
99 } |
|
100 |
|
101 var tcp *net.TCPConn |
|
102 for _, srv := range srvs { |
|
103 addrStr := fmt.Sprintf("%s:%d", srv.Target, srv.Port) |
|
104 var addr *net.TCPAddr |
|
105 addr, err = net.ResolveTCPAddr("tcp", addrStr) |
|
106 if err != nil { |
|
107 err = fmt.Errorf("ResolveTCPAddr(%s): %s", |
|
108 addrStr, err.Error()) |
|
109 continue |
|
110 } |
|
111 tcp, err = net.DialTCP("tcp", nil, addr) |
|
112 if tcp != nil { |
|
113 break |
|
114 } |
|
115 } |
|
116 if tcp == nil { |
|
117 return nil, err |
|
118 } |
|
119 |
|
120 return newClient(tcp, jid, password, tlsconf, exts, pr, status) |
|
121 } |
|
122 |
|
123 // Connect to the specified host and port. This is otherwise identical |
|
124 // to NewClient. |
|
125 func NewClientFromHost(jid *JID, password string, tlsconf tls.Config, |
|
126 exts []Extension, pr Presence, status chan<- Status, host string, |
|
127 port int) (*Client, error) { |
|
128 |
|
129 addrStr := fmt.Sprintf("%s:%d", host, port) |
|
130 addr, err := net.ResolveTCPAddr("tcp", addrStr) |
|
131 if err != nil { |
|
132 return nil, err |
|
133 } |
|
134 tcp, err := net.DialTCP("tcp", nil, addr) |
|
135 if err != nil { |
|
136 return nil, err |
|
137 } |
|
138 |
|
139 return newClient(tcp, jid, password, tlsconf, exts, pr, status) |
|
140 } |
|
141 |
|
142 func newClient(tcp *net.TCPConn, jid *JID, password string, tlsconf tls.Config, |
|
143 exts []Extension, pr Presence, status chan<- Status) (*Client, error) { |
|
144 |
92 // Include the mandatory extensions. |
145 // Include the mandatory extensions. |
93 roster := newRosterExt() |
146 roster := newRosterExt() |
94 exts = append(exts, roster.Extension) |
147 exts = append(exts, roster.Extension) |
95 exts = append(exts, bindExt) |
148 exts = append(exts, bindExt) |
96 |
149 |
114 } |
167 } |
115 extStanza[k] = v |
168 extStanza[k] = v |
116 } |
169 } |
117 } |
170 } |
118 |
171 |
119 // Resolve the domain in the JID. |
172 // The thing that called this made a TCP connection, so now we |
120 _, srvs, err := net.LookupSRV(clientSrv, "tcp", jid.Domain) |
173 // can signal that it's connected. |
121 if err != nil { |
|
122 return nil, fmt.Errorf("LookupSrv %s: %v", jid.Domain, err) |
|
123 } |
|
124 if len(srvs) == 0 { |
|
125 return nil, fmt.Errorf("LookupSrv %s: no results", jid.Domain) |
|
126 } |
|
127 |
|
128 var tcp *net.TCPConn |
|
129 for _, srv := range srvs { |
|
130 addrStr := fmt.Sprintf("%s:%d", srv.Target, srv.Port) |
|
131 var addr *net.TCPAddr |
|
132 addr, err = net.ResolveTCPAddr("tcp", addrStr) |
|
133 if err != nil { |
|
134 err = fmt.Errorf("ResolveTCPAddr(%s): %s", |
|
135 addrStr, err.Error()) |
|
136 continue |
|
137 } |
|
138 tcp, err = net.DialTCP("tcp", nil, addr) |
|
139 if tcp != nil { |
|
140 break |
|
141 } |
|
142 } |
|
143 if tcp == nil { |
|
144 return nil, err |
|
145 } |
|
146 cl.setStatus(StatusConnected) |
174 cl.setStatus(StatusConnected) |
147 |
175 |
148 // Start the transport handler, initially unencrypted. |
176 // Start the transport handler, initially unencrypted. |
149 recvReader, recvWriter := io.Pipe() |
177 recvReader, recvWriter := io.Pipe() |
150 sendReader, sendWriter := io.Pipe() |
178 sendReader, sendWriter := io.Pipe() |