Skip to content

Commit 32e200b

Browse files
committed
QFJ-285 Add proxy support (compatible with SSL)
1 parent 9fbce5a commit 32e200b

File tree

5 files changed

+339
-19
lines changed

5 files changed

+339
-19
lines changed

quickfixj-core/src/main/java/quickfix/Initiator.java

+48
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,52 @@ public interface Initiator extends Connector {
6868
* @see quickfix.SessionFactory#SETTING_CONNECTION_TYPE
6969
*/
7070
String SETTING_SOCKET_LOCAL_PORT = "SocketLocalPort";
71+
72+
/**
73+
* Initiator setting for proxy type. Only valid when session connection
74+
* type is "initiator".
75+
*/
76+
String SETTING_PROXY_TYPE = "ProxyType";
77+
78+
/**
79+
* Initiator setting for proxy version. Only valid when session connection
80+
* type is "initiator". - http 1.0 / 1.1
81+
*/
82+
String SETTING_PROXY_VERSION = "ProxyVersion";
83+
84+
/**
85+
* Initiator setting for proxy host. Only valid when session connection
86+
* type is "initiator".
87+
*/
88+
String SETTING_PROXY_HOST = "ProxyHost";
89+
90+
/**
91+
* Initiator setting for proxy port. Only valid when session connection
92+
* type is "initiator".
93+
*/
94+
String SETTING_PROXY_PORT = "ProxyPort";
95+
96+
/**
97+
* Initiator setting for proxy port. Only valid when session connection
98+
* type is "initiator".
99+
*/
100+
String SETTING_PROXY_USER = "ProxyUser";
101+
102+
/**
103+
* Initiator setting for proxy port. Only valid when session connection
104+
* type is "initiator".
105+
*/
106+
String SETTING_PROXY_PASSWORD = "ProxyPassword";
107+
108+
/**
109+
* Initiator setting for proxy domain. Only valid when session connection
110+
* type is "initiator".
111+
*/
112+
String SETTING_PROXY_DOMAIN = "ProxyDomain";
113+
114+
/**
115+
* Initiator setting for proxy workstation. Only valid when session connection
116+
* type is "initiator".
117+
*/
118+
String SETTING_PROXY_WORKSTATION = "ProxyWorkstation";
71119
}

quickfixj-core/src/main/java/quickfix/mina/ProtocolFactory.java

+117-1
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,28 @@
2121

2222
import java.net.InetSocketAddress;
2323
import java.net.SocketAddress;
24+
import java.util.ArrayList;
25+
import java.util.List;
26+
import java.util.HashMap;
27+
2428

2529
import org.apache.mina.core.service.IoAcceptor;
2630
import org.apache.mina.core.service.IoConnector;
31+
import org.apache.mina.transport.socket.SocketConnector;
2732
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
2833
import org.apache.mina.transport.socket.nio.NioSocketConnector;
2934
import org.apache.mina.transport.vmpipe.VmPipeAcceptor;
3035
import org.apache.mina.transport.vmpipe.VmPipeAddress;
3136
import org.apache.mina.transport.vmpipe.VmPipeConnector;
37+
import org.apache.mina.proxy.ProxyConnector;
38+
import org.apache.mina.proxy.handlers.ProxyRequest;
39+
import org.apache.mina.proxy.handlers.http.HttpAuthenticationMethods;
40+
import org.apache.mina.proxy.handlers.http.HttpProxyConstants;
41+
import org.apache.mina.proxy.handlers.http.HttpProxyRequest;
42+
import org.apache.mina.proxy.handlers.socks.SocksProxyConstants;
43+
import org.apache.mina.proxy.handlers.socks.SocksProxyRequest;
44+
import org.apache.mina.proxy.session.ProxyIoSession;
45+
3246

