diff options
author | 2016-05-07 19:57:10 +0300 | |
---|---|---|
committer | 2016-05-07 19:57:10 +0300 | |
commit | b1d5d5801e90ef0d4e282a78543f1435b8b7d223 (patch) | |
tree | 70dcd3a4a67c4a15847b3c17357897709f2334ee /src/main/java/com/juick/xmpp/s2s/ConnectionOut.java | |
parent | f2a2660e753fa11478fd3edadfdff9c000b22cc9 (diff) |
STARTTLS
Diffstat (limited to 'src/main/java/com/juick/xmpp/s2s/ConnectionOut.java')
-rw-r--r-- | src/main/java/com/juick/xmpp/s2s/ConnectionOut.java | 186 |
1 files changed, 102 insertions, 84 deletions
diff --git a/src/main/java/com/juick/xmpp/s2s/ConnectionOut.java b/src/main/java/com/juick/xmpp/s2s/ConnectionOut.java index 59fdfb60..4ebeffb6 100644 --- a/src/main/java/com/juick/xmpp/s2s/ConnectionOut.java +++ b/src/main/java/com/juick/xmpp/s2s/ConnectionOut.java @@ -1,140 +1,158 @@ package com.juick.xmpp.s2s; +import com.juick.xmpp.extensions.StreamFeatures; import com.juick.xmpp.utils.XmlUtils; import java.io.EOFException; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; +import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.Channels; import java.nio.channels.CompletionHandler; +import java.util.concurrent.ExecutionException; import java.util.logging.Level; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLSocket; + /** - * * @author ugnich */ -public class ConnectionOut extends Connection { +public class ConnectionOut extends Connection implements Runnable { public boolean streamReady = false; public String to; String checkSID = null; String dbKey = null; - public ConnectionOut(String hostname) { + public ConnectionOut(String hostname) throws Exception { super(); to = hostname; } - public ConnectionOut(String hostname, String checkSID, String dbKey) { + public ConnectionOut(String hostname, String checkSID, String dbKey) throws Exception { super(); to = hostname; this.checkSID = checkSID; this.dbKey = dbKey; } - public void parseStream() { - LOGGER.info("STREAM TO " + to + " START"); + void sendOpenStream() throws IOException { + sendStanza("<?xml version='1.0'?><stream:stream xmlns='jabber:server' " + + "xmlns:stream='http://etherx.jabber.org/streams' xmlns:db='jabber:server:dialback' from='" + + XMPPComponent.HOSTNAME + "' to='" + to + "' version='1.0'>"); + } + + void processDialback() throws Exception { + if (checkSID != null) { + sendDialbackVerify(checkSID, dbKey); + } + sendStanza("<db:result from='" + XMPPComponent.HOSTNAME + "' to='" + to + "'>" + + generateDialbackKey(to, XMPPComponent.HOSTNAME, streamID) + "</db:result>"); + } + @Override + public void run() { + LOGGER.info("STREAM TO " + to + " START"); try { HostnamePort addr = DNSQueries.getServerAddress(to); - socket = AsynchronousSocketChannel.open(); - socket.connect(new InetSocketAddress(addr.hostname, addr.port), socket, new CompletionHandler<Void, AsynchronousSocketChannel>() { - @Override - public void completed(Void result, AsynchronousSocketChannel attachment) { - try { - parser.setInput(new InputStreamReader(Channels.newInputStream(socket))); + socket = new Socket(InetAddress.getByName(addr.hostname), addr.port); + parser.setInput(new InputStreamReader(socket.getInputStream())); - writer = new OutputStreamWriter(Channels.newOutputStream(socket)); + writer = new OutputStreamWriter(socket.getOutputStream()); - sendStanza("<?xml version='1.0'?><stream:stream xmlns='jabber:server' " + - "xmlns:stream='http://etherx.jabber.org/streams' xmlns:db='jabber:server:dialback' from='" + - XMPPComponent.HOSTNAME + "' to='" + to + "' version='1.0'>"); + sendOpenStream(); - parser.next(); // stream:stream - streamID = parser.getAttributeValue(null, "id"); - if (streamID == null || streamID.isEmpty()) { - throw new Exception("STREAM TO " + to + " INVALID FIRST PACKET"); - } + parser.next(); // stream:stream + streamID = parser.getAttributeValue(null, "id"); + if (streamID == null || streamID.isEmpty()) { + throw new Exception("STREAM TO " + to + " INVALID FIRST PACKET"); + } - LOGGER.info("STREAM TO " + to + " " + streamID + " OPEN"); - XMPPComponent.addConnectionOut(ConnectionOut.this); + LOGGER.info("STREAM TO " + to + " " + streamID + " OPEN"); + XMPPComponent.addConnectionOut(ConnectionOut.this); - if (checkSID != null) { - sendDialbackVerify(checkSID, dbKey); + while (parser.next() != XmlPullParser.END_DOCUMENT) { + if (parser.getEventType() != XmlPullParser.START_TAG) { + continue; + } + logParser(); + + String tag = parser.getName(); + if (tag.equals("result") && parser.getNamespace().equals(NS_DB)) { + String type = parser.getAttributeValue(null, "type"); + if (type != null && type.equals("valid")) { + streamReady = true; + LOGGER.info("STREAM TO " + to + " " + streamID + " READY"); + + String cache = XMPPComponent.getFromCache(to); + if (cache != null) { + LOGGER.info("STREAM TO " + to + " " + streamID + " SENDING CACHE"); + sendStanza(cache); } - sendStanza("<db:result from='" + XMPPComponent.HOSTNAME + "' to='" + to + "'>" + generateDialbackKey(to, XMPPComponent.HOSTNAME, streamID) + "</db:result>"); - - while (parser.next() != XmlPullParser.END_DOCUMENT) { - if (parser.getEventType() != XmlPullParser.START_TAG) { - continue; - } - logParser(); - - String tag = parser.getName(); - if (tag.equals("db:result")) { - String type = parser.getAttributeValue(null, "type"); - if (type != null && type.equals("valid")) { - streamReady = true; - LOGGER.info("STREAM TO " + to + " " + streamID + " READY"); - - String cache = XMPPComponent.getFromCache(to); - if (cache != null) { - LOGGER.info("STREAM TO " + to + " " + streamID + " SENDING CACHE"); - sendStanza(cache); - } - - } else { - LOGGER.info("STREAM TO " + to + " " + streamID + " DIALBACK FAIL"); - } - XmlUtils.skip(parser); - } else if (tag.equals("db:verify")) { - String from = parser.getAttributeValue(null, "from"); - String type = parser.getAttributeValue(null, "type"); - String sid = parser.getAttributeValue(null, "id"); - if (from != null && from.equals(to) && sid != null && !sid.isEmpty() && type != null) { - ConnectionIn c = XMPPComponent.getConnectionIn(sid); - if (c != null) { - c.sendDialbackResult(from, type); - } - } - XmlUtils.skip(parser); - } else { - LOGGER.info("STREAM TO " + to + " " + streamID + ": " + XmlUtils.parseToString(parser, true)); - } + } else { + LOGGER.info("STREAM TO " + to + " " + streamID + " DIALBACK FAIL"); + } + XmlUtils.skip(parser); + } else if (tag.equals("verify") && parser.getNamespace().equals(NS_DB)) { + String from = parser.getAttributeValue(null, "from"); + String type = parser.getAttributeValue(null, "type"); + String sid = parser.getAttributeValue(null, "id"); + if (from != null && from.equals(to) && sid != null && !sid.isEmpty() && type != null) { + ConnectionIn c = XMPPComponent.getConnectionIn(sid); + if (c != null) { + c.sendDialbackResult(from, type); } - - LOGGER.warning("STREAM TO " + to + " " + streamID + " FINISHED"); - XMPPComponent.removeConnectionOut(ConnectionOut.this); - closeConnection(); - } catch (EOFException eofex) { - LOGGER.info(String.format("STREAM %s %s CLOSED (dirty)", to, streamID)); - XMPPComponent.removeConnectionOut(ConnectionOut.this); - closeConnection(); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, "s2s out exception", e); - XMPPComponent.removeConnectionOut(ConnectionOut.this); + } + XmlUtils.skip(parser); + } else if (tag.equals("features") && parser.getNamespace().equals(NS_STREAM)) { + StreamFeatures features = StreamFeatures.parse(parser); + if (!isSecured() && features.STARTTLS >= 0) { + System.out.println("STREAM TO " + to + " " + streamID + " SECURING"); + sendStanza("<starttls xmlns=\"" + NS_TLS + "\" />"); + } else { + processDialback(); + } + } else if (tag.equals("proceed") && parser.getNamespace().equals(NS_TLS)) { + try { + socket = sc.getSocketFactory().createSocket(socket, socket.getInetAddress().getHostAddress(), + socket.getPort(), true); + ((SSLSocket) socket).startHandshake(); + setSecured(true); + System.out.println("STREAM " + streamID + " SECURED"); + restartParser(); + sendOpenStream(); + } catch (SSLException sex) { + System.err.println("STREAM " + streamID + " SSL ERROR"); + sendStanza("<failed xmlns\"" + NS_TLS + "\" />"); + XMPPComponent.removeConnectionOut(this); closeConnection(); } + } else if (isSecured() && tag.equals("stream") && parser.getNamespace().equals(NS_STREAM)) { + streamID = parser.getAttributeValue(null, "id"); + } else { + LOGGER.info("STREAM TO " + to + " " + streamID + ": " + XmlUtils.parseToString(parser, true)); } + } - @Override - public void failed(Throwable exc, AsynchronousSocketChannel attachment) { - LOGGER.log(Level.WARNING, "s2s out failed", exc); - XMPPComponent.removeConnectionOut(ConnectionOut.this); - closeConnection(); - } - }); + LOGGER.warning("STREAM TO " + to + " " + streamID + " FINISHED"); + XMPPComponent.removeConnectionOut(ConnectionOut.this); + closeConnection(); + } catch (EOFException eofex) { + LOGGER.info(String.format("STREAM %s %s CLOSED (dirty)", to, streamID)); + XMPPComponent.removeConnectionOut(ConnectionOut.this); + closeConnection(); } catch (Exception e) { - LOGGER.warning(e.toString()); - XMPPComponent.removeConnectionOut(this); + LOGGER.log(Level.SEVERE, "s2s out exception", e); + XMPPComponent.removeConnectionOut(ConnectionOut.this); closeConnection(); } } |