diff options
Diffstat (limited to 'src/com/isode')
45 files changed, 2205 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(); } |