Package tigase.server.bosh

Source Code of tigase.server.bosh.BoshConnectionManager$BoshTask

/*
* Tigase Jabber/XMPP Server
* Copyright (C) 2004-2007 "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 General Public License as published by
* the Free Software Foundation, either 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. Look for COPYING file in the top folder.
* If not, see http://www.gnu.org/licenses/.
*
* $Rev: 1246 $
* Last modified by $Author: kobit $
* $Date: 2008-11-28 17:27:36 +0000 (Fri, 28 Nov 2008) $
*/
package tigase.server.bosh;

import java.util.Map;
import java.util.LinkedHashMap;
import java.util.Queue;
import java.util.LinkedList;
import java.util.UUID;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
import tigase.server.Command;
import tigase.server.Packet;
import tigase.util.JIDUtils;
import tigase.xmpp.StanzaType;
import tigase.xmpp.Authorization;
import tigase.xmpp.XMPPIOService;
import tigase.xmpp.PacketErrorTypeException;
import tigase.server.xmppclient.ClientConnectionManager;

import static tigase.server.bosh.Constants.*;

/**
* Describe class BoshConnectionManager here.
*
*
* Created: Sat Jun  2 12:24:29 2007
*
* @author <a href="mailto:artur.hefczyc@tigase.org">Artur Hefczyc</a>
* @version $Rev: 1246 $
*/
public class BoshConnectionManager extends ClientConnectionManager
  implements BoshSessionTaskHandler {

  /**
   * Variable <code>log</code> is a class logger.
   */
  private static final Logger log =
    Logger.getLogger("tigase.server.bosh.BoshConnectionManager");

  private static final String ROUTINGS_PROP_KEY = "routings";
  private static final String ROUTING_MODE_PROP_KEY = "multi-mode";
  private static final boolean ROUTING_MODE_PROP_VAL = true;
  private static final String ROUTING_ENTRY_PROP_KEY = ".+";
  private static final String ROUTING_ENTRY_PROP_VAL = DEF_SM_NAME + "@localhost";

  private static final int DEF_PORT_NO = 5280;
  private int[] PORTS = {DEF_PORT_NO};
//   private static final String HOSTNAMES_PROP_KEY = "hostnames";
//   private String[] HOSTNAMES_PROP_VAL =  {"localhost", "hostname"};

//  private RoutingsContainer routings = null;
//   private Set<String> hostnames = new TreeSet<String>();
  private long max_wait = MAX_WAIT_DEF_PROP_VAL;
  private long min_polling = MIN_POLLING_PROP_VAL;
  private long max_inactivity = MAX_INACTIVITY_PROP_VAL;
  private int concurrent_requests = CONCURRENT_REQUESTS_PROP_VAL;
  private int hold_requests = HOLD_REQUESTS_PROP_VAL;
  private long max_pause = MAX_PAUSE_PROP_VAL;
  private Map<UUID, BoshSession> sessions =
    new LinkedHashMap<UUID, BoshSession>();

//   public void processPacket(Packet packet) {
//     log.finer("Processing packet: " + packet.getElemName()
//       + ", type: " + packet.getType());
//     log.finest("Processing packet: " + packet.toString());
//     if (packet.isCommand() && packet.getCommand() != Command.OTHER) {
//       processCommand(packet);
//     } else {
//       writePacketToSocket(packet);
//     }
//   }

  protected BoshSession getBoshSessionTo(Packet packet) {
    UUID sid = UUID.fromString(JIDUtils.getNodeResource(packet.getTo()));
    return sessions.get(sid);
  }

  protected void writePacketToSocket(Packet packet) {
    BoshSession session = getBoshSessionTo(packet);
    if (session != null) {
      Queue<Packet> out_results = new LinkedList<Packet>();
      session.processPacket(packet, out_results);
      addOutPackets(out_results, session);
    } else {
      log.warning("Session does not exist for packet: " + packet.toString());
      try {
        Packet error =
            Authorization.ITEM_NOT_FOUND.getResponseMessage(packet,
              "The user connection is no longer active.", true);
        addOutPacket(error);
      } catch (PacketErrorTypeException e) {
        log.finest("Ups, already error packet. Dropping it to prevent infinite loop.");
      }
      // In case the SessionManager lost synchronization for any reason, let's
      // notify it that the user connection no longer exists.
      Packet command = Command.STREAM_CLOSED.getPacket(null, null,
        StanzaType.set, "bosh-missing-1");
      command.setFrom(packet.getTo());
      command.setTo(packet.getFrom());
      log.fine("Sending a command to close the remote session for non-existen Bosh connection: " + command.toString());
      addOutPacket(command);
    }
  }

  protected void processCommand(Packet packet) {
    switch (packet.getCommand()) {
    case CLOSE:
      BoshSession session = getBoshSessionTo(packet);
      if (session != null) {
        log.fine("Closing session: " + session.getSid());
        session.close();
        sessions.remove(session.getSid());
      } else {
        log.warning("Session does not exist for packet: " + packet.toString());
      }
      break;
    default:
      super.processCommand(packet);
      break;
    } // end of switch (pc.getCommand())
  }

  protected String changeDataReceiver(Packet packet, String newAddress,
    String command_sessionId, XMPPIOService serv) {
    BoshSession session = getBoshSessionTo(packet);
    if (session != null) {
      String sessionId = session.getSessionId();
      if (sessionId.equals(command_sessionId)) {
        String old_receiver = session.getDataReceiver();
        session.setDataReceiver(newAddress);
        return old_receiver;
      } else {
        log.warning("Incorrect session ID, ignoring data redirect for: "
          + newAddress);
      }
    }
    return null;
  }

  public Queue<Packet> processSocketData(XMPPIOService srv) {
    BoshIOService serv = (BoshIOService)srv;
    Packet p = null;
    while ((p = serv.getReceivedPackets().poll()) != null) {
      log.finer("Processing packet: " + p.getElemName()
        + ", type: " + p.getType());
      log.finest("Processing socket data: " + p.toString());
      String sid_str = p.getAttribute(SID_ATTR);
      UUID sid = null;
      try {
        Queue<Packet> out_results = new LinkedList<Packet>();
        BoshSession bs = null;
        if (sid_str == null) {
          String hostname = p.getAttribute("to");
          if (hostname != null && isLocalDomain(hostname)) {
            bs = new BoshSession(getDefHostName(),
              routings.computeRouting(hostname), this);
            sid = bs.getSid();
            sessions.put(sid, bs);
            bs.init(p, serv, max_wait, min_polling, max_inactivity,
              concurrent_requests, hold_requests, max_pause, out_results);
          } else {
            log.warning("Invalid hostname. Closing invalid connection");
            serv.sendErrorAndStop(Authorization.NOT_ALLOWED, p, "Invalid hostname.");
          }
        } else {
          sid = UUID.fromString(sid_str);
          bs = sessions.get(sid);
          if (bs != null) {
            bs.processSocketPacket(p, serv, out_results);
          } else {
            log.warning("There is no session with given SID. Closing invalid connection");
            serv.sendErrorAndStop(Authorization.ITEM_NOT_FOUND, p, "Invalid SID");
          }
        }
        addOutPackets(out_results, bs);
      } catch (Exception e) {
        log.log(Level.WARNING,
          "Problem processing socket data for sid =  " + sid,  e);
      }
      //addOutPackets(out_results);
    } // end of while ()
    return null;
  }

  private void addOutPackets(Queue<Packet> out_results, BoshSession bs) {
    for (Packet res: out_results) {
      res.setFrom(getFromAddress(bs.getSid().toString()));
      res.setTo(bs.getDataReceiver());
      addOutPacket(res);
    }
    out_results.clear();
  }

  private String getFromAddress(String id) {
    return JIDUtils.getJID(getName(), getDefHostName(), id);
  }

  public Map<String, Object> getDefaults(Map<String, Object> params) {
    Map<String, Object> props = super.getDefaults(params);
    props.put(MAX_WAIT_DEF_PROP_KEY, MAX_WAIT_DEF_PROP_VAL);
    props.put(MIN_POLLING_PROP_KEY, MIN_POLLING_PROP_VAL);
    props.put(MAX_INACTIVITY_PROP_KEY, MAX_INACTIVITY_PROP_VAL);
    props.put(CONCURRENT_REQUESTS_PROP_KEY, CONCURRENT_REQUESTS_PROP_VAL);
    props.put(HOLD_REQUESTS_PROP_KEY, HOLD_REQUESTS_PROP_VAL);
    props.put(MAX_PAUSE_PROP_KEY, MAX_PAUSE_PROP_VAL);
    return props;
  }

  public void setProperties(Map<String, Object> props) {
    super.setProperties(props);
    max_wait = (Long)props.get(MAX_WAIT_DEF_PROP_KEY);
    min_polling  = (Long)props.get(MIN_POLLING_PROP_KEY);
    max_inactivity = (Long)props.get(MAX_INACTIVITY_PROP_KEY);
    concurrent_requests = (Integer)props.get(CONCURRENT_REQUESTS_PROP_KEY);
    hold_requests = (Integer)props.get(HOLD_REQUESTS_PROP_KEY);
    max_pause = (Long)props.get(MAX_PAUSE_PROP_KEY);
  }

  protected int[] getDefPlainPorts() {
    return PORTS;
  }

  protected int[] getDefSSLPorts() {
    return null;
  }

  public void serviceStopped(BoshIOService service) {
    super.serviceStopped(service);
    UUID sid = service.getSid();
    if (sid != null) {
      BoshSession bs = sessions.get(sid);
      if (bs != null) {
        bs.disconnected(service);
      }
    }
  }

  public void serviceStarted(BoshIOService service) {
    super.serviceStarted(service);
  }

  /**
   * Method <code>getMaxInactiveTime</code> returns max keep-alive time
   * for inactive connection. we shoulnd not really close external component
   * connection at all, so let's say something like: 1000 days...
   *
   * @return a <code>long</code> value
   */
  protected long getMaxInactiveTime() {
    return 10*MINUTE;
  }

  public void xmppStreamClosed(BoshIOService serv) {
    log.finer("Stream closed.");
  }

  public String xmppStreamOpened(BoshIOService serv,
    Map<String, String> attribs) {
    log.fine("Ups, what just happened? Stream open. Hey, this is a Bosh connection manager. c2s and s2s are not supported on the same port as Bosh yet.");
    return "<?xml version='1.0'?><stream:stream"
        + " xmlns='jabber:client'"
        + " xmlns:stream='http://etherx.jabber.org/streams'"
        + " id='1'"
        + " from='" + getDefHostName() + "'"
        + " version='1.0' xml:lang='en'>"
        + "<stream:error>"
        + "<invalid-namespace xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>"
        + "<text xmlns='urn:ietf:params:xml:ns:xmpp-streams' xml:lang='langcode'>"
        + "Ups, what just happened? Stream open. Hey, this is a Bosh connection manager. c2s and s2s are not supported on the same port... yet."
        + "</text>"
        + "</stream:error>"
        + "</stream:stream>"
        ;
  }

  protected BoshIOService getXMPPIOServiceInstance() {
    return new BoshIOService();
  }

  public void writeRawData(BoshIOService ios, String data) {
    super.writeRawData(ios, data);
  }


  private Timer boshTasks = new Timer("BoshTasks");

  public TimerTask scheduleTask(BoshSession bs, long delay) {
    BoshTask bt = new BoshTask(bs);
    boshTasks.schedule(bt, delay);
    return bt;
  }

  public void cancelTask(TimerTask tt) {
    tt.cancel();
  }

  private class BoshTask extends TimerTask {

    private BoshSession bs = null;

    public BoshTask(BoshSession bs) {
      this.bs = bs;
    }

    public void run() {
      Queue<Packet> out_results = new LinkedList<Packet>();
      if (bs.task(out_results, this)) {
        sessions.remove(bs.getSid());
      }
      addOutPackets(out_results, bs);
    }

  }

}
TOP

Related Classes of tigase.server.bosh.BoshConnectionManager$BoshTask

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.