All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.lastbamboo.common.sip.stack.message.SipMessageUtils Maven / Gradle / Ivy

The newest version!
package org.lastbamboo.common.sip.stack.message;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.lastbamboo.common.sip.stack.message.header.SipHeader;
import org.lastbamboo.common.sip.stack.message.header.SipHeaderImpl;
import org.lastbamboo.common.sip.stack.message.header.SipHeaderNames;
import org.lastbamboo.common.sip.stack.message.header.SipHeaderParamNames;
import org.lastbamboo.common.sip.stack.message.header.SipHeaderValue;
import org.lastbamboo.common.sip.stack.message.header.SipHeaderValueImpl;

/**
 * Collection of utility methods for handling SIP messages.
 */
public class SipMessageUtils
    {

    private static final Logger LOG = LoggerFactory.getLogger(SipMessageUtils.class);
    
    private SipMessageUtils()
        {
        // Should not be constructed.
        }

    /**
     * Creates a paramater string from the specified map of parameter names
     * and values.
     * 
     * @param paramsMap A map of parameter names to values.
     * @return The parameter names and values as a string.
     */
    public static String toParamString(final Map paramsMap)
        {
        final StringBuilder sb = new StringBuilder();
        //sb.append(value);
        final Collection params = paramsMap.entrySet();
        for (final Iterator iter = params.iterator(); iter.hasNext();)
            {
            final Map.Entry param = (Map.Entry) iter.next();
            sb.append(";");
            sb.append(param.getKey());
            sb.append("=");
            sb.append(param.getValue());
            }
        return sb.toString();
        }

    public static String extractName(final String nameValue) 
        throws IOException
        {
        return extractName(nameValue, ":");
        }

    public static String extractValue(final String nameValue) 
        throws IOException
        {
        return extractValue(nameValue, ":");
        }
    
    private static String extractName(final String nameValue, 
        final String separator) throws IOException
        {
        final String name = StringUtils.substringBefore(nameValue, separator);
        if (StringUtils.isBlank(name))
            {
            throw new IOException("Bad header: "+nameValue);
            }
        return name.trim();
        }

    private static String extractValue(final String nameValue, 
        final String separator) throws IOException
        {
        final String value = StringUtils.substringAfter(nameValue, separator);
        if (StringUtils.isBlank(value))
            {
            throw new IOException("Bad header: "+nameValue);
            }
        return value.trim();
        }
    
    public static Map convertHeaders(
        Map> headers)
        {
        final Map newHeaders = 
            new HashMap();
        
        final Set>> entries = 
            headers.entrySet();
        for (final Map.Entry> entry : entries)
            {
            final List values = entry.getValue();
            final List headerValues = createValues(values);
            final SipHeader header = 
                new SipHeaderImpl(entry.getKey(), headerValues);
            newHeaders.put(header.getName(), header);
            }
        return newHeaders;
        }
    
    private static List createValues(final List values)
        {
        final List headerValues = 
            new LinkedList();
        
        for (final String value : values)
            {
            // We use a scanner here because the "value" from the list of
            // strings can actually contain two values separated with a comma.
            final Scanner scan = new Scanner(value);
            scan.useDelimiter(",");
            while (scan.hasNext())
                {
                final String curValue = scan.next();
                try
                    {
                    final SipHeaderValue headerValue = 
                        new SipHeaderValueImpl(curValue);
                    headerValues.add(headerValue);
                    }
                catch (final IOException e)
                    {
                    LOG.warn("Could not parse header value: "+value);
                    }
                }
            }
        return headerValues;
        }

    public static Map extractHeaderParams(
        final String headerValue) throws IOException
        {
        final String paramsString = 
            StringUtils.substringAfter(headerValue, ";");
        final String[] paramStrings = StringUtils.split(paramsString, ";");
        final Map paramMap = 
            new ConcurrentHashMap();
        for (int i = 0; i < paramStrings.length; i++)
            {
            final String nameValue = paramStrings[i].trim();
            final String name = extractName(nameValue, "=");
            final String value = extractValue(nameValue, "=");
            paramMap.put(name, value);
            }
        return paramMap;
        }

    public static String extractCSeqMethod(final SipHeader cseq)
        {
        // This should probably technically allow any whitespace after the
        // sequence number and before the method, but that's unlikely to
        // arise in practice.
        return StringUtils.substringAfter(cseq.getValue().getBaseValue(), " ");
        }

    /**
     * Extracts the {@link URI} from a header value.  This method assumes the 
     * {@link URI} is within an opening "<" and a closing ">".
     * 
     * @param header The header.
     * @return A new {@link URI} from the header.
     */
    public static URI extractUri(final SipHeader header)
        {
        return extractUri(header.getValue().getBaseValue());
        }
    
    /**
     * Extracts the {@link URI} from a header value.  This method assumes the 
     * {@link URI} is within an opening "<" and a closing ">".
     * 
     * @param headerValue The header value string.
     * @return A new {@link URI} from the header.
     */
    private static URI extractUri(final String headerValue)
        {
        LOG.debug("Creating URI from header value: "+headerValue);
        final String uriString = 
            StringUtils.substringBetween(headerValue, "<", ">");
        LOG.debug("Creating URI from URI string: "+uriString);
        try
            {
            return new URI(uriString);
            }
        catch (final URISyntaxException e)
            {
            LOG.error("Could not create URI from string: "+uriString);
            throw new IllegalArgumentException(
                "Could not create URI from: "+uriString);
            }
        }

    public static int extractCSeqNumber(final SipMessage message)
        {
        final SipHeaderValue cSeqValue = 
            message.getHeader(SipHeaderNames.CSEQ).getValue();
        final String cSeqString = cSeqValue.getBaseValue();
        //final String cSeqString = message.getHeader(SipHeaderNames.CSEQ);
        //final SipHeaderValue cSeqValue = header.getValue();
        //final String cSeqString = cSeqValue.getBaseValue();
        final String sequenceString = 
            StringUtils.substringBefore(cSeqString, " ");
        if (!NumberUtils.isNumber(sequenceString))
            {
            throw new IllegalArgumentException("Bad cseq: "+cSeqString);
            }
        return Integer.parseInt(sequenceString);
        }

    /**
     * Extracts the URI from the request line of a SIP message.  The request
     * line must meet the form specified in RFC 3261, as in:

* * Request-Line = Method SP Request-URI SP SIP-Version CRLF * * @param request The SIP request. * @return The request URI from the request line. * @throws IOException If the request line does not match the expected * syntax. */ public static URI extractUriFromRequestLine(final SipMessage request) throws IOException { // Note the Request-Line requires a single space character as the // separator, not arbitrary whitespace. This is specified in section // 7.1 of RFC 3261, on page 27: // // Request-Line = Method SP Request-URI SP SIP-Version CRLF if (LOG.isDebugEnabled()) { LOG.debug("Extracting URI from request line: "+ request.getStartLine()); } final String requestLine = request.getStartLine(); final String uri = StringUtils.substringBetween(requestLine, " "); try { return new URI(uri); } catch (final URISyntaxException e) { LOG.warn("COuld not parse URI", e); throw new IOException ("Attempted to parse invalid URI in " + "request line: "+requestLine); } } /** * Extracts the sent-by host from a Via header. * * @param via The Via header to extract the sent-by host from. * @return The address for the host. * @throws UnknownHostException If there's an error readin the host in * the expected format. */ public static InetAddress extractSentByFromVia(final SipHeaderValue via) throws UnknownHostException { final String baseValue = via.getBaseValue(); final String hostString = StringUtils.substringAfterLast(baseValue, " "); // Note this does return InetAddress.getByName(hostString); } /** * Utility method for extracting the host and port information from the * topmost Via header in a SIP message. * * @param message The SIP message to extract the host and port from. * @return The host and port indicated in the topmost Via. * @throws IOException If there's an unexpected error reading the data. */ public static InetSocketAddress extractNextHopFromVia( final SipMessage message) throws IOException { // Route the message to the client listed in the next Via header. final SipHeader via = message.getHeader(SipHeaderNames.VIA); if (via == null) { LOG.warn("No Via header in message: "+message); throw new IOException("No Via header in message!"); } if (LOG.isDebugEnabled()) { LOG.debug("Accessing value for Via: "+via); } final SipHeaderValue topMostVia = via.getValue(); final String portString = topMostVia.getParamValue(SipHeaderParamNames.RPORT); if (StringUtils.isBlank(portString)) { LOG.warn("No port in Via: "+topMostVia); throw new IOException("Can't handle via with no port"); } final int port = Integer.parseInt(portString); final String hostString; // Use the received parameter if it exists. if (topMostVia.hasParam(SipHeaderParamNames.RECEIVED)) { hostString = topMostVia.getParamValue(SipHeaderParamNames.RECEIVED); } else { LOG.debug("Not using received parameter..."); final String baseValue = topMostVia.getBaseValue(); hostString = StringUtils.substringAfterLast(baseValue, " "); LOG.debug("Using host string: "+hostString); } return new InetSocketAddress(hostString, port); } public static int extractContentLength(final Map headers) { final SipHeader header = headers.get(SipHeaderNames.CONTENT_LENGTH); if (header == null) { if (LOG.isDebugEnabled()) { LOG.debug("No Content-Length header"); } return 0; } final String lengthString = header.getValue().getBaseValue(); if (!NumberUtils.isNumber(lengthString)) { LOG.warn("Content-Length not a number: " + lengthString); return 0; } if (LOG.isDebugEnabled()) { LOG.debug("Parsing length: "+lengthString); } return Integer.parseInt(lengthString); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy