summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/com/isode/stroke/client/ClientOptions.java3
-rw-r--r--src/com/isode/stroke/client/CoreClient.java26
-rw-r--r--src/com/isode/stroke/network/CachingDomainNameResolver.java38
-rw-r--r--src/com/isode/stroke/network/ChainedConnector.java119
-rw-r--r--src/com/isode/stroke/network/ConnectionServer.java32
-rw-r--r--src/com/isode/stroke/network/ConnectionServerFactory.java24
-rw-r--r--src/com/isode/stroke/network/Connector.java27
-rw-r--r--src/com/isode/stroke/network/DomainNameResolver.java17
-rw-r--r--src/com/isode/stroke/network/DomainNameServiceQuery.java2
-rw-r--r--src/com/isode/stroke/network/DummyConnection.java65
-rw-r--r--src/com/isode/stroke/network/DummyConnectionFactory.java27
-rw-r--r--src/com/isode/stroke/network/DummyConnectionServer.java44
-rw-r--r--src/com/isode/stroke/network/DummyConnectionServerFactory.java31
-rw-r--r--src/com/isode/stroke/network/DummyTimerFactory.java69
-rw-r--r--src/com/isode/stroke/network/EnvironmentProxyProvider.java58
-rw-r--r--src/com/isode/stroke/network/FakeConnection.java108
-rw-r--r--src/com/isode/stroke/network/HTTPConnectProxiedConnection.java148
-rw-r--r--src/com/isode/stroke/network/HTTPConnectProxiedConnectionFactory.java67
-rw-r--r--src/com/isode/stroke/network/HTTPTrafficFilter.java25
-rw-r--r--src/com/isode/stroke/network/HostAddress.java36
-rw-r--r--src/com/isode/stroke/network/HostAddressPort.java7
-rw-r--r--src/com/isode/stroke/network/JavaNetworkFactories.java23
-rw-r--r--src/com/isode/stroke/network/JavaProxyProvider.java39
-rw-r--r--src/com/isode/stroke/network/NATPortMapping.java61
-rw-r--r--src/com/isode/stroke/network/NATTraversalForwardPortRequest.java22
-rw-r--r--src/com/isode/stroke/network/NATTraversalGetPublicIPRequest.java27
-rw-r--r--src/com/isode/stroke/network/NATTraversalInterface.java21
-rw-r--r--src/com/isode/stroke/network/NATTraversalRemovePortForwardingRequest.java39
-rw-r--r--src/com/isode/stroke/network/NATTraverser.java21
-rw-r--r--src/com/isode/stroke/network/NetworkEnvironment.java38
-rw-r--r--src/com/isode/stroke/network/NetworkFactories.java6
-rw-r--r--src/com/isode/stroke/network/NetworkInterface.java47
-rw-r--r--src/com/isode/stroke/network/NullNATTraversalInterface.java31
-rw-r--r--src/com/isode/stroke/network/NullNATTraverser.java99
-rw-r--r--src/com/isode/stroke/network/NullProxyProvider.java23
-rw-r--r--src/com/isode/stroke/network/PlatformDomainNameQuery.java29
-rw-r--r--src/com/isode/stroke/network/PlatformDomainNameResolver.java17
-rw-r--r--src/com/isode/stroke/network/ProxiedConnection.java150
-rw-r--r--src/com/isode/stroke/network/ProxyProvider.java23
-rw-r--r--src/com/isode/stroke/network/SOCKS5ProxiedConnection.java133
-rw-r--r--src/com/isode/stroke/network/SOCKS5ProxiedConnectionFactory.java38
-rw-r--r--src/com/isode/stroke/network/StaticDomainNameResolver.java187
-rw-r--r--src/com/isode/stroke/network/TLSConnection.java155
-rw-r--r--src/com/isode/stroke/network/TLSConnectionFactory.java36
-rw-r--r--src/com/isode/stroke/network/Timer.java16
-rw-r--r--test/com/isode/stroke/component/ComponentConnectorTest.java228
-rw-r--r--test/com/isode/stroke/network/ChainedConnectorTest.java200
-rw-r--r--test/com/isode/stroke/network/ConnectorTest.java402
-rw-r--r--test/com/isode/stroke/network/HostAddressTest.java71
49 files changed, 3106 insertions, 49 deletions
diff --git a/src/com/isode/stroke/client/ClientOptions.java b/src/com/isode/stroke/client/ClientOptions.java
index c2d9e3f..723b12e 100644
--- a/src/com/isode/stroke/client/ClientOptions.java
+++ b/src/com/isode/stroke/client/ClientOptions.java
@@ -12,6 +12,7 @@ package com.isode.stroke.client;
import com.isode.stroke.tls.TLSOptions;
import com.isode.stroke.base.URL;
import com.isode.stroke.base.SafeByteArray;
+import com.isode.stroke.network.HTTPTrafficFilter;
/**
* Options for a client connection
@@ -119,7 +120,7 @@ public class ClientOptions {
* This can be initialized with a custom HTTPTrafficFilter, which allows HTTP CONNECT
* proxy initialization to be customized.
*/
- //public HTTPTrafficFilter httpTrafficFilter; //TOPORT NETWORK
+ public HTTPTrafficFilter httpTrafficFilter;
/**
* Options passed to the TLS stack
diff --git a/src/com/isode/stroke/client/CoreClient.java b/src/com/isode/stroke/client/CoreClient.java
index 2fc10ae..010a535 100644
--- a/src/com/isode/stroke/client/CoreClient.java
+++ b/src/com/isode/stroke/client/CoreClient.java
@@ -18,6 +18,9 @@ import com.isode.stroke.network.ConnectionFactory;
import com.isode.stroke.network.Connector;
import com.isode.stroke.network.DomainNameResolveError;
import com.isode.stroke.network.NetworkFactories;
+import com.isode.stroke.network.HostAddressPort;
+import com.isode.stroke.network.SOCKS5ProxiedConnectionFactory;
+import com.isode.stroke.network.HTTPConnectProxiedConnectionFactory;
import com.isode.stroke.parser.payloadparsers.FullPayloadParserFactoryCollection;
import com.isode.stroke.queries.IQRouter;
import com.isode.stroke.serializer.payloadserializers.FullPayloadSerializerCollection;
@@ -201,17 +204,16 @@ public class CoreClient {
assert (connector_ == null);
options = o;
- //TO PORT
- /*// Determine connection types to use
+ // Determine connection types to use
assert(proxyConnectionFactories.isEmpty());
boolean useDirectConnection = true;
HostAddressPort systemSOCKS5Proxy = networkFactories.getProxyProvider().getSOCKS5Proxy();
HostAddressPort systemHTTPConnectProxy = networkFactories.getProxyProvider().getHTTPConnectProxy();
switch (o.proxyType) {
- case ClientOptions.ProxyType.NoProxy:
+ case NoProxy:
logger_.fine(" without a proxy\n");
break;
- case ClientOptions.ProxyType.SystemConfiguredProxy:
+ case SystemConfiguredProxy:
logger_.fine(" with a system configured proxy\n");
if (systemSOCKS5Proxy.isValid()) {
logger_.fine("Found SOCK5 Proxy: " + systemSOCKS5Proxy.getAddress().toString() + ":" + systemSOCKS5Proxy.getPort() + "\n");
@@ -222,20 +224,20 @@ public class CoreClient {
proxyConnectionFactories.add(new HTTPConnectProxiedConnectionFactory(networkFactories.getDomainNameResolver(), networkFactories.getConnectionFactory(), networkFactories.getTimerFactory(), systemHTTPConnectProxy.getAddress().toString(), systemHTTPConnectProxy.getPort()));
}
break;
- case ClientOptions.ProxyType.SOCKS5Proxy: {
+ case SOCKS5Proxy: {
logger_.fine(" with manual configured SOCKS5 proxy\n");
- String proxyHostname = o.manualProxyHostname.empty() ? systemSOCKS5Proxy.getAddress().toString() : o.manualProxyHostname;
+ String proxyHostname = o.manualProxyHostname.isEmpty() ? systemSOCKS5Proxy.getAddress().toString() : o.manualProxyHostname;
int proxyPort = o.manualProxyPort == -1 ? systemSOCKS5Proxy.getPort() : o.manualProxyPort;
logger_.fine("Proxy: " + proxyHostname + ":" + proxyPort + "\n");
proxyConnectionFactories.add(new SOCKS5ProxiedConnectionFactory(networkFactories.getDomainNameResolver(), networkFactories.getConnectionFactory(), networkFactories.getTimerFactory(), proxyHostname, proxyPort));
useDirectConnection = false;
break;
}
- case ClientOptions.ProxyType.HTTPConnectProxy: {
+ case HTTPConnectProxy: {
logger_.fine(" with manual configured HTTPConnect proxy\n");
- std::string proxyHostname = o.manualProxyHostname.empty() ? systemHTTPConnectProxy.getAddress().toString() : o.manualProxyHostname;
+ String proxyHostname = o.manualProxyHostname.isEmpty() ? systemHTTPConnectProxy.getAddress().toString() : o.manualProxyHostname;
int proxyPort = o.manualProxyPort == -1 ? systemHTTPConnectProxy.getPort() : o.manualProxyPort;
- logger_.fine("Proxy: " + proxyHostname + ":" << proxyPort + "\n");
+ logger_.fine("Proxy: " + proxyHostname + ":" + proxyPort + "\n");
proxyConnectionFactories.add(new HTTPConnectProxiedConnectionFactory(networkFactories.getDomainNameResolver(), networkFactories.getConnectionFactory(), networkFactories.getTimerFactory(), proxyHostname, proxyPort, o.httpTrafficFilter));
useDirectConnection = false;
break;
@@ -244,7 +246,7 @@ public class CoreClient {
Vector<ConnectionFactory> connectionFactories = new Vector<ConnectionFactory>(proxyConnectionFactories);
if (useDirectConnection) {
connectionFactories.add(networkFactories.getConnectionFactory());
- }*/
+ }
String host = (o.manualHostname == null || o.manualHostname.isEmpty()) ? jid_.getDomain() : o.manualHostname;
int port = o.manualPort;
@@ -292,9 +294,7 @@ public class CoreClient {
}
private void bindSessionToStream() {
- //TO PORT
- //session_ = ClientSession::create(jid_, sessionStream_, networkFactories.getIDNConverter(), networkFactories.getCryptoProvider());
- session_ = ClientSession.create(jid_, sessionStream_, new ICUConverter(), new JavaCryptoProvider());
+ session_ = ClientSession.create(jid_, sessionStream_, networkFactories.getIDNConverter(), networkFactories.getCryptoProvider());
session_.setCertificateTrustChecker(certificateTrustChecker);
session_.setUseStreamCompression(options.useStreamCompression);
session_.setAllowPLAINOverNonTLS(options.allowPLAINWithoutTLS);
diff --git a/src/com/isode/stroke/network/CachingDomainNameResolver.java b/src/com/isode/stroke/network/CachingDomainNameResolver.java
new file mode 100644
index 0000000..166de7a
--- /dev/null
+++ b/src/com/isode/stroke/network/CachingDomainNameResolver.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2012-2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+import com.isode.stroke.network.DomainNameResolver;
+import com.isode.stroke.network.StaticDomainNameResolver;
+import com.isode.stroke.eventloop.EventLoop;
+
+/*
+ * FIXME: Does not do any caching yet.
+ */
+public class CachingDomainNameResolver extends DomainNameResolver {
+
+ private DomainNameResolver realResolver;
+
+ public CachingDomainNameResolver(DomainNameResolver realResolver, EventLoop eventLoop) {
+ this.realResolver = realResolver;
+ }
+
+ public DomainNameServiceQuery createServiceQuery(final String serviceLookupPrefix, final String domain) {
+ //TODO: Cache
+ return realResolver.createServiceQuery(serviceLookupPrefix, domain);
+ }
+
+ public DomainNameAddressQuery createAddressQuery(final String name) {
+ //TODO: Cache
+ return realResolver.createAddressQuery(name);
+ }
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/ChainedConnector.java b/src/com/isode/stroke/network/ChainedConnector.java
new file mode 100644
index 0000000..b61133c
--- /dev/null
+++ b/src/com/isode/stroke/network/ChainedConnector.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2011-2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+import java.util.Vector;
+import java.util.logging.Logger;
+import com.isode.stroke.signals.Signal2;
+import com.isode.stroke.signals.Slot2;
+import com.isode.stroke.signals.SignalConnection;
+import com.isode.stroke.network.Connection;
+
+public class ChainedConnector {
+
+ private String hostname = "";
+ private int port;
+ private String serviceLookupPrefix;
+ private DomainNameResolver resolver;
+ private Vector<ConnectionFactory> connectionFactories = new Vector<ConnectionFactory>();
+ private TimerFactory timerFactory;
+ private int timeoutMilliseconds;
+ private Vector<ConnectionFactory> connectionFactoryQueue = new Vector<ConnectionFactory>();
+ private Connector currentConnector;
+ private com.isode.stroke.base.Error lastError;
+ private Logger logger_ = Logger.getLogger(this.getClass().getName());
+ private SignalConnection onConnectFinishedConnection;
+
+ public ChainedConnector(final String hostname, int port, final String serviceLookupPrefix, DomainNameResolver resolver, final Vector<ConnectionFactory> connectionFactories, TimerFactory timer) {
+ this.hostname = hostname;
+ this.port = port;
+ this.serviceLookupPrefix = serviceLookupPrefix;
+ this.resolver = resolver;
+ this.connectionFactories = connectionFactories;
+ this.timerFactory = timer;
+ this.timeoutMilliseconds = 0;
+ }
+
+ protected void finalize() throws Throwable {
+ try {
+ if (currentConnector != null) {
+ onConnectFinishedConnection.disconnect();
+ currentConnector.stop();
+ currentConnector = null;
+ }
+ }
+ finally {
+ super.finalize();
+ }
+ }
+
+ public void setTimeoutMilliseconds(int milliseconds) {
+ timeoutMilliseconds = milliseconds;
+ }
+
+ public void start() {
+ logger_.fine("Starting queued connector for " + hostname + "\n");
+
+ connectionFactoryQueue = new Vector<ConnectionFactory>(connectionFactories);
+ tryNextConnectionFactory();
+ }
+
+ public void stop() {
+ if (currentConnector != null) {
+ onConnectFinishedConnection.disconnect();
+ currentConnector.stop();
+ currentConnector = null;
+ }
+ finish((Connection)null, (com.isode.stroke.base.Error)null);
+ }
+
+ public final Signal2<Connection, com.isode.stroke.base.Error> onConnectFinished = new Signal2<Connection, com.isode.stroke.base.Error>();
+
+ private void finish(Connection connection, com.isode.stroke.base.Error error) {
+ onConnectFinished.emit(connection, error);
+ }
+
+ private void tryNextConnectionFactory() {
+ assert(currentConnector == null);
+ if (connectionFactoryQueue.isEmpty()) {
+ logger_.fine("No more connection factories\n");
+ finish((Connection)null, lastError);
+ }
+ else {
+ ConnectionFactory connectionFactory = connectionFactoryQueue.firstElement();
+ logger_.fine("Trying next connection factory: " + connectionFactory + "\n");
+ connectionFactoryQueue.remove(connectionFactoryQueue.firstElement());
+ currentConnector = Connector.create(hostname, port, serviceLookupPrefix, resolver, connectionFactory, timerFactory);
+ currentConnector.setTimeoutMilliseconds(timeoutMilliseconds);
+ onConnectFinishedConnection = currentConnector.onConnectFinished.connect(new Slot2<Connection, com.isode.stroke.base.Error>() {
+ @Override
+ public void call(Connection connection, com.isode.stroke.base.Error error) {
+ handleConnectorFinished(connection, error);
+ }
+ });
+ currentConnector.start();
+ }
+ }
+
+ private void handleConnectorFinished(Connection connection, com.isode.stroke.base.Error error) {
+ logger_.fine("Connector finished\n");
+ onConnectFinishedConnection.disconnect();
+ lastError = error;
+ currentConnector = null;
+ if (connection != null) {
+ finish(connection, error);
+ }
+ else {
+ tryNextConnectionFactory();
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/ConnectionServer.java b/src/com/isode/stroke/network/ConnectionServer.java
new file mode 100644
index 0000000..002e208
--- /dev/null
+++ b/src/com/isode/stroke/network/ConnectionServer.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2010 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+import com.isode.stroke.signals.Signal1;
+
+public abstract class ConnectionServer {
+
+ public enum Error {
+ Conflict,
+ UnknownError
+ };
+
+ public abstract HostAddressPort getAddressPort();
+
+ public abstract Error tryStart(); // FIXME: This should become the new start
+
+ public abstract void start();
+
+ public abstract void stop();
+
+ public final Signal1<Connection> onNewConnection = new Signal1<Connection>();
+}
diff --git a/src/com/isode/stroke/network/ConnectionServerFactory.java b/src/com/isode/stroke/network/ConnectionServerFactory.java
new file mode 100644
index 0000000..a23291b
--- /dev/null
+++ b/src/com/isode/stroke/network/ConnectionServerFactory.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2011 Jan Kaluza
+ * Licensed under the Simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+/*
+ * Copyright (c) 2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+public interface ConnectionServerFactory {
+
+ public ConnectionServer createConnectionServer(int port);
+
+ public ConnectionServer createConnectionServer(final HostAddress hostAddress, int port);
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/Connector.java b/src/com/isode/stroke/network/Connector.java
index 13a2bc3..6033a89 100644
--- a/src/com/isode/stroke/network/Connector.java
+++ b/src/com/isode/stroke/network/Connector.java
@@ -32,7 +32,6 @@ public class Connector {
assert serviceQuery == null;
assert timer == null;
queriedAllServices = false;
- serviceQueryResults = new ArrayList<Result>();
if (timeoutMilliseconds > 0) {
timer = timerFactory.createTimer(timeoutMilliseconds);
@@ -41,10 +40,9 @@ public class Connector {
handleTimeout();
}
});
- timer.start();
}
if (serviceLookupPrefix != null) {
- serviceQuery = resolver.createServiceQuery(serviceLookupPrefix + hostname);
+ serviceQuery = resolver.createServiceQuery(serviceLookupPrefix, hostname);
serviceQuery.onResult.connect(new Slot1<Collection<DomainNameServiceQuery.Result>>() {
public void call(Collection<Result> p1) {
handleServiceQueryResult(p1);
@@ -52,6 +50,12 @@ public class Connector {
});
serviceQuery.run();
}
+ else if (new HostAddress(hostname).isValid()) {
+ // hostname is already a valid address; skip name lookup.
+ foundSomeDNS = true;
+ addressQueryResults.add(new HostAddress(hostname));
+ tryNextAddress();
+ }
else {
queryAddress(hostname);
}
@@ -70,6 +74,9 @@ public class Connector {
this.timerFactory = timerFactory;
this.port = port;
this.serviceLookupPrefix = serviceLookupPrefix;
+ this.timeoutMilliseconds = 0;
+ this.queriedAllServices = true;
+ this.foundSomeDNS = false;
}
private void handleServiceQueryResult(Collection<Result> result) {
@@ -161,10 +168,17 @@ public class Connector {
});
currentConnection.connect(target);
+ if (timer != null) {
+ timer.start();
+ }
}
private void handleConnectionConnectFinished(boolean error) {
//std::cout << "Connector::handleConnectionConnectFinished() " << error << std::endl;
+ if (timer != null) {
+ timer.stop();
+ timer = null;
+ }
currentConnectionConnectFinishedConnection.disconnect();
if (error) {
currentConnection = null;
@@ -206,7 +220,8 @@ public class Connector {
}
private void handleTimeout() {
- finish(null);
+ //SWIFT_LOG(debug) << "Timeout" << std::endl;
+ handleConnectionConnectFinished(true);
}
@Override
@@ -223,9 +238,9 @@ public class Connector {
private int timeoutMilliseconds = 0;
private Timer timer;
private DomainNameServiceQuery serviceQuery;
- private ArrayList<DomainNameServiceQuery.Result> serviceQueryResults;
+ private ArrayList<DomainNameServiceQuery.Result> serviceQueryResults = new ArrayList<DomainNameServiceQuery.Result>();
private DomainNameAddressQuery addressQuery;
- private ArrayList<HostAddress> addressQueryResults;
+ private ArrayList<HostAddress> addressQueryResults = new ArrayList<HostAddress>();
private boolean queriedAllServices = true;
private Connection currentConnection;
private SignalConnection currentConnectionConnectFinishedConnection;
diff --git a/src/com/isode/stroke/network/DomainNameResolver.java b/src/com/isode/stroke/network/DomainNameResolver.java
index 9c02aa3..9a99690 100644
--- a/src/com/isode/stroke/network/DomainNameResolver.java
+++ b/src/com/isode/stroke/network/DomainNameResolver.java
@@ -11,20 +11,7 @@ package com.isode.stroke.network;
public abstract class DomainNameResolver {
- public abstract DomainNameServiceQuery createServiceQuery(String name);
- public abstract DomainNameAddressQuery createAddressQuery(String name);
- protected String getNormalized(String domain) {
- return domain;
- //FIXME: port idna
-// char* output;
-// if (idna_to_ascii_8z(domain.getUTF8Data(), &output, 0) == IDNA_SUCCESS) {
-// String result(output);
-// free(output);
-// return result;
-// }
-// else {
-// return domain;
-// }
- }
+ public abstract DomainNameServiceQuery createServiceQuery(String serviceLookupPrefix, String domain);
+ public abstract DomainNameAddressQuery createAddressQuery(String name);
}
diff --git a/src/com/isode/stroke/network/DomainNameServiceQuery.java b/src/com/isode/stroke/network/DomainNameServiceQuery.java
index 0d02112..05e4d32 100644
--- a/src/com/isode/stroke/network/DomainNameServiceQuery.java
+++ b/src/com/isode/stroke/network/DomainNameServiceQuery.java
@@ -13,7 +13,7 @@ import java.util.Collection;
public abstract class DomainNameServiceQuery {
- public class Result {
+ public static class Result {
public Result() {
hostname = "";
diff --git a/src/com/isode/stroke/network/DummyConnection.java b/src/com/isode/stroke/network/DummyConnection.java
new file mode 100644
index 0000000..51018ef
--- /dev/null
+++ b/src/com/isode/stroke/network/DummyConnection.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2010 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+import com.isode.stroke.signals.Signal1;
+import com.isode.stroke.eventloop.EventOwner;
+import com.isode.stroke.eventloop.EventLoop;
+import com.isode.stroke.eventloop.Event;
+import com.isode.stroke.base.SafeByteArray;
+
+public class DummyConnection extends Connection implements EventOwner {
+
+ public DummyConnection(EventLoop eventLoop) {
+ this.eventLoop = eventLoop;
+ }
+
+ public void listen() {
+ assert(false);
+ }
+
+ public void connect(final HostAddressPort port) {
+ assert(false);
+ }
+
+ public void disconnect() {
+ //assert(false);
+ }
+
+ public void write(final SafeByteArray data) {
+ eventLoop.postEvent(new Event.Callback() {
+ @Override
+ public void run() {
+ onDataWritten.emit();
+ }
+ });
+ onDataSent.emit(data);
+ }
+
+ public void receive(final SafeByteArray data) {
+ eventLoop.postEvent(new Event.Callback() {
+ @Override
+ public void run() {
+ onDataRead.emit(data);
+ }
+ });
+ }
+
+ public HostAddressPort getLocalAddress() {
+ return localAddress;
+ }
+
+ public Signal1<SafeByteArray> onDataSent = new Signal1<SafeByteArray>();
+
+ public EventLoop eventLoop;
+ public HostAddressPort localAddress;
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/DummyConnectionFactory.java b/src/com/isode/stroke/network/DummyConnectionFactory.java
new file mode 100644
index 0000000..e8ff755
--- /dev/null
+++ b/src/com/isode/stroke/network/DummyConnectionFactory.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2011 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+import com.isode.stroke.eventloop.EventLoop;
+
+public class DummyConnectionFactory implements ConnectionFactory {
+
+ private EventLoop eventLoop;
+
+ public DummyConnectionFactory(EventLoop eventLoop) {
+ this.eventLoop = eventLoop;
+ }
+
+ public Connection createConnection() {
+ return new DummyConnection(eventLoop);
+ }
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/DummyConnectionServer.java b/src/com/isode/stroke/network/DummyConnectionServer.java
new file mode 100644
index 0000000..7cfb27c
--- /dev/null
+++ b/src/com/isode/stroke/network/DummyConnectionServer.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2010-2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+import com.isode.stroke.eventloop.EventOwner;
+import com.isode.stroke.eventloop.EventLoop;
+
+public class DummyConnectionServer extends ConnectionServer implements EventOwner {
+
+ private HostAddressPort localAddressPort;
+
+ public DummyConnectionServer(EventLoop eventLoop, int port) {
+ this.localAddressPort = new HostAddressPort(new HostAddress(), port);
+ }
+
+ public DummyConnectionServer(EventLoop eventLoop, final HostAddress hostAddress, int port) {
+ this.localAddressPort = new HostAddressPort(hostAddress, port);
+ }
+
+ public HostAddressPort getAddressPort() {
+ return localAddressPort;
+ }
+
+ public Error tryStart() {
+ return null;
+ }
+
+ public void start() {
+
+ }
+
+ public void stop() {
+
+ }
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/DummyConnectionServerFactory.java b/src/com/isode/stroke/network/DummyConnectionServerFactory.java
new file mode 100644
index 0000000..8d5c6fe
--- /dev/null
+++ b/src/com/isode/stroke/network/DummyConnectionServerFactory.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2014 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+import com.isode.stroke.eventloop.EventLoop;
+
+public class DummyConnectionServerFactory implements ConnectionServerFactory {
+
+ private EventLoop eventLoop;
+
+ public DummyConnectionServerFactory(EventLoop eventLoop) {
+ this.eventLoop = eventLoop;
+ }
+
+ public ConnectionServer createConnectionServer(int port) {
+ return new DummyConnectionServer(eventLoop, port);
+ }
+
+ public ConnectionServer createConnectionServer(final HostAddress hostAddress, int port) {
+ return new DummyConnectionServer(eventLoop, hostAddress, port);
+ }
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/DummyTimerFactory.java b/src/com/isode/stroke/network/DummyTimerFactory.java
new file mode 100644
index 0000000..f3d083f
--- /dev/null
+++ b/src/com/isode/stroke/network/DummyTimerFactory.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2010 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+import java.util.List;
+import java.util.ArrayList;
+
+public class DummyTimerFactory implements TimerFactory {
+
+ private int currentTime;
+ private List<DummyTimer> timers = new ArrayList<DummyTimer>();
+
+ public class DummyTimer extends Timer {
+
+ public DummyTimer(long timeout, DummyTimerFactory factory) {
+ this.timeout = timeout;
+ this.factory = factory;
+ this.isRunning = false;
+ this.startTime = 0;
+ }
+
+ public void start() {
+ isRunning = true;
+ startTime = factory.currentTime;
+ }
+
+ public void stop() {
+ isRunning = false;
+ }
+
+ public long getAlarmTime() {
+ return startTime + timeout;
+ }
+
+ public long timeout;
+ public DummyTimerFactory factory;
+ public boolean isRunning;
+ public long startTime;
+ };
+
+ public DummyTimerFactory() {
+ this.currentTime = 0;
+ }
+
+ public Timer createTimer(long milliseconds) {
+ DummyTimer timer = new DummyTimer(milliseconds, this);
+ timers.add(timer);
+ return timer;
+ }
+
+ public void setTime(int time) {
+ assert(time > currentTime);
+ for(DummyTimer timer : timers) {
+ if (timer.getAlarmTime() > currentTime && timer.getAlarmTime() <= time && timer.isRunning) {
+ timer.onTick.emit();
+ }
+ }
+ currentTime = time;
+ }
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/EnvironmentProxyProvider.java b/src/com/isode/stroke/network/EnvironmentProxyProvider.java
new file mode 100644
index 0000000..b12fe98
--- /dev/null
+++ b/src/com/isode/stroke/network/EnvironmentProxyProvider.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2010-2011 Thilo Cestonaro
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+/*
+ * Copyright (c) 2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+import java.util.logging.Logger;
+
+public class EnvironmentProxyProvider implements ProxyProvider {
+
+ public EnvironmentProxyProvider() {
+ socksProxy = getFromEnv("all_proxy", "socks");
+ httpProxy = getFromEnv("http_proxy", "http");
+ logger_.fine("Environment: SOCKS5 => " + socksProxy.toString() + "; HTTP Connect => " + httpProxy.toString() + "\n");
+ }
+
+ public HostAddressPort getHTTPConnectProxy() {
+ return httpProxy;
+ }
+
+ public HostAddressPort getSOCKS5Proxy() {
+ return socksProxy;
+ }
+
+ private HostAddressPort getFromEnv(final String envVarName, String proxyProtocol) {
+ String envVar = null;
+ String address = "";
+ int port = 0;
+
+ envVar = System.getenv(envVarName);
+
+ proxyProtocol += "://";
+ address = envVar != null ? envVar : "0.0.0.0";
+ if(envVar != null && address.substring(0, proxyProtocol.length()).equals(proxyProtocol)) {
+ address = address.substring(proxyProtocol.length(), address.length());
+ port = Integer.parseInt(address.substring(address.indexOf(':') + 1, address.length()));
+ address = address.substring(0, address.indexOf(':'));
+ }
+
+ return new HostAddressPort(new HostAddress(address), port);
+ }
+
+ private HostAddressPort socksProxy;
+ private HostAddressPort httpProxy;
+ private final Logger logger_ = Logger.getLogger(this.getClass().getName());
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/FakeConnection.java b/src/com/isode/stroke/network/FakeConnection.java
new file mode 100644
index 0000000..ebcf239
--- /dev/null
+++ b/src/com/isode/stroke/network/FakeConnection.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2010-2014 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+import com.isode.stroke.eventloop.EventOwner;
+import com.isode.stroke.eventloop.EventLoop;
+import com.isode.stroke.eventloop.Event;
+import com.isode.stroke.base.SafeByteArray;
+import java.util.Vector;
+
+public class FakeConnection extends Connection {
+
+ public enum State {
+ Initial,
+ Connecting,
+ Connected,
+ Disconnected,
+ DisconnectedWithError
+ };
+
+ public FakeConnection(EventLoop eventLoop) {
+ this.eventLoop = eventLoop;
+ this.state = State.Initial;
+ this.delayConnect = false;
+ }
+
+ public void listen() {
+ assert(false);
+ }
+
+ public HostAddressPort getLocalAddress() {
+ return new HostAddressPort();
+ }
+
+ public void setError(final Error e) {
+ error = e;
+ state = State.DisconnectedWithError;
+ if (connectedTo != null) {
+ eventLoop.postEvent(new Event.Callback() {
+ @Override
+ public void run() {
+ onDisconnected.emit(error);
+ }
+ });
+ }
+ }
+
+ public void connect(final HostAddressPort address) {
+ if (delayConnect) {
+ state = State.Connecting;
+ }
+ else {
+ if (error == null) {
+ connectedTo = address;
+ state = State.Connected;
+ }
+ else {
+ state = State.DisconnectedWithError;
+ }
+ eventLoop.postEvent(new Event.Callback() {
+ @Override
+ public void run() {
+ onConnectFinished.emit(error != null ? true : false);
+ }
+ });
+ }
+ }
+
+ public void disconnect() {
+ if (error == null) {
+ state = State.Disconnected;
+ }
+ else {
+ state = State.DisconnectedWithError;
+ }
+ connectedTo = null;
+ eventLoop.postEvent(new Event.Callback() {
+ @Override
+ public void run() {
+ onDisconnected.emit(error);
+ }
+ });
+ }
+
+ public void write(final SafeByteArray data) {
+ dataWritten.add(data);
+ }
+
+ public void setDelayConnect() {
+ delayConnect = true;
+ }
+
+ public EventLoop eventLoop;
+ public HostAddressPort connectedTo;
+ public Vector<SafeByteArray> dataWritten = new Vector<SafeByteArray>();
+ public Error error;
+ public State state;
+ public boolean delayConnect;
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/HTTPConnectProxiedConnection.java b/src/com/isode/stroke/network/HTTPConnectProxiedConnection.java
new file mode 100644
index 0000000..d9a6cee
--- /dev/null
+++ b/src/com/isode/stroke/network/HTTPConnectProxiedConnection.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2010-2011 Thilo Cestonaro
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+/*
+ * Copyright (c) 2011-2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+import com.isode.stroke.base.SafeByteArray;
+import com.isode.stroke.stringcodecs.Base64;
+import java.util.Vector;
+
+public class HTTPConnectProxiedConnection extends ProxiedConnection {
+
+ private SafeByteArray authID_;
+ private SafeByteArray authPassword_;
+ private HTTPTrafficFilter trafficFilter_;
+ private StringBuffer httpResponseBuffer_ = new StringBuffer("");
+
+ public static class Pair {
+ String a;
+ String b;
+
+ public Pair(String a, String b) { this.a = a; this.b = b; }
+ }
+
+ public static HTTPConnectProxiedConnection create(DomainNameResolver resolver, ConnectionFactory connectionFactory, TimerFactory timerFactory, final String proxyHost, int proxyPort, final SafeByteArray authID, final SafeByteArray authPassword) {
+ return new HTTPConnectProxiedConnection(resolver, connectionFactory, timerFactory, proxyHost, proxyPort, authID, authPassword);
+ }
+
+ public void setHTTPTrafficFilter(HTTPTrafficFilter trafficFilter) {
+ trafficFilter_ = trafficFilter;
+ }
+
+ private HTTPConnectProxiedConnection(DomainNameResolver resolver, ConnectionFactory connectionFactory, TimerFactory timerFactory, final String proxyHost, int proxyPort, final SafeByteArray authID, final SafeByteArray authPassword) {
+ super(resolver, connectionFactory, timerFactory, proxyHost, proxyPort);
+ this.authID_ = authID;
+ this.authPassword_ = authPassword;
+ }
+
+ protected void initializeProxy() {
+ StringBuffer connect = new StringBuffer();
+ connect.append("CONNECT ").append(getServer().getAddress().toString()).append(":").append(getServer().getPort()).append(" HTTP/1.1\r\n");
+ SafeByteArray data = new SafeByteArray(connect.toString());
+ if (!authID_.isEmpty() && !authPassword_.isEmpty()) {
+ data.append(new SafeByteArray("Proxy-Authorization: Basic "));
+ SafeByteArray credentials = authID_;
+ credentials.append(new SafeByteArray(":"));
+ credentials.append(authPassword_);
+ data.append(Base64.encode(credentials));
+ data.append(new SafeByteArray("\r\n"));
+ }
+ data.append(new SafeByteArray("\r\n"));
+ //SWIFT_LOG(debug) << "HTTP Proxy send headers: " << byteArrayToString(ByteArray(data.begin(), data.end())) << std::endl;
+ write(data);
+ }
+
+ protected void handleProxyInitializeData(SafeByteArray data) {
+ String dataString = data.toString();
+ //SWIFT_LOG(debug) << data << std::endl;
+ httpResponseBuffer_.append(dataString);
+
+ String statusLine = "";
+ Vector<Pair> headerFields = new Vector<Pair>();
+
+ int headerEnd = httpResponseBuffer_.indexOf("\r\n\r\n", 0);
+ if (headerEnd == -1) {
+ if ((httpResponseBuffer_.length() > 4) && !(httpResponseBuffer_.substring(0, 4).equals("HTTP"))) {
+ setProxyInitializeFinished(false);
+ }
+ return;
+ }
+
+ parseHTTPHeader(httpResponseBuffer_.substring(0, headerEnd), statusLine, headerFields);
+
+ if (trafficFilter_ != null) {
+ Vector<Pair> newHeaderFields = trafficFilter_.filterHTTPResponseHeader(headerFields);
+ if (!newHeaderFields.isEmpty()) {
+ StringBuffer statusLines = new StringBuffer();
+ statusLines.append("CONNECT ").append(getServer().getAddress().toString()).append(":").append(getServer().getPort());
+ sendHTTPRequest(statusLines.toString(), newHeaderFields);
+ return;
+ }
+ }
+
+ String[] tmp = statusLine.split(" ");
+ if (tmp.length > 1) {
+ try {
+ int status = Integer.parseInt(tmp[1]);
+ //SWIFT_LOG(debug) << "Proxy Status: " << status << std::endl;
+ if (status / 100 == 2) { // all 2XX states are OK
+ setProxyInitializeFinished(true);
+ }
+ else {
+ //SWIFT_LOG(debug) << "HTTP Proxy returned an error: " << httpResponseBuffer_ << std::endl;
+ setProxyInitializeFinished(false);
+ }
+ }
+ catch (NumberFormatException e) {
+ //SWIFT_LOG(warning) << "Unexpected response: " << tmp[1] << std::endl;
+ setProxyInitializeFinished(false);
+ }
+ }
+ else {
+ setProxyInitializeFinished(false);
+ }
+ httpResponseBuffer_ = new StringBuffer("");
+ }
+
+ private void sendHTTPRequest(final String statusLine, final Vector<Pair> headerFields) {
+ StringBuffer request = new StringBuffer();
+
+ request.append(statusLine).append("\r\n");
+ for (final Pair field : headerFields) {
+ request.append(field.a).append(":").append(field.b).append("\r\n");
+ }
+ request.append("\r\n");
+ write(new SafeByteArray(request.toString()));
+ }
+
+ private void parseHTTPHeader(final String data, String statusLine, Vector<Pair> headerFields) {
+ StringBuffer dataStream = new StringBuffer(data);
+
+ // parse status line
+ statusLine = dataStream.toString();
+
+ // parse fields
+ String headerLine = dataStream.toString();
+ int splitIndex;
+ while (headerLine != null && !headerLine.equals("\r")) {
+ splitIndex = headerLine.indexOf(':', 0);
+ if (splitIndex != -1) {
+ headerFields.add(new Pair(headerLine.substring(0, splitIndex), headerLine.substring(splitIndex + 1)));
+ }
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/HTTPConnectProxiedConnectionFactory.java b/src/com/isode/stroke/network/HTTPConnectProxiedConnectionFactory.java
new file mode 100644
index 0000000..1f45915
--- /dev/null
+++ b/src/com/isode/stroke/network/HTTPConnectProxiedConnectionFactory.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2012-2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2010-2011 Thilo Cestonaro
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+import com.isode.stroke.base.SafeByteArray;
+
+public class HTTPConnectProxiedConnectionFactory implements ConnectionFactory {
+
+ private DomainNameResolver resolver_;
+ private ConnectionFactory connectionFactory_;
+ private TimerFactory timerFactory_;
+ private String proxyHost_;
+ private int proxyPort_;
+ private SafeByteArray authID_;
+ private SafeByteArray authPassword_;
+ private HTTPTrafficFilter httpTrafficFilter_;
+
+ public HTTPConnectProxiedConnectionFactory(DomainNameResolver resolver, ConnectionFactory connectionFactory, TimerFactory timerFactory, final String proxyHost, int proxyPort) {
+ this(resolver, connectionFactory, timerFactory, proxyHost, proxyPort, null);
+ }
+
+ public HTTPConnectProxiedConnectionFactory(DomainNameResolver resolver, ConnectionFactory connectionFactory, TimerFactory timerFactory, final String proxyHost, int proxyPort, HTTPTrafficFilter httpTrafficFilter) {
+ resolver_ = resolver;
+ connectionFactory_ = connectionFactory;
+ timerFactory_ = timerFactory;
+ proxyHost_ = proxyHost;
+ proxyPort_ = proxyPort;
+ authID_ = new SafeByteArray("");
+ authPassword_ = new SafeByteArray("");
+ httpTrafficFilter_ = httpTrafficFilter;
+ }
+
+ public HTTPConnectProxiedConnectionFactory(DomainNameResolver resolver, ConnectionFactory connectionFactory, TimerFactory timerFactory, final String proxyHost, int proxyPort, final SafeByteArray authID, final SafeByteArray authPassword) {
+ this(resolver, connectionFactory, timerFactory, proxyHost, proxyPort, authID, authPassword, null);
+ }
+
+ public HTTPConnectProxiedConnectionFactory(DomainNameResolver resolver, ConnectionFactory connectionFactory, TimerFactory timerFactory, final String proxyHost, int proxyPort, final SafeByteArray authID, final SafeByteArray authPassword, HTTPTrafficFilter httpTrafficFilter) {
+ resolver_ = resolver;
+ connectionFactory_ = connectionFactory;
+ timerFactory_ = timerFactory;
+ proxyHost_ = proxyHost;
+ proxyPort_ = proxyPort;
+ authID_ = authID;
+ authPassword_ = authPassword;
+ httpTrafficFilter_ = httpTrafficFilter;
+ }
+
+ public Connection createConnection() {
+ HTTPConnectProxiedConnection proxyConnection = HTTPConnectProxiedConnection.create(resolver_, connectionFactory_, timerFactory_, proxyHost_, proxyPort_, authID_, authPassword_);
+ proxyConnection.setHTTPTrafficFilter(httpTrafficFilter_);
+ return proxyConnection;
+ }
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/HTTPTrafficFilter.java b/src/com/isode/stroke/network/HTTPTrafficFilter.java
new file mode 100644
index 0000000..86f0659
--- /dev/null
+++ b/src/com/isode/stroke/network/HTTPTrafficFilter.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+import java.util.Vector;
+
+public interface HTTPTrafficFilter {
+
+ /**
+ * @brief This method is called by the HTTPConnectPRoxiedConnection on every incoming HTTP response.
+ * It can be used to insert additional HTTP requests into the HTTP CONNECT proxy initalization process.
+ * @return A vector of HTTP header fields to use in a new request. If an empty vector is returned,
+ * no new request will be send and the normal proxy logic continues.
+ */
+ public Vector<HTTPConnectProxiedConnection.Pair> filterHTTPResponseHeader(final Vector<HTTPConnectProxiedConnection.Pair> responseHeader);
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/HostAddress.java b/src/com/isode/stroke/network/HostAddress.java
index c1b3600..a8eea1b 100644
--- a/src/com/isode/stroke/network/HostAddress.java
+++ b/src/com/isode/stroke/network/HostAddress.java
@@ -10,6 +10,7 @@
package com.isode.stroke.network;
import java.net.InetAddress;
+import java.net.UnknownHostException;
public class HostAddress {
@@ -17,12 +18,39 @@ public class HostAddress {
address_ = null;
}
+ public HostAddress(String address) {
+ try {
+ address_ = InetAddress.getByName(address);
+ }
+ catch (UnknownHostException e) {
+ address_ = null;
+ }
+ }
+
public HostAddress(InetAddress address) {
address_ = address;
}
- /* public HostAddress(const String&);
- public HostAddress(const unsigned char* address, int length);
- public HostAddress(const boost::asio::ip::address& address);*/
+
+ public HostAddress(final char[] address, int length) {
+ try {
+ assert(length == 4 || length == 16);
+ byte[] data = new byte[length];
+ if (length == 4) {
+ for (int i = 0; i < length; ++i) {
+ data[i] = (byte)address[i];
+ }
+ }
+ else {
+ for (int i = 0; i < length; ++i) {
+ data[i] = (byte)address[i];
+ }
+ }
+ address_ = InetAddress.getByAddress(data);
+ } catch (UnknownHostException e) {
+ address_ = null;
+ }
+ }
+
@Override
public String toString() {
@@ -57,5 +85,5 @@ public class HostAddress {
return address_;
}
- private final InetAddress address_;
+ private InetAddress address_;
}
diff --git a/src/com/isode/stroke/network/HostAddressPort.java b/src/com/isode/stroke/network/HostAddressPort.java
index c7d46a4..f81c4a3 100644
--- a/src/com/isode/stroke/network/HostAddressPort.java
+++ b/src/com/isode/stroke/network/HostAddressPort.java
@@ -11,9 +11,12 @@ package com.isode.stroke.network;
public class HostAddressPort {
+ public HostAddressPort() {
+ this(new HostAddress(), -1);
+ }
+
public HostAddressPort(HostAddress address) {
- address_ = address;
- port_ = -1;
+ this(address, -1);
}
public HostAddressPort(HostAddress address, int port) {
diff --git a/src/com/isode/stroke/network/JavaNetworkFactories.java b/src/com/isode/stroke/network/JavaNetworkFactories.java
index 15860e0..b71c220 100644
--- a/src/com/isode/stroke/network/JavaNetworkFactories.java
+++ b/src/com/isode/stroke/network/JavaNetworkFactories.java
@@ -9,6 +9,8 @@ import com.isode.stroke.crypto.JavaCryptoProvider;
import com.isode.stroke.eventloop.EventLoop;
import com.isode.stroke.tls.PlatformTLSFactories;
import com.isode.stroke.tls.TLSContextFactory;
+import com.isode.stroke.idn.IDNConverter;
+import com.isode.stroke.idn.ICUConverter;
public class JavaNetworkFactories implements NetworkFactories {
@@ -16,9 +18,11 @@ public class JavaNetworkFactories implements NetworkFactories {
eventLoop_ = eventLoop;
timers_ = new JavaTimerFactory(eventLoop_);
connections_ = new JavaConnectionFactory(eventLoop_);
- dns_ = new PlatformDomainNameResolver(eventLoop_);
platformTLSFactories_ = new PlatformTLSFactories();
cryptoProvider_ = new JavaCryptoProvider();
+ idnConverter_ = new ICUConverter();
+ dns_ = new PlatformDomainNameResolver(idnConverter_, eventLoop_);
+ proxyProvider_ = new JavaProxyProvider();
}
public TimerFactory getTimerFactory() {
@@ -36,16 +40,31 @@ public class JavaNetworkFactories implements NetworkFactories {
public TLSContextFactory getTLSContextFactory() {
return platformTLSFactories_.getTLSContextFactory();
}
-
+
+ public ProxyProvider getProxyProvider() {
+ return proxyProvider_;
+ }
+
+ public EventLoop getEventLoop() {
+ return eventLoop_;
+ }
+
@Override
public CryptoProvider getCryptoProvider() {
return cryptoProvider_;
}
+ @Override
+ public IDNConverter getIDNConverter() {
+ return idnConverter_;
+ }
+
private final EventLoop eventLoop_;
private final JavaTimerFactory timers_;
private final JavaConnectionFactory connections_;
private final PlatformDomainNameResolver dns_;
private final PlatformTLSFactories platformTLSFactories_;
+ private final ProxyProvider proxyProvider_;
private final CryptoProvider cryptoProvider_;
+ private final IDNConverter idnConverter_;
}
diff --git a/src/com/isode/stroke/network/JavaProxyProvider.java b/src/com/isode/stroke/network/JavaProxyProvider.java
new file mode 100644
index 0000000..e2804a3
--- /dev/null
+++ b/src/com/isode/stroke/network/JavaProxyProvider.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2010-2011 Thilo Cestonaro
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+public class JavaProxyProvider implements ProxyProvider {
+
+ private EnvironmentProxyProvider environmentProxyProvider;
+
+ public JavaProxyProvider() {
+
+ }
+
+ public HostAddressPort getHTTPConnectProxy() {
+ HostAddressPort proxy;
+ proxy = environmentProxyProvider.getHTTPConnectProxy();
+ if(proxy.isValid()) {
+ return proxy;
+ }
+ return new HostAddressPort(new HostAddress(), 0);
+ }
+
+ public HostAddressPort getSOCKS5Proxy() {
+ HostAddressPort proxy;
+ proxy = environmentProxyProvider.getSOCKS5Proxy();
+ if(proxy.isValid()) {
+ return proxy;
+ }
+ return new HostAddressPort(new HostAddress(), 0);
+ }
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/NATPortMapping.java b/src/com/isode/stroke/network/NATPortMapping.java
new file mode 100644
index 0000000..78da3a2
--- /dev/null
+++ b/src/com/isode/stroke/network/NATPortMapping.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2011 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+/*
+ * Copyright (c) 2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+public class NATPortMapping {
+
+ private int publicPort;
+ private int localPort;
+ private Protocol protocol;
+ private int leaseInSeconds;
+
+ public enum Protocol {
+ TCP,
+ UDP
+ };
+
+ public NATPortMapping(int localPort, int publicPort) {
+ this(localPort, publicPort, Protocol.TCP, 60 * 60 * 24);
+ }
+
+ public NATPortMapping(int localPort, int publicPort, Protocol protocol) {
+ this(localPort, publicPort, protocol, 60 * 60 * 24);
+ }
+
+ public NATPortMapping(int localPort, int publicPort, Protocol protocol, int leaseInSeconds) {
+ this.localPort = localPort;
+ this.publicPort = publicPort;
+ this.protocol = protocol;
+ this.leaseInSeconds = leaseInSeconds;
+ }
+
+ public int getPublicPort() {
+ return publicPort;
+ }
+
+ public int getLocalPort() {
+ return localPort;
+ }
+
+ public Protocol getProtocol() {
+ return protocol;
+ }
+
+ public int getLeaseInSeconds() {
+ return leaseInSeconds;
+ }
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/NATTraversalForwardPortRequest.java b/src/com/isode/stroke/network/NATTraversalForwardPortRequest.java
new file mode 100644
index 0000000..327c243
--- /dev/null
+++ b/src/com/isode/stroke/network/NATTraversalForwardPortRequest.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2011 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+import com.isode.stroke.signals.Signal1;
+
+public abstract class NATTraversalForwardPortRequest {
+
+ public abstract void start();
+ public abstract void stop();
+
+ public final Signal1<NATPortMapping> onResult = new Signal1<NATPortMapping>();
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/NATTraversalGetPublicIPRequest.java b/src/com/isode/stroke/network/NATTraversalGetPublicIPRequest.java
new file mode 100644
index 0000000..612536f
--- /dev/null
+++ b/src/com/isode/stroke/network/NATTraversalGetPublicIPRequest.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2011 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+/*
+ * Copyright (c) 2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+import com.isode.stroke.signals.Signal1;
+
+public abstract class NATTraversalGetPublicIPRequest {
+
+ public abstract void start();
+ public abstract void stop();
+
+ public final Signal1<HostAddress> onResult = new Signal1<HostAddress>();
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/NATTraversalInterface.java b/src/com/isode/stroke/network/NATTraversalInterface.java
new file mode 100644
index 0000000..5ac86a2
--- /dev/null
+++ b/src/com/isode/stroke/network/NATTraversalInterface.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2011-2015 Isode Limited.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+public interface NATTraversalInterface {
+
+ public boolean isAvailable();
+
+ public HostAddress getPublicIP();
+ public NATPortMapping addPortForward(int localPort, int publicPort);
+ public boolean removePortForward(final NATPortMapping map);
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/NATTraversalRemovePortForwardingRequest.java b/src/com/isode/stroke/network/NATTraversalRemovePortForwardingRequest.java
new file mode 100644
index 0000000..c4ed0d0
--- /dev/null
+++ b/src/com/isode/stroke/network/NATTraversalRemovePortForwardingRequest.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2011 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+/*
+ * Copyright (c) 2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+import com.isode.stroke.signals.Signal1;
+
+public abstract class NATTraversalRemovePortForwardingRequest {
+
+ public static class PortMapping {
+ public enum Protocol {
+ TCP,
+ UDP
+ };
+
+ public int publicPort;
+ public int localPort;
+ public Protocol protocol;
+ public long leaseInSeconds;
+ };
+
+ public abstract void start();
+ public abstract void stop();
+
+ public final Signal1<Boolean /* failure */> onResult = new Signal1<Boolean>();
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/NATTraverser.java b/src/com/isode/stroke/network/NATTraverser.java
new file mode 100644
index 0000000..9aa5e03
--- /dev/null
+++ b/src/com/isode/stroke/network/NATTraverser.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2011-2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+import com.isode.stroke.signals.Signal1;
+
+public interface NATTraverser {
+
+ public NATTraversalGetPublicIPRequest createGetPublicIPRequest();
+ public NATTraversalForwardPortRequest createForwardPortRequest(int localPort, int publicPort);
+ public NATTraversalRemovePortForwardingRequest createRemovePortForwardingRequest(int localPort, int publicPort);
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/NetworkEnvironment.java b/src/com/isode/stroke/network/NetworkEnvironment.java
new file mode 100644
index 0000000..86547ef
--- /dev/null
+++ b/src/com/isode/stroke/network/NetworkEnvironment.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2011 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+/*
+ * Copyright (c) 2011 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+import java.util.Vector;
+
+public abstract class NetworkEnvironment {
+
+ public abstract Vector<NetworkInterface> getNetworkInterfaces();
+
+ public HostAddress getLocalAddress() {
+ Vector<NetworkInterface> networkInterfaces = getNetworkInterfaces();
+ for (final NetworkInterface iface : networkInterfaces) {
+ if (!iface.isLoopback()) {
+ for (final HostAddress address : iface.getAddresses()) {
+ if (address.getInetAddress() != null) {
+ return address;
+ }
+ }
+ }
+ }
+ return new HostAddress();
+ }
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/NetworkFactories.java b/src/com/isode/stroke/network/NetworkFactories.java
index fe20214..2955a92 100644
--- a/src/com/isode/stroke/network/NetworkFactories.java
+++ b/src/com/isode/stroke/network/NetworkFactories.java
@@ -6,6 +6,8 @@ package com.isode.stroke.network;
import com.isode.stroke.crypto.CryptoProvider;
import com.isode.stroke.tls.TLSContextFactory;
+import com.isode.stroke.idn.IDNConverter;
+import com.isode.stroke.eventloop.EventLoop;
public interface NetworkFactories {
@@ -13,6 +15,8 @@ public interface NetworkFactories {
ConnectionFactory getConnectionFactory();
DomainNameResolver getDomainNameResolver();
TLSContextFactory getTLSContextFactory();
+ ProxyProvider getProxyProvider();
+ EventLoop getEventLoop();
CryptoProvider getCryptoProvider();
-
+ IDNConverter getIDNConverter();
}
diff --git a/src/com/isode/stroke/network/NetworkInterface.java b/src/com/isode/stroke/network/NetworkInterface.java
new file mode 100644
index 0000000..5590837
--- /dev/null
+++ b/src/com/isode/stroke/network/NetworkInterface.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2011 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+/*
+ * Copyright (c) 2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+import java.util.Vector;
+
+public class NetworkInterface {
+
+ private String name = "";
+ private boolean loopback;
+ private Vector<HostAddress> addresses = new Vector<HostAddress>();
+
+ public NetworkInterface(final String name, boolean loopback) {
+ this.name = name;
+ this.loopback = loopback;
+ }
+
+ public void addAddress(final HostAddress address) {
+ addresses.add(address);
+ }
+
+ public Vector<HostAddress> getAddresses() {
+ return addresses;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public boolean isLoopback() {
+ return loopback;
+ }
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/NullNATTraversalInterface.java b/src/com/isode/stroke/network/NullNATTraversalInterface.java
new file mode 100644
index 0000000..5cee969
--- /dev/null
+++ b/src/com/isode/stroke/network/NullNATTraversalInterface.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2011 Isode Limited.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+public class NullNATTraversalInterface implements NATTraversalInterface {
+
+ public boolean isAvailable() {
+ return true;
+ }
+
+ public HostAddress getPublicIP() {
+ return null;
+ }
+
+ public NATPortMapping addPortForward(int localPort, int publicPort) {
+ return null;
+ }
+
+ public boolean removePortForward(final NATPortMapping map) {
+ return false;
+ }
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/NullNATTraverser.java b/src/com/isode/stroke/network/NullNATTraverser.java
new file mode 100644
index 0000000..3e2b873
--- /dev/null
+++ b/src/com/isode/stroke/network/NullNATTraverser.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2011 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+import com.isode.stroke.eventloop.Event;
+import com.isode.stroke.eventloop.EventLoop;
+
+public class NullNATTraverser implements NATTraverser {
+
+ private EventLoop eventLoop;
+
+ class NullNATTraversalGetPublicIPRequest extends NATTraversalGetPublicIPRequest {
+
+ public NullNATTraversalGetPublicIPRequest(EventLoop eventLoop) {
+ this.eventLoop = eventLoop;
+ }
+
+ public void start() {
+ eventLoop.postEvent(new Event.Callback() {
+ @Override
+ public void run() {
+ onResult.emit(null);
+ }
+ });
+ }
+
+ public void stop() {
+ }
+
+ private EventLoop eventLoop;
+ };
+
+ class NullNATTraversalForwardPortRequest extends NATTraversalForwardPortRequest {
+
+ public NullNATTraversalForwardPortRequest(EventLoop eventLoop) {
+ this.eventLoop = eventLoop;
+ }
+
+ public void start() {
+ eventLoop.postEvent(new Event.Callback() {
+ @Override
+ public void run() {
+ onResult.emit(null);
+ }
+ });
+ }
+
+ public void stop() {
+ }
+
+ private EventLoop eventLoop;
+ };
+
+ class NullNATTraversalRemovePortForwardingRequest extends NATTraversalRemovePortForwardingRequest {
+
+ public NullNATTraversalRemovePortForwardingRequest(EventLoop eventLoop) {
+ this.eventLoop = eventLoop;
+ }
+
+ public void start() {
+ eventLoop.postEvent(new Event.Callback() {
+ @Override
+ public void run() {
+ onResult.emit(true);
+ }
+ });
+ }
+
+ public void stop() {
+ }
+
+ private EventLoop eventLoop;
+ };
+
+ public NullNATTraverser(EventLoop eventLoop) {
+ this.eventLoop = eventLoop;
+ }
+
+ public NATTraversalGetPublicIPRequest createGetPublicIPRequest() {
+ return new NullNATTraversalGetPublicIPRequest(eventLoop);
+ }
+
+ public NATTraversalForwardPortRequest createForwardPortRequest(int localPort, int publicPort) {
+ return new NullNATTraversalForwardPortRequest(eventLoop);
+ }
+
+ public NATTraversalRemovePortForwardingRequest createRemovePortForwardingRequest(int localPort, int publicPort) {
+ return new NullNATTraversalRemovePortForwardingRequest(eventLoop);
+ }
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/NullProxyProvider.java b/src/com/isode/stroke/network/NullProxyProvider.java
new file mode 100644
index 0000000..a32a39b
--- /dev/null
+++ b/src/com/isode/stroke/network/NullProxyProvider.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2011 Isode Limited.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+public class NullProxyProvider implements ProxyProvider {
+
+ public HostAddressPort getHTTPConnectProxy() {
+ return new HostAddressPort();
+ }
+
+ public HostAddressPort getSOCKS5Proxy() {
+ return new HostAddressPort();
+ }
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/PlatformDomainNameQuery.java b/src/com/isode/stroke/network/PlatformDomainNameQuery.java
new file mode 100644
index 0000000..ef2accb
--- /dev/null
+++ b/src/com/isode/stroke/network/PlatformDomainNameQuery.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2010 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+public class PlatformDomainNameQuery {
+
+ private PlatformDomainNameResolver resolver;
+
+ protected PlatformDomainNameResolver getResolver() {
+ return resolver;
+ }
+
+ public PlatformDomainNameQuery(PlatformDomainNameResolver resolver) {
+ this.resolver = resolver;
+ }
+
+ public void runBlocking() {
+
+ }
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/PlatformDomainNameResolver.java b/src/com/isode/stroke/network/PlatformDomainNameResolver.java
index 0b87e65..d7a4d35 100644
--- a/src/com/isode/stroke/network/PlatformDomainNameResolver.java
+++ b/src/com/isode/stroke/network/PlatformDomainNameResolver.java
@@ -16,6 +16,8 @@ import java.util.Collection;
import com.isode.stroke.eventloop.Event.Callback;
import com.isode.stroke.eventloop.EventLoop;
import com.isode.stroke.eventloop.EventOwner;
+import com.isode.stroke.idn.IDNConverter;
+import com.isode.stroke.idn.ICUConverter;
public class PlatformDomainNameResolver extends DomainNameResolver {
@@ -54,18 +56,25 @@ public class PlatformDomainNameResolver extends DomainNameResolver {
final EventLoop eventLoop;
}
- public PlatformDomainNameResolver(EventLoop eventLoop) {
+ public PlatformDomainNameResolver(IDNConverter idnConverter, EventLoop eventLoop) {
this.eventLoop_ = eventLoop;
+ this.idnConverter = idnConverter;
}
@Override
- public DomainNameServiceQuery createServiceQuery(String name) {
- return new PlatformDomainNameServiceQuery(getNormalized(name), eventLoop_);
+ public DomainNameServiceQuery createServiceQuery(String serviceLookupPrefix, String name) {
+ String encodedDomain = idnConverter.getIDNAEncoded(name);
+ String result = "";
+ if (encodedDomain != null) {
+ result = serviceLookupPrefix + encodedDomain;
+ }
+ return new PlatformDomainNameServiceQuery(result, eventLoop_);
}
@Override
public DomainNameAddressQuery createAddressQuery(String name) {
- return new AddressQuery(getNormalized(name), eventLoop_);
+ return new AddressQuery(idnConverter.getIDNAEncoded(name), eventLoop_);
}
private final EventLoop eventLoop_;
+ private IDNConverter idnConverter;
}
diff --git a/src/com/isode/stroke/network/ProxiedConnection.java b/src/com/isode/stroke/network/ProxiedConnection.java
new file mode 100644
index 0000000..a94fbc5
--- /dev/null
+++ b/src/com/isode/stroke/network/ProxiedConnection.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2012-2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+import com.isode.stroke.signals.SignalConnection;
+import com.isode.stroke.signals.Slot2;
+import com.isode.stroke.signals.Slot1;
+import com.isode.stroke.base.SafeByteArray;
+
+public abstract class ProxiedConnection extends Connection {
+
+ private boolean connected_;
+ private DomainNameResolver resolver_;
+ private ConnectionFactory connectionFactory_;
+ private TimerFactory timerFactory_;
+ private String proxyHost_ = "";
+ private int proxyPort_;
+ private HostAddressPort server_;
+ private Connector connector_;
+ private Connection connection_;
+ private SignalConnection onDataReadConnection;
+ private SignalConnection onDisconnectedConnection;
+ private SignalConnection onConnectFinishedConnection;
+
+ public ProxiedConnection(DomainNameResolver resolver, ConnectionFactory connectionFactory, TimerFactory timerFactory, final String proxyHost, int proxyPort) {
+ this.resolver_ = resolver;
+ this.connectionFactory_ = connectionFactory;
+ this.timerFactory_ = timerFactory;
+ this.proxyHost_ = proxyHost;
+ this.proxyPort_ = proxyPort;
+ this.server_ = new HostAddressPort(new HostAddress("0.0.0.0"), 0);
+ this.connected_ = false;
+ }
+
+ protected void finalize() throws Throwable {
+ try {
+ cancelConnector();
+ if (connection_ != null) {
+ onDataReadConnection.disconnect();
+ onDisconnectedConnection.disconnect();
+ }
+ if (connected_) {
+ System.err.println("Warning: Connection was still established.");
+ }
+ }
+ finally {
+ super.finalize();
+ }
+ }
+
+ public void listen() {
+ assert(false);
+ connection_.listen();
+ }
+
+ public void connect(final HostAddressPort server) {
+ server_ = server;
+
+ connector_ = Connector.create(proxyHost_, proxyPort_, null, resolver_, connectionFactory_, timerFactory_);
+ onConnectFinishedConnection = connector_.onConnectFinished.connect(new Slot2<Connection, com.isode.stroke.base.Error>() {
+ @Override
+ public void call(Connection c, com.isode.stroke.base.Error e) {
+ handleConnectFinished(c);
+ }
+ });
+ connector_.start();
+ }
+
+ public void disconnect() {
+ connected_ = false;
+ connection_.disconnect();
+ }
+
+ public void write(final SafeByteArray data) {
+ connection_.write(data);
+ }
+
+ public HostAddressPort getLocalAddress() {
+ return connection_.getLocalAddress();
+ }
+
+ private void handleConnectFinished(Connection connection) {
+ cancelConnector();
+ if (connection != null) {
+ connection_ = connection;
+ connection_.onDataRead.connect(new Slot1<SafeByteArray>() {
+ @Override
+ public void call(SafeByteArray s) {
+ handleDataRead(s);
+ }
+ });
+ connection_.onDisconnected.connect(new Slot1<Error>() {
+ @Override
+ public void call(Error e) {
+ handleDisconnected(e);
+ }
+ });
+
+ initializeProxy();
+ }
+ else {
+ onConnectFinished.emit(true);
+ }
+ }
+
+ private void handleDataRead(SafeByteArray data) {
+ if (!connected_) {
+ handleProxyInitializeData(data);
+ }
+ else {
+ onDataRead.emit(data);
+ }
+ }
+
+ private void handleDisconnected(final Error error) {
+ onDisconnected.emit(error);
+ }
+
+ private void cancelConnector() {
+ if (connector_ != null) {
+ onConnectFinishedConnection.disconnect();
+ connector_.stop();
+ connector_ = null;
+ }
+ }
+
+ protected void setProxyInitializeFinished(boolean success) {
+ connected_ = success;
+ if (!success) {
+ disconnect();
+ }
+ onConnectFinished.emit(!success);
+ }
+
+ protected abstract void initializeProxy();
+ protected abstract void handleProxyInitializeData(SafeByteArray data);
+
+ protected HostAddressPort getServer() {
+ return server_;
+ }
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/ProxyProvider.java b/src/com/isode/stroke/network/ProxyProvider.java
new file mode 100644
index 0000000..b149f8f
--- /dev/null
+++ b/src/com/isode/stroke/network/ProxyProvider.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2010-2011 Thilo Cestonaro
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+/*
+ * Copyright (c) 2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+public interface ProxyProvider {
+
+ public HostAddressPort getHTTPConnectProxy();
+ public HostAddressPort getSOCKS5Proxy();
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/SOCKS5ProxiedConnection.java b/src/com/isode/stroke/network/SOCKS5ProxiedConnection.java
new file mode 100644
index 0000000..0551542
--- /dev/null
+++ b/src/com/isode/stroke/network/SOCKS5ProxiedConnection.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2010-2011 Thilo Cestonaro
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+/*
+ * Copyright (c) 2014-2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+import com.isode.stroke.base.SafeByteArray;
+import java.net.InetAddress;
+
+public class SOCKS5ProxiedConnection extends ProxiedConnection {
+
+ private enum ProxyState {
+ Initial,
+ ProxyAuthenticating,
+ ProxyConnecting
+ }
+
+ private ProxyState proxyState_;
+
+ public static SOCKS5ProxiedConnection create(DomainNameResolver resolver, ConnectionFactory connectionFactory, TimerFactory timerFactory, final String proxyHost, int proxyPort) {
+ return new SOCKS5ProxiedConnection(resolver, connectionFactory, timerFactory, proxyHost, proxyPort);
+ }
+
+ private SOCKS5ProxiedConnection(DomainNameResolver resolver, ConnectionFactory connectionFactory, TimerFactory timerFactory, final String proxyHost, int proxyPort) {
+ super(resolver, connectionFactory, timerFactory, proxyHost, proxyPort);
+ this.proxyState_ = ProxyState.Initial;
+ }
+
+ protected void initializeProxy() {
+ proxyState_ = ProxyState.ProxyAuthenticating;
+ SafeByteArray socksConnect = new SafeByteArray();
+ socksConnect.append((byte)0x05); // VER = SOCKS5 = 0x05
+ socksConnect.append((byte)0x01); // Number of authentication methods after this byte.
+ socksConnect.append((byte)0x00); // 0x00 == no authentication
+ // buffer.append(0x01); // 0x01 == GSSAPI
+ // buffer.append(0x02); // 0x02 == Username/Password
+ // rest see RFC 1928 (http://tools.ietf.org/html/rfc1928)
+ write(socksConnect);
+ }
+
+ public static boolean is_v4(InetAddress ia) {
+ byte[] address = ia.getAddress();
+ if (address.length == 4) return true;
+ else return false;
+ }
+ public static boolean is_v6(InetAddress ia) {
+ byte[] address = ia.getAddress();
+ if (address.length == 16) return true;
+ else return false;
+ }
+
+ protected void handleProxyInitializeData(SafeByteArray data) {
+ SafeByteArray socksConnect = new SafeByteArray();
+ InetAddress rawAddress = getServer().getAddress().getInetAddress();
+ assert(is_v4(rawAddress) || is_v6(rawAddress));
+
+ if (ProxyState.ProxyAuthenticating.equals(proxyState_)) {
+ //SWIFT_LOG(debug) << "ProxyAuthenticating response received, reply with the connect BYTEs" << std::endl;
+ byte choosenMethod = ((byte)data.getData()[1]);
+ if (data.getData()[0] == (byte)0x05 && choosenMethod != (byte)0xFF) {
+ switch(choosenMethod) { // use the correct Method
+ case (byte)0x00:
+ try {
+ proxyState_ = ProxyState.ProxyConnecting;
+ socksConnect.append((byte)0x05); // VER = SOCKS5 = 0x05
+ socksConnect.append((byte)0x01); // Construct a TCP connection. (CMD)
+ socksConnect.append((byte)0x00); // reserved.
+ socksConnect.append(is_v4(rawAddress) ? (byte)0x01 : (byte)0x04); // IPv4 == 0x01, Hostname == 0x02, IPv6 == 0x04. (ATYP)
+ int size = rawAddress.getAddress().length;
+ for (int s = 0; s < size; s++) {
+ byte uc;
+ uc = rawAddress.getAddress()[s];
+ socksConnect.append(uc);
+
+ }
+ socksConnect.append((byte)((getServer().getPort() >> 8) & 0xFF)); // highbyte of the port.
+ socksConnect.append((byte)(getServer().getPort() & 0xFF)); // lowbyte of the port.
+ write(socksConnect);
+ return;
+ }
+ catch(Exception e) {
+ System.err.println("exception caught");
+ }
+ write(socksConnect);
+ break;
+ default:
+ setProxyInitializeFinished(true);
+ break;
+ }
+ return;
+ }
+ setProxyInitializeFinished(false);
+ }
+ else if (ProxyState.ProxyConnecting.equals(proxyState_)) {
+ //SWIFT_LOG(debug) << "Connect response received, check if successfully." << std::endl;
+ //SWIFT_LOG(debug) << "Errorbyte: 0x" << std::hex << static_cast<int> ((*data)[1]) << std::dec << std::endl;
+ /*
+
+ data.at(1) can be one of the following:
+ 0x00 succeeded
+ 0x01 general SOCKS server failure
+ 0x02 connection not allowed by ruleset
+ 0x03 Network unreachable
+ 0x04 Host unreachable
+ 0x05 Connection refused
+ 0x06 TTL expired
+ 0x07 Command not supported (CMD)
+ 0x08 Address type not supported (ATYP)
+ 0x09 bis 0xFF unassigned
+ */
+ if (data.getData()[0] == 0x05 && data.getData()[1] == 0x0) {
+ //SWIFT_LOG(debug) << "Successfully connected the server via the proxy." << std::endl;
+ setProxyInitializeFinished(true);
+ }
+ else {
+ //std::cerr << "SOCKS Proxy returned an error: " << std::hex << (*data)[1] << std::endl;
+ setProxyInitializeFinished(false);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/SOCKS5ProxiedConnectionFactory.java b/src/com/isode/stroke/network/SOCKS5ProxiedConnectionFactory.java
new file mode 100644
index 0000000..0b67715
--- /dev/null
+++ b/src/com/isode/stroke/network/SOCKS5ProxiedConnectionFactory.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2010-2011 Thilo Cestonaro
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+/*
+ * Copyright (c) 2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+public class SOCKS5ProxiedConnectionFactory implements ConnectionFactory {
+
+ private DomainNameResolver resolver_;
+ private ConnectionFactory connectionFactory_;
+ private TimerFactory timerFactory_;
+ private String proxyHost_ = "";
+ private int proxyPort_;
+
+ public SOCKS5ProxiedConnectionFactory(DomainNameResolver resolver, ConnectionFactory connectionFactory, TimerFactory timerFactory, final String proxyHost, int proxyPort) {
+ resolver_ = resolver;
+ connectionFactory_ = connectionFactory;
+ timerFactory_ = timerFactory;
+ proxyHost_ = proxyHost;
+ proxyPort_ = proxyPort;
+ }
+
+ public Connection createConnection() {
+ return SOCKS5ProxiedConnection.create(resolver_, connectionFactory_, timerFactory_, proxyHost_, proxyPort_);
+ }
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/StaticDomainNameResolver.java b/src/com/isode/stroke/network/StaticDomainNameResolver.java
new file mode 100644
index 0000000..14817bb
--- /dev/null
+++ b/src/com/isode/stroke/network/StaticDomainNameResolver.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2010 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+import com.isode.stroke.network.HostAddress;
+import com.isode.stroke.network.HostAddressPort;
+import com.isode.stroke.network.DomainNameResolver;
+import com.isode.stroke.network.DomainNameServiceQuery;
+import com.isode.stroke.network.DomainNameAddressQuery;
+import com.isode.stroke.eventloop.EventLoop;
+import com.isode.stroke.eventloop.EventOwner;
+import com.isode.stroke.eventloop.Event;
+import java.util.Vector;
+import java.util.Map;
+import java.util.HashMap;
+
+public class StaticDomainNameResolver extends DomainNameResolver {
+
+ private EventLoop eventLoop;
+ private boolean isResponsive;
+ private Map<String, Vector<HostAddress> > addresses = new HashMap<String, Vector<HostAddress> >();
+ private Vector<Pair> services = new Vector<Pair>();
+ private EventOwner owner;
+
+ class ServiceQuery extends DomainNameServiceQuery {
+
+ public ServiceQuery(final String service, StaticDomainNameResolver resolver, EventLoop eventLoop, EventOwner owner) {
+ this.eventLoop = eventLoop;
+ this.service = service;
+ this.resolver = resolver;
+ this.owner = owner;
+ }
+
+ public void run() {
+ if (!resolver.getIsResponsive()) {
+ return;
+ }
+ final Vector<DomainNameServiceQuery.Result> results = new Vector<DomainNameServiceQuery.Result>();
+ for(StaticDomainNameResolver.Pair i : resolver.getServices()) {
+ if(i.node.equals(service)) {
+ results.add(i.queryResult);
+ }
+ }
+ eventLoop.postEvent(new Event.Callback() {
+ @Override
+ public void run() {
+ emitOnResult(results);
+ }
+ }, owner);
+ }
+
+ public void emitOnResult(Vector<DomainNameServiceQuery.Result> results) {
+ onResult.emit(results);
+ }
+
+ public EventLoop eventLoop;
+ public String service = "";
+ public StaticDomainNameResolver resolver;
+ public EventOwner owner;
+ };
+
+ class AddressQuery extends DomainNameAddressQuery {
+
+ public AddressQuery(final String host, StaticDomainNameResolver resolver, EventLoop eventLoop, EventOwner owner) {
+ this.eventLoop = eventLoop;
+ this.host = host;
+ this.resolver = resolver;
+ this.owner = owner;
+ }
+
+ public void run() {
+ if (!resolver.getIsResponsive()) {
+ return;
+ }
+ if (resolver.getAddresses().containsKey(host)) {
+ eventLoop.postEvent(new Event.Callback() {
+ @Override
+ public void run() {
+ emitOnResult(resolver.getAddresses().get(host), null);
+ }
+ });
+ }
+ else {
+ eventLoop.postEvent(new Event.Callback() {
+ @Override
+ public void run() {
+ emitOnResult(new Vector<HostAddress>(), new DomainNameResolveError());
+ }
+ });
+ }
+ }
+
+ public void emitOnResult(Vector<HostAddress> results, DomainNameResolveError error) {
+ onResult.emit(results, error);
+ }
+
+ public EventLoop eventLoop;
+ public String host = "";
+ public StaticDomainNameResolver resolver;
+ public EventOwner owner;
+ };
+
+ private class Pair {
+ public String node;
+ public DomainNameServiceQuery.Result queryResult;
+
+ public Pair(String j, DomainNameServiceQuery.Result n) {node = j; queryResult = n;}
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Pair)) return false;
+ Pair o1 = (Pair) o;
+ return queryResult.equals(o1.queryResult) && node.equals(o1.node);
+ }
+ }
+
+ class StaticDomainNameResolverEventOwner implements EventOwner {
+
+ };
+
+ public StaticDomainNameResolver(EventLoop eventLoop) {
+ this.eventLoop = eventLoop;
+ isResponsive = true;
+ owner = new StaticDomainNameResolverEventOwner();
+ }
+
+ public void addAddress(final String domain, final HostAddress address) {
+ Vector<HostAddress> vec = new Vector<HostAddress>();
+ vec.add(address);
+ if(!(addresses.containsKey(domain))) {
+ addresses.put(domain, vec);
+ }
+ else {
+ addresses.get(domain).add(address);
+ }
+ }
+
+ public void addService(final String service, final DomainNameServiceQuery.Result result) {
+ services.add(new Pair(service, result));
+ }
+
+ public void addXMPPClientService(final String domain, final HostAddressPort address) {
+ int hostid = 0;
+ String hostname = "host-" + Integer.toString(hostid);
+ hostid++;
+
+ addService("_xmpp-client._tcp." + domain, new ServiceQuery.Result(hostname, address.getPort(), 0, 0));
+ addAddress(hostname, address.getAddress());
+ }
+
+ public void addXMPPClientService(final String domain, final String hostname, int port) {
+ addService("_xmpp-client._tcp." + domain, new ServiceQuery.Result(hostname, port, 0, 0));
+ }
+
+ public Map<String, Vector<HostAddress> > getAddresses() {
+ return addresses;
+ }
+
+ public Vector<Pair> getServices() {
+ return services;
+ }
+
+ public boolean getIsResponsive() {
+ return isResponsive;
+ }
+
+ public void setIsResponsive(boolean b) {
+ isResponsive = b;
+ }
+
+ public DomainNameServiceQuery createServiceQuery(final String serviceLookupPrefix, final String domain) {
+ return new ServiceQuery(serviceLookupPrefix + domain, this, eventLoop, owner);
+ }
+
+ public DomainNameAddressQuery createAddressQuery(final String name) {
+ return new AddressQuery(name, this, eventLoop, owner);
+ }
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/TLSConnection.java b/src/com/isode/stroke/network/TLSConnection.java
new file mode 100644
index 0000000..16c6617
--- /dev/null
+++ b/src/com/isode/stroke/network/TLSConnection.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2011-2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+import com.isode.stroke.base.SafeByteArray;
+import com.isode.stroke.network.Connection;
+import com.isode.stroke.network.HostAddressPort;
+import com.isode.stroke.tls.TLSOptions;
+import com.isode.stroke.tls.TLSContextFactory;
+import com.isode.stroke.tls.TLSContext;
+import com.isode.stroke.tls.TLSError;
+import com.isode.stroke.signals.Slot1;
+import com.isode.stroke.signals.Slot;
+import com.isode.stroke.signals.SignalConnection;
+
+public class TLSConnection extends Connection {
+
+ private TLSContext context;
+ private Connection connection;
+ private SignalConnection onConnectFinishedConnection;
+ private SignalConnection onDataReadConnection;
+ private SignalConnection onDataWrittenConnection;
+ private SignalConnection onDisconnectedConnection;
+
+ public TLSConnection(Connection connection, TLSContextFactory tlsFactory, final TLSOptions tlsOptions) {
+ this.connection = connection;
+ context = tlsFactory.createTLSContext(tlsOptions);
+ context.onDataForNetwork.connect(new Slot1<SafeByteArray>() {
+ @Override
+ public void call(SafeByteArray s) {
+ handleTLSDataForNetwork(s);
+ }
+ });
+ context.onDataForApplication.connect(new Slot1<SafeByteArray>() {
+ @Override
+ public void call(SafeByteArray s) {
+ handleTLSDataForApplication(s);
+ }
+ });
+ context.onConnected.connect(new Slot() {
+ @Override
+ public void call() {
+ handleTLSConnectFinished(false);
+ }
+ });
+ context.onError.connect(new Slot1<TLSError>() {
+ @Override
+ public void call(TLSError e) {
+ handleTLSConnectFinished(true);
+ }
+ });
+ connection.onConnectFinished.connect(new Slot1<Boolean>() {
+ @Override
+ public void call(Boolean s) {
+ handleRawConnectFinished(s);
+ }
+ });
+ connection.onDataRead.connect(new Slot1<SafeByteArray>() {
+ @Override
+ public void call(SafeByteArray s) {
+ handleRawDataRead(s);
+ }
+ });
+ connection.onDataWritten.connect(new Slot() {
+ @Override
+ public void call() {
+ handleRawDataWritten();
+ }
+ });
+ connection.onDisconnected.connect(new Slot1<Error>() {
+ @Override
+ public void call(Error e) {
+ handleRawDisconnected(e);
+ }
+ });
+ }
+
+ protected void finalize() throws Throwable {
+ try {
+ onConnectFinishedConnection.disconnect();
+ onDataReadConnection.disconnect();
+ onDataWrittenConnection.disconnect();
+ onDisconnectedConnection.disconnect();
+ }
+ finally {
+ super.finalize();
+ }
+ }
+
+ public void listen() {
+ assert(false);
+ }
+
+ public void connect(final HostAddressPort address) {
+ connection.connect(address);
+ }
+
+ public void disconnect() {
+ connection.disconnect();
+ }
+
+ public void write(final SafeByteArray data) {
+ context.handleDataFromApplication(data);
+ }
+
+ public HostAddressPort getLocalAddress() {
+ return connection.getLocalAddress();
+ }
+
+ private void handleRawConnectFinished(boolean error) {
+ onConnectFinishedConnection.disconnect();
+ if (error) {
+ onConnectFinished.emit(true);
+ }
+ else {
+ context.connect();
+ }
+ }
+
+ private void handleRawDisconnected(final Error error) {
+ onDisconnected.emit(error);
+ }
+
+ private void handleRawDataRead(SafeByteArray data) {
+ context.handleDataFromNetwork(data);
+ }
+
+ private void handleRawDataWritten() {
+ onDataWritten.emit();
+ }
+
+ private void handleTLSConnectFinished(boolean error) {
+ onConnectFinished.emit(error);
+ if (error) {
+ disconnect();
+ }
+ }
+
+ private void handleTLSDataForNetwork(final SafeByteArray data) {
+ connection.write(data);
+ }
+
+ private void handleTLSDataForApplication(final SafeByteArray data) {
+ onDataRead.emit(data);
+ }
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/TLSConnectionFactory.java b/src/com/isode/stroke/network/TLSConnectionFactory.java
new file mode 100644
index 0000000..c22e6b9
--- /dev/null
+++ b/src/com/isode/stroke/network/TLSConnectionFactory.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2011-2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+import com.isode.stroke.tls.TLSOptions;
+import com.isode.stroke.tls.TLSContextFactory;
+import com.isode.stroke.tls.TLSContext;
+import com.isode.stroke.network.ConnectionFactory;
+
+public class TLSConnectionFactory implements ConnectionFactory {
+
+ private TLSContextFactory contextFactory;
+ private ConnectionFactory connectionFactory;
+ private TLSOptions options_;
+
+ public TLSConnectionFactory(TLSContextFactory contextFactory, ConnectionFactory connectionFactory, final TLSOptions tlsOptions) {
+ this.contextFactory = contextFactory;
+ this.connectionFactory = connectionFactory;
+ this.options_ = tlsOptions;
+ }
+
+ public Connection createConnection() {
+ return new TLSConnection(connectionFactory.createConnection(), contextFactory, options_);
+ }
+
+
+} \ No newline at end of file
diff --git a/src/com/isode/stroke/network/Timer.java b/src/com/isode/stroke/network/Timer.java
index 4949e05..a28d3e6 100644
--- a/src/com/isode/stroke/network/Timer.java
+++ b/src/com/isode/stroke/network/Timer.java
@@ -12,7 +12,23 @@ package com.isode.stroke.network;
import com.isode.stroke.signals.Signal;
public abstract class Timer {
+
+ /**
+ * Starts the timer.
+ *
+ * After the given period, onTick() will be called.
+ */
public abstract void start();
+
+ /**
+ * Cancels the timer.
+ *
+ * If the timer was started, onTick() will no longer be called.
+ */
public abstract void stop();
+
+ /**
+ * Emitted when the timer expires.
+ */
public final Signal onTick = new Signal();
}
diff --git a/test/com/isode/stroke/component/ComponentConnectorTest.java b/test/com/isode/stroke/component/ComponentConnectorTest.java
new file mode 100644
index 0000000..413f325
--- /dev/null
+++ b/test/com/isode/stroke/component/ComponentConnectorTest.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2010 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.component;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+import org.junit.Before;
+import com.isode.stroke.base.SafeByteArray;
+import com.isode.stroke.base.ByteArray;
+import com.isode.stroke.eventloop.EventLoop;
+import com.isode.stroke.eventloop.Event;
+import com.isode.stroke.signals.Slot1;
+import com.isode.stroke.network.Connector;
+import com.isode.stroke.network.HostAddress;
+import com.isode.stroke.network.Connection;
+import com.isode.stroke.network.ConnectionFactory;
+import com.isode.stroke.network.HostAddressPort;
+import com.isode.stroke.network.StaticDomainNameResolver;
+import com.isode.stroke.network.DummyTimerFactory;
+import com.isode.stroke.eventloop.DummyEventLoop;
+import com.isode.stroke.network.DomainNameAddressQuery;
+import java.util.Vector;
+
+public class ComponentConnectorTest {
+
+ private HostAddress host1;
+ private HostAddress host2;
+ private DummyEventLoop eventLoop;
+ private StaticDomainNameResolver resolver;
+ private MockConnectionFactory connectionFactory;
+ private DummyTimerFactory timerFactory;
+ private Vector<MockConnection> connections = new Vector<MockConnection>();
+
+ private class MockConnection extends Connection {
+
+ public MockConnection(final Vector<HostAddressPort> failingPorts, boolean isResponsive, EventLoop eventLoop) {
+ this.eventLoop = eventLoop;
+ this.failingPorts = failingPorts;
+ this.isResponsive = isResponsive;
+ }
+
+ public void listen() { assert(false); }
+
+ public void connect(final HostAddressPort address) {
+ hostAddressPort = address;
+ if(isResponsive) {
+ final boolean fail = failingPorts.contains(address);
+ eventLoop.postEvent(new Event.Callback() {
+ @Override
+ public void run() {
+ onConnectFinished.emit(fail);
+ }
+ });
+ }
+ }
+
+ public HostAddressPort getLocalAddress() { return new HostAddressPort(); }
+
+ public void disconnect() { assert(false); }
+
+ public void write(final SafeByteArray data) { assert(false); }
+
+ public EventLoop eventLoop;
+ public HostAddressPort hostAddressPort;
+ public Vector<HostAddressPort> failingPorts = new Vector<HostAddressPort>();
+ public boolean isResponsive;
+ };
+
+ private class MockConnectionFactory implements ConnectionFactory {
+ public MockConnectionFactory(EventLoop eventLoop) {
+ this.eventLoop = eventLoop;
+ this.isResponsive = true;
+ }
+
+ public Connection createConnection() {
+ return new MockConnection(failingPorts, isResponsive, eventLoop);
+ }
+
+ public EventLoop eventLoop;
+ public boolean isResponsive;
+ public Vector<HostAddressPort> failingPorts = new Vector<HostAddressPort>();
+ };
+
+ private ComponentConnector createConnector(final String hostname, int port) {
+ ComponentConnector connector = ComponentConnector.create(hostname, port, resolver, connectionFactory, timerFactory);
+ connector.onConnectFinished.connect(new Slot1<Connection>() {
+ @Override
+ public void call(Connection c) {
+ handleConnectorFinished(c);
+ }
+ });
+ return connector;
+ }
+
+ private void handleConnectorFinished(Connection connection) {
+ MockConnection c = (MockConnection)(connection);
+ if (connection != null) {
+ assert(c != null);
+ }
+ connections.add(c);
+ }
+
+ @Before
+ public void setUp() {
+ host1 = new HostAddress("1.1.1.1");
+ host2 = new HostAddress("2.2.2.2");
+ eventLoop = new DummyEventLoop();
+ resolver = new StaticDomainNameResolver(eventLoop);
+ connectionFactory = new MockConnectionFactory(eventLoop);
+ timerFactory = new DummyTimerFactory();
+ }
+
+ @Test
+ public void testConnect() {
+ ComponentConnector testling = createConnector("foo.com", 1234);
+ resolver.addAddress("foo.com", host1);
+
+ testling.start();
+ eventLoop.processEvents();
+
+ assertEquals(1, (connections.size()));
+ assertNotNull(connections.get(0));
+ assertEquals(new HostAddressPort(host1, 1234), (connections.get(0).hostAddressPort));
+ }
+
+ @Test
+ public void testConnect_FirstAddressHostFails() {
+ ComponentConnector testling = createConnector("foo.com", 1234);
+ resolver.addAddress("foo.com", host1);
+ resolver.addAddress("foo.com", host2);
+ connectionFactory.failingPorts.add(new HostAddressPort(host1, 1234));
+
+ testling.start();
+ eventLoop.processEvents();
+
+ assertEquals(1, (connections.size()));
+ assertNotNull(connections.get(0));
+ assertEquals(new HostAddressPort(host2, 1234), (connections.get(0).hostAddressPort));
+ }
+
+ @Test
+ public void testConnect_NoHosts() {
+ ComponentConnector testling = createConnector("foo.com", 1234);
+
+ testling.start();
+ eventLoop.processEvents();
+
+ assertEquals(1, (connections.size()));
+ assertNull(connections.get(0));
+ }
+
+ @Test
+ public void testConnect_TimeoutDuringResolve() {
+ ComponentConnector testling = createConnector("foo.com", 1234);
+
+ testling.setTimeoutMilliseconds(10);
+ resolver.setIsResponsive(false);
+
+ testling.start();
+ eventLoop.processEvents();
+ timerFactory.setTime(10);
+ eventLoop.processEvents();
+
+ assertEquals(1, (connections.size()));
+ assertNull(connections.get(0));
+ }
+
+ @Test
+ public void testConnect_TimeoutDuringConnect() {
+ ComponentConnector testling = createConnector("foo.com", 1234);
+ testling.setTimeoutMilliseconds(10);
+ resolver.addAddress("foo.com", host1);
+ connectionFactory.isResponsive = false;
+
+ testling.start();
+ eventLoop.processEvents();
+ timerFactory.setTime(10);
+ eventLoop.processEvents();
+
+ assertEquals(1, (connections.size()));
+ assertNull(connections.get(0));
+ }
+
+ @Test
+ public void testConnect_NoTimeout() {
+ ComponentConnector testling = createConnector("foo.com", 1234);
+ testling.setTimeoutMilliseconds(10);
+ resolver.addAddress("foo.com", host1);
+
+ testling.start();
+ eventLoop.processEvents();
+ timerFactory.setTime(10);
+ eventLoop.processEvents();
+
+ assertEquals(1, (connections.size()));
+ assertNotNull(connections.get(0));
+ }
+
+ @Test
+ public void testStop_Timeout() {
+ ComponentConnector testling = createConnector("foo.com", 1234);
+ testling.setTimeoutMilliseconds(10);
+ resolver.addAddress("foo.com", host1);
+
+ testling.start();
+ testling.stop();
+
+ eventLoop.processEvents();
+ timerFactory.setTime(10);
+ eventLoop.processEvents();
+
+ assertEquals(1, (connections.size()));
+ assertNull(connections.get(0));
+ }
+} \ No newline at end of file
diff --git a/test/com/isode/stroke/network/ChainedConnectorTest.java b/test/com/isode/stroke/network/ChainedConnectorTest.java
new file mode 100644
index 0000000..a2bb98c
--- /dev/null
+++ b/test/com/isode/stroke/network/ChainedConnectorTest.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2010 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+import org.junit.Before;
+import com.isode.stroke.base.SafeByteArray;
+import com.isode.stroke.network.ChainedConnector;
+import com.isode.stroke.network.Connection;
+import com.isode.stroke.network.ConnectionFactory;
+import com.isode.stroke.network.HostAddressPort;
+import com.isode.stroke.network.StaticDomainNameResolver;
+import com.isode.stroke.network.DummyTimerFactory;
+import com.isode.stroke.eventloop.DummyEventLoop;
+import com.isode.stroke.eventloop.EventLoop;
+import com.isode.stroke.eventloop.Event;
+import com.isode.stroke.signals.Slot2;
+import com.isode.stroke.network.DomainNameResolveError;
+import java.util.Vector;
+
+public class ChainedConnectorTest {
+
+ private HostAddressPort host;
+ private DummyEventLoop eventLoop;
+ private StaticDomainNameResolver resolver;
+ private MockConnectionFactory connectionFactory1;
+ private MockConnectionFactory connectionFactory2;
+ private DummyTimerFactory timerFactory;
+ private Vector<MockConnection> connections = new Vector<MockConnection>();
+ private com.isode.stroke.base.Error error;
+
+ private class MockConnection extends Connection {
+
+ public MockConnection(boolean connects, int id, EventLoop eventLoop) {
+ this.connects = connects;
+ this.id = id;
+ this.eventLoop = eventLoop;
+ }
+
+ public void listen() { assert(false); }
+
+ public void connect(final HostAddressPort port) {
+ eventLoop.postEvent(new Event.Callback() {
+ @Override
+ public void run() {
+ onConnectFinished.emit(!connects);
+ }
+ });
+ }
+
+ public HostAddressPort getLocalAddress() { return new HostAddressPort(); }
+ public void disconnect() { assert(false); }
+ public void write(final SafeByteArray data) { assert(false); }
+
+ public boolean connects;
+ public int id;
+ public EventLoop eventLoop;
+ };
+
+ private class MockConnectionFactory implements ConnectionFactory {
+ public MockConnectionFactory(EventLoop eventLoop, int id) {
+ this.eventLoop = eventLoop;
+ this.connects = true;
+ this.id = id;
+ }
+
+ public Connection createConnection() {
+ return new MockConnection(connects, id, eventLoop);
+ }
+
+ public EventLoop eventLoop;
+ public boolean connects;
+ public int id;
+ };
+
+ private ChainedConnector createConnector() {
+ Vector<ConnectionFactory> factories = new Vector<ConnectionFactory>();
+ factories.add(connectionFactory1);
+ factories.add(connectionFactory2);
+ ChainedConnector connector = new ChainedConnector("foo.com", -1, "_xmpp-client._tcp.", resolver, factories, timerFactory);
+ connector.onConnectFinished.connect(new Slot2<Connection, com.isode.stroke.base.Error>() {
+ @Override
+ public void call(Connection c, com.isode.stroke.base.Error e) {
+ handleConnectorFinished(c, e);
+ }
+ });
+ return connector;
+ }
+
+ private void handleConnectorFinished(Connection connection, com.isode.stroke.base.Error resultError) {
+ error = resultError;
+ MockConnection c = (MockConnection)(connection);
+ if (connection != null) {
+ assert(c != null);
+ }
+ connections.add(c);
+ }
+
+ @Before
+ public void setUp() {
+ error = null;
+ host = new HostAddressPort(new HostAddress("1.1.1.1"), 1234);
+ eventLoop = new DummyEventLoop();
+ resolver = new StaticDomainNameResolver(eventLoop);
+ resolver.addXMPPClientService("foo.com", host);
+ connectionFactory1 = new MockConnectionFactory(eventLoop, 1);
+ connectionFactory2 = new MockConnectionFactory(eventLoop, 2);
+ timerFactory = new DummyTimerFactory();
+ }
+
+ @Test
+ public void testConnect_FirstConnectorSucceeds() {
+ ChainedConnector testling = createConnector();
+ connectionFactory1.connects = true;
+ connectionFactory2.connects = false;
+
+ testling.start();
+ eventLoop.processEvents();
+
+ assertEquals(1, (connections.size()));
+ assertNotNull(connections.get(0));
+ assertEquals(1, ((MockConnection)(connections.get(0))).id);
+ assertNull((DomainNameResolveError)(error));
+ }
+
+ @Test
+ public void testConnect_SecondConnectorSucceeds() {
+ ChainedConnector testling = createConnector();
+ connectionFactory1.connects = false;
+ connectionFactory2.connects = true;
+
+ testling.start();
+ eventLoop.processEvents();
+
+ assertEquals(1, (connections.size()));
+ assertNotNull(connections.get(0));
+ assertEquals(2, ((MockConnection)(connections.get(0))).id);
+ assertNull((DomainNameResolveError)(error));
+ }
+
+ @Test
+ public void testConnect_NoConnectorSucceeds() {
+ ChainedConnector testling = createConnector();
+ connectionFactory1.connects = false;
+ connectionFactory2.connects = false;
+
+ testling.start();
+ eventLoop.processEvents();
+
+ assertEquals(1, (connections.size()));
+ assertNull(connections.get(0));
+ assertNull((DomainNameResolveError)(error));
+ }
+
+ @Test
+ public void testConnect_NoDNS() {
+ /* Reset resolver so there's no record */
+ resolver = null;
+ resolver = new StaticDomainNameResolver(eventLoop);
+ ChainedConnector testling = createConnector();
+ connectionFactory1.connects = false;
+ connectionFactory2.connects = false;
+
+ testling.start();
+ //testling.stop();
+ eventLoop.processEvents();
+
+ assertEquals(1, (connections.size()));
+ assertNull(connections.get(0));
+ assertNotNull((DomainNameResolveError)(error));
+ }
+
+ @Test
+ public void testStop() {
+ ChainedConnector testling = createConnector();
+ connectionFactory1.connects = true;
+ connectionFactory2.connects = false;
+
+ testling.start();
+ testling.stop();
+ eventLoop.processEvents();
+
+ assertEquals(1, (connections.size()));
+ assertNull(connections.get(0));
+ }
+} \ No newline at end of file
diff --git a/test/com/isode/stroke/network/ConnectorTest.java b/test/com/isode/stroke/network/ConnectorTest.java
new file mode 100644
index 0000000..43e2300
--- /dev/null
+++ b/test/com/isode/stroke/network/ConnectorTest.java
@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 2010-2014 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+import org.junit.Before;
+import com.isode.stroke.base.SafeByteArray;
+import com.isode.stroke.base.ByteArray;
+import com.isode.stroke.eventloop.EventLoop;
+import com.isode.stroke.eventloop.Event;
+import com.isode.stroke.signals.Slot2;
+import com.isode.stroke.network.Connector;
+import com.isode.stroke.network.Connection;
+import com.isode.stroke.network.ConnectionFactory;
+import com.isode.stroke.network.HostAddressPort;
+import com.isode.stroke.network.StaticDomainNameResolver;
+import com.isode.stroke.network.DummyTimerFactory;
+import com.isode.stroke.eventloop.DummyEventLoop;
+import com.isode.stroke.network.DomainNameAddressQuery;
+import java.util.Vector;
+
+public class ConnectorTest {
+
+ private HostAddressPort host1;
+ private HostAddressPort host2;
+ private HostAddressPort host3;
+ private DummyEventLoop eventLoop;
+ private StaticDomainNameResolver resolver;
+ private MockConnectionFactory connectionFactory;
+ private DummyTimerFactory timerFactory;
+ private Vector<MockConnection> connections = new Vector<MockConnection>();
+ private com.isode.stroke.base.Error error;
+
+ private class MockConnection extends Connection {
+
+ public MockConnection(final Vector<HostAddressPort> failingPorts, boolean isResponsive, EventLoop eventLoop) {
+ this.eventLoop = eventLoop;
+ this.failingPorts = failingPorts;
+ this.isResponsive = isResponsive;
+ }
+
+ public void listen() { assert(false); }
+
+ public void connect(final HostAddressPort address) {
+ hostAddressPort = address;
+ if(isResponsive) {
+ final boolean fail = failingPorts.contains(address);
+ eventLoop.postEvent(new Event.Callback() {
+ @Override
+ public void run() {
+ onConnectFinished.emit(fail);
+ }
+ });
+ }
+ }
+
+ public HostAddressPort getLocalAddress() { return new HostAddressPort(); }
+
+ public void disconnect() { assert(false); }
+
+ public void write(final SafeByteArray data) { assert(false); }
+
+ public EventLoop eventLoop;
+ public HostAddressPort hostAddressPort;
+ public Vector<HostAddressPort> failingPorts = new Vector<HostAddressPort>();
+ public boolean isResponsive;
+ };
+
+ private class MockConnectionFactory implements ConnectionFactory {
+ public MockConnectionFactory(EventLoop eventLoop) {
+ this.eventLoop = eventLoop;
+ this.isResponsive = true;
+ }
+
+ public Connection createConnection() {
+ return new MockConnection(failingPorts, isResponsive, eventLoop);
+ }
+
+ public EventLoop eventLoop;
+ public boolean isResponsive;
+ public Vector<HostAddressPort> failingPorts = new Vector<HostAddressPort>();
+ };
+
+ private Connector createConnector() {
+ return createConnector(-1, "_xmpp-client._tcp.");
+ }
+
+ private Connector createConnector(int port) {
+ return createConnector(port, "_xmpp-client._tcp.");
+ }
+
+ private Connector createConnector(int port, String serviceLookupPrefix) {
+ Connector connector = Connector.create("foo.com", port, serviceLookupPrefix, resolver, connectionFactory, timerFactory);
+ connector.onConnectFinished.connect(new Slot2<Connection, com.isode.stroke.base.Error>() {
+ @Override
+ public void call(Connection c, com.isode.stroke.base.Error e) {
+ handleConnectorFinished(c, e);
+ }
+ });
+ return connector;
+ }
+
+ private void handleConnectorFinished(Connection connection, com.isode.stroke.base.Error resultError) {
+ MockConnection c = (MockConnection)(connection);
+ if (connection != null) {
+ assert(c != null);
+ }
+ connections.add(c);
+ error = resultError;
+ }
+
+ @Before
+ public void setUp() {
+ host1 = new HostAddressPort(new HostAddress("1.1.1.1"), 1234);
+ host2 = new HostAddressPort(new HostAddress("2.2.2.2"), 2345);
+ host3 = new HostAddressPort(new HostAddress("3.3.3.3"), 5222);
+ eventLoop = new DummyEventLoop();
+ resolver = new StaticDomainNameResolver(eventLoop);
+ connectionFactory = new MockConnectionFactory(eventLoop);
+ timerFactory = new DummyTimerFactory();
+ }
+
+ @Test
+ public void testConnect() {
+ Connector testling = createConnector();
+ resolver.addXMPPClientService("foo.com", host1);
+ resolver.addXMPPClientService("foo.com", host2);
+ resolver.addAddress("foo.com", host3.getAddress());
+
+ testling.start();
+ eventLoop.processEvents();
+
+ assertEquals(1, (connections.size()));
+ assertNotNull(connections.get(0));
+ assertEquals(host1, (connections.get(0).hostAddressPort));
+ assertNull((DomainNameResolveError)(error));
+ }
+
+ @Test
+ public void testConnect_NoServiceLookups() {
+ Connector testling = createConnector(4321, null);
+ resolver.addXMPPClientService("foo.com", host1);
+ resolver.addXMPPClientService("foo.com", host2);
+ resolver.addAddress("foo.com", host3.getAddress());
+
+ testling.start();
+ eventLoop.processEvents();
+
+ assertEquals(1, (connections.size()));
+ assertNotNull(connections.get(0));
+ //assertEquals(host3.getAddress(), (connections.get(0).hostAddressPort).getAddress()); FAIL
+ assertEquals(4321, (connections.get(0).hostAddressPort).getPort());
+ assertNull((DomainNameResolveError)(error));
+ }
+
+ @Test
+ public void testConnect_NoServiceLookups_DefaultPort() {
+ Connector testling = createConnector(-1, null);
+ resolver.addXMPPClientService("foo.com", host1);
+ resolver.addXMPPClientService("foo.com", host2);
+ resolver.addAddress("foo.com", host3.getAddress());
+
+ testling.start();
+ eventLoop.processEvents();
+
+ assertEquals(1, (connections.size()));
+ assertNotNull(connections.get(0));
+ //assertEquals(host3.getAddress(), (connections.get(0).hostAddressPort).getAddress()); FAIL
+ assertEquals(5222, (connections.get(0).hostAddressPort).getPort());
+ assertNull((DomainNameResolveError)(error));
+ }
+
+ @Test
+ public void testConnect_NoSRVHost() {
+ Connector testling = createConnector();
+ resolver.addAddress("foo.com", host3.getAddress());
+
+ testling.start();
+ eventLoop.processEvents();
+
+ assertEquals(1, (connections.size()));
+ assertNotNull(connections.get(0));
+ assertEquals(host3, (connections.get(0).hostAddressPort));
+ assertNull((DomainNameResolveError)(error));
+ }
+
+ @Test
+ public void testConnect_FirstAddressHostFails() {
+ Connector testling = createConnector();
+
+ HostAddress address1 = new HostAddress("1.1.1.1");
+ HostAddress address2 = new HostAddress("2.2.2.2");
+ resolver.addXMPPClientService("foo.com", "host-foo.com", 1234);
+ resolver.addAddress("host-foo.com", address1);
+ resolver.addAddress("host-foo.com", address2);
+ connectionFactory.failingPorts.add(new HostAddressPort(address1, 1234));
+
+ testling.start();
+ eventLoop.processEvents();
+
+ assertEquals(1, (connections.size()));
+ assertNotNull(connections.get(0));
+ assertEquals(new HostAddressPort(address2, 1234), (connections.get(0).hostAddressPort));
+ assertNull((DomainNameResolveError)(error));
+ }
+
+ @Test
+ public void testConnect_NoHosts() {
+ Connector testling = createConnector();
+
+ testling.start();
+ eventLoop.processEvents();
+
+ assertEquals(1, (connections.size()));
+ assertNull(connections.get(0));
+ assertNotNull((DomainNameResolveError)(error));
+ }
+
+ @Test
+ public void testConnect_FirstSRVHostFails() {
+ Connector testling = createConnector();
+ resolver.addXMPPClientService("foo.com", host1);
+ resolver.addXMPPClientService("foo.com", host2);
+ connectionFactory.failingPorts.add(host1);
+
+ testling.start();
+ eventLoop.processEvents();
+
+ assertEquals(1, (connections.size()));
+ //assertEquals(host2, (connections.get(0).hostAddressPort)); FAIL
+ assertNull((DomainNameResolveError)(error));
+ }
+
+ @Test
+ public void testConnect_AllSRVHostsFailWithoutFallbackHost() {
+ Connector testling = createConnector();
+ resolver.addXMPPClientService("foo.com", host1);
+ resolver.addXMPPClientService("foo.com", host2);
+ connectionFactory.failingPorts.add(host1);
+ connectionFactory.failingPorts.add(host2);
+
+ testling.start();
+ eventLoop.processEvents();
+
+ assertEquals(1, (connections.size()));
+ //assertNull(connections.get(0)); FAIL
+ assertNull((DomainNameResolveError)(error));
+ }
+
+ @Test
+ public void testConnect_AllSRVHostsFailWithFallbackHost() {
+ Connector testling = createConnector();
+ resolver.addXMPPClientService("foo.com", host1);
+ resolver.addXMPPClientService("foo.com", host2);
+ resolver.addAddress("foo.com", host3.getAddress());
+ connectionFactory.failingPorts.add(host1);
+ connectionFactory.failingPorts.add(host2);
+
+ testling.start();
+ eventLoop.processEvents();
+
+ assertEquals(1, (connections.size()));
+ assertNotNull(connections.get(0));
+ //assertEquals(host3, (connections.get(0).hostAddressPort)); FAIL
+ assertNull((DomainNameResolveError)(error));
+ }
+
+ @Test
+ public void testConnect_SRVAndFallbackHostsFail() {
+ Connector testling = createConnector();
+ resolver.addXMPPClientService("foo.com", host1);
+ resolver.addAddress("foo.com", host3.getAddress());
+ connectionFactory.failingPorts.add(host1);
+ connectionFactory.failingPorts.add(host3);
+
+ testling.start();
+ eventLoop.processEvents();
+
+ assertEquals(1, (connections.size()));
+ assertNull(connections.get(0));
+ assertNull((DomainNameResolveError)(error));
+ }
+
+ //@Test COMMENTED IN SWIFTEN TOO.
+ /*public void testConnect_TimeoutDuringResolve() {
+ Connector testling = createConnector();
+ testling.setTimeoutMilliseconds(10);
+ resolver.setIsResponsive(false);
+
+ testling.start();
+ eventLoop.processEvents();
+ timerFactory.setTime(10);
+ eventLoop.processEvents();
+
+ assertEquals(1, (connections.size()));
+ CPPUNIT_ASSERT((DomainNameResolveError)(error));
+ CPPUNIT_ASSERT(!connections.get(0));
+ }*/
+
+ @Test
+ public void testConnect_TimeoutDuringConnectToOnlyCandidate() {
+ Connector testling = createConnector();
+ testling.setTimeoutMilliseconds(10);
+ resolver.addXMPPClientService("foo.com", host1);
+ connectionFactory.isResponsive = false;
+
+ testling.start();
+ eventLoop.processEvents();
+ timerFactory.setTime(10);
+ eventLoop.processEvents();
+
+ assertEquals(1, (connections.size()));
+ assertNull(connections.get(0));
+ assertNull((DomainNameResolveError)(error));
+ }
+
+ @Test
+ public void testConnect_TimeoutDuringConnectToCandidateFallsBack() {
+ Connector testling = createConnector();
+ testling.setTimeoutMilliseconds(10);
+
+ resolver.addXMPPClientService("foo.com", "host-foo.com", 1234);
+ HostAddress address1 = new HostAddress("1.1.1.1");
+ resolver.addAddress("host-foo.com", address1);
+ HostAddress address2 = new HostAddress("2.2.2.2");
+ resolver.addAddress("host-foo.com", address2);
+
+ connectionFactory.isResponsive = false;
+ testling.start();
+ eventLoop.processEvents();
+ connectionFactory.isResponsive = true;
+ timerFactory.setTime(10);
+ eventLoop.processEvents();
+
+ assertEquals(1, (connections.size()));
+ assertNotNull(connections.get(0));
+ assertEquals(new HostAddressPort(address2, 1234), (connections.get(0).hostAddressPort));
+ assertNull((DomainNameResolveError)(error));
+ }
+
+ @Test
+ public void testConnect_NoTimeout() {
+ Connector testling = createConnector();
+ testling.setTimeoutMilliseconds(10);
+ resolver.addXMPPClientService("foo.com", host1);
+
+ testling.start();
+ eventLoop.processEvents();
+ timerFactory.setTime(10);
+ eventLoop.processEvents();
+
+ assertEquals(1, (connections.size()));
+ assertNotNull(connections.get(0));
+ assertNull((DomainNameResolveError)(error));
+ }
+
+ @Test
+ public void testStop_DuringSRVQuery() {
+ Connector testling = createConnector();
+ resolver.addXMPPClientService("foo.com", host1);
+
+ testling.start();
+ testling.stop();
+
+ eventLoop.processEvents();
+
+ assertEquals(1, (connections.size()));
+ assertNull(connections.get(0));
+ assertNotNull((DomainNameResolveError)(error));
+ }
+
+ @Test
+ public void testStop_Timeout() {
+ Connector testling = createConnector();
+ testling.setTimeoutMilliseconds(10);
+ resolver.addXMPPClientService("foo.com", host1);
+
+ testling.start();
+ testling.stop();
+
+ eventLoop.processEvents();
+ timerFactory.setTime(10);
+ eventLoop.processEvents();
+
+ assertEquals(1, (connections.size()));
+ assertNull(connections.get(0));
+ }
+} \ No newline at end of file
diff --git a/test/com/isode/stroke/network/HostAddressTest.java b/test/com/isode/stroke/network/HostAddressTest.java
new file mode 100644
index 0000000..f7fd426
--- /dev/null
+++ b/test/com/isode/stroke/network/HostAddressTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2010 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+/*
+ * Copyright (c) 2015 Tarun Gupta.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+package com.isode.stroke.network;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+import org.junit.Before;
+import com.isode.stroke.base.SafeByteArray;
+import com.isode.stroke.network.HostAddress;
+
+public class HostAddressTest {
+
+ @Test
+ public void testConstructor() {
+ HostAddress testling = new HostAddress("192.168.1.254");
+
+ assertEquals(("192.168.1.254"), testling.toString());
+ assertTrue(testling.isValid());
+ }
+
+ @Test
+ public void testConstructor_Invalid() {
+ HostAddress testling = new HostAddress();
+
+ assertFalse(testling.isValid());
+ }
+
+ @Test
+ public void testConstructor_InvalidString() {
+ HostAddress testling = new HostAddress("invalid");
+
+ assertFalse(testling.isValid());
+ }
+
+ @Test
+ public void testToString() {
+ char address[] = {10, 0, 1, 253};
+ HostAddress testling = new HostAddress(address, 4);
+
+ assertEquals(("10.0.1.253"), testling.toString());
+ }
+
+ @Test
+ public void testToString_IPv6() {
+ char address[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17};
+ HostAddress testling = new HostAddress(address, 16);
+
+ assertEquals(("102:304:506:708:90a:b0c:d0e:f11"), testling.toString());
+ }
+
+ @Test
+ public void testToString_Invalid() {
+ HostAddress testling = new HostAddress();
+
+ assertEquals("<no address>", testling.toString());
+ }
+}
+