<commit_before>/*
 * Tigase Jabber/XMPP Server
 * Copyright (C) 2004-2007 "<NAME>" <<EMAIL>>
 *
 * 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$
 * Last modified by $Author$
 * $Date$
 */
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:<EMAIL>"><NAME></a>
 * @version $Rev$
 */
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);<commit_msg>Invalid session SID no longer generates WARNING level log<commit_after>/*
 * Tigase Jabber/XMPP Server
 * Copyright (C) 2004-2007 "<NAME>" <<EMAIL>>
 *
 * 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$
 * Last modified by $Author$
 * $Date$
 */
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:<EMAIL>"><NAME></a>
 * @version $Rev$
 */
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.info("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.info("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.info("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.info("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.info("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);
{'fraction_non_alphanumeric': 0.11649861922805214, 'fraction_numerical': 0.0032110975531436645, 'mean_word_length': 4.1341905703923505, 'pattern_counts': {'":': 0, '<': 47, '<?xml version=': 0, '>': 47, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3520340', 'n_tokens_mistral': 5497, 'n_tokens_neox': 4896, 'n_words': 1263}