3347
import quickfix.ConfigError;
3448
import quickfix.RuntimeError;
@@ -58,7 +72,7 @@ public static String getTypeString(int type) {
5872

5973
public static SocketAddress createSocketAddress(int transportType, String host,
6074
int port) throws ConfigError {
61-
if (transportType == SOCKET) {
75+
if (transportType == SOCKET || transportType == PROXY) {
6276
return host != null ? new InetSocketAddress(host, port) : new InetSocketAddress(port);
6377
} else if (transportType == VM_PIPE) {
6478
return new VmPipeAddress(port);
@@ -102,6 +116,108 @@ public static IoAcceptor createIoAcceptor(int transportType) {
102116
}
103117
}
104118

119+
public static ProxyConnector createIoProxyConnector(SocketConnector socketConnector,
120+
InetSocketAddress address,
121+
InetSocketAddress proxyAddress,
122+
String proxyType,
123+
String proxyVersion,
124+
String proxyUser,
125+
String proxyPassword,
126+
String proxyDomain,
127+
String proxyWorkstation ) throws ConfigError {
128+
129+
// Create proxy connector.
130+
ProxyRequest req;
131+
132+
ProxyConnector connector = new ProxyConnector(socketConnector);
133+
connector.setConnectTimeoutMillis(5000);
134+
135+
if (proxyType.equalsIgnoreCase("http")) {
136+
req = createHttpProxyRequest(address, proxyVersion, proxyUser, proxyDomain, proxyWorkstation);
137+
} else if (proxyType.equalsIgnoreCase("socks")) {
138+
req = createSocksProxyRequest(address, proxyVersion, proxyUser, proxyPassword);
139+
} else {
140+
throw new ConfigError("Proxy type must be http or socks");
141+
}
142+
143+
ProxyIoSession proxyIoSession = new ProxyIoSession(proxyAddress, req);
144+
145+
List<HttpAuthenticationMethods> l = new ArrayList<>();
146+
l.add(HttpAuthenticationMethods.NO_AUTH);
147+
l.add(HttpAuthenticationMethods.DIGEST);
148+
l.add(HttpAuthenticationMethods.BASIC);
149+
150+
proxyIoSession.setPreferedOrder(l);
151+
connector.setProxyIoSession(proxyIoSession);
152+
153+
return connector;
154+
}
155+
156+
157+
private static ProxyRequest createHttpProxyRequest(InetSocketAddress address,
158+
String proxyVersion,
159+
String proxyUser,
160+
String proxyDomain,
161+
String proxyWorkstation) {
162+
String uri = "http://" + address.getAddress().getHostAddress() + ":" + address.getPort();
163+
HashMap<String, String> props = new HashMap<>();
164+
props.put(HttpProxyConstants.USER_PROPERTY, proxyUser);
165+
props.put(HttpProxyConstants.PWD_PROPERTY, proxyUser);
166+
if (proxyDomain != null && proxyWorkstation != null) {
167+
props.put(HttpProxyConstants.DOMAIN_PROPERTY, proxyDomain);
168+
props.put(HttpProxyConstants.WORKSTATION_PROPERTY, proxyWorkstation);
169+
}
170+
171+
HttpProxyRequest req = new HttpProxyRequest(uri);
172+
req.setProperties(props);
173+
if (proxyVersion != null && proxyVersion.equalsIgnoreCase("1.1")) {
174+
req.setHttpVersion(HttpProxyConstants.HTTP_1_1);
175+
} else {
176+
req.setHttpVersion(HttpProxyConstants.HTTP_1_0);
177+
}
178+
179+
return req;
180+
}
181+
182+
183+
private static ProxyRequest createSocksProxyRequest(InetSocketAddress address,
184+
String proxyVersion,
185+
String proxyUser,
186+
String proxyPassword) throws ConfigError {
187+
SocksProxyRequest req;
188+
if (proxyVersion.equalsIgnoreCase("4")) {
189+
req = new SocksProxyRequest(
190+
SocksProxyConstants.SOCKS_VERSION_4,
191+
SocksProxyConstants.ESTABLISH_TCPIP_STREAM,
192+
address,
193+
proxyUser);
194+
195+
} else if (proxyVersion.equalsIgnoreCase("4a")) {
196+
req = new SocksProxyRequest(
197+
SocksProxyConstants.ESTABLISH_TCPIP_STREAM,
198+
address.getAddress().getHostAddress(),
199+
address.getPort(),
200+
proxyUser);
201+
202+
} else if (proxyVersion.equalsIgnoreCase("5")) {
203+
req = new SocksProxyRequest(
204+
SocksProxyConstants.SOCKS_VERSION_5,
205+
SocksProxyConstants.ESTABLISH_TCPIP_STREAM,
206+
address,
207+
proxyUser);
208+
209+
} else {
210+
throw new ConfigError("SOCKS ProxyType must be 4,4a or 5");
211+
}
212+
213+
if (proxyPassword != null) {
214+
req.setPassword(proxyPassword);
215+
}
216+
217+
return req;
218+
}
219+
220+
105221
public static IoConnector createIoConnector(SocketAddress address) throws ConfigError {
106222
if (address instanceof InetSocketAddress) {
107223
return new NioSocketConnector();

quickfixj-core/src/main/java/quickfix/mina/initiator/AbstractSocketInitiator.java

+39-3
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,46 @@ protected void createSessionInitiators()
104104
sslConfig = SSLSupport.getSslConfig(getSettings(), sessionID);
105105
}
106106

107+
String proxyUser = null;
108+
String proxyPassword = null;
109+
String proxyHost = null;
110+
111+
String proxyType = null;
112+
String proxyVersion = null;
113+
114+
String proxyWorkstation = null;
115+
String proxyDomain = null;
116+
117+
int proxyPort = -1;
118+
119+
if (getSettings().isSetting(sessionID, Initiator.SETTING_PROXY_TYPE)) {
120+
proxyType = settings.getString(sessionID, Initiator.SETTING_PROXY_TYPE);
121+
if (getSettings().isSetting(sessionID, Initiator.SETTING_PROXY_VERSION)) {
122+
proxyVersion = settings.getString(sessionID,
123+
Initiator.SETTING_PROXY_VERSION);
124+
}
125+
126+
if (getSettings().isSetting(sessionID, Initiator.SETTING_PROXY_USER)) {
127+
proxyUser = settings.getString(sessionID, Initiator.SETTING_PROXY_USER);
128+
proxyPassword = settings.getString(sessionID,
129+
Initiator.SETTING_PROXY_PASSWORD);
130+
}
131+
if (getSettings().isSetting(sessionID, Initiator.SETTING_PROXY_WORKSTATION)
132+
&& getSettings().isSetting(sessionID, Initiator.SETTING_PROXY_DOMAIN)) {
133+
proxyWorkstation = settings.getString(sessionID,
134+
Initiator.SETTING_PROXY_WORKSTATION);
135+
proxyDomain = settings.getString(sessionID, Initiator.SETTING_PROXY_DOMAIN);
136+
}
137+
138+
proxyHost = settings.getString(sessionID, Initiator.SETTING_PROXY_HOST);
139+
proxyPort = (int) settings.getLong(sessionID, Initiator.SETTING_PROXY_PORT);
140+
}
141+
107142
final IoSessionInitiator ioSessionInitiator = new IoSessionInitiator(session,
108-
socketAddresses, localAddress, reconnectingIntervals, getScheduledExecutorService(),
109-
networkingOptions, getEventHandlingStrategy(), getIoFilterChainBuilder(),
110-
sslEnabled, sslConfig);
143+
socketAddresses, localAddress, reconnectingIntervals,
144+
getScheduledExecutorService(), networkingOptions,
145+
getEventHandlingStrategy(), getIoFilterChainBuilder(), sslEnabled, sslConfig,
146+
proxyType, proxyVersion, proxyHost, proxyPort, proxyUser, proxyPassword, proxyDomain, proxyWorkstation);
111147

112148
initiators.add(ioSessionInitiator);
113149
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*******************************************************************************
2+
* Copyright (c) quickfixengine.org All rights reserved.
3+
*
4+
* This file is part of the QuickFIX FIX Engine
5+
*
6+
* This file may be distributed under the terms of the quickfixengine.org
7+
* license as defined by quickfixengine.org and appearing in the file
8+
* LICENSE included in the packaging of this file.
9+
*
10+
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
11+
* THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
12+
* PARTICULAR PURPOSE.
13+
*
14+
* See http://www.quickfixengine.org/LICENSE for licensing information.
15+
*
16+
* Contact [email protected] if any conditions of this licensing
17+
* are not clear to you.
18+
******************************************************************************/
19+
20+
package quickfix.mina.initiator;
21+
22+
import org.apache.mina.core.session.IoSession;
23+
import org.apache.mina.proxy.AbstractProxyIoHandler;
24+
25+
import quickfix.mina.ssl.SSLFilter;
26+
27+
class InitiatorProxyIoHandler extends AbstractProxyIoHandler {
28+
private final InitiatorIoHandler initiatorIoHandler;
29+
private final SSLFilter sslFilter;
30+
31+
InitiatorProxyIoHandler(InitiatorIoHandler initiatorIoHandler, SSLFilter sslFilter) {
32+
super();
33+
this.initiatorIoHandler = initiatorIoHandler;
34+
this.sslFilter = sslFilter;
35+
}
36+
37+
@Override
38+
public void sessionCreated(IoSession session) throws Exception {
39+
this.initiatorIoHandler.sessionCreated(session);
40+
}
41+
42+
@Override
43+
public void sessionClosed(IoSession ioSession) throws Exception {
44+
this.initiatorIoHandler.sessionClosed(ioSession);
45+
}
46+
47+
@Override
48+
public void messageReceived(IoSession session, Object message) throws Exception {
49+
this.initiatorIoHandler.messageReceived(session, message);
50+
}
51+
52+
@Override
53+
public void messageSent(IoSession session, Object message) throws Exception {
54+
this.initiatorIoHandler.messageSent(session, message);
55+
}
56+
57+
@Override
58+
public void exceptionCaught(IoSession ioSession, Throwable cause) throws Exception {
59+
this.initiatorIoHandler.exceptionCaught(ioSession, cause);
60+
}
61+
62+
@Override
63+
public void proxySessionOpened(IoSession ioSession) throws Exception {
64+
if (this.sslFilter != null) {
65+
this.sslFilter.initiateHandshake(ioSession);
66+
}
67+
}
68+
}

0 commit comments

Comments
 (0)