/* * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.mobicents.servlet.sip.core; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.net.UnknownHostException; import java.text.ParseException; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import javax.sip.InvalidArgumentException; import javax.sip.ListeningPoint; import javax.sip.SipProvider; import javax.sip.address.SipURI; import javax.sip.header.ContactHeader; import javax.sip.header.ViaHeader; import org.apache.log4j.Logger; import org.mobicents.servlet.sip.JainSipUtils; import org.mobicents.servlet.sip.SipFactories; /** * @author <A HREF="mailto:jean.deruellimport javax.sip.SipProvider; e@gmail.com">Jean Deruelle</A> * */ public class ExtendedListeningPoint { private static transient Logger logger = Logger.getLogger(ExtendedListeningPoint.class); // the listening point this class is extending private ListeningPoint listeningPoint; // the sip provider attached to private SipProvider sipProvider; private String globalIpAddress; String mostOutboundAddress = null; private int globalPort; private List<String> ipAddresses; private boolean isAnyLocalAddress; private boolean useStaticAddress; // String host = null; int port = -1; String transport; /** * */ public ExtendedListeningPoint(SipProvider sipProvider, ListeningPoint listeningPoint) { this.sipProvider = sipProvider; this.listeningPoint = listeningPoint; this.globalIpAddress = null; this.globalPort = -1; ipAddresses = new ArrayList<String>(); try { isAnyLocalAddress = InetAddress.getByName(listeningPoint.getIPAddress()).isAnyLocalAddress(); } catch (UnknownHostException e) { logger.warn("Unable to enumerate mapped interfaces. Binding to 0.0.0.0 may not work."); isAnyLocalAddress = false; } if(isAnyLocalAddress) { try{ Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces(); while(networkInterfaces.hasMoreElements()) { NetworkInterface networkInterface = networkInterfaces.nextElement(); Enumeration<InetAddress> bindings = networkInterface.getInetAddresses(); while(bindings.hasMoreElements()) { InetAddress addr = bindings.nextElement(); String networkInterfaceIpAddress = addr.getHostAddress(); ipAddresses.add(networkInterfaceIpAddress); } } } catch (SocketException e) { logger.warn("Unable to enumerate network interfaces. Binding to 0.0.0.0 may not work."); } } else { ipAddresses.add(listeningPoint.getIPAddress()); } mostOutboundAddress = JainSipUtils.getMostOutboundAddress(ipAddresses); transport = listeningPoint.getTransport(); port = listeningPoint.getPort(); } /** * */ protected String getIpAddress(boolean usePublicAddress) { // Making use of the global ip address discovered by STUN if it is present if(usePublicAddress && globalIpAddress != null) { return globalIpAddress; } else { return mostOutboundAddress; } } /** * Create a Contact Header based on the host, port and transport of this listening point * @param usePublicAddress if true, the host will be the global ip address found by STUN otherwise * it will be the local network interface ipaddress * @param displayName the display name to use * @return the Contact header */ public ContactHeader createContactHeader(String displayName, boolean usePublicAddress) { try { String host = getIpAddress(usePublicAddress); javax.sip.address.SipURI sipURI = SipFactories.addressFactory.createSipURI(null, host); sipURI.setHost(host); sipURI.setPort(port); sipURI.setTransportParam(transport); javax.sip.address.Address contactAddress = SipFactories.addressFactory.createAddress(sipURI); ContactHeader contact = SipFactories.headerFactory.createContactHeader(contactAddress); if(displayName != null && displayName.length() > 0) { contactAddress.setDisplayName(displayName); } return contact; } catch (ParseException ex) { logger.error ("Unexpected error while creating the contact header for the extended listening point",ex); throw new IllegalArgumentException("Unexpected exception when creating a sip URI", ex); } } /** * Create a Via Header based on the host, port and transport of this listening point * @param usePublicAddress if true, the host will be the global ip address found by STUN otherwise * it will be the local network interface ipaddress * @param branch the branch id to use * @return the via header */ public ViaHeader createViaHeader(String branch, boolean usePublicAddress) { try { String host = getIpAddress(usePublicAddress); ViaHeader via = SipFactories.headerFactory.createViaHeader(host, port, transport, branch); return via; } catch (ParseException ex) { logger.error ("Unexpected error while creating a via header",ex); throw new IllegalArgumentException("Unexpected exception when creating via header ", ex); } catch (InvalidArgumentException e) { logger.error ("Unexpected error while creating a via header",e); throw new IllegalArgumentException("Unexpected exception when creating via header ", e); } } /** * Create a Record Route URI based on the host, port and transport of this listening point * @param usePublicAddress if true, the host will be the global ip address found by STUN otherwise * it will be the local network interface ipaddress * @return the record route uri */ public javax.sip.address.SipURI createRecordRouteURI(boolean usePublicAddress) { try { String host = getIpAddress(usePublicAddress); SipURI sipUri = SipFactories.addressFactory.createSipURI(null, host); sipUri.setPort(port); sipUri.setTransportParam(transport); // Do we want to add an ID here? return sipUri; } catch (ParseException ex) { logger.error ("Unexpected error while creating a record route URI",ex); throw new IllegalArgumentException("Unexpected exception when creating a record route URI", ex); } } /** * Retrieve the jain sip listening point being extended by this class * @return the jain sip listening point being extended by this class */ public ListeningPoint getListeningPoint() { return listeningPoint; } /** * Retrieve the sip provider associated to the jain sip listening point being extended by this class * @return the sip provider associated to the jain sip listening point being extended by this class */ public SipProvider getSipProvider() { return sipProvider; } /** * Retrieve the global ip address of this listening point (found through STUN), null if no global * ip address is asccoiated to it * @return the global ip address of this listening point, null if no global * ip address is asccoiated to it */ public String getGlobalIpAddress() { return globalIpAddress; } /** * Retrieve the global port of this listening point (found through STUN), -1 if no global * port is asccoiated to it * @return the global port of this listening point, -1 if no global * port is asccoiated to it */ public int getGlobalPort() { return globalPort; } /** * Set the global ip address (found through STUN) of this extended listening point * @param globalIpAddress the global ip address of this listening point */ public void setGlobalIpAddress(String globalIpAddress) { this.globalIpAddress = globalIpAddress; } /** * Set the global port (found through STUN) of this extended listening point * @param globalPort the global port of this listening point */ public void setGlobalPort(int globalPort) { this.globalPort = globalPort; } /** * If we are using a statically assigned IP address instead of our local address (for example when IP LB is used) * @return */ public boolean isUseStaticAddress() { return useStaticAddress; } /** * If we are using a statically assigned IP address instead of our local address (for example when IP LB is used) * @param useStaticAddress */ public void setUseStaticAddress(boolean useStaticAddress) { this.useStaticAddress = useStaticAddress; } @Override public String toString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder = stringBuilder.append("ExtendedListeningPoint:") .append("ipAddress=") .append(listeningPoint.getIPAddress()); if(isAnyLocalAddress) { stringBuilder = stringBuilder.append(",maps to following ipaddress:"); for(String mappedIpAddress: ipAddresses) { stringBuilder = stringBuilder.append("\n \t mapped ipaddress:"); stringBuilder = stringBuilder.append(mappedIpAddress); } stringBuilder = stringBuilder.append("\n"); } stringBuilder = stringBuilder.append(", port=") .append(listeningPoint.getPort()) .append(", transport=") .append(transport) .append(", globalIpAddress=") .append(globalIpAddress) .append(", gloablPort=") .append(globalPort); return stringBuilder.toString(); } /** * Return the list of real ip address represented by this listening point. * This can be many ip address because the listening point IP address could be 0.0.0.0 * @return the list of real ip address represented by this listening point. */ public List<String> getIpAddresses() { return ipAddresses; } /** * Retrieve either the global ip address found by STUN or the local network interface one * depending on the boolean value in parameter * @param true means we want to retrieve the global ip address found by STUN * @return Retrieve either the global ip address found by STUN or the local network interface one * depending on the boolean value in parameter */ public String getHost(boolean usePublicAddress){ String host = getIpAddress(usePublicAddress); return host; } /** * Retrieve the port associated with this listening point * @return port associated with this listening point */ public int getPort() { return port; } public void setPort(int port) { this.port = port; } /** * Retrieve the transport associated with this listening point * @return the transport associated with this listening point */ public String getTransport() { return transport; } /** * return true if the ip address maps to 0.0.0.0. * If it's true call getIpAddresses ti get the real list of ip addresses it maps too * @return true if the ip adress is a any local address */ public boolean isAnyLocalAddress() { return isAnyLocalAddress; } }