/* * File Name : MessageHandler.java * * The JAIN MGCP API implementaion. * * The source code contained in this file is in in the public domain. * It can be used in any project or product without prior permission, * license or royalty payments. There is NO WARRANTY OF ANY KIND, * EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, * THE IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * AND DATA ACCURACY. We do not warrant or make any representations * regarding the use of the software or the results thereof, including * but not limited to the correctness, accuracy, reliability or * usefulness of the software. */ package org.mobicents.mgcp.stack; import jain.protocol.ip.mgcp.message.parms.EndpointIdentifier; import java.io.UnsupportedEncodingException; import java.net.InetAddress; import java.util.ArrayList; import org.apache.log4j.Logger; import org.mobicents.mgcp.stack.parser.Utils; import org.mobicents.mgcp.stack.utils.PacketRepresentation; /** * * @author Oleg Kulikov */ public class MessageHandler { private JainMgcpStackImpl stack; private static Logger logger = Logger.getLogger(MessageHandler.class); private Utils utils = null; private static ArrayList<String> mList = new ArrayList<String>(); /** Creates a new instance of MessageHandler */ public MessageHandler(JainMgcpStackImpl jainMgcpStackImpl) { this.stack = jainMgcpStackImpl; utils = jainMgcpStackImpl.getUtilsFactory().allocate(); } /** * RFC 3435, $3.5.5: split piggy backed messages again * <P> * Messages within the packet are split on their separator "EOL DOT EOL". * * @param packet * the packet to split * @return array of all separate messages */ public static String[] piggyDismount(byte[] msgBuffer, int length) { try { int msgStart = 0; int msgLength = 0; String currentLine = null; for (int i = 0; i < length - 1; i++) { if ((msgBuffer[i] == '\n' || msgBuffer[i] == '\r') && msgBuffer[i + 1] == '.') { msgLength = i - msgStart; try { currentLine = new String(msgBuffer, msgStart, msgLength + 1, "UTF-8"); mList.add(currentLine); } catch (UnsupportedEncodingException e) { logger.error(e); } i = i + 3; msgStart = i; } } try { msgLength = length - msgStart; currentLine = new String(msgBuffer, msgStart, msgLength, "UTF-8"); mList.add(currentLine); } catch (UnsupportedEncodingException e) { logger.error(e); // Should never happen though } String[] result = new String[mList.size()]; return (String[]) mList.toArray(result); } finally { mList.clear(); } } public boolean isRequest(String header) { header = header.trim(); char ch = header.charAt(0); if (Character.isDigit(ch)) { return false; } return true; // Dont use matcher due to bug // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6337993 // Matcher m = p.matcher(header); // return m.matches(); // return header.matches("[\\w]{4}(\\s|\\S)*"); } public void scheduleMessages(PacketRepresentation pr) { try { final InetAddress address = pr.getRemoteAddress(); final int port = pr.getRemotePort(); for (String msg : piggyDismount(pr.getRawData(), pr.getLength())) { int pos = msg.indexOf("\n"); // extract message header to determine transaction handle // parameter and type of the received message String header = msg.substring(0, pos).trim(); if (logger.isDebugEnabled()) { logger.debug("Message header: " + header); } // check message type if this message is command then create new // transaction handler for specified type of this message. if // received message is a response then try to find corresponded // transaction to handle this message String tokens[] = utils.splitStringBySpace(header); if (isRequest(header)) { final String verb = tokens[0]; final String remoteTxIdString = tokens[1]; final EndpointIdentifier endpoint = utils.decodeEndpointIdentifier(tokens[2].trim()); if (logger.isDebugEnabled()) { logger.debug("Processing command message = " + verb + " remote Tx = " + remoteTxIdString); } Integer remoteTxIdIntegere = new Integer(remoteTxIdString); // Check if the Response still in responseTx Map TransactionHandler completedTxHandler = stack.getCompletedTransactions().get(remoteTxIdIntegere); if (completedTxHandler != null) { EndpointHandler eh = completedTxHandler.getEndpointHandler(); completedTxHandler.markRetransmision(); eh.scheduleTransactionHandler(completedTxHandler); if (logger.isDebugEnabled()) { logger.debug("Received Command for which stack has already sent response Tx = " + verb + " " + remoteTxIdIntegere); } return; } Integer tmpLoaclTID = stack.getRemoteTxToLocalTxMap().get(remoteTxIdIntegere); if (tmpLoaclTID != null) { TransactionHandler ongoingTxHandler = stack.getLocalTransactions().get(tmpLoaclTID); ongoingTxHandler.sendProvisionalResponse(); if (logger.isDebugEnabled()) { logger.debug("Received Command for ongoing Tx = " + remoteTxIdIntegere); } return; } // If we are here, it means this is new TX, we have to // create TxH and EH TransactionHandler handler; if (verb.equalsIgnoreCase("crcx")) { handler = new CreateConnectionHandler(stack, address, port); } else if (verb.equalsIgnoreCase("mdcx")) { handler = new ModifyConnectionHandler(stack, address, port); } else if (verb.equalsIgnoreCase("dlcx")) { handler = new DeleteConnectionHandler(stack, address, port); } else if (verb.equalsIgnoreCase("epcf")) { handler = new EndpointConfigurationHandler(stack, address, port); } else if (verb.equalsIgnoreCase("rqnt")) { handler = new NotificationRequestHandler(stack, address, port); } else if (verb.equalsIgnoreCase("ntfy")) { handler = new NotifyHandler(stack, address, port); } else if (verb.equalsIgnoreCase("rsip")) { handler = new RestartInProgressHandler(stack, address, port); } else if (verb.equalsIgnoreCase("auep")) { handler = new AuditEndpointHandler(stack, address, port); } else if (verb.equalsIgnoreCase("aucx")) { handler = new AuditConnectionHandler(stack, address, port); } else { logger.warn("Unsupported message verbose " + verb); return; } // This makes this command to be set in queue to process handler.receiveRequest(endpoint, msg, remoteTxIdIntegere); boolean useFakeOnWildcard = false; if (handler instanceof CreateConnectionHandler) { useFakeOnWildcard = EndpointHandler.isAnyOfWildcard(handler.getEndpointId()); } EndpointHandler eh = stack.getEndpointHandler(handler.getEndpointId(), useFakeOnWildcard); eh.addTransactionHandler(handler); eh.scheduleTransactionHandler(handler); // handle.receiveCommand(msg); } else { // RESPONSE HANDLING if (logger.isDebugEnabled()) { logger.debug("Processing response message"); } // String domainName = address.getHostName(); String tid = tokens[1]; // XXX:TransactionHandler handler = (TransactionHandler) // stack.getLocalTransaction(Integer.valueOf(tid)); TransactionHandler handler = (TransactionHandler) stack.getLocalTransactions().get( Integer.valueOf(tid)); if (handler == null) { logger.warn("--- Address:" + address + "\nPort:" + port + "\nID:" + this.hashCode() + "\n Unknown transaction: " + tid); return; } handler.receiveResponse(msg); // EndpointHandler // eh=stack.getEndpointHandler(handler.getEndpointId()); EndpointHandler eh = handler.getEndpointHandler(); eh.scheduleTransactionHandler(handler); } } } finally { pr.release(); } } }