@Override public void timeOutExpired(Packet packet) { // If we still haven't received confirmation from the SM then // the packet either has been lost or the server is overloaded // In either case we disconnect the connection. log.warning("No response within time limit received for a packet: " + packet.toString()); BoshSession session = getBoshSession(packet.getFrom()); if (session != null) { log.fine("Closing session for timeout: " + session.getSid()); session.close(); if (log.isLoggable(Level.FINE)) { log.log( Level.FINE, "{0} : {1} ({2})", new Object[] { BOSH_OPERATION_TYPE.REMOVE, session.getSid(), "Closing session for timeout" }); } sessions.remove(session.getSid()); } else { log.info("Session does not exist for packet: " + packet.toString()); } }
@Override protected boolean writePacketToSocket(Packet packet) { BoshSession session = getBoshSession(packet.getTo()); if (session != null) { synchronized (session) { Queue<Packet> out_results = new ArrayDeque<Packet>(); session.processPacket(packet, out_results); addOutPackets(out_results, session); } return true; } else { log.info("Session does not exist for packet: " + packet.toString()); return false; } }
@Override protected JID changeDataReceiver( Packet packet, JID newAddress, String command_sessionId, XMPPIOService<Object> serv) { BoshSession session = getBoshSession(packet.getTo()); if (session != null) { String sessionId = session.getSessionId(); if (sessionId.equals(command_sessionId)) { JID old_receiver = session.getDataReceiver(); session.setDataReceiver(newAddress); return old_receiver; } else { log.info("Incorrect session ID, ignoring data redirect for: " + newAddress); } } return null; }
@Override public boolean addOutStreamClosed(Packet packet, BoshSession bs, boolean withTimeout) { packet.setPacketFrom(getFromAddress(bs.getSid().toString())); packet.setPacketTo(bs.getDataReceiver()); packet.initVars(packet.getPacketFrom(), packet.getPacketTo()); bs.close(); if (log.isLoggable(Level.FINEST)) { log.log( Level.FINEST, "{0} : {1} ({2})", new Object[] {BOSH_OPERATION_TYPE.REMOVE, bs.getSid(), "Closing bosh session"}); } sessions.remove(bs.getSid()); if (withTimeout) { return addOutPacketWithTimeout(packet, stoppedHandler, 15l, TimeUnit.SECONDS); } else { return addOutPacket(packet); } }
/** * Method adds packets to the output queue stamping it with the appropriate {@link BoshSession} * data * * @param out_results collection of {@link Packet} objects to be added to queue * @param bs related {@link BoshSession} */ protected void addOutPackets(Queue<Packet> out_results, BoshSession bs) { for (Packet res : out_results) { res.setPacketFrom(getFromAddress(bs.getSid().toString())); res.setPacketTo(bs.getDataReceiver()); if (res.getCommand() != null) { switch (res.getCommand()) { case STREAM_CLOSED: case GETFEATURES: res.initVars(res.getPacketFrom(), res.getPacketTo()); break; default: // Do nothing... } } addOutPacket(res); } out_results.clear(); }
@Override public boolean serviceStopped(XMPPIOService<Object> xmppService) { BoshIOService service = (BoshIOService) xmppService; boolean result = super.serviceStopped(service); UUID sid = service.getSid(); if (sid != null) { BoshSession bs = sessions.get(sid); if (bs != null) { if (log.isLoggable(Level.FINE)) { log.log( Level.FINE, "{0} : {1} ({2})", new Object[] {BOSH_OPERATION_TYPE.REMOVE, bs.getSid(), "Closing bosh session"}); } bs.disconnected(service); } } return result; }
@Override protected void processCommand(Packet packet) { BoshSession session = getBoshSession(packet.getTo()); switch (packet.getCommand()) { case USER_LOGIN: String jid = Command.getFieldValue(packet, "user-jid"); if (jid != null) { if (session != null) { try { BareJID fromJID = BareJID.bareJIDInstance(jid); BareJID hostJid = getSeeOtherHostForJID(fromJID, Phase.LOGIN); if (hostJid != null) { Element streamErrorElement = see_other_host_strategy.getStreamError( "urn:ietf:params:xml:ns:xmpp-streams", hostJid); Packet redirectPacket = Packet.packetInstance(streamErrorElement); redirectPacket.setPacketTo(packet.getTo()); writePacketToSocket(redirectPacket); session.sendWaitingPackets(); session.close(); if (log.isLoggable(Level.FINE)) { log.log( Level.FINE, "{0} : {1} ({2})", new Object[] { BOSH_OPERATION_TYPE.REMOVE, session.getSid(), "See other host" }); } sessions.remove(session.getSid()); } else { session.setUserJid(jid); } } catch (TigaseStringprepException ex) { log.log(Level.SEVERE, "user JID violates RFC6122 (XMPP:Address Format): ", ex); } } else { if (log.isLoggable(Level.FINE)) { log.log(Level.FINE, "Missing XMPPIOService for USER_LOGIN command: {0}", packet); } } } else { log.log(Level.WARNING, "Missing user-jid for USER_LOGIN command: {0}", packet); } break; case CLOSE: if (session != null) { if (log.isLoggable(Level.FINER)) { log.log(Level.FINER, "Closing session for command CLOSE: {0}", session.getSid()); } try { List<Element> err_el = packet.getElement().getChildrenStaticStr(Iq.IQ_COMMAND_PATH); if ((err_el != null) && (err_el.size() > 0)) { Element error = new Element("stream:error"); error.addChild(err_el.get(0)); Packet condition = Packet.packetInstance(error); condition.setPacketTo(packet.getTo()); writePacketToSocket(condition); session.sendWaitingPackets(); bosh_session_close_delay = 100; } } catch (TigaseStringprepException ex) { Logger.getLogger(BoshConnectionManager.class.getName()).log(Level.SEVERE, null, ex); } if (bosh_session_close_delay > 0) { try { Thread.sleep(bosh_session_close_delay); } catch (InterruptedException ex) { // Intentionally left blank } } session.close(); if (log.isLoggable(Level.FINE)) { log.log( Level.FINE, "{0} : {1} ({2})", new Object[] { BOSH_OPERATION_TYPE.REMOVE, session.getSid(), "Closing session for command CLOSE" }); } sessions.remove(session.getSid()); } else { if (log.isLoggable(Level.FINE)) { log.log(Level.FINE, "Session does not exist for packet: {0}", packet); } } break; case CHECK_USER_CONNECTION: if (session != null) { // It's ok, the session has been found, respond with OK. addOutPacket(packet.okResult((String) null, 0)); } else { // Session is no longer active, respond with an error. try { addOutPacket( Authorization.ITEM_NOT_FOUND.getResponseMessage(packet, "Connection gone.", false)); } catch (PacketErrorTypeException e) { // Hm, error already, ignoring... log.log(Level.INFO, "Error packet is not really expected here: {0}", packet); } } break; default: super.processCommand(packet); break; } // end of switch (pc.getCommand()) }
/** * Returns full jid of passed BoshSession instance * * @param bs {@link BoshSession} for which JID should be retrieved * @return JID address related to particular {@link BoshSession} */ @Override public JID getJidForBoshSession(BoshSession bs) { return getFromAddress(bs.getSid().toString()); }
@Override public Queue<Packet> processSocketData(XMPPIOService<Object> srv) { BoshIOService serv = (BoshIOService) srv; Packet p = null; while ((p = serv.getReceivedPackets().poll()) != null) { Queue<Packet> out_results = new ArrayDeque<Packet>(2); BoshSession bs = null; String sid_str = null; synchronized (sessions) { if (log.isLoggable(Level.FINER)) { log.log( Level.FINER, "Processing packet: {0}, type: {1}", new Object[] {p.getElemName(), p.getType()}); } if (log.isLoggable(Level.FINEST)) { log.log(Level.FINEST, "Processing socket data: {0}", p); } sid_str = p.getAttributeStaticStr(SID_ATTR); UUID sid = null; if (sid_str == null) { String hostname = p.getAttributeStaticStr(Packet.TO_ATT); if ((hostname != null) && isLocalDomain(hostname)) { if (!isAllowed(srv, hostname)) { if (log.isLoggable(Level.FINE)) { log.log(Level.FINE, "Policy violation. Closing connection: {0}", p); } try { serv.sendErrorAndStop(Authorization.NOT_ALLOWED, p, "Policy violation."); } catch (IOException e) { log.log( Level.WARNING, "Problem sending invalid hostname error for sid = " + sid, e); } } else { bs = new BoshSession( getDefVHostItem().getDomain(), JID.jidInstanceNS(routings.computeRouting(hostname)), this, sendNodeHostname ? getDefHostName().getDomain() : null, maxSessionWaitingPackets); sid = bs.getSid(); sessions.put(sid, bs); if (log.isLoggable(Level.FINE)) { log.log( Level.FINE, "{0} : {1} ({2})", new Object[] {BOSH_OPERATION_TYPE.CREATE, sid, "Socket bosh session"}); } } } else { try { serv.sendErrorAndStop(Authorization.NOT_ALLOWED, p, "Invalid hostname."); } catch (IOException e) { log.log(Level.WARNING, "Problem sending invalid hostname error for sid = " + sid, e); } } } else { try { sid = UUID.fromString(sid_str); bs = sessions.get(sid); } catch (IllegalArgumentException e) { log.log( Level.WARNING, "Problem processing socket data, sid = " + sid_str + " does not conform to the UUID string representation.", e); } } } try { if (bs != null) { synchronized (bs) { if (sid_str == null) { bs.init( p, serv, max_wait, min_polling, max_inactivity, concurrent_requests, hold_requests, max_pause, max_batch_size, batch_queue_timeout, out_results); } else { bs.processSocketPacket(p, serv, out_results); } } } else { if (log.isLoggable(Level.FINE)) { log.log( Level.FINE, "{0} : {1} ({2})", new Object[] {BOSH_OPERATION_TYPE.INVALID_SID, sid_str, "Invalid SID"}); } serv.sendErrorAndStop(Authorization.ITEM_NOT_FOUND, p, "Invalid SID"); } addOutPackets(out_results, bs); } catch (IOException e) { log.log(Level.WARNING, "Problem processing socket data for sid = " + sid_str, e); } // addOutPackets(out_results); } // end of while () return null; }
protected Map<String, String> preBindSession(Map<String, String> attr) { String hostname = attr.get(TO_ATTR); Queue<Packet> out_results = new ArrayDeque<Packet>(2); BoshSession bs = new BoshSession( getDefVHostItem().getDomain(), JID.jidInstanceNS(routings.computeRouting(hostname)), this, sendNodeHostname ? getDefHostName().getDomain() : null, maxSessionWaitingPackets); String jid = attr.get(FROM_ATTR); String uuid = UUID.randomUUID().toString(); JID userId = JID.jidInstanceNS(jid); if (null == userId.getResource()) { userId = userId.copyWithResourceNS(uuid); attr.put(FROM_ATTR, userId.toString()); bs.setUserJid(jid); } long rid = (long) (Math.random() * 10000000); attr.put(RID_ATTR, Long.toString(rid)); UUID sid = bs.getSid(); sessions.put(sid, bs); if (log.isLoggable(Level.FINE)) { log.log( Level.FINE, "{0} : {1} ({2})", new Object[] {BOSH_OPERATION_TYPE.CREATE, bs.getSid(), "Pre-bind"}); } attr.put(SID_ATTR, sid.toString()); Packet p = null; try { Element el = new Element("body"); el.setAttributes(attr); p = Packet.packetInstance(el); } catch (TigaseStringprepException ex) { Logger.getLogger(BoshConnectionManager.class.getName()).log(Level.SEVERE, null, ex); } bs.init( p, null, max_wait, min_polling, max_inactivity, concurrent_requests, hold_requests, max_pause, max_batch_size, batch_queue_timeout, out_results, true); addOutPackets(out_results, bs); attr.put("hostname", getDefHostName().toString()); return attr; }
@Override public boolean addOutStreamOpen(Packet packet, BoshSession bs) { packet.initVars(getFromAddress(bs.getSid().toString()), bs.getDataReceiver()); return addOutPacketWithTimeout(packet, startedHandler, 15l, TimeUnit.SECONDS); }