/* * Tigase Jabber/XMPP Server * Copyright (C) 2004-2012 "Artur Hefczyc" <artur.hefczyc@tigase.org> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. Look for COPYING file in the top folder. * If not, see http://www.gnu.org/licenses/. * * $Rev$ * Last modified by $Author$ * $Date$ */ package tigase.server.xmppserver.proc; //~--- non-JDK imports -------------------------------------------------------- import tigase.net.ConnectionType; import tigase.server.xmppserver.CID; import tigase.server.xmppserver.CIDConnections; import tigase.server.xmppserver.LocalhostException; import tigase.server.xmppserver.NotLocalhostException; import tigase.server.xmppserver.S2SConnection; import tigase.server.xmppserver.S2SIOService; //~--- JDK imports ------------------------------------------------------------ import java.util.Map; import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; //~--- classes ---------------------------------------------------------------- /** * Created: Dec 9, 2010 1:59:56 PM * * @author <a href="mailto:artur.hefczyc@tigase.org">Artur Hefczyc</a> * @version $Rev$ */ public class StreamOpen extends S2SAbstractProcessor { private static final Logger log = Logger.getLogger(StreamOpen.class.getName()); // ~--- methods -------------------------------------------------------------- /** * Method description * * * @param serv */ @Override public void serviceStarted(S2SIOService serv) { switch (serv.connectionType()) { case connect: CID cid = (CID) serv.getSessionData().get("cid"); serv.getSessionData().put(S2SIOService.HOSTNAME_KEY, cid.getLocalHost()); // Send init xmpp stream here // XMPPIOService serv = (XMPPIOService)service; String data = "<stream:stream" + " xmlns:stream='http://etherx.jabber.org/streams'" + " xmlns='jabber:server'" + " xmlns:db='jabber:server:dialback'" + " from='" + cid.getLocalHost() + "'" + " to='" + cid.getRemoteHost() + "'" + " version='1.0'>"; if (log.isLoggable(Level.FINEST)) { log.log(Level.FINEST, "{0}, sending: {1}", new Object[] { serv, data }); } S2SConnection s2s_conn = (S2SConnection) serv.getSessionData().get(S2SIOService.S2S_CONNECTION_KEY); if (s2s_conn == null) { log.log(Level.WARNING, "Protocol error s2s_connection not set for outgoing connection: {0}", serv); serv.stop(); } else { s2s_conn.setS2SIOService(serv); serv.setS2SConnection(s2s_conn); } serv.xmppStreamOpen(data); break; default: // Do nothing, more data should come soon... break; } // end of switch (service.connectionType()) } /** * Method description * * * @param serv */ @Override public void serviceStopped(S2SIOService serv) { CID cid = (CID) serv.getSessionData().get("cid"); if (cid == null) { if (serv.connectionType() == ConnectionType.connect) { log.log(Level.WARNING, "Protocol error cid not set for outgoing connection: {0}", serv); } return; } try { CIDConnections cid_conns = handler.getCIDConnections(cid, false); if (cid_conns == null) { if (log.isLoggable(Level.FINE)) { log.log(Level.FINE, "Protocol error cid_conns not found for outgoing connection: {0}", serv); } return; } else { cid_conns.connectionStopped(serv); } } catch (NotLocalhostException ex) { log.log(Level.WARNING, "Not a local host for cid: {0}", cid); } catch (LocalhostException ex) { log.log(Level.WARNING, "A local host for cid: {0}", cid); } } /** * Method description * * * @param serv * @param attribs * * @return */ @Override public String streamOpened(S2SIOService serv, Map<String, String> attribs) { CID cid = (CID) serv.getSessionData().get("cid"); String remote_hostname = attribs.get("from"); String local_hostname = attribs.get("to"); String version = attribs.get(VERSION_ATT_NAME); if (version != null) { serv.getSessionData().put(VERSION_ATT_NAME, version); } if (cid == null) { if ((remote_hostname != null) && (local_hostname != null)) { cid = new CID(local_hostname, remote_hostname); } } try { CIDConnections cid_conns = handler.getCIDConnections(cid, false); switch (serv.connectionType()) { case connect: { // It must be always set for connect connection type String remote_id = attribs.get("id"); if (log.isLoggable(Level.FINEST)) { log.log(Level.FINEST, "{0}, Connect Stream opened for: {1}, session id{2}", new Object[] { serv, cid, remote_id }); } if (cid_conns == null) { // This should actually not happen. Let's be clear here about // handling unexpected // cases. log.log( Level.WARNING, "{0} This might be a bug in s2s code, should not happen." + " Missing CIDConnections for stream open to ''connect'' service type.", serv); generateStreamError(false, "internal-server-error", serv); return null; } if (log.isLoggable(Level.FINEST)) { log.log( Level.FINEST, "{0}, stream open for cid: {1}, outgoint: {2}, incoming: {3}", new Object[] { serv, cid, cid_conns.getOutgoingCount(), cid_conns.getIncomingCount() }); } serv.setSessionId(remote_id); return null; } case accept: { if (local_hostname != null) { serv.getSessionData().put(S2SIOService.HOSTNAME_KEY, local_hostname); } else { if (log.isLoggable(Level.FINEST)) { log.log(Level.FINEST, "{0}, Unknown local hostname.", serv); } } String id = UUID.randomUUID().toString(); serv.setSessionId(id); String stream_open = "<stream:stream" + " xmlns:stream='http://etherx.jabber.org/streams'" + " xmlns='jabber:server'" + " xmlns:db='jabber:server:dialback'" + " id='" + id + "'"; if (cid != null) { stream_open += " from='" + cid.getLocalHost() + "'" + " to='" + cid.getRemoteHost() + "'"; if (cid_conns == null) { cid_conns = handler.getCIDConnections(cid, true); } if (log.isLoggable(Level.FINEST)) { log.log(Level.FINEST, "{0}, Accept Stream opened for: {1}, session id: {2}", new Object[] { serv, cid, id }); } serv.getSessionData().put("cid", cid); cid_conns.addIncoming(serv); } else { if (log.isLoggable(Level.FINEST)) { log.log(Level.FINEST, "{0}, Accept Stream opened for unknown CID, session id: {1}", new Object[] { serv, id }); } } // Spec examples show that the version should always be included but // this seems to break some servers. if (FORCE_VERSION || attribs.containsKey("version")) { stream_open += " version='1.0'"; } stream_open += ">"; return stream_open; } default: log.log(Level.SEVERE, "{0}, Warning, program shouldn't reach that point.", serv); break; } // end of switch (serv.connectionType()) } catch (NotLocalhostException ex) { generateStreamError(false, "host-unknown", serv); } catch (LocalhostException ex) { generateStreamError(false, "invalid-from", serv); } return null; } } // ~ Formatted in Sun Code Convention // ~ Formatted by Jindent --- http://www.jindent.com