mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-11-23 04:22:05 +01:00
1. Added support for TLS. SMACK-76
2. Added support for SASL. SMACK-24 3. Modified constructors to include serviceName. SMACK-75 git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/trunk@2733 b35dd754-fafc-0310-a699-88a17e54d16e
This commit is contained in:
parent
ad6be5887c
commit
c914101965
1 changed files with 259 additions and 161 deletions
|
@ -20,15 +20,21 @@
|
||||||
|
|
||||||
package org.jivesoftware.smack;
|
package org.jivesoftware.smack;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.debugger.SmackDebugger;
|
||||||
|
import org.jivesoftware.smack.filter.PacketFilter;
|
||||||
|
import org.jivesoftware.smack.filter.PacketIDFilter;
|
||||||
import org.jivesoftware.smack.packet.*;
|
import org.jivesoftware.smack.packet.*;
|
||||||
import org.jivesoftware.smack.debugger.*;
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
import org.jivesoftware.smack.filter.*;
|
|
||||||
|
|
||||||
import javax.net.SocketFactory;
|
import javax.net.SocketFactory;
|
||||||
import java.lang.reflect.Constructor;
|
import javax.net.ssl.SSLContext;
|
||||||
import java.net.*;
|
import javax.net.ssl.SSLSocket;
|
||||||
import java.util.*;
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a connection to a XMPP server. A simple use of this API might
|
* Creates a connection to a XMPP server. A simple use of this API might
|
||||||
|
@ -77,42 +83,56 @@ public class XMPPConnection {
|
||||||
}
|
}
|
||||||
private SmackDebugger debugger = null;
|
private SmackDebugger debugger = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IP address or host name of the server. This information is only used when
|
||||||
|
* creating new socket connections to the server. If this information is not
|
||||||
|
* configured then it will be assumed that the host name matches the service name.
|
||||||
|
*/
|
||||||
String host;
|
String host;
|
||||||
int port;
|
int port;
|
||||||
Socket socket;
|
Socket socket;
|
||||||
|
/**
|
||||||
|
* Hostname of the XMPP server. Usually servers use the same service name as the name
|
||||||
|
* of the server. However, there are some servers like google where host would be
|
||||||
|
* talk.google.com and the serviceName would be gmail.com.
|
||||||
|
*/
|
||||||
|
String serviceName;
|
||||||
|
|
||||||
String connectionID;
|
String connectionID;
|
||||||
private String user = null;
|
private String user = null;
|
||||||
private boolean connected = false;
|
private boolean connected = false;
|
||||||
private boolean authenticated = false;
|
private boolean authenticated = false;
|
||||||
private boolean anonymous = false;
|
private boolean anonymous = false;
|
||||||
|
private boolean usingTLS = false;
|
||||||
|
|
||||||
PacketWriter packetWriter;
|
PacketWriter packetWriter;
|
||||||
PacketReader packetReader;
|
PacketReader packetReader;
|
||||||
|
|
||||||
Roster roster = null;
|
Roster roster = null;
|
||||||
private AccountManager accountManager = null;
|
private AccountManager accountManager = null;
|
||||||
|
private SASLAuthentication saslAuthentication = new SASLAuthentication(this);
|
||||||
|
|
||||||
Writer writer;
|
Writer writer;
|
||||||
Reader reader;
|
Reader reader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new connection to the specified XMPP server. The default port of 5222 will
|
* Creates a new connection to the specified XMPP server. The default port of 5222 will
|
||||||
* be used.
|
* be used. The IP address of the server is assumed to match the service name.
|
||||||
*
|
*
|
||||||
* @param host the name of the XMPP server to connect to; e.g. <tt>jivesoftware.com</tt>.
|
* @param serviceName the name of the XMPP server to connect to; e.g. <tt>jivesoftware.com</tt>.
|
||||||
* @throws XMPPException if an error occurs while trying to establish the connection.
|
* @throws XMPPException if an error occurs while trying to establish the connection.
|
||||||
* Two possible errors can occur which will be wrapped by an XMPPException --
|
* Two possible errors can occur which will be wrapped by an XMPPException --
|
||||||
* UnknownHostException (XMPP error code 504), and IOException (XMPP error code
|
* UnknownHostException (XMPP error code 504), and IOException (XMPP error code
|
||||||
* 502). The error codes and wrapped exceptions can be used to present more
|
* 502). The error codes and wrapped exceptions can be used to present more
|
||||||
* appropiate error messages to end-users.
|
* appropiate error messages to end-users.
|
||||||
*/
|
*/
|
||||||
public XMPPConnection(String host) throws XMPPException {
|
public XMPPConnection(String serviceName) throws XMPPException {
|
||||||
this(host, 5222);
|
this(serviceName, 5222, serviceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new connection to the specified XMPP server on the given port.
|
* Creates a new connection to the specified XMPP server on the given port. The IP address
|
||||||
|
* of the server is assumed to match the service name.
|
||||||
*
|
*
|
||||||
* @param host the name of the XMPP server to connect to; e.g. <tt>jivesoftware.com</tt>.
|
* @param host the name of the XMPP server to connect to; e.g. <tt>jivesoftware.com</tt>.
|
||||||
* @param port the port on the server that should be used; e.g. <tt>5222</tt>.
|
* @param port the port on the server that should be used; e.g. <tt>5222</tt>.
|
||||||
|
@ -123,6 +143,22 @@ public class XMPPConnection {
|
||||||
* appropiate error messages to end-users.
|
* appropiate error messages to end-users.
|
||||||
*/
|
*/
|
||||||
public XMPPConnection(String host, int port) throws XMPPException {
|
public XMPPConnection(String host, int port) throws XMPPException {
|
||||||
|
this(host, port, host);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new connection to the specified XMPP server on the given host and port.
|
||||||
|
*
|
||||||
|
* @param host the host name, or null for the loopback address.
|
||||||
|
* @param port the port on the server that should be used; e.g. <tt>5222</tt>.
|
||||||
|
* @param serviceName the name of the XMPP server to connect to; e.g. <tt>jivesoftware.com</tt>.
|
||||||
|
* @throws XMPPException if an error occurs while trying to establish the connection.
|
||||||
|
* Two possible errors can occur which will be wrapped by an XMPPException --
|
||||||
|
* UnknownHostException (XMPP error code 504), and IOException (XMPP error code
|
||||||
|
* 502). The error codes and wrapped exceptions can be used to present more
|
||||||
|
* appropiate error messages to end-users.
|
||||||
|
*/
|
||||||
|
public XMPPConnection(String host, int port, String serviceName) throws XMPPException {
|
||||||
this.host = host;
|
this.host = host;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
try {
|
try {
|
||||||
|
@ -140,6 +176,7 @@ public class XMPPConnection {
|
||||||
new XMPPError(502),
|
new XMPPError(502),
|
||||||
ioe);
|
ioe);
|
||||||
}
|
}
|
||||||
|
this.serviceName = serviceName;
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,16 +188,19 @@ public class XMPPConnection {
|
||||||
* XMPP server. A typical use for a custom SocketFactory is when connecting through a
|
* XMPP server. A typical use for a custom SocketFactory is when connecting through a
|
||||||
* SOCKS proxy.
|
* SOCKS proxy.
|
||||||
*
|
*
|
||||||
* @param host the name of the XMPP server to connect to; e.g. <tt>jivesoftware.com</tt>.
|
* @param host the host name, or null for the loopback address.
|
||||||
* @param port the port on the server that should be used; e.g. <tt>5222</tt>.
|
* @param port the port on the server that should be used; e.g. <tt>5222</tt>.
|
||||||
* @param socketFactory a SocketFactory that will be used to create the socket to the XMPP server.
|
* @param serviceName the name of the XMPP server to connect to; e.g. <tt>jivesoftware.com</tt>.
|
||||||
|
* @param socketFactory a SocketFactory that will be used to create the socket to the XMPP
|
||||||
|
* server.
|
||||||
* @throws XMPPException if an error occurs while trying to establish the connection.
|
* @throws XMPPException if an error occurs while trying to establish the connection.
|
||||||
* Two possible errors can occur which will be wrapped by an XMPPException --
|
* Two possible errors can occur which will be wrapped by an XMPPException --
|
||||||
* UnknownHostException (XMPP error code 504), and IOException (XMPP error code
|
* UnknownHostException (XMPP error code 504), and IOException (XMPP error code
|
||||||
* 502). The error codes and wrapped exceptions can be used to present more
|
* 502). The error codes and wrapped exceptions can be used to present more
|
||||||
* appropiate error messages to end-users.
|
* appropiate error messages to end-users.
|
||||||
*/
|
*/
|
||||||
public XMPPConnection(String host, int port, SocketFactory socketFactory) throws XMPPException {
|
public XMPPConnection(String host, int port, String serviceName, SocketFactory socketFactory)
|
||||||
|
throws XMPPException {
|
||||||
this.host = host;
|
this.host = host;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
try {
|
try {
|
||||||
|
@ -178,6 +218,7 @@ public class XMPPConnection {
|
||||||
new XMPPError(502),
|
new XMPPError(502),
|
||||||
ioe);
|
ioe);
|
||||||
}
|
}
|
||||||
|
this.serviceName = serviceName;
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +228,6 @@ public class XMPPConnection {
|
||||||
* one of the other constructors.
|
* one of the other constructors.
|
||||||
*/
|
*/
|
||||||
XMPPConnection() {
|
XMPPConnection() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -202,9 +242,20 @@ public class XMPPConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the host name of the XMPP server for this connection.
|
* Returns the name of the service provided by the XMPP server for this connection. After
|
||||||
|
* authenticating with the server the returned value may be different.
|
||||||
*
|
*
|
||||||
* @return the host name of the XMPP server.
|
* @return the name of the service provided by the XMPP server.
|
||||||
|
*/
|
||||||
|
public String getServiceName() {
|
||||||
|
return serviceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the host name of the server where the XMPP server is running. This would be the
|
||||||
|
* IP address of the server or a name that may be resolved by a DNS server.
|
||||||
|
*
|
||||||
|
* @return the host name of the server where the XMPP server is running.
|
||||||
*/
|
*/
|
||||||
public String getHost() {
|
public String getHost() {
|
||||||
return host;
|
return host;
|
||||||
|
@ -294,69 +345,29 @@ public class XMPPConnection {
|
||||||
}
|
}
|
||||||
// Do partial version of nameprep on the username.
|
// Do partial version of nameprep on the username.
|
||||||
username = username.toLowerCase().trim();
|
username = username.toLowerCase().trim();
|
||||||
// If we send an authentication packet in "get" mode with just the username,
|
|
||||||
// the server will return the list of authentication protocols it supports.
|
|
||||||
Authentication discoveryAuth = new Authentication();
|
|
||||||
discoveryAuth.setType(IQ.Type.GET);
|
|
||||||
discoveryAuth.setUsername(username);
|
|
||||||
|
|
||||||
PacketCollector collector =
|
String response = null;
|
||||||
packetReader.createPacketCollector(new PacketIDFilter(discoveryAuth.getPacketID()));
|
if (usingTLS) {
|
||||||
// Send the packet
|
// Authenticate using SASL
|
||||||
packetWriter.sendPacket(discoveryAuth);
|
response = saslAuthentication.authenticate(username, password, resource);
|
||||||
// Wait up to a certain number of seconds for a response from the server.
|
|
||||||
IQ response = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
|
|
||||||
if (response == null) {
|
|
||||||
throw new XMPPException("No response from the server.");
|
|
||||||
}
|
|
||||||
// If the server replied with an error, throw an exception.
|
|
||||||
else if (response.getType() == IQ.Type.ERROR) {
|
|
||||||
throw new XMPPException(response.getError());
|
|
||||||
}
|
|
||||||
// Otherwise, no error so continue processing.
|
|
||||||
Authentication authTypes = (Authentication) response;
|
|
||||||
collector.cancel();
|
|
||||||
|
|
||||||
// Now, create the authentication packet we'll send to the server.
|
|
||||||
Authentication auth = new Authentication();
|
|
||||||
auth.setUsername(username);
|
|
||||||
|
|
||||||
// Figure out if we should use digest or plain text authentication.
|
|
||||||
if (authTypes.getDigest() != null) {
|
|
||||||
auth.setDigest(connectionID, password);
|
|
||||||
}
|
|
||||||
else if (authTypes.getPassword() != null) {
|
|
||||||
auth.setPassword(password);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new XMPPException("Server does not support compatible authentication mechanism.");
|
// Authenticate using Non-SASL
|
||||||
|
response = new NonSASLAuthentication(this).authenticate(username, password, resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
auth.setResource(resource);
|
|
||||||
|
|
||||||
collector = packetReader.createPacketCollector(new PacketIDFilter(auth.getPacketID()));
|
|
||||||
// Send the packet.
|
|
||||||
packetWriter.sendPacket(auth);
|
|
||||||
// Wait up to a certain number of seconds for a response from the server.
|
|
||||||
response = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
|
|
||||||
if (response == null) {
|
|
||||||
throw new XMPPException("Authentication failed.");
|
|
||||||
}
|
|
||||||
else if (response.getType() == IQ.Type.ERROR) {
|
|
||||||
throw new XMPPException(response.getError());
|
|
||||||
}
|
|
||||||
// Set the user.
|
// Set the user.
|
||||||
if (response.getTo() != null) {
|
if (response != null) {
|
||||||
this.user = response.getTo();
|
this.user = response;
|
||||||
|
// Update the serviceName with the one returned by the server
|
||||||
|
this.serviceName = StringUtils.parseServer(response);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.user = username + "@" + this.host;
|
this.user = username + "@" + this.serviceName;
|
||||||
if (resource != null) {
|
if (resource != null) {
|
||||||
this.user += "/" + resource;
|
this.user += "/" + resource;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We're done with the collector, so explicitly cancel it.
|
|
||||||
collector.cancel();
|
|
||||||
|
|
||||||
// Create the roster.
|
// Create the roster.
|
||||||
this.roster = new Roster(this);
|
this.roster = new Roster(this);
|
||||||
|
@ -383,8 +394,8 @@ public class XMPPConnection {
|
||||||
/**
|
/**
|
||||||
* Logs in to the server anonymously. Very few servers are configured to support anonymous
|
* Logs in to the server anonymously. Very few servers are configured to support anonymous
|
||||||
* authentication, so it's fairly likely logging in anonymously will fail. If anonymous login
|
* authentication, so it's fairly likely logging in anonymously will fail. If anonymous login
|
||||||
* does succeed, your XMPP address will likely be in the form "server/123ABC" (where "123ABC" is a
|
* does succeed, your XMPP address will likely be in the form "server/123ABC" (where "123ABC"
|
||||||
* random value generated by the server).
|
* is a random value generated by the server).
|
||||||
*
|
*
|
||||||
* @throws XMPPException if an error occurs or anonymous logins are not supported by the server.
|
* @throws XMPPException if an error occurs or anonymous logins are not supported by the server.
|
||||||
* @throws IllegalStateException if not connected to the server, or already logged in
|
* @throws IllegalStateException if not connected to the server, or already logged in
|
||||||
|
@ -418,7 +429,7 @@ public class XMPPConnection {
|
||||||
this.user = response.getTo();
|
this.user = response.getTo();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.user = this.host + "/" + ((Authentication) response).getResource();
|
this.user = this.serviceName + "/" + ((Authentication) response).getResource();
|
||||||
}
|
}
|
||||||
// We're done with the collector, so explicitly cancel it.
|
// We're done with the collector, so explicitly cancel it.
|
||||||
collector.cancel();
|
collector.cancel();
|
||||||
|
@ -732,70 +743,11 @@ public class XMPPConnection {
|
||||||
* @throws XMPPException if establishing a connection to the server fails.
|
* @throws XMPPException if establishing a connection to the server fails.
|
||||||
*/
|
*/
|
||||||
private void init() throws XMPPException {
|
private void init() throws XMPPException {
|
||||||
try {
|
// Set the reader and writer instance variables
|
||||||
reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
|
initReaderAndWriter();
|
||||||
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"));
|
|
||||||
}
|
|
||||||
catch (IOException ioe) {
|
|
||||||
throw new XMPPException(
|
|
||||||
"XMPPError establishing connection with server.",
|
|
||||||
new XMPPError(502),
|
|
||||||
ioe);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If debugging is enabled, we open a window and write out all network traffic.
|
try
|
||||||
if (DEBUG_ENABLED) {
|
{
|
||||||
// Detect the debugger class to use.
|
|
||||||
String className = null;
|
|
||||||
// Use try block since we may not have permission to get a system
|
|
||||||
// property (for example, when an applet).
|
|
||||||
try {
|
|
||||||
className = System.getProperty("smack.debuggerClass");
|
|
||||||
}
|
|
||||||
catch (Throwable t) {
|
|
||||||
}
|
|
||||||
Class debuggerClass = null;
|
|
||||||
if (className != null) {
|
|
||||||
try {
|
|
||||||
debuggerClass = Class.forName(className);
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (debuggerClass == null) {
|
|
||||||
try {
|
|
||||||
debuggerClass =
|
|
||||||
Class.forName("org.jivesoftware.smackx.debugger.EnhancedDebugger");
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
try {
|
|
||||||
debuggerClass = Class.forName("org.jivesoftware.smack.debugger.LiteDebugger");
|
|
||||||
}
|
|
||||||
catch (Exception ex2) {
|
|
||||||
ex2.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Create a new debugger instance. If an exception occurs then disable the debugging
|
|
||||||
// option
|
|
||||||
try {
|
|
||||||
Constructor constructor =
|
|
||||||
debuggerClass.getConstructor(
|
|
||||||
new Class[] { XMPPConnection.class, Writer.class, Reader.class });
|
|
||||||
debugger =
|
|
||||||
(SmackDebugger) constructor.newInstance(new Object[] { this, writer, reader });
|
|
||||||
reader = debugger.getReader();
|
|
||||||
writer = debugger.getWriter();
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
DEBUG_ENABLED = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
packetWriter = new PacketWriter(this);
|
packetWriter = new PacketWriter(this);
|
||||||
packetReader = new PacketReader(this);
|
packetReader = new PacketReader(this);
|
||||||
|
|
||||||
|
@ -819,36 +771,107 @@ public class XMPPConnection {
|
||||||
// Notify that a new connection has been established
|
// Notify that a new connection has been established
|
||||||
connectionEstablished(this);
|
connectionEstablished(this);
|
||||||
}
|
}
|
||||||
catch (XMPPException ex)
|
catch (XMPPException ex)
|
||||||
{
|
{
|
||||||
// An exception occurred in setting up the connection. Make sure we shut down the
|
// An exception occurred in setting up the connection. Make sure we shut down the
|
||||||
// readers and writers and close the socket.
|
// readers and writers and close the socket.
|
||||||
|
|
||||||
if (packetWriter != null) {
|
if (packetWriter != null) {
|
||||||
try { packetWriter.shutdown(); } catch (Throwable ignore) { }
|
try { packetWriter.shutdown(); } catch (Throwable ignore) { }
|
||||||
packetWriter = null;
|
packetWriter = null;
|
||||||
}
|
}
|
||||||
if (packetReader != null) {
|
if (packetReader != null) {
|
||||||
try { packetReader.shutdown(); } catch (Throwable ignore) { }
|
try { packetReader.shutdown(); } catch (Throwable ignore) { }
|
||||||
packetReader = null;
|
packetReader = null;
|
||||||
}
|
}
|
||||||
if (reader != null) {
|
if (reader != null) {
|
||||||
try { reader.close(); } catch (Throwable ignore) { }
|
try { reader.close(); } catch (Throwable ignore) { }
|
||||||
reader = null;
|
reader = null;
|
||||||
}
|
}
|
||||||
if (writer != null) {
|
if (writer != null) {
|
||||||
try { writer.close(); } catch (Throwable ignore) { }
|
try { writer.close(); } catch (Throwable ignore) { }
|
||||||
writer = null;
|
writer = null;
|
||||||
}
|
}
|
||||||
if (socket != null) {
|
if (socket != null) {
|
||||||
try { socket.close(); } catch (Exception e) { }
|
try { socket.close(); } catch (Exception e) { }
|
||||||
socket = null;
|
socket = null;
|
||||||
}
|
}
|
||||||
authenticated = false;
|
authenticated = false;
|
||||||
connected = false;
|
connected = false;
|
||||||
|
|
||||||
throw ex; // Everything stoppped. Now throw the exception.
|
throw ex; // Everything stoppped. Now throw the exception.
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initReaderAndWriter() throws XMPPException {
|
||||||
|
try {
|
||||||
|
reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
|
||||||
|
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"));
|
||||||
|
}
|
||||||
|
catch (IOException ioe) {
|
||||||
|
throw new XMPPException(
|
||||||
|
"XMPPError establishing connection with server.",
|
||||||
|
new XMPPError(502),
|
||||||
|
ioe);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If debugging is enabled, we open a window and write out all network traffic.
|
||||||
|
if (DEBUG_ENABLED) {
|
||||||
|
if (debugger == null) {
|
||||||
|
// Detect the debugger class to use.
|
||||||
|
String className = null;
|
||||||
|
// Use try block since we may not have permission to get a system
|
||||||
|
// property (for example, when an applet).
|
||||||
|
try {
|
||||||
|
className = System.getProperty("smack.debuggerClass");
|
||||||
|
}
|
||||||
|
catch (Throwable t) {
|
||||||
|
}
|
||||||
|
Class debuggerClass = null;
|
||||||
|
if (className != null) {
|
||||||
|
try {
|
||||||
|
debuggerClass = Class.forName(className);
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (debuggerClass == null) {
|
||||||
|
try {
|
||||||
|
debuggerClass =
|
||||||
|
Class.forName("org.jivesoftware.smackx.debugger.EnhancedDebugger");
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
try {
|
||||||
|
debuggerClass = Class.forName("org.jivesoftware.smack.debugger.LiteDebugger");
|
||||||
|
}
|
||||||
|
catch (Exception ex2) {
|
||||||
|
ex2.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Create a new debugger instance. If an exception occurs then disable the debugging
|
||||||
|
// option
|
||||||
|
try {
|
||||||
|
Constructor constructor =
|
||||||
|
debuggerClass.getConstructor(
|
||||||
|
new Class[] { XMPPConnection.class, Writer.class, Reader.class });
|
||||||
|
debugger = (SmackDebugger) constructor
|
||||||
|
.newInstance(new Object[]{this, writer, reader});
|
||||||
|
reader = debugger.getReader();
|
||||||
|
writer = debugger.getWriter();
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
DEBUG_ENABLED = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Obtain new reader and writer from the existing debugger
|
||||||
|
reader = debugger.newConnectionReader(reader);
|
||||||
|
writer = debugger.newConnectionWriter(writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -864,4 +887,79 @@ public class XMPPConnection {
|
||||||
listeners[i].connectionEstablished(connection);
|
listeners[i].connectionEstablished(connection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***********************************************
|
||||||
|
* TLS code below
|
||||||
|
**********************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the connection to the server has successfully negotiated TLS. Once TLS
|
||||||
|
* has been negotiatied the connection has been secured.
|
||||||
|
*
|
||||||
|
* @return true if the connection to the server has successfully negotiated TLS.
|
||||||
|
*/
|
||||||
|
public boolean isUsingTLS() {
|
||||||
|
return usingTLS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the SASLAuthentication manager that is responsible for authenticating with
|
||||||
|
* the server.
|
||||||
|
*
|
||||||
|
* @return the SASLAuthentication manager that is responsible for authenticating with
|
||||||
|
* the server.
|
||||||
|
*/
|
||||||
|
public SASLAuthentication getSASLAuthentication() {
|
||||||
|
return saslAuthentication;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notification message saying that the server supports TLS so confirm the server that we
|
||||||
|
* want to secure the connection.
|
||||||
|
*/
|
||||||
|
void startTLSReceived() {
|
||||||
|
try {
|
||||||
|
writer.write("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>");
|
||||||
|
writer.flush();
|
||||||
|
} catch (IOException e) {
|
||||||
|
packetReader.notifyConnectionError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The server has indicated that TLS negotiation can start. We now need to secure the
|
||||||
|
* existing plain connection and perform a handshake. This method won't return until the
|
||||||
|
* connection has finished the handshake or an error occured while securing the connection.
|
||||||
|
*/
|
||||||
|
void proceedTLSReceived() {
|
||||||
|
try {
|
||||||
|
SSLContext context = SSLContext.getInstance("TLS");
|
||||||
|
// Accept any certificate presented by the server
|
||||||
|
context.init(null, // KeyManager not required
|
||||||
|
new javax.net.ssl.TrustManager[] { new OpenTrustManager() },
|
||||||
|
new java.security.SecureRandom());
|
||||||
|
Socket plain = socket;
|
||||||
|
// Secure the plain connection
|
||||||
|
socket = context.getSocketFactory().createSocket(plain,
|
||||||
|
plain.getInetAddress().getHostName(), plain.getPort(), true);
|
||||||
|
socket.setSoTimeout(0);
|
||||||
|
socket.setKeepAlive(true);
|
||||||
|
// Initialize the reader and writer with the new secured version
|
||||||
|
initReaderAndWriter();
|
||||||
|
// Proceed to do the handshake
|
||||||
|
((SSLSocket)socket).startHandshake();
|
||||||
|
|
||||||
|
// Set that TLS was successful
|
||||||
|
usingTLS = true;
|
||||||
|
|
||||||
|
// Set the new writer to use
|
||||||
|
packetWriter.setWriter(writer);
|
||||||
|
// Send a new opening stream to the server
|
||||||
|
packetWriter.openStream();
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
packetReader.notifyConnectionError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in a new issue