Need Applet Proxy - Proposed Code

I am trying to develop an applet that uses Jabber & Smack as its message transport. Unfortunately, the Jabber server must reside on a different server, and the applet (when used in demo mode) really wants to remain unsigned.

Is there an existing Java (server-side) forwarder/proxy that would take care of this?

Not having found one, and looking over the code in XMPPConnection and SSLXMPPConnection, it appears that currently the code expects to always open a socket to a destination with the same host name as the user’'s ID. Whereas a proxy/forwarder would want these as different.

The following code change would facilitate this by allowing creation of a factory class that could derive anonimous extentions to XMPPConnection that would allow for easy overrides with custom Socket creation logic.

Basicly changing the core constructor of XMPPConnection to:

public XMPPConnection(String host, int port) throws XMPPException {

this.host = host;

this.port = port;

this.socket = createSocket(host, port);

init();

}

And isolating the socket creation logic in:

public Socket createSocket(String host, int port) throws XMPPException {

Socket s;

try {

s = new Socket(host, port);

}

catch (UnknownHostException uhe) {

throw new XMPPException(

"Could not connect to " + host + “:” + port + “.”,

new XMPPError(504),

uhe);

}

catch (IOException ioe) {

throw new XMPPException(

"XMPPError connecting to " + host + “:” + port + “.”,

new XMPPError(502),

ioe);

}

return s;

}

The factored out createSocket() would allow code such as:

new XMPPConnection(“host”, sockNum)

{ public Socket createSocket(String host, int port) throws XMPPException

{ return … create_my_custom_proxy_socket(host, port);

}

};

As best I can tell, this should let me create a custom proxy socket, and do any initialization in a maner transparent to the rest of Smack.

Have I missed something in the Smack library? Is this covered in some other way?

Harrison

I’‘m a bit confused about the custom socket you’‘d create. What is a proxy socket. Perhaps if you can explain the technical details a bit more, I’‘ll understand how making this change can solve the problem you’'re running into.

Thanks,

Matt

The way I implemented proxy support into Smack is by adding a new option to the SmackConfiguration class to hold the SocketFactory.

I can post code if you want, but it’‘s actually trivial to implement it yourself. I didn’'t implement the configuration parsing, just the getter/setter methods.

I’'d like to see that into the main code, though, so if the team is interested I can see how to add the configuration parsing stuff.

Further thought has also led me to think that a SocketFactory approach is more appropriate than my first sample. However I was thinking of perhaps adding a new constructor to XMPPConnection that took as an additional argument the SocketFactory. However, I like the idea of putting the details in the config.

(My original approach was ok for testing but left no easy way to reconfigure post compile.)

A ProxySocket socket factory would know how to open a socket to a proxy/forwarder on the applet server, then would authenticate, and pass the ultimate destination to the forwarder. The forwarder would forward (both ways) all subsequent packets until the connection was closed. The socket factory would then pass the socket back to XMPPConnection, which would know nothing about the special actions of the returned Socket. All of this is to satisfy the Applet sandbox constraint that restricts unsigned applets to only opening sockets back to the server the applet came from.

Also the SSL support could be refactored to be just a special socket factory passed to XMPPConnection.

Yes the code changes are pretty simple but it would be nice to have them in the official code base.

Thanks

Harrison

I’'d be interested in seeing some specific API proposals from people so that we can consider adding this feature into the official codebase.

Also, it would be great to have sample code for the proxy socket for use in an applet. Others might find that quite useful.

Thanks!

-Matt

All modifications went into SmackConfiguration exclusively.

  1. I added the following member variable:

private static SocketFactory socketFactory = null;

  1. I added the corresponding getter/setter:

/**

  • Returns the socket factory used for XMPP connections (not-SSL).

  • @return a socket factory.

*/

public static SocketFactory getSocketFactory() {

// Return the default value factory if socketFactory has not been initialized yet

if (null == socketFactory) {

return SocketFactory.getDefault();

}

return socketFactory;

}

/**

  • Sets the socket factory used for XMPP connections (not-SSL).

  • @param factory a socket factory.

*/

public static void setSocketFactory(SocketFactory factory) {

socketFactory = factory;

}

I forgot to add that this line is required in XMPPConnection’'s constructor:

try {

this.socket = SmackConfiguration.getSocketFactory().createSocket(host, port);

}

This sounds like a worthy change. I’'ll investigate adding it to the main codebase.

Thanks,

Matt

The way I actually implemented this is a bit different. There is a new constructor in XMPPConnection that takes a host, port, and SocketFactory. I thought this was better than making it a SmackConfiguration setting since most SocketFactory instances probably won’'t work with a default constructor. The other great thing about this change is that SSLXMPPConnection is now implemented more cleanly.

Regards,

Matt

Thanks for adding the changes. I’‘ve been working to come up with actual samples of proxy/tunneling socket factories. (I’'ve sidestepped my need for the moment.)

In looking over tunneling code (samples at Sun, and the Java TightVNC client) I’'ve come to realize that as far as tunneling goes, the universal tunnel (tunnel through http) has performance drawbacks, while faster tunnels are more limited in the circumstances where they will work.

This has led be to envision a socket factory that will try to establish a connection via each of several tunnel implementation, until it finds the fastest that will work in the current circumstances.

This in turn led me to put the host and port in the socket factory constructor. This is because I anticipate a ‘‘Multi’’ socket factory that has a list of other socket factories. When asked for a socket factory, this Multi socket factory would try each on its list, until it found one that would work.

Each of the individual socket factories (in the Multi factory list) might point to a different port (or even a different host) e.g. Jabber port, http port, … This led me to factor the host and port to the socket factory constructor (and for convience, seperate mutators for the socket factory.)

My application is trying to use the Jabber transport for various async notification tasks. My goal is to be able to provide an on-line demo, via an unsigned Java applet. I’‘ll have no advanced knowledge of the firewall that the applet must communicate through, and I don’'t want the applet to have to ask the user for extra priviledges.

Thanks again for including the socket factory.

Harrison

Harrison,

One thing we discussed yesterday was the possibility of implementing JEP-25 (HTTP Polling) as a SocketFactory. JEP-25 should work with virtually any firewall so would be a great feature to have. The basic design would be:

  • Write a servlet that acts as a proxy between an XMPP server and clients. The servlet should implement JEP-25.

  • Write a SocketFactory that has sockets that communicate with the servlet.

  • Incoming packets should be easy to handle – http polls can be turned into a InputStream.

  • The outgoing stream would need to go through an XML parser to divide the stream into packets. This is sort of a pain, but not terribly difficult.

Regards,

Matt

Any news on this feature? - Is it to be included in the upcoming 2.0 release? If this was included then we might switch to Jive as this feature is essential for our application.