001/**
002 *
003 * Copyright 2003-2007 Jive Software.
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.jivesoftware.smack;
019
020import org.jivesoftware.smack.packet.Session;
021import org.jivesoftware.smack.proxy.ProxyInfo;
022import org.jivesoftware.smack.util.DNSUtil;
023import org.jivesoftware.smack.util.dns.HostAddress;
024
025import javax.net.SocketFactory;
026import javax.net.ssl.SSLContext;
027import javax.security.auth.callback.CallbackHandler;
028
029import java.util.ArrayList;
030import java.util.Collections;
031import java.util.List;
032
033/**
034 * Configuration to use while establishing the connection to the server. It is possible to
035 * configure the path to the trustore file that keeps the trusted CA root certificates and
036 * enable or disable all or some of the checkings done while verifying server certificates.<p>
037 *
038 * It is also possible to configure if TLS, SASL, and compression are used or not.
039 *
040 * @author Gaston Dombiak
041 */
042public class ConnectionConfiguration implements Cloneable {
043
044    /**
045     * Hostname of the XMPP server. Usually servers use the same service name as the name
046     * of the server. However, there are some servers like google where host would be
047     * talk.google.com and the serviceName would be gmail.com.
048     */
049    private String serviceName;
050
051    protected List<HostAddress> hostAddresses;
052
053    private String keystorePath;
054    private String keystoreType;
055    private String pkcs11Library;
056    private SSLContext customSSLContext;
057
058    private boolean compressionEnabled = false;
059
060    /**
061     * Used to get information from the user
062     */
063    private CallbackHandler callbackHandler;
064
065    private boolean debuggerEnabled = SmackConfiguration.DEBUG_ENABLED;
066
067    // Flag that indicates if a reconnection should be attempted when abruptly disconnected
068    private boolean reconnectionAllowed = true;
069    
070    // Holds the socket factory that is used to generate the socket in the connection
071    private SocketFactory socketFactory;
072    
073    // Holds the authentication information for future reconnections
074    private String username;
075    private String password;
076    private String resource;
077    private boolean sendPresence = true;
078    private boolean rosterLoadedAtLogin = true;
079    private boolean legacySessionDisabled = false;
080    private boolean useDnsSrvRr = true;
081    private SecurityMode securityMode = SecurityMode.enabled;
082
083    /**
084     * Permanent store for the Roster, needed for roster versioning
085     */
086    private RosterStore rosterStore;
087
088    // Holds the proxy information (such as proxyhost, proxyport, username, password etc)
089    protected ProxyInfo proxy;
090
091    /**
092     * Creates a new ConnectionConfiguration for the specified service name.
093     * A DNS SRV lookup will be performed to find out the actual host address
094     * and port to use for the connection.
095     *
096     * @param serviceName the name of the service provided by an XMPP server.
097     */
098    public ConnectionConfiguration(String serviceName) {
099        init(serviceName, ProxyInfo.forDefaultProxy());
100    }
101
102     /**
103     * Creates a new ConnectionConfiguration for the specified service name 
104     * with specified proxy.
105     * A DNS SRV lookup will be performed to find out the actual host address
106     * and port to use for the connection.
107     *
108     * @param serviceName the name of the service provided by an XMPP server.
109     * @param proxy the proxy through which XMPP is to be connected
110     */
111    public ConnectionConfiguration(String serviceName,ProxyInfo proxy) {
112        init(serviceName, proxy);
113    }
114
115    /**
116     * Creates a new ConnectionConfiguration using the specified host, port and
117     * service name. This is useful for manually overriding the DNS SRV lookup
118     * process that's used with the {@link #ConnectionConfiguration(String)}
119     * constructor. For example, say that an XMPP server is running at localhost
120     * in an internal network on port 5222 but is configured to think that it's
121     * "example.com" for testing purposes. This constructor is necessary to connect
122     * to the server in that case since a DNS SRV lookup for example.com would not
123     * point to the local testing server.
124     *
125     * @param host the host where the XMPP server is running.
126     * @param port the port where the XMPP is listening.
127     * @param serviceName the name of the service provided by an XMPP server.
128     */
129    public ConnectionConfiguration(String host, int port, String serviceName) {
130        initHostAddresses(host, port);
131        init(serviceName, ProxyInfo.forDefaultProxy());
132    }
133        
134        /**
135     * Creates a new ConnectionConfiguration using the specified host, port and
136     * service name. This is useful for manually overriding the DNS SRV lookup
137     * process that's used with the {@link #ConnectionConfiguration(String)}
138     * constructor. For example, say that an XMPP server is running at localhost
139     * in an internal network on port 5222 but is configured to think that it's
140     * "example.com" for testing purposes. This constructor is necessary to connect
141     * to the server in that case since a DNS SRV lookup for example.com would not
142     * point to the local testing server.
143     *
144     * @param host the host where the XMPP server is running.
145     * @param port the port where the XMPP is listening.
146     * @param serviceName the name of the service provided by an XMPP server.
147     * @param proxy the proxy through which XMPP is to be connected
148     */
149    public ConnectionConfiguration(String host, int port, String serviceName, ProxyInfo proxy) {
150        initHostAddresses(host, port);
151        init(serviceName, proxy);
152    }
153
154    /**
155     * Creates a new ConnectionConfiguration for a connection that will connect
156     * to the desired host and port.
157     *
158     * @param host the host where the XMPP server is running.
159     * @param port the port where the XMPP is listening.
160     */
161    public ConnectionConfiguration(String host, int port) {
162        initHostAddresses(host, port);
163        init(host, ProxyInfo.forDefaultProxy());
164    }
165        
166        /**
167     * Creates a new ConnectionConfiguration for a connection that will connect
168     * to the desired host and port with desired proxy.
169     *
170     * @param host the host where the XMPP server is running.
171     * @param port the port where the XMPP is listening.
172     * @param proxy the proxy through which XMPP is to be connected
173     */
174    public ConnectionConfiguration(String host, int port, ProxyInfo proxy) {
175        initHostAddresses(host, port);
176        init(host, proxy);
177    }
178
179    protected void init(String serviceName, ProxyInfo proxy) {
180        this.serviceName = serviceName;
181        this.proxy = proxy;
182
183        keystorePath = System.getProperty("javax.net.ssl.keyStore");
184        keystoreType = "jks";
185        pkcs11Library = "pkcs11.config";
186                
187                //Setting the SocketFactory according to proxy supplied
188        socketFactory = proxy.getSocketFactory();
189    }
190
191    /**
192     * Sets the server name, also known as XMPP domain of the target server.
193     *
194     * @param serviceName the XMPP domain of the target server.
195     */
196    void setServiceName(String serviceName) {
197        this.serviceName = serviceName;
198    }
199
200    /**
201     * Returns the server name of the target server.
202     *
203     * @return the server name of the target server.
204     */
205    public String getServiceName() {
206        return serviceName;
207    }
208
209    /**
210     * Returns the TLS security mode used when making the connection. By default,
211     * the mode is {@link SecurityMode#enabled}.
212     *
213     * @return the security mode.
214     */
215    public SecurityMode getSecurityMode() {
216        return securityMode;
217    }
218
219    /**
220     * Sets the TLS security mode used when making the connection. By default,
221     * the mode is {@link SecurityMode#enabled}.
222     *
223     * @param securityMode the security mode.
224     */
225    public void setSecurityMode(SecurityMode securityMode) {
226        this.securityMode = securityMode;
227    }
228
229    /**
230     * Retuns the path to the keystore file. The key store file contains the 
231     * certificates that may be used to authenticate the client to the server,
232     * in the event the server requests or requires it.
233     *
234     * @return the path to the keystore file.
235     */
236    public String getKeystorePath() {
237        return keystorePath;
238    }
239
240    /**
241     * Sets the path to the keystore file. The key store file contains the 
242     * certificates that may be used to authenticate the client to the server,
243     * in the event the server requests or requires it.
244     *
245     * @param keystorePath the path to the keystore file.
246     */
247    public void setKeystorePath(String keystorePath) {
248        this.keystorePath = keystorePath;
249    }
250
251    /**
252     * Returns the keystore type, or <tt>null</tt> if it's not set.
253     *
254     * @return the keystore type.
255     */
256    public String getKeystoreType() {
257        return keystoreType;
258    }
259
260    /**
261     * Sets the keystore type.
262     *
263     * @param keystoreType the keystore type.
264     */
265    public void setKeystoreType(String keystoreType) {
266        this.keystoreType = keystoreType;
267    }
268
269
270    /**
271     * Returns the PKCS11 library file location, needed when the
272     * Keystore type is PKCS11.
273     *
274     * @return the path to the PKCS11 library file
275     */
276    public String getPKCS11Library() {
277        return pkcs11Library;
278    }
279
280    /**
281     * Sets the PKCS11 library file location, needed when the
282     * Keystore type is PKCS11
283     *
284     * @param pkcs11Library the path to the PKCS11 library file
285     */
286    public void setPKCS11Library(String pkcs11Library) {
287        this.pkcs11Library = pkcs11Library;
288    }
289
290    /**
291     * Gets the custom SSLContext previously set with {@link #setCustomSSLContext(SSLContext)} for
292     * SSL sockets. This is null by default.
293     *
294     * @return the custom SSLContext or null.
295     */
296    public SSLContext getCustomSSLContext() {
297        return this.customSSLContext;
298    }
299
300    /**
301     * Sets a custom SSLContext for creating SSL sockets.
302     * <p>
303     * For more information on how to create a SSLContext see <a href=
304     * "http://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#X509TrustManager"
305     * >Java Secure Socket Extension (JSEE) Reference Guide: Creating Your Own X509TrustManager</a>
306     *
307     * @param context the custom SSLContext for new sockets
308     */
309    public void setCustomSSLContext(SSLContext context) {
310        this.customSSLContext = context;
311    }
312
313    /**
314     * Returns true if the connection is going to use stream compression. Stream compression
315     * will be requested after TLS was established (if TLS was enabled) and only if the server
316     * offered stream compression. With stream compression network traffic can be reduced
317     * up to 90%. By default compression is disabled.
318     *
319     * @return true if the connection is going to use stream compression.
320     */
321    public boolean isCompressionEnabled() {
322        return compressionEnabled;
323    }
324
325    /**
326     * Sets if the connection is going to use stream compression. Stream compression
327     * will be requested after TLS was established (if TLS was enabled) and only if the server
328     * offered stream compression. With stream compression network traffic can be reduced
329     * up to 90%. By default compression is disabled.
330     *
331     * @param compressionEnabled if the connection is going to use stream compression.
332     */
333    public void setCompressionEnabled(boolean compressionEnabled) {
334        this.compressionEnabled = compressionEnabled;
335    }
336
337    /**
338     * Returns true if the new connection about to be establish is going to be debugged. By
339     * default the value of {@link SmackConfiguration#DEBUG_ENABLED} is used.
340     *
341     * @return true if the new connection about to be establish is going to be debugged.
342     */
343    public boolean isDebuggerEnabled() {
344        return debuggerEnabled;
345    }
346
347    /**
348     * Sets if the new connection about to be establish is going to be debugged. By
349     * default the value of {@link SmackConfiguration#DEBUG_ENABLED} is used.
350     *
351     * @param debuggerEnabled if the new connection about to be establish is going to be debugged.
352     */
353    public void setDebuggerEnabled(boolean debuggerEnabled) {
354        this.debuggerEnabled = debuggerEnabled;
355    }
356    
357    /**
358     * Sets if the reconnection mechanism is allowed to be used. By default
359     * reconnection is allowed.
360     *
361     * @param isAllowed if the reconnection mechanism should be enabled for this connection.
362     */
363    public void setReconnectionAllowed(boolean isAllowed) {
364        this.reconnectionAllowed = isAllowed;
365    }
366
367    /**
368     * Returns if the reconnection mechanism is allowed to be used. By default reconnection is
369     * allowed. You can disable the reconnection mechanism with {@link
370     * #setReconnectionAllowed(boolean)}.
371     *
372     * @return true, if the reconnection mechanism is enabled.
373     */
374    public boolean isReconnectionAllowed() {
375        return this.reconnectionAllowed;
376    }
377
378    /**
379     * Sets the socket factory used to create new xmppConnection sockets.
380     * This is useful when connecting through SOCKS5 proxies.
381     *
382     * @param socketFactory used to create new sockets.
383     */
384    public void setSocketFactory(SocketFactory socketFactory) {
385        this.socketFactory = socketFactory;
386    }
387
388    /**
389     * Sets if an initial available presence will be sent to the server. By default
390     * an available presence will be sent to the server indicating that this presence
391     * is not online and available to receive messages. If you want to log in without
392     * being 'noticed' then pass a <tt>false</tt> value.
393     *
394     * @param sendPresence true if an initial available presence will be sent while logging in.
395     */
396    public void setSendPresence(boolean sendPresence) {
397        this.sendPresence = sendPresence;
398    }
399
400    /**
401     * Returns true if the roster will be loaded from the server when logging in. This
402     * is the common behaviour for clients but sometimes clients may want to differ this
403     * or just never do it if not interested in rosters.
404     *
405     * @return true if the roster will be loaded from the server when logging in.
406     */
407    public boolean isRosterLoadedAtLogin() {
408        return rosterLoadedAtLogin;
409    }
410
411    /**
412     * Sets if the roster will be loaded from the server when logging in. This
413     * is the common behaviour for clients but sometimes clients may want to differ this
414     * or just never do it if not interested in rosters.
415     *
416     * @param rosterLoadedAtLogin if the roster will be loaded from the server when logging in.
417     */
418    public void setRosterLoadedAtLogin(boolean rosterLoadedAtLogin) {
419        this.rosterLoadedAtLogin = rosterLoadedAtLogin;
420    }
421
422    /**
423     * Returns true if a {@link Session} will be requested on login if the server
424     * supports it. Although this was mandatory on RFC 3921, RFC 6120/6121 don't
425     * even mention this part of the protocol.
426     *
427     * @return true if a session has to be requested when logging in.
428     */
429    public boolean isLegacySessionDisabled() {
430        return legacySessionDisabled;
431    }
432
433    /**
434     * Sets if a {@link Session} will be requested on login if the server supports
435     * it. Although this was mandatory on RFC 3921, RFC 6120/6121 don't even
436     * mention this part of the protocol.
437     *
438     * @param legacySessionDisabled if a session has to be requested when logging in.
439     */
440    public void setLegacySessionDisabled(boolean legacySessionDisabled) {
441        this.legacySessionDisabled = legacySessionDisabled;
442    }
443
444    /**
445     * Returns a CallbackHandler to obtain information, such as the password or
446     * principal information during the SASL authentication. A CallbackHandler
447     * will be used <b>ONLY</b> if no password was specified during the login while
448     * using SASL authentication.
449     *
450     * @return a CallbackHandler to obtain information, such as the password or
451     * principal information during the SASL authentication.
452     */
453    public CallbackHandler getCallbackHandler() {
454        return callbackHandler;
455    }
456
457    /**
458     * Sets a CallbackHandler to obtain information, such as the password or
459     * principal information during the SASL authentication. A CallbackHandler
460     * will be used <b>ONLY</b> if no password was specified during the login while
461     * using SASL authentication.
462     *
463     * @param callbackHandler to obtain information, such as the password or
464     * principal information during the SASL authentication.
465     */
466    public void setCallbackHandler(CallbackHandler callbackHandler) {
467        this.callbackHandler = callbackHandler;
468    }
469
470    /**
471     * Returns the socket factory used to create new xmppConnection sockets.
472     * This is useful when connecting through SOCKS5 proxies.
473     * 
474     * @return socketFactory used to create new sockets.
475     */
476    public SocketFactory getSocketFactory() {
477        return this.socketFactory;
478    }
479
480    public List<HostAddress> getHostAddresses() {
481        return Collections.unmodifiableList(hostAddresses);
482    }
483
484    /**
485     * Set the permanent roster store
486     */
487    public void setRosterStore(RosterStore store) {
488        rosterStore = store;
489    }
490
491    /**
492     * Get the permanent roster store
493     */
494    public RosterStore getRosterStore() {
495        return rosterStore;
496    }
497
498
499    /**
500     * An enumeration for TLS security modes that are available when making a connection
501     * to the XMPP server.
502     */
503    public static enum SecurityMode {
504
505        /**
506         * Securirty via TLS encryption is required in order to connect. If the server
507         * does not offer TLS or if the TLS negotiaton fails, the connection to the server
508         * will fail.
509         */
510        required,
511
512        /**
513         * Security via TLS encryption is used whenever it's available. This is the
514         * default setting.
515         */
516        enabled,
517
518        /**
519         * Security via TLS encryption is disabled and only un-encrypted connections will
520         * be used. If only TLS encryption is available from the server, the connection
521         * will fail.
522         */
523        disabled
524    }
525
526    /**
527     * Returns the username to use when trying to reconnect to the server.
528     *
529     * @return the username to use when trying to reconnect to the server.
530     */
531    public String getUsername() {
532        return this.username;
533    }
534
535    /**
536     * Returns the password to use when trying to reconnect to the server.
537     *
538     * @return the password to use when trying to reconnect to the server.
539     */
540    public String getPassword() {
541        return this.password;
542    }
543
544    /**
545     * Returns the resource to use when trying to reconnect to the server.
546     *
547     * @return the resource to use when trying to reconnect to the server.
548     */
549    public String getResource() {
550        return resource;
551    }
552
553    /**
554     * Returns true if an available presence should be sent when logging in while reconnecting.
555     *
556     * @return true if an available presence should be sent when logging in while reconnecting
557     */
558    public boolean isSendPresence() {
559        return sendPresence;
560    }
561
562    void setLoginInfo(String username, String password, String resource) {
563        this.username = username;
564        this.password = password;
565        this.resource = resource;
566    }
567
568    void maybeResolveDns() throws Exception {
569        if (!useDnsSrvRr) return;
570        hostAddresses = DNSUtil.resolveXMPPDomain(serviceName);
571    }
572
573    private void initHostAddresses(String host, int port) {
574        hostAddresses = new ArrayList<HostAddress>(1);
575        HostAddress hostAddress;
576        hostAddress = new HostAddress(host, port);
577        hostAddresses.add(hostAddress);
578        useDnsSrvRr = false;
579    }
580}