mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2025-09-10 18:59:41 +02:00
Merge from 3.3 branch
git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/trunk@13663 b35dd754-fafc-0310-a699-88a17e54d16e
This commit is contained in:
commit
dac68c64a9
163 changed files with 2304 additions and 2366 deletions
|
@ -178,12 +178,12 @@ public abstract class Connection {
|
|||
protected SmackDebugger debugger = null;
|
||||
|
||||
/**
|
||||
* The Reader which is used for the {@see debugger}.
|
||||
* The Reader which is used for the debugger.
|
||||
*/
|
||||
protected Reader reader;
|
||||
|
||||
/**
|
||||
* The Writer which is used for the {@see debugger}.
|
||||
* The Writer which is used for the debugger.
|
||||
*/
|
||||
protected Writer writer;
|
||||
|
||||
|
|
|
@ -40,18 +40,11 @@ import java.util.concurrent.BlockingQueue;
|
|||
class PacketWriter {
|
||||
|
||||
private Thread writerThread;
|
||||
private Thread keepAliveThread;
|
||||
private Writer writer;
|
||||
private XMPPConnection connection;
|
||||
private final BlockingQueue<Packet> queue;
|
||||
volatile boolean done;
|
||||
|
||||
/**
|
||||
* Timestamp when the last stanza was sent to the server. This information is used
|
||||
* by the keep alive process to only send heartbeats when the connection has been idle.
|
||||
*/
|
||||
private long lastActive = System.currentTimeMillis();
|
||||
|
||||
/**
|
||||
* Creates a new packet writer with the specified connection.
|
||||
*
|
||||
|
@ -117,25 +110,6 @@ class PacketWriter {
|
|||
writerThread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the keep alive process. A white space (aka heartbeat) is going to be
|
||||
* sent to the server every 30 seconds (by default) since the last stanza was sent
|
||||
* to the server.
|
||||
*/
|
||||
void startKeepAliveProcess() {
|
||||
// Schedule a keep-alive task to run if the feature is enabled. will write
|
||||
// out a space character each time it runs to keep the TCP/IP connection open.
|
||||
int keepAliveInterval = SmackConfiguration.getKeepAliveInterval();
|
||||
if (keepAliveInterval > 0) {
|
||||
KeepAliveTask task = new KeepAliveTask(keepAliveInterval);
|
||||
keepAliveThread = new Thread(task);
|
||||
task.setThread(keepAliveThread);
|
||||
keepAliveThread.setDaemon(true);
|
||||
keepAliveThread.setName("Smack Keep Alive (" + connection.connectionCounterValue + ")");
|
||||
keepAliveThread.start();
|
||||
}
|
||||
}
|
||||
|
||||
void setWriter(Writer writer) {
|
||||
this.writer = writer;
|
||||
}
|
||||
|
@ -149,9 +123,6 @@ class PacketWriter {
|
|||
synchronized (queue) {
|
||||
queue.notifyAll();
|
||||
}
|
||||
// Interrupt the keep alive thread if one was created
|
||||
if (keepAliveThread != null)
|
||||
keepAliveThread.interrupt();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -191,13 +162,10 @@ class PacketWriter {
|
|||
while (!done && (writerThread == thisThread)) {
|
||||
Packet packet = nextPacket();
|
||||
if (packet != null) {
|
||||
synchronized (writer) {
|
||||
writer.write(packet.toXML());
|
||||
if (queue.isEmpty()) {
|
||||
writer.flush();
|
||||
// Keep track of the last time a stanza was sent to the server
|
||||
lastActive = System.currentTimeMillis();
|
||||
}
|
||||
writer.write(packet.toXML());
|
||||
|
||||
if (queue.isEmpty()) {
|
||||
writer.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -205,13 +173,11 @@ class PacketWriter {
|
|||
// we won't have time to entirely flush it before the socket is forced closed
|
||||
// by the shutdown process.
|
||||
try {
|
||||
synchronized (writer) {
|
||||
while (!queue.isEmpty()) {
|
||||
Packet packet = queue.remove();
|
||||
writer.write(packet.toXML());
|
||||
}
|
||||
writer.flush();
|
||||
while (!queue.isEmpty()) {
|
||||
Packet packet = queue.remove();
|
||||
writer.write(packet.toXML());
|
||||
}
|
||||
writer.flush();
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
@ -268,54 +234,4 @@ class PacketWriter {
|
|||
writer.write(stream.toString());
|
||||
writer.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* A TimerTask that keeps connections to the server alive by sending a space
|
||||
* character on an interval.
|
||||
*/
|
||||
private class KeepAliveTask implements Runnable {
|
||||
|
||||
private int delay;
|
||||
private Thread thread;
|
||||
|
||||
public KeepAliveTask(int delay) {
|
||||
this.delay = delay;
|
||||
}
|
||||
|
||||
protected void setThread(Thread thread) {
|
||||
this.thread = thread;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
// Sleep a minimum of 15 seconds plus delay before sending first heartbeat. This will give time to
|
||||
// properly finish TLS negotiation and then start sending heartbeats.
|
||||
Thread.sleep(15000 + delay);
|
||||
}
|
||||
catch (InterruptedException ie) {
|
||||
// Do nothing
|
||||
}
|
||||
while (!done && keepAliveThread == thread) {
|
||||
synchronized (writer) {
|
||||
// Send heartbeat if no packet has been sent to the server for a given time
|
||||
if (System.currentTimeMillis() - lastActive >= delay) {
|
||||
try {
|
||||
writer.write(" ");
|
||||
writer.flush();
|
||||
}
|
||||
catch (Exception e) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
// Sleep until we should write the next keep-alive.
|
||||
Thread.sleep(delay);
|
||||
}
|
||||
catch (InterruptedException ie) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
* Copyright 2003-2007 Jive Software.
|
||||
*
|
||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
* Copyright 2003-2007 Jive Software.
|
||||
*
|
||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
|
|
|
@ -315,8 +315,13 @@ public class SASLAuthentication implements UserAuthentication {
|
|||
currentMechanism = constructor.newInstance(this);
|
||||
// Trigger SASL authentication with the selected mechanism. We use
|
||||
// connection.getHost() since GSAPI requires the FQDN of the server, which
|
||||
// may not match the XMPP domain.
|
||||
currentMechanism.authenticate(username, connection.getServiceName(), password);
|
||||
// may not match the XMPP domain.
|
||||
|
||||
//The serviceName is basically the value that XMPP server sends to the client as being the location
|
||||
//of the XMPP service we are trying to connect to. This should have the format: host [ "/" serv-name ]
|
||||
//as per RFC-2831 guidelines
|
||||
String serviceName = connection.getServiceName();
|
||||
currentMechanism.authenticate(username, connection.getHost(), serviceName, password);
|
||||
|
||||
// Wait until SASL negotiation finishes
|
||||
synchronized (this) {
|
||||
|
@ -383,7 +388,7 @@ public class SASLAuthentication implements UserAuthentication {
|
|||
public String authenticateAnonymously() throws XMPPException {
|
||||
try {
|
||||
currentMechanism = new SASLAnonymous(this);
|
||||
currentMechanism.authenticate(null,null,"");
|
||||
currentMechanism.authenticate(null,null,null,"");
|
||||
|
||||
// Wait until SASL negotiation finishes
|
||||
synchronized (this) {
|
||||
|
|
|
@ -48,7 +48,7 @@ import org.xmlpull.v1.XmlPullParser;
|
|||
*/
|
||||
public final class SmackConfiguration {
|
||||
|
||||
private static final String SMACK_VERSION = "3.2.2";
|
||||
private static final String SMACK_VERSION = "3.3.0";
|
||||
|
||||
private static int packetReplyTimeout = 5000;
|
||||
private static int keepAliveInterval = 30000;
|
||||
|
@ -58,11 +58,6 @@ public final class SmackConfiguration {
|
|||
private static int localSocks5ProxyPort = 7777;
|
||||
private static int packetCollectorSize = 5000;
|
||||
|
||||
/**
|
||||
* defaultPingInterval (in seconds)
|
||||
*/
|
||||
private static int defaultPingInterval = 1800; // 30 min (30*60)
|
||||
|
||||
/**
|
||||
* This automatically enables EntityCaps for new connections if it is set to true
|
||||
*/
|
||||
|
@ -117,8 +112,8 @@ public final class SmackConfiguration {
|
|||
else if (parser.getName().equals("packetCollectorSize")) {
|
||||
packetCollectorSize = parseIntProperty(parser, packetCollectorSize);
|
||||
}
|
||||
else if (parser.getName().equals("defaultPingInterval")) {
|
||||
defaultPingInterval = parseIntProperty(parser, defaultPingInterval);
|
||||
else if (parser.getName().equals("autoEnableEntityCaps")) {
|
||||
autoEnableEntityCaps = Boolean.parseBoolean(parser.nextText());
|
||||
}
|
||||
else if (parser.getName().equals("autoEnableEntityCaps")) {
|
||||
autoEnableEntityCaps = Boolean.parseBoolean(parser.nextText());
|
||||
|
@ -320,21 +315,12 @@ public final class SmackConfiguration {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the default ping interval (seconds)
|
||||
* Set if Entity Caps are enabled or disabled for every new connection
|
||||
*
|
||||
* @return
|
||||
* @param true if Entity Caps should be auto enabled, false if not
|
||||
*/
|
||||
public static int getDefaultPingInterval() {
|
||||
return defaultPingInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default ping interval (seconds). Set it to '-1' to disable the periodic ping
|
||||
*
|
||||
* @param defaultPingInterval
|
||||
*/
|
||||
public static void setDefaultPingInterval(int defaultPingInterval) {
|
||||
SmackConfiguration.defaultPingInterval = defaultPingInterval;
|
||||
public static void setAutoEnableEntityCaps(boolean b) {
|
||||
autoEnableEntityCaps = b;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -345,15 +331,6 @@ public final class SmackConfiguration {
|
|||
return autoEnableEntityCaps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if Entity Caps are enabled or disabled for every new connection
|
||||
*
|
||||
* @param true if Entity Caps should be auto enabled, false if not
|
||||
*/
|
||||
public static void setAutoEnableEntityCaps(boolean b) {
|
||||
autoEnableEntityCaps = b;
|
||||
}
|
||||
|
||||
private static void parseClassToLoad(XmlPullParser parser) throws Exception {
|
||||
String className = parser.nextText();
|
||||
// Attempt to load the class so that the class can get initialized
|
||||
|
|
24
source/org/jivesoftware/smack/SmackError.java
Normal file
24
source/org/jivesoftware/smack/SmackError.java
Normal file
|
@ -0,0 +1,24 @@
|
|||
package org.jivesoftware.smack;
|
||||
|
||||
public enum SmackError {
|
||||
NO_RESPONSE_FROM_SERVER("No response from server.");
|
||||
|
||||
private String message;
|
||||
|
||||
private SmackError(String errMessage) {
|
||||
message = errMessage;
|
||||
}
|
||||
|
||||
public String getErrorMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public static SmackError getErrorCode(String message) {
|
||||
for (SmackError code : values()) {
|
||||
if (code.message.equals(message)) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -650,10 +650,6 @@ public class XMPPConnection extends Connection {
|
|||
// Make note of the fact that we're now connected.
|
||||
connected = true;
|
||||
|
||||
// Start keep alive process (after TLS was negotiated - if available)
|
||||
packetWriter.startKeepAliveProcess();
|
||||
|
||||
|
||||
if (isFirstInitialization) {
|
||||
// Notify listeners that a new connection has been established
|
||||
for (ConnectionCreationListener listener : getConnectionCreationListeners()) {
|
||||
|
|
|
@ -41,10 +41,12 @@ import java.io.PrintWriter;
|
|||
* @author Matt Tucker
|
||||
*/
|
||||
public class XMPPException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 6881651633890968625L;
|
||||
|
||||
private StreamError streamError = null;
|
||||
private XMPPError error = null;
|
||||
private Throwable wrappedThrowable = null;
|
||||
private SmackError smackError = null;
|
||||
|
||||
/**
|
||||
* Creates a new XMPPException.
|
||||
|
@ -62,6 +64,16 @@ public class XMPPException extends Exception {
|
|||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new XMPPException with a Smack specific error code.
|
||||
*
|
||||
* @param code the root cause of the exception.
|
||||
*/
|
||||
public XMPPException(SmackError code) {
|
||||
super(code.getErrorMessage());
|
||||
smackError = code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new XMPPException with the Throwable that was the root cause of the
|
||||
* exception.
|
||||
|
@ -74,7 +86,7 @@ public class XMPPException extends Exception {
|
|||
}
|
||||
|
||||
/**
|
||||
* Cretaes a new XMPPException with the stream error that was the root case of the
|
||||
* Creates a new XMPPException with the stream error that was the root case of the
|
||||
* exception. When a stream error is received from the server then the underlying
|
||||
* TCP connection will be closed by the server.
|
||||
*
|
||||
|
@ -144,6 +156,16 @@ public class XMPPException extends Exception {
|
|||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SmackError asscociated with this exception, or <tt>null</tt> if there
|
||||
* isn't one.
|
||||
*
|
||||
* @return the SmackError asscociated with this exception.
|
||||
*/
|
||||
public SmackError getSmackError() {
|
||||
return smackError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the StreamError asscociated with this exception, or <tt>null</tt> if there
|
||||
* isn't one. The underlying TCP connection is closed by the server after sending the
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
* Copyright 2003-2007 Jive Software.
|
||||
*
|
||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
* Copyright 2003-2007 Jive Software.
|
||||
* Copyright 2003 Jive Software.
|
||||
*
|
||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
312
source/org/jivesoftware/smack/keepalive/KeepAliveManager.java
Normal file
312
source/org/jivesoftware/smack/keepalive/KeepAliveManager.java
Normal file
|
@ -0,0 +1,312 @@
|
|||
/**
|
||||
* Copyright 2012-2013 Florian Schmaus
|
||||
*
|
||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jivesoftware.smack.keepalive;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.jivesoftware.smack.Connection;
|
||||
import org.jivesoftware.smack.ConnectionCreationListener;
|
||||
import org.jivesoftware.smack.ConnectionListener;
|
||||
import org.jivesoftware.smack.PacketCollector;
|
||||
import org.jivesoftware.smack.PacketListener;
|
||||
import org.jivesoftware.smack.SmackConfiguration;
|
||||
import org.jivesoftware.smack.filter.PacketFilter;
|
||||
import org.jivesoftware.smack.filter.PacketIDFilter;
|
||||
import org.jivesoftware.smack.packet.Packet;
|
||||
import org.jivesoftware.smack.ping.PingFailedListener;
|
||||
import org.jivesoftware.smack.ping.packet.Ping;
|
||||
|
||||
/**
|
||||
* Using an implementation of <a href="http://www.xmpp.org/extensions/xep-0199.html">XMPP Ping (XEP-0199)</a>. This
|
||||
* class provides keepalive functionality with the server that will periodically "ping" the server to maintain and/or
|
||||
* verify that the connection still exists.
|
||||
* <p>
|
||||
* The ping is done at the application level and is therefore protocol agnostic. It will thus work for both standard TCP
|
||||
* connections as well as BOSH or any other transport protocol. It will also work regardless of whether the server
|
||||
* supports the Ping extension, since an error response to the ping serves the same purpose as a pong.
|
||||
*
|
||||
* @author Florian Schmaus
|
||||
*/
|
||||
public class KeepAliveManager {
|
||||
private static Map<Connection, KeepAliveManager> instances = new HashMap<Connection, KeepAliveManager>();
|
||||
private static volatile ScheduledExecutorService periodicPingExecutorService;
|
||||
|
||||
static {
|
||||
if (SmackConfiguration.getKeepAliveInterval() > 0) {
|
||||
Connection.addConnectionCreationListener(new ConnectionCreationListener() {
|
||||
public void connectionCreated(Connection connection) {
|
||||
new KeepAliveManager(connection);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private Connection connection;
|
||||
private long pingInterval = SmackConfiguration.getKeepAliveInterval();
|
||||
private Set<PingFailedListener> pingFailedListeners = Collections.synchronizedSet(new HashSet<PingFailedListener>());
|
||||
private volatile ScheduledFuture<?> periodicPingTask;
|
||||
private volatile long lastSuccessfulContact = -1;
|
||||
|
||||
/**
|
||||
* Retrieves a {@link KeepAliveManager} for the specified {@link Connection}, creating one if it doesn't already
|
||||
* exist.
|
||||
*
|
||||
* @param connection
|
||||
* The connection the manager is attached to.
|
||||
* @return The new or existing manager.
|
||||
*/
|
||||
public synchronized static KeepAliveManager getInstanceFor(Connection connection) {
|
||||
KeepAliveManager pingManager = instances.get(connection);
|
||||
|
||||
if (pingManager == null) {
|
||||
pingManager = new KeepAliveManager(connection);
|
||||
instances.put(connection, pingManager);
|
||||
}
|
||||
return pingManager;
|
||||
}
|
||||
|
||||
/*
|
||||
* Start the executor service if it hasn't been started yet.
|
||||
*/
|
||||
private synchronized static void enableExecutorService() {
|
||||
if (periodicPingExecutorService == null) {
|
||||
periodicPingExecutorService = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
|
||||
@Override
|
||||
public Thread newThread(Runnable runnable) {
|
||||
Thread pingThread = new Thread(runnable, "Smack Keepalive");
|
||||
pingThread.setDaemon(true);
|
||||
return pingThread;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Stop the executor service if all monitored connections are disconnected.
|
||||
*/
|
||||
private synchronized static void handleDisconnect(Connection con) {
|
||||
if (periodicPingExecutorService != null) {
|
||||
instances.remove(con);
|
||||
|
||||
if (instances.isEmpty()) {
|
||||
periodicPingExecutorService.shutdownNow();
|
||||
periodicPingExecutorService = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private KeepAliveManager(Connection connection) {
|
||||
this.connection = connection;
|
||||
init();
|
||||
handleConnect();
|
||||
}
|
||||
|
||||
/*
|
||||
* Call after every connection to add the packet listener.
|
||||
*/
|
||||
private void handleConnect() {
|
||||
// Listen for all incoming packets and reset the scheduled ping whenever
|
||||
// one arrives.
|
||||
connection.addPacketListener(new PacketListener() {
|
||||
|
||||
@Override
|
||||
public void processPacket(Packet packet) {
|
||||
// reschedule the ping based on this last server contact
|
||||
lastSuccessfulContact = System.currentTimeMillis();
|
||||
schedulePingServerTask();
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
connection.addConnectionListener(new ConnectionListener() {
|
||||
|
||||
@Override
|
||||
public void connectionClosed() {
|
||||
stopPingServerTask();
|
||||
handleDisconnect(connection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionClosedOnError(Exception arg0) {
|
||||
stopPingServerTask();
|
||||
handleDisconnect(connection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reconnectionSuccessful() {
|
||||
handleConnect();
|
||||
schedulePingServerTask();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reconnectingIn(int seconds) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reconnectionFailed(Exception e) {
|
||||
}
|
||||
});
|
||||
|
||||
instances.put(connection, this);
|
||||
schedulePingServerTask();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ping interval.
|
||||
*
|
||||
* @param pingInterval
|
||||
* The new ping time interval in milliseconds.
|
||||
*/
|
||||
public void setPingInterval(long newPingInterval) {
|
||||
if (pingInterval == newPingInterval)
|
||||
return;
|
||||
|
||||
// Enable the executor service
|
||||
if (newPingInterval > 0)
|
||||
enableExecutorService();
|
||||
|
||||
pingInterval = newPingInterval;
|
||||
|
||||
if (pingInterval < 0) {
|
||||
stopPinging();
|
||||
}
|
||||
else {
|
||||
schedulePingServerTask();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops pinging the server. This cannot stop a ping that has already started, but will prevent another from being triggered.
|
||||
* <p>
|
||||
* To restart, call {@link #setPingInterval(long)}.
|
||||
*/
|
||||
public void stopPinging() {
|
||||
pingInterval = -1;
|
||||
stopPingServerTask();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ping interval.
|
||||
*
|
||||
* @return The ping interval in milliseconds.
|
||||
*/
|
||||
public long getPingInterval() {
|
||||
return pingInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add listener for notification when a server ping fails.
|
||||
*
|
||||
* <p>
|
||||
* Please note that this doesn't necessarily mean that the connection is lost, a slow to respond server could also
|
||||
* cause a failure due to taking too long to respond and thus causing a reply timeout.
|
||||
*
|
||||
* @param listener
|
||||
* The listener to be called
|
||||
*/
|
||||
public void addPingFailedListener(PingFailedListener listener) {
|
||||
pingFailedListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the listener.
|
||||
*
|
||||
* @param listener
|
||||
* The listener to be removed.
|
||||
*/
|
||||
public void removePingFailedListener(PingFailedListener listener) {
|
||||
pingFailedListeners.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the elapsed time (in milliseconds) since the last successful contact with the server
|
||||
* (i.e. the last time any message was received).
|
||||
* <p>
|
||||
* <b>Note</b>: Result is -1 if no message has been received since manager was created and
|
||||
* 0 if the elapsed time is negative due to a clock reset.
|
||||
*
|
||||
* @return Elapsed time since last message was received.
|
||||
*/
|
||||
public long getTimeSinceLastContact() {
|
||||
if (lastSuccessfulContact == -1)
|
||||
return lastSuccessfulContact;
|
||||
long delta = System.currentTimeMillis() - lastSuccessfulContact;
|
||||
|
||||
return (delta < 0) ? 0 : delta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels any existing periodic ping task if there is one and schedules a new ping task if pingInterval is greater
|
||||
* then zero.
|
||||
*
|
||||
* This is designed so only one executor is used for scheduling all pings on all connections. This results in only 1 thread used for pinging.
|
||||
*/
|
||||
private synchronized void schedulePingServerTask() {
|
||||
enableExecutorService();
|
||||
stopPingServerTask();
|
||||
|
||||
if (pingInterval > 0) {
|
||||
periodicPingTask = periodicPingExecutorService.schedule(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Ping ping = new Ping();
|
||||
PacketFilter responseFilter = new PacketIDFilter(ping.getPacketID());
|
||||
final PacketCollector response = connection.createPacketCollector(responseFilter);
|
||||
connection.sendPacket(ping);
|
||||
|
||||
if (!pingFailedListeners.isEmpty()) {
|
||||
// Schedule a collector for the ping reply, notify listeners if none is received.
|
||||
periodicPingExecutorService.schedule(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Packet result = response.nextResult(1);
|
||||
|
||||
// Stop queuing results
|
||||
response.cancel();
|
||||
|
||||
// The actual result of the reply can be ignored since we only care if we actually got one.
|
||||
if (result == null) {
|
||||
for (PingFailedListener listener : pingFailedListeners) {
|
||||
listener.pingFailed();
|
||||
}
|
||||
}
|
||||
}
|
||||
}, SmackConfiguration.getPacketReplyTimeout(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
}, getPingInterval(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
private void stopPingServerTask() {
|
||||
if (periodicPingTask != null) {
|
||||
periodicPingTask.cancel(true);
|
||||
periodicPingTask = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,8 +3,6 @@
|
|||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
* Copyright 2003-2007 Jive Software.
|
||||
*
|
||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
|
|
27
source/org/jivesoftware/smack/ping/PingFailedListener.java
Normal file
27
source/org/jivesoftware/smack/ping/PingFailedListener.java
Normal file
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* Copyright 2012 Florian Schmaus
|
||||
*
|
||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jivesoftware.smack.ping;
|
||||
|
||||
/**
|
||||
* Defines the callback used whenever the server ping fails.
|
||||
*/
|
||||
public interface PingFailedListener {
|
||||
/**
|
||||
* Called when the server ping fails.
|
||||
*/
|
||||
void pingFailed();
|
||||
}
|
39
source/org/jivesoftware/smack/ping/packet/Ping.java
Normal file
39
source/org/jivesoftware/smack/ping/packet/Ping.java
Normal file
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* Copyright 2012 Florian Schmaus
|
||||
*
|
||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jivesoftware.smack.ping.packet;
|
||||
|
||||
import org.jivesoftware.smack.packet.IQ;
|
||||
import org.jivesoftware.smackx.ping.PingManager;
|
||||
|
||||
public class Ping extends IQ {
|
||||
|
||||
public static final String NAMESPACE = "urn:xmpp:ping";
|
||||
public static final String ELEMENT = "ping";
|
||||
|
||||
public Ping() {
|
||||
}
|
||||
|
||||
public Ping(String to) {
|
||||
setTo(to);
|
||||
setType(IQ.Type.GET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getChildElementXML() {
|
||||
return "<" + ELEMENT + " xmlns=\'" + NAMESPACE + "\' />";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* Copyright 2012 Florian Schmaus
|
||||
*
|
||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jivesoftware.smack.ping.provider;
|
||||
|
||||
import org.jivesoftware.smack.packet.IQ;
|
||||
import org.jivesoftware.smack.ping.packet.Ping;
|
||||
import org.jivesoftware.smack.provider.IQProvider;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
|
||||
public class PingProvider implements IQProvider {
|
||||
|
||||
public IQ parseIQ(XmlPullParser parser) throws Exception {
|
||||
// No need to use the ping constructor with arguments. IQ will already
|
||||
// have filled out all relevant fields ('from', 'to', 'id').
|
||||
return new Ping();
|
||||
}
|
||||
|
||||
}
|
|
@ -3,8 +3,6 @@
|
|||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
* Copyright 2003-2007 Jive Software.
|
||||
*
|
||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
* Copyright 2003-2007 Jive Software.
|
||||
*
|
||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
* Copyright 2003-2007 Jive Software.
|
||||
*
|
||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
|
@ -92,8 +90,7 @@ class HTTPProxySocketFactory
|
|||
else
|
||||
{
|
||||
String password = proxy.getProxyPassword();
|
||||
proxyLine = "\r\nProxy-Authorization: Basic "
|
||||
+ new String(StringUtils.encodeBase64(username + ":" + password));
|
||||
proxyLine = "\r\nProxy-Authorization: Basic " + StringUtils.encodeBase64(username + ":" + password);
|
||||
}
|
||||
socket.getOutputStream().write((hostport + " HTTP/1.1\r\nHost: "
|
||||
+ hostport + proxyLine + "\r\n\r\n").getBytes("UTF-8"));
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
* Copyright 2003-2007 Jive Software.
|
||||
*
|
||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
* Copyright 2003-2007 Jive Software.
|
||||
*
|
||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
* Copyright 2003-2007 Jive Software.
|
||||
*
|
||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
* Copyright 2003-2007 Jive Software.
|
||||
*
|
||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
|
|
|
@ -51,6 +51,30 @@ import javax.security.sasl.SaslException;
|
|||
* using the CallbackHandler method.</li>
|
||||
* <li>{@link #challengeReceived(String)} -- Handle a challenge from the server.</li>
|
||||
* </ul>
|
||||
*
|
||||
* Basic XMPP SASL authentication steps:
|
||||
* 1. Client authentication initialization, stanza sent to the server (Base64 encoded):
|
||||
* <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/>
|
||||
* 2. Server sends back to the client the challenge response (Base64 encoded)
|
||||
* sample:
|
||||
* realm=<sasl server realm>,nonce="OA6MG9tEQGm2hh",qop="auth",charset=utf-8,algorithm=md5-sess
|
||||
* 3. The client responds back to the server (Base 64 encoded):
|
||||
* sample:
|
||||
* username=<userid>,realm=<sasl server realm from above>,nonce="OA6MG9tEQGm2hh",
|
||||
* cnonce="OA6MHXh6VqTrRk",nc=00000001,qop=auth,
|
||||
* digest-uri=<digesturi>,
|
||||
* response=d388dad90d4bbd760a152321f2143af7,
|
||||
* charset=utf-8,
|
||||
* authzid=<id>
|
||||
* 4. The server evaluates if the user is present and contained in the REALM
|
||||
* if successful it sends: <response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/> (Base64 encoded)
|
||||
* if not successful it sends:
|
||||
* sample:
|
||||
* <challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
|
||||
* cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZA==
|
||||
* </challenge>
|
||||
*
|
||||
|
||||
*
|
||||
* @author Jay Kline
|
||||
*/
|
||||
|
@ -62,37 +86,88 @@ public abstract class SASLMechanism implements CallbackHandler {
|
|||
protected String password;
|
||||
protected String hostname;
|
||||
|
||||
|
||||
public SASLMechanism(SASLAuthentication saslAuthentication) {
|
||||
this.saslAuthentication = saslAuthentication;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and sends the <tt>auth</tt> stanza to the server. Note that this method of
|
||||
* authentication is not recommended, since it is very inflexable. Use
|
||||
* authentication is not recommended, since it is very inflexable. Use
|
||||
* {@link #authenticate(String, String, CallbackHandler)} whenever possible.
|
||||
*
|
||||
*
|
||||
* Explanation of auth stanza:
|
||||
*
|
||||
* The client authentication stanza needs to include the digest-uri of the form: xmpp/serverName
|
||||
* From RFC-2831:
|
||||
* digest-uri = "digest-uri" "=" digest-uri-value
|
||||
* digest-uri-value = serv-type "/" host [ "/" serv-name ]
|
||||
*
|
||||
* digest-uri:
|
||||
* Indicates the principal name of the service with which the client
|
||||
* wishes to connect, formed from the serv-type, host, and serv-name.
|
||||
* For example, the FTP service
|
||||
* on "ftp.example.com" would have a "digest-uri" value of "ftp/ftp.example.com"; the SMTP
|
||||
* server from the example above would have a "digest-uri" value of
|
||||
* "smtp/mail3.example.com/example.com".
|
||||
*
|
||||
* host:
|
||||
* The DNS host name or IP address for the service requested. The DNS host name
|
||||
* must be the fully-qualified canonical name of the host. The DNS host name is the
|
||||
* preferred form; see notes on server processing of the digest-uri.
|
||||
*
|
||||
* serv-name:
|
||||
* Indicates the name of the service if it is replicated. The service is
|
||||
* considered to be replicated if the client's service-location process involves resolution
|
||||
* using standard DNS lookup operations, and if these operations involve DNS records (such
|
||||
* as SRV, or MX) which resolve one DNS name into a set of other DNS names. In this case,
|
||||
* the initial name used by the client is the "serv-name", and the final name is the "host"
|
||||
* component. For example, the incoming mail service for "example.com" may be replicated
|
||||
* through the use of MX records stored in the DNS, one of which points at an SMTP server
|
||||
* called "mail3.example.com"; it's "serv-name" would be "example.com", it's "host" would be
|
||||
* "mail3.example.com". If the service is not replicated, or the serv-name is identical to
|
||||
* the host, then the serv-name component MUST be omitted
|
||||
*
|
||||
* digest-uri verification is needed for ejabberd 2.0.3 and higher
|
||||
*
|
||||
* @param username the username of the user being authenticated.
|
||||
* @param host the hostname where the user account resides.
|
||||
* @param host the hostname where the user account resides.
|
||||
* @param serviceName the xmpp service location - used by the SASL client in digest-uri creation
|
||||
* serviceName format is: host [ "/" serv-name ] as per RFC-2831
|
||||
* @param password the password for this account.
|
||||
* @throws IOException If a network error occurs while authenticating.
|
||||
* @throws XMPPException If a protocol error occurs or the user is not authenticated.
|
||||
*/
|
||||
public void authenticate(String username, String host, String password) throws IOException, XMPPException {
|
||||
public void authenticate(String username, String host, String serviceName, String password) throws IOException, XMPPException {
|
||||
//Since we were not provided with a CallbackHandler, we will use our own with the given
|
||||
//information
|
||||
|
||||
//Set the authenticationID as the username, since they must be the same in this case.
|
||||
this.authenticationId = username;
|
||||
this.password = password;
|
||||
this.hostname = host;
|
||||
this.hostname = host;
|
||||
|
||||
String[] mechanisms = { getName() };
|
||||
Map<String,String> props = new HashMap<String,String>();
|
||||
sc = Sasl.createSaslClient(mechanisms, username, "xmpp", host, props, this);
|
||||
Map<String,String> props = new HashMap<String,String>();
|
||||
sc = Sasl.createSaslClient(mechanisms, username, "xmpp", serviceName, props, this);
|
||||
authenticate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #authenticate(String, String, String, String)}, but with the hostname used as the serviceName.
|
||||
* <p>
|
||||
* Kept for backward compatibility only.
|
||||
*
|
||||
* @param username the username of the user being authenticated.
|
||||
* @param host the hostname where the user account resides.
|
||||
* @param password the password for this account.
|
||||
* @throws IOException If a network error occurs while authenticating.
|
||||
* @throws XMPPException If a protocol error occurs or the user is not authenticated.
|
||||
* @deprecated Please use {@link #authenticate(String, String, String, String)} instead.
|
||||
*/
|
||||
public void authenticate(String username, String host, String password) throws IOException, XMPPException {
|
||||
authenticate(username, host, host, password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and sends the <tt>auth</tt> stanza to the server. The callback handler will handle
|
||||
* any additional information, such as the authentication ID or realm, if it is needed.
|
||||
|
@ -178,7 +253,13 @@ public abstract class SASLMechanism implements CallbackHandler {
|
|||
pcb.setPassword(password.toCharArray());
|
||||
} else if(callbacks[i] instanceof RealmCallback) {
|
||||
RealmCallback rcb = (RealmCallback)callbacks[i];
|
||||
rcb.setText(hostname);
|
||||
//Retrieve the REALM from the challenge response that the server returned when the client initiated the authentication
|
||||
//exchange. If this value is not null or empty, *this value* has to be sent back to the server in the client's response
|
||||
//to the server's challenge
|
||||
String text = rcb.getDefaultText();
|
||||
//The SASL client (sc) created in smack uses rcb.getText when creating the negotiatedRealm to send it back to the server
|
||||
//Make sure that this value matches the server's realm
|
||||
rcb.setText(text);
|
||||
} else if(callbacks[i] instanceof RealmChoiceCallback){
|
||||
//unused
|
||||
//RealmChoiceCallback rccb = (RealmChoiceCallback)callbacks[i];
|
||||
|
@ -319,5 +400,5 @@ public abstract class SASLMechanism implements CallbackHandler {
|
|||
stanza.append("</failure>");
|
||||
return stanza.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ import java.io.IOException;
|
|||
*/
|
||||
public class Base32Encoder implements StringEncoder {
|
||||
|
||||
private static Base32Encoder instance;
|
||||
private static Base32Encoder instance = new Base32Encoder();
|
||||
private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ2345678";
|
||||
|
||||
private Base32Encoder() {
|
||||
|
@ -37,9 +37,6 @@ public class Base32Encoder implements StringEncoder {
|
|||
}
|
||||
|
||||
public static Base32Encoder getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new Base32Encoder();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,66 +7,9 @@
|
|||
package org.jivesoftware.smack.util;
|
||||
|
||||
/**
|
||||
* <p>Encodes and decodes to and from Base64 notation.</p>
|
||||
* <p>Homepage: <a href="http://iharder.net/base64">http://iharder.net/base64</a>.</p>
|
||||
* <p>Encodes and decodes to and from Base64 notation.</p>
|
||||
* This code was obtained from <a href="http://iharder.net/base64">http://iharder.net/base64</a></p>
|
||||
*
|
||||
* <p>
|
||||
* Change Log:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>v2.2.1 - Fixed bug using URL_SAFE and ORDERED encodings. Fixed bug
|
||||
* when using very small files (~< 40 bytes).</li>
|
||||
* <li>v2.2 - Added some helper methods for encoding/decoding directly from
|
||||
* one file to the next. Also added a main() method to support command line
|
||||
* encoding/decoding from one file to the next. Also added these Base64 dialects:
|
||||
* <ol>
|
||||
* <li>The default is RFC3548 format.</li>
|
||||
* <li>Calling Base64.setFormat(Base64.BASE64_FORMAT.URLSAFE_FORMAT) generates
|
||||
* URL and file name friendly format as described in Section 4 of RFC3548.
|
||||
* http://www.faqs.org/rfcs/rfc3548.html</li>
|
||||
* <li>Calling Base64.setFormat(Base64.BASE64_FORMAT.ORDERED_FORMAT) generates
|
||||
* URL and file name friendly format that preserves lexical ordering as described
|
||||
* in http://www.faqs.org/qa/rfcc-1940.html</li>
|
||||
* </ol>
|
||||
* Special thanks to Jim Kellerman at <a href="http://www.powerset.com/">http://www.powerset.com/</a>
|
||||
* for contributing the new Base64 dialects.
|
||||
* </li>
|
||||
*
|
||||
* <li>v2.1 - Cleaned up javadoc comments and unused variables and methods. Added
|
||||
* some convenience methods for reading and writing to and from files.</li>
|
||||
* <li>v2.0.2 - Now specifies UTF-8 encoding in places where the code fails on systems
|
||||
* with other encodings (like EBCDIC).</li>
|
||||
* <li>v2.0.1 - Fixed an error when decoding a single byte, that is, when the
|
||||
* encoded data was a single byte.</li>
|
||||
* <li>v2.0 - I got rid of methods that used booleans to set options.
|
||||
* Now everything is more consolidated and cleaner. The code now detects
|
||||
* when data that's being decoded is gzip-compressed and will decompress it
|
||||
* automatically. Generally things are cleaner. You'll probably have to
|
||||
* change some method calls that you were making to support the new
|
||||
* options format (<tt>int</tt>s that you "OR" together).</li>
|
||||
* <li>v1.5.1 - Fixed bug when decompressing and decoding to a
|
||||
* byte[] using <tt>decode( String s, boolean gzipCompressed )</tt>.
|
||||
* Added the ability to "suspend" encoding in the Output Stream so
|
||||
* you can turn on and off the encoding if you need to embed base64
|
||||
* data in an otherwise "normal" stream (like an XML file).</li>
|
||||
* <li>v1.5 - Output stream pases on flush() command but doesn't do anything itself.
|
||||
* This helps when using GZIP streams.
|
||||
* Added the ability to GZip-compress objects before encoding them.</li>
|
||||
* <li>v1.4 - Added helper methods to read/write files.</li>
|
||||
* <li>v1.3.6 - Fixed OutputStream.flush() so that 'position' is reset.</li>
|
||||
* <li>v1.3.5 - Added flag to turn on and off line breaks. Fixed bug in input stream
|
||||
* where last buffer being read, if not completely full, was not returned.</li>
|
||||
* <li>v1.3.4 - Fixed when "improperly padded stream" error was thrown at the wrong time.</li>
|
||||
* <li>v1.3.3 - Fixed I/O streams which were totally messed up.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* I am placing this code in the Public Domain. Do with it as you will.
|
||||
* This software comes with no guarantees or warranties but with
|
||||
* plenty of well-wishing instead!
|
||||
* Please visit <a href="http://iharder.net/base64">http://iharder.net/base64</a>
|
||||
* periodically to check for updates or to contribute improvements.
|
||||
* </p>
|
||||
*
|
||||
* @author Robert Harder
|
||||
* @author rob@iharder.net
|
||||
|
@ -368,33 +311,6 @@ public class Base64
|
|||
/** Defeats instantiation. */
|
||||
private Base64(){}
|
||||
|
||||
|
||||
/**
|
||||
* Encodes or decodes two files from the command line;
|
||||
* <strong>feel free to delete this method (in fact you probably should)
|
||||
* if you're embedding this code into a larger program.</strong>
|
||||
*/
|
||||
public final static void main( String[] args )
|
||||
{
|
||||
if( args.length < 3 ){
|
||||
usage("Not enough arguments.");
|
||||
} // end if: args.length < 3
|
||||
else {
|
||||
String flag = args[0];
|
||||
String infile = args[1];
|
||||
String outfile = args[2];
|
||||
if( flag.equals( "-e" ) ){
|
||||
Base64.encodeFileToFile( infile, outfile );
|
||||
} // end if: encode
|
||||
else if( flag.equals( "-d" ) ) {
|
||||
Base64.decodeFileToFile( infile, outfile );
|
||||
} // end else if: decode
|
||||
else {
|
||||
usage( "Unknown flag: " + flag );
|
||||
} // end else
|
||||
} // end else
|
||||
} // end main
|
||||
|
||||
/**
|
||||
* Prints command line usage.
|
||||
*
|
||||
|
|
|
@ -16,20 +16,18 @@ package org.jivesoftware.smack.util;
|
|||
|
||||
|
||||
/**
|
||||
* A Base 64 encoding implementation.
|
||||
* @author Florian Schmaus
|
||||
*/
|
||||
public class Base64Encoder implements StringEncoder {
|
||||
|
||||
private static Base64Encoder instance;
|
||||
private static Base64Encoder instance = new Base64Encoder();
|
||||
|
||||
private Base64Encoder() {
|
||||
// Use getInstance()
|
||||
}
|
||||
|
||||
public static Base64Encoder getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new Base64Encoder();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
|
48
source/org/jivesoftware/smack/util/Base64FileUrlEncoder.java
Normal file
48
source/org/jivesoftware/smack/util/Base64FileUrlEncoder.java
Normal file
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jivesoftware.smack.util;
|
||||
|
||||
|
||||
/**
|
||||
* A Base 64 encoding implementation that generates filename and Url safe encodings.
|
||||
*
|
||||
* <p>
|
||||
* Note: This does NOT produce standard Base 64 encodings, but a variant as defined in
|
||||
* Section 4 of RFC3548:
|
||||
* <a href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org/rfcs/rfc3548.html</a>.
|
||||
*
|
||||
* @author Robin Collier
|
||||
*/
|
||||
public class Base64FileUrlEncoder implements StringEncoder {
|
||||
|
||||
private static Base64FileUrlEncoder instance = new Base64FileUrlEncoder();
|
||||
|
||||
private Base64FileUrlEncoder() {
|
||||
// Use getInstance()
|
||||
}
|
||||
|
||||
public static Base64FileUrlEncoder getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public String encode(String s) {
|
||||
return Base64.encodeBytes(s.getBytes(), Base64.URL_SAFE);
|
||||
}
|
||||
|
||||
public String decode(String s) {
|
||||
return new String(Base64.decode(s, Base64.URL_SAFE));
|
||||
}
|
||||
|
||||
}
|
|
@ -81,7 +81,12 @@ public class DNSUtil {
|
|||
* @return List of HostAddress, which encompasses the hostname and port that the
|
||||
* XMPP server can be reached at for the specified domain.
|
||||
*/
|
||||
public static List<HostAddress> resolveXMPPDomain(String domain) {
|
||||
public static List<HostAddress> resolveXMPPDomain(final String domain) {
|
||||
if (dnsResolver == null) {
|
||||
List<HostAddress> addresses = new ArrayList<HostAddress>(1);
|
||||
addresses.add(new HostAddress(domain, 5222));
|
||||
return addresses;
|
||||
}
|
||||
return resolveDomain(domain, 'c');
|
||||
}
|
||||
|
||||
|
@ -102,7 +107,12 @@ public class DNSUtil {
|
|||
* @return List of HostAddress, which encompasses the hostname and port that the
|
||||
* XMPP server can be reached at for the specified domain.
|
||||
*/
|
||||
public static List<HostAddress> resolveXMPPServerDomain(String domain) {
|
||||
public static List<HostAddress> resolveXMPPServerDomain(final String domain) {
|
||||
if (dnsResolver == null) {
|
||||
List<HostAddress> addresses = new ArrayList<HostAddress>(1);
|
||||
addresses.add(new HostAddress(domain, 5269));
|
||||
return addresses;
|
||||
}
|
||||
return resolveDomain(domain, 's');
|
||||
}
|
||||
|
||||
|
@ -117,9 +127,6 @@ public class DNSUtil {
|
|||
}
|
||||
}
|
||||
|
||||
if (dnsResolver == null)
|
||||
throw new IllegalStateException("No DNS resolver active.");
|
||||
|
||||
List<HostAddress> addresses = new ArrayList<HostAddress>();
|
||||
|
||||
// Step one: Do SRV lookups
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
* Copyright 2003-2007 Jive Software.
|
||||
* Copyright 2013 Robin Collier.
|
||||
*
|
||||
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -17,48 +17,49 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jivesoftware.smack.util;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
/**
|
||||
* Defines the various date and time profiles used in XMPP along with their associated formats.
|
||||
* @author Robin Collier
|
||||
*
|
||||
*/
|
||||
public enum DateFormatType
|
||||
{
|
||||
XEP_0082_DATE_PROFILE("yyyy-MM-dd"),
|
||||
XEP_0082_DATETIME_PROFILE("yyyy-MM-dd'T'HH:mm:ssZ"),
|
||||
XEP_0082_DATETIME_MILLIS_PROFILE("yyyy-MM-dd'T'HH:mm:ss.SSSZ"),
|
||||
XEP_0082_TIME_PROFILE("hh:mm:ss"),
|
||||
XEP_0082_TIME_ZONE_PROFILE("hh:mm:ssZ"),
|
||||
XEP_0082_TIME_MILLIS_PROFILE("hh:mm:ss.SSS"),
|
||||
XEP_0082_TIME_MILLIS_ZONE_PROFILE("hh:mm:ss.SSSZ"),
|
||||
XEP_0091_DATETIME("yyyyMMdd'T'HH:mm:ss");
|
||||
|
||||
private String formatString;
|
||||
|
||||
private DateFormatType(String dateFormat)
|
||||
{
|
||||
formatString = dateFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the format string as defined in either XEP-0082 or XEP-0091.
|
||||
* @return The defined string format for the date.
|
||||
*/
|
||||
public String getFormatString()
|
||||
{
|
||||
return formatString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link SimpleDateFormat} object with the format defined by {@link #getFormatString()}.
|
||||
* @return A new date formatter.
|
||||
*/
|
||||
public SimpleDateFormat createFormatter()
|
||||
{
|
||||
return new SimpleDateFormat(getFormatString());
|
||||
}
|
||||
}
|
||||
package org.jivesoftware.smack.util;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
/**
|
||||
* Defines the various date and time profiles used in XMPP along with their associated formats.
|
||||
*
|
||||
* @author Robin Collier
|
||||
*
|
||||
*/
|
||||
public enum DateFormatType {
|
||||
// @formatter:off
|
||||
XEP_0082_DATE_PROFILE("yyyy-MM-dd"),
|
||||
XEP_0082_DATETIME_PROFILE("yyyy-MM-dd'T'HH:mm:ssZ"),
|
||||
XEP_0082_DATETIME_MILLIS_PROFILE("yyyy-MM-dd'T'HH:mm:ss.SSSZ"),
|
||||
XEP_0082_TIME_PROFILE("hh:mm:ss"),
|
||||
XEP_0082_TIME_ZONE_PROFILE("hh:mm:ssZ"),
|
||||
XEP_0082_TIME_MILLIS_PROFILE("hh:mm:ss.SSS"),
|
||||
XEP_0082_TIME_MILLIS_ZONE_PROFILE("hh:mm:ss.SSSZ"),
|
||||
XEP_0091_DATETIME("yyyyMMdd'T'HH:mm:ss");
|
||||
// @formatter:on
|
||||
|
||||
private String formatString;
|
||||
|
||||
private DateFormatType(String dateFormat) {
|
||||
formatString = dateFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the format string as defined in either XEP-0082 or XEP-0091.
|
||||
*
|
||||
* @return The defined string format for the date.
|
||||
*/
|
||||
public String getFormatString() {
|
||||
return formatString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link SimpleDateFormat} object with the format defined by {@link #getFormatString()}.
|
||||
*
|
||||
* @return A new date formatter.
|
||||
*/
|
||||
public SimpleDateFormat createFormatter() {
|
||||
return new SimpleDateFormat(getFormatString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
*/
|
||||
package org.jivesoftware.smack.util;
|
||||
|
||||
// TODO move StringEncoder, Base64Encoder and Base32Encoder to smack.util
|
||||
|
||||
public interface StringEncoder {
|
||||
/**
|
||||
* Encodes an string to another representation
|
||||
|
@ -26,7 +24,7 @@ public interface StringEncoder {
|
|||
* @param string
|
||||
* @return
|
||||
*/
|
||||
public String encode(String string);
|
||||
String encode(String string);
|
||||
|
||||
/**
|
||||
* Decodes an string back to it's initial representation
|
||||
|
@ -34,5 +32,5 @@ public interface StringEncoder {
|
|||
* @param string
|
||||
* @return
|
||||
*/
|
||||
public String decode(String string);
|
||||
String decode(String string);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ package org.jivesoftware.smack.util;
|
|||
import org.jivesoftware.smack.PacketCollector;
|
||||
import org.jivesoftware.smack.SmackConfiguration;
|
||||
import org.jivesoftware.smack.Connection;
|
||||
import org.jivesoftware.smack.SmackError;
|
||||
import org.jivesoftware.smack.XMPPException;
|
||||
import org.jivesoftware.smack.filter.PacketFilter;
|
||||
import org.jivesoftware.smack.filter.PacketIDFilter;
|
||||
|
@ -47,7 +48,7 @@ final public class SyncPacketSend
|
|||
response.cancel();
|
||||
|
||||
if (result == null) {
|
||||
throw new XMPPException("No response from server.");
|
||||
throw new XMPPException(SmackError.NO_RESPONSE_FROM_SERVER);
|
||||
}
|
||||
else if (result.getError() != null) {
|
||||
throw new XMPPException(result.getError());
|
||||
|
|
|
@ -22,18 +22,19 @@ import org.xbill.DNS.Lookup;
|
|||
import org.xbill.DNS.Record;
|
||||
import org.xbill.DNS.Type;
|
||||
|
||||
public class DNSJavaResolver extends DNSResolver {
|
||||
/**
|
||||
* This implementation uses the <a href="http://www.dnsjava.org/">dnsjava</a> implementation for resolving DNS addresses.
|
||||
*
|
||||
*/
|
||||
public class DNSJavaResolver implements DNSResolver {
|
||||
|
||||
private static DNSJavaResolver instance;
|
||||
private static DNSJavaResolver instance = new DNSJavaResolver();
|
||||
|
||||
private DNSJavaResolver() {
|
||||
|
||||
}
|
||||
|
||||
public static DNSResolver getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new DNSJavaResolver();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,8 +17,17 @@ package org.jivesoftware.smack.util.dns;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class DNSResolver {
|
||||
/**
|
||||
* Implementations of this interface define a class that is capable of resolving DNS addresses.
|
||||
*
|
||||
*/
|
||||
public interface DNSResolver {
|
||||
|
||||
public abstract List<SRVRecord> lookupSRVRecords(String name);
|
||||
/**
|
||||
* Gets a list of service records for the specified service.
|
||||
* @param name The symbolic name of the service.
|
||||
* @return The list of SRV records mapped to the service name.
|
||||
*/
|
||||
List<SRVRecord> lookupSRVRecords(String name);
|
||||
|
||||
}
|
||||
|
|
|
@ -23,10 +23,10 @@ public class HostAddress {
|
|||
/**
|
||||
* Creates a new HostAddress with the given FQDN. The port will be set to the default XMPP client port: 5222
|
||||
*
|
||||
* @param fqdn
|
||||
* @throws IllegalArgumentException
|
||||
* @param fqdn Fully qualified domain name.
|
||||
* @throws IllegalArgumentException If the fqdn is null.
|
||||
*/
|
||||
public HostAddress(String fqdn) throws IllegalArgumentException {
|
||||
public HostAddress(String fqdn) {
|
||||
if (fqdn == null)
|
||||
throw new IllegalArgumentException("FQDN is null");
|
||||
if (fqdn.charAt(fqdn.length() - 1) == '.') {
|
||||
|
@ -39,7 +39,14 @@ public class HostAddress {
|
|||
this.port = 5222;
|
||||
}
|
||||
|
||||
public HostAddress(String fqdn, int port) throws IllegalArgumentException {
|
||||
/**
|
||||
* Creates a new HostAddress with the given FQDN. The port will be set to the default XMPP client port: 5222
|
||||
*
|
||||
* @param fqdn Fully qualified domain name.
|
||||
* @param port The port to connect on.
|
||||
* @throws IllegalArgumentException If the fqdn is null or port is out of valid range (0 - 65535).
|
||||
*/
|
||||
public HostAddress(String fqdn, int port) {
|
||||
this(fqdn);
|
||||
if (port < 0 || port > 65535)
|
||||
throw new IllegalArgumentException(
|
||||
|
@ -60,10 +67,12 @@ public class HostAddress {
|
|||
this.exception = e;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return fqdn + ":" + port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
|
@ -80,6 +89,13 @@ public class HostAddress {
|
|||
return port == address.port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 1;
|
||||
result = 37 * result + fqdn.hashCode();
|
||||
return result * 37 + port;
|
||||
}
|
||||
|
||||
public String getErrorMessage() {
|
||||
String error;
|
||||
if (exception == null) {
|
||||
|
|
|
@ -28,12 +28,12 @@ import javax.naming.directory.InitialDirContext;
|
|||
import org.jivesoftware.smack.util.DNSUtil;
|
||||
|
||||
/**
|
||||
* A DNS resolver (mostly for SRV records), which makes use of the API provided in the javax.* namepsace.
|
||||
* A DNS resolver (mostly for SRV records), which makes use of the API provided in the javax.* namespace.
|
||||
*
|
||||
* @author Florian Schmaus
|
||||
*
|
||||
*/
|
||||
public class JavaxResolver extends DNSResolver {
|
||||
public class JavaxResolver implements DNSResolver {
|
||||
|
||||
private static JavaxResolver instance;
|
||||
private static DirContext dirContext;
|
||||
|
@ -48,14 +48,14 @@ public class JavaxResolver extends DNSResolver {
|
|||
}
|
||||
|
||||
// Try to set this DNS resolver as primary one
|
||||
DNSUtil.setDNSResolver(maybeGetInstance());
|
||||
DNSUtil.setDNSResolver(getInstance());
|
||||
}
|
||||
|
||||
private JavaxResolver() {
|
||||
|
||||
}
|
||||
|
||||
public static DNSResolver maybeGetInstance() {
|
||||
public static DNSResolver getInstance() {
|
||||
if (instance == null && isSupported()) {
|
||||
instance = new JavaxResolver();
|
||||
}
|
||||
|
|
|
@ -29,13 +29,13 @@ public class SRVRecord extends HostAddress implements Comparable<SRVRecord> {
|
|||
/**
|
||||
* Create a new SRVRecord
|
||||
*
|
||||
* @param fqdn
|
||||
* @param port
|
||||
* @param priority
|
||||
* @param weight
|
||||
* @throws IllegalArgumentException
|
||||
* @param fqdn Fully qualified domain name
|
||||
* @param port The connection port
|
||||
* @param priority Priority of the target host
|
||||
* @param weight Relative weight for records with same priority
|
||||
* @throws IllegalArgumentException fqdn is null or any other field is not in valid range (0-65535).
|
||||
*/
|
||||
public SRVRecord(String fqdn, int port, int priority, int weight) throws IllegalArgumentException {
|
||||
public SRVRecord(String fqdn, int port, int priority, int weight) {
|
||||
super(fqdn, port);
|
||||
if (weight < 0 || weight > 65535)
|
||||
throw new IllegalArgumentException(
|
||||
|
@ -60,6 +60,7 @@ public class SRVRecord extends HostAddress implements Comparable<SRVRecord> {
|
|||
return weight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(SRVRecord other) {
|
||||
// According to RFC2782,
|
||||
// "[a] client MUST attempt to contact the target host with the lowest-numbered priority it can reach".
|
||||
|
@ -71,6 +72,7 @@ public class SRVRecord extends HostAddress implements Comparable<SRVRecord> {
|
|||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + " prio:" + priority + ":w:" + weight;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue