/*
* Copyright 2007 Sun Microsystems, Inc.
*
* This file is part of jVoiceBridge.
*
* jVoiceBridge is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation and distributed hereunder
* to you.
*
* jVoiceBridge 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. If not, see <http://www.gnu.org/licenses/>.
*
* Sun designates this particular file as subject to the "Classpath"
* exception as provided by Sun in the License file that accompanied this
* code.
*/
package com.sun.voip.server;
import com.sun.voip.CallParticipant;
import com.sun.voip.Logger;
import com.sun.voip.SdpManager;
import com.sun.voip.MediaInfo;
import com.sun.voip.SdpInfo;
import com.sun.voip.RtpPacket;
import javax.sip.*;
import javax.sip.header.*;
import javax.sip.message.*;
import javax.sip.address.*;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Vector;
import java.text.ParseException;
import org.voicebridge.*;
/**
* A utility class used to construct and parse sip
* messages, and other SIP-transaction-related tasks.
*/
public class SipUtil {
/* static variables */
private static HeaderFactory headerFactory;
private static AddressFactory addressFactory;
private static MessageFactory messageFactory;
private static SipProvider sipProvider;
private static String ourIpAddress;
private static int ourSipPort;
private static String ourPublicIpAddress;
private static int ourPublicSipPort;
private static Vector supportedMedia = new Vector();
private static boolean initialized = false;
private SdpManager sdpManager;
public SipUtil() {
this(null);
}
public SipUtil(MediaInfo mediaInfo)
{
if (!initialized) {
initialize();
}
sdpManager = new SdpManager();
if (mediaInfo == null)
{
try {
mediaInfo = sdpManager.findMediaInfo(RtpPacket.PCMU_ENCODING, 8000, 1);
Logger.println("SipUtil: Preference default media " + mediaInfo);
} catch (ParseException e) {
Logger.println("SipUtil: Invalid media info, can't set preference" + e.getMessage());
}
}
sdpManager.setPreferredMediaInfo(mediaInfo);
}
/**
* Static initializer.
*/
public static void initialize() {
headerFactory = SipServer.getHeaderFactory();
addressFactory = SipServer.getAddressFactory();
messageFactory = SipServer.getMessageFactory();
sipProvider = SipServer.getSipProvider();
ourIpAddress = SipServer.getSipStack().getIPAddress();
ourSipPort = sipProvider.getListeningPoint().getPort();
ourPublicIpAddress = ourIpAddress;
String s = System.getProperty("com.sun.voip.server.PUBLIC_IP_ADDRESS");
if (s != null && s.length() > 0) {
try {
ourPublicIpAddress = InetAddress.getByName(s).getHostAddress();
} catch (UnknownHostException e) {
Logger.println("Invalid public IP address, using " + ourIpAddress);
}
}
Logger.println("Bridge public address: " + ourPublicIpAddress);
ourPublicSipPort = ourSipPort;
s = System.getProperty("com.sun.voip.server.PUBLIC_SIP_PORT");
if (s != null) {
try {
ourPublicSipPort = Integer.parseInt(s);
} catch (NumberFormatException e) {
Logger.println("Invalid public SIP Port, using " + ourSipPort);
}
}
Logger.println("Bridge public SIP port: " + ourSipPort);
supportedMedia.add(new MediaInfo(
(byte)0, RtpPacket.PCMU_ENCODING, 8000, 1, false));
// supportedMedia.add(new MediaInfo(
// (byte)101, RtpPacket.PCM_ENCODING, 8000, 1, false));
supportedMedia.add(new MediaInfo(
(byte)102, RtpPacket.PCM_ENCODING, 8000, 2, false));
supportedMedia.add(new MediaInfo(
(byte)103, RtpPacket.PCM_ENCODING, 16000, 1, false));
supportedMedia.add(new MediaInfo(
(byte)104, RtpPacket.PCM_ENCODING, 16000, 2, false));
supportedMedia.add(new MediaInfo(
(byte)105, RtpPacket.PCM_ENCODING, 32000, 1, false));
supportedMedia.add(new MediaInfo(
(byte)106, RtpPacket.PCM_ENCODING, 32000, 2, false));
supportedMedia.add(new MediaInfo(
(byte)107, RtpPacket.PCM_ENCODING, 44100, 1, false));
supportedMedia.add(new MediaInfo(
(byte)108, RtpPacket.PCM_ENCODING, 44100, 2, false));
if (false) {
supportedMedia.add(new MediaInfo(
(byte)109, RtpPacket.PCM_ENCODING, 48000, 1, false));
supportedMedia.add(new MediaInfo(
(byte)110, RtpPacket.PCM_ENCODING, 48000, 2, false));
}
supportedMedia.add(new MediaInfo(
(byte)111, RtpPacket.PCM_ENCODING, 48000, 2, false));
supportedMedia.add(new MediaInfo(
(byte)112, RtpPacket.PCMU_ENCODING, 16000, 1, false));
supportedMedia.add(new MediaInfo(
(byte)113, RtpPacket.PCMU_ENCODING, 16000, 2, false));
supportedMedia.add(new MediaInfo(
(byte)114, RtpPacket.PCMU_ENCODING, 32000, 1, false));
supportedMedia.add(new MediaInfo(
(byte)115, RtpPacket.PCMU_ENCODING, 32000, 2, false));
if (false) {
supportedMedia.add(new MediaInfo(
(byte)116, RtpPacket.PCMU_ENCODING, 44100, 1, false));
supportedMedia.add(new MediaInfo(
(byte)117, RtpPacket.PCMU_ENCODING, 44100, 2, false));
supportedMedia.add(new MediaInfo(
(byte)118, RtpPacket.PCMU_ENCODING, 48000, 1, false));
supportedMedia.add(new MediaInfo(
(byte)119, RtpPacket.PCMU_ENCODING, 48000, 2, false));
}
supportedMedia.add(new MediaInfo(
(byte)120, RtpPacket.SPEEX_ENCODING, 8000, 1, false));
supportedMedia.add(new MediaInfo(
(byte)121, RtpPacket.SPEEX_ENCODING, 8000, 2, false));
supportedMedia.add(new MediaInfo(
(byte)122, RtpPacket.SPEEX_ENCODING, 16000, 1, false));
supportedMedia.add(new MediaInfo(
(byte)123, RtpPacket.SPEEX_ENCODING, 16000, 2, false));
supportedMedia.add(new MediaInfo(
(byte)124, RtpPacket.SPEEX_ENCODING, 32000, 1, false));
supportedMedia.add(new MediaInfo(
(byte)125, RtpPacket.SPEEX_ENCODING, 32000, 2, false));
SdpManager.setSupportedMedia(supportedMedia);
initialized = true;
}
public ClientTransaction sendInvite(CallParticipant cp, InetSocketAddress isa)
throws InvalidArgumentException, SipException, ParseException {
if (Bridge.getPublicHost().equals(isa.getAddress()) == false) {
isa = new InetSocketAddress(Bridge.getPublicHost(), isa.getPort());
}
String sdp = generateSdp(cp, isa);
return sendInvite(cp, sdp);
}
public String generateSdp(CallParticipant cp, InetSocketAddress isa) {
String sdp = sdpManager.generateSdp(cp, "MeetingCentral", isa);
String s = "a=conferenceId:" + cp.getConferenceId();
if (cp.getMediaPreference() != null) {
s += ":" + cp.getMediaPreference();
if (cp.getConferenceDisplayName() != null) {
s += ":" + cp.getConferenceDisplayName();
}
}
sdp += s + "\r\n";
if (cp.getRemoteCallId() != null) {
if (Logger.logLevel >= Logger.LOG_MOREINFO) {
Logger.println("Setting callId in sdp to "
+ cp.getRemoteCallId());
}
sdp += "a=callId:" + cp.getRemoteCallId() + "\r\n";
}
if (cp.isDistributedBridge()) {
sdp += "a=userName:DistributedBridge\r\n";
sdp += "a=distributedBridge\r\n";
}
sdp += "a=transmitMediaInfoOk\r\n";
return sdp;
}
/**
* Builds and sends a standard INVITE message, with a
* CSeq number 1.
* @param cp the CallParticipant
* @param tpccName String identifying who is making the call.
* @return transaction Id of newly created transaction.
* @throws ParseException if message cannot be parsed
* @throws SipException if general Sip Exception occurs.
*/
public ClientTransaction sendInvite(CallParticipant cp, String sdp)
throws ParseException, InvalidArgumentException, SipException {
// variables used for message building
SipURI fromAddress = null;
Address fromNameAddress = null;
FromHeader fromHeader = null;
SipURI toAddress = null;
Address toNameAddress = null;
ToHeader toHeader = null;
SipURI requestURI = null;
CallIdHeader callIdHeader = null;
CSeqHeader cSeqHeader = null;
AllowEventsHeader allowEventsHeader = null;
ViaHeader viaHeader = null;
ArrayList viaHeaders = null;
ContentTypeHeader contentTypeHeader = null;
Request invite = null;
String obProxy = null;
/*
* We need a name and number to identify the party placing the call.
* There are some restrictions when using the Vocal Proxy.
*
* If the number being called has 4 digits, then the request is
* going to the proxy. The vocal proxy requires the <tpccName>
* in the From: header to be provisioned.
* We use 4099 which we provisioned.
*
* We generate a header like this:
*
* From: "<display name>" <sip:<tpccName>@129.148.75.131:5060>
* To: "20315" <sip:20315@129.148.75.22:5060>
*
* 20315 is the phone being called.
*
* "<display name>" is the string that will show up as the callerID
* on phone 20315.
*
* <tpccName> is the identifier of who's making the call.
*/
String fromName = cp.getDisplayName();
String fromNumber = cp.getDisplayName(); //cp.getFromPhoneNumber();
String toNumber = cp.getPhoneNumber();
String transport = "udp";
Logger.println("XXX from = " + fromName + " " + cp);
// int toSipPort = SipServer.getSipAddress().getPort();
// XXX this should be the proxy or gateway port!
int toSipPort = 5060;
String proxy = cp.getSipProxy();
if (proxy == null) {
proxy = SipServer.getDefaultSipProxy();
}
String voipGateway = null;
if (toNumber.indexOf("sip:") == 0) {
/*
* If a SIP URI is specified, parse it and send
* the request directly to the target unless sendSipUriToProxy is false.
*
* If this request is sent to the proxy
* the endpoint must be registered with the proxy.
*/
Address address = null;
SipURI sipURI = null;
String host = null;
String user = null;
try {
address = addressFactory.createAddress(toNumber);
sipURI = (SipURI)address.getURI();
host = sipURI.getHost();
user = sipURI.getUser();
} catch (ParseException e) {
Logger.println("parse exception: " + toNumber + " sipUri " + sipURI + " host " + host + " user " + user);
}
if (Logger.logLevel >= Logger.LOG_SIP) {
Logger.println("address: " + address);
Logger.println("sipURI: " + sipURI);
Logger.println("host: " + host);
Logger.println("user: " + user);
}
if (SipServer.getSendSipUriToProxy() == false && user != null) {
InetAddress inetAddress;
try {
inetAddress = InetAddress.getByName(host);
voipGateway = host; //inetAddress.getHostAddress();
int port = sipURI.getPort();
if (port > 0) {
toSipPort = port;
}
toNumber = user;
/*
* Keep just the User information from the URI.
* XXX Not sure why I should do this.
*/
//cp.setPhoneNumber(toNumber);
Logger.println("Call " + cp + " Sending INVITE directly to " + inetAddress + ":" + toSipPort);
} catch (UnknownHostException e) {
/*
* Let proxy handle it
*/
voipGateway = proxy;
Logger.println("Call " + cp + " Using proxy " + proxy + " for " + toNumber);
// XXX Not sure why I should do this.
//cp.setPhoneNumber(toNumber.substring(4)); // skip sip:
toNumber = toNumber.substring(4);
}
} else {
voipGateway = proxy;
Logger.println("Call " + cp + " Using proxy " + proxy + " for " + toNumber);
// XXX Not sure why I should do this.
//cp.setPhoneNumber(toNumber.substring(4)); // skip sip:
toNumber = toNumber.substring(4);
}
} else { // telephone number
transport = System.getProperty("com.sun.voip.server.PROTOCOL");
if (toNumber.indexOf("tel:") == 0)
{
toNumber = toNumber.substring(4);
}
voipGateway = proxy;
Logger.println("Call " + cp + " Using proxy " + proxy + " for " + toNumber);
}
if (toNumber.indexOf("@") < 0 && CallHandler.enablePSTNCalls() == false) {
throw new SipException("PSTN calls are not allowed: " + cp);
}
ArrayList<ProxyCredentials> proxyCredentialList = SipServer.getProxyCredentials();
boolean gatewayRequired = false;
if (voipGateway == null)
{
if (proxy == null)
{
if (proxyCredentialList.size() == 0)
{
Logger.println("Call " + cp + " no voipGateway is available!");
throw new SipException("No voip Gateway! " + cp);
} else gatewayRequired = true;
} else {
voipGateway = proxy;
gatewayRequired = true;
}
} else {
if (voipGateway.equals(proxy))
gatewayRequired = true;
}
if (gatewayRequired)
{
Logger.println("XXXX gatewayRequired");
if (proxyCredentialList.size() != 0)
{
Logger.println("XXXX gatewayRequired 1");
int voipIndex = 0;
for (int i=0; i<proxyCredentialList.size(); i++)
{
ProxyCredentials proxyCredentials = proxyCredentialList.get(i);
if (voipGateway.equals(proxyCredentials.getName()))
{
voipIndex = i;
}
}
ProxyCredentials proxyCredentials = proxyCredentialList.get(voipIndex);
//fromName = proxyCredentials.getUserDisplay();
voipGateway = proxyCredentials.getHost();
obProxy = proxyCredentials.getProxy();
//fromAddress = addressFactory.createSipURI(proxyCredentials.getUserName(), voipGateway);
fromAddress = addressFactory.createSipURI(fromName, voipGateway);
//cp.setProxyCredentials(proxyCredentials); // we need this to match SIP transaction later
//cp.setDisplayName(proxyCredentials.getUserDisplay()); // we need this to get proxy authentication details later
} else {
Logger.println("XXXX gatewayRequired 2");
}
Logger.println("XXXX gatewayRequired 3");
toAddress = addressFactory.createSipURI(toNumber, voipGateway);
} else {
Logger.println("XXXX gatewayRequired 4");
Logger.println("fromNumber " + fromNumber);
if (fromNumber.startsWith("sip:"))
fromAddress = (SipURI)addressFactory.createAddress(fromNumber).getURI();
else
fromAddress = addressFactory.createSipURI(fromNumber, ourIpAddress);
fromAddress.setPort(ourSipPort);
toAddress = addressFactory.createSipURI(toNumber, voipGateway);
}
Logger.println("XXXX gatewayRequired 5");
Logger.println("from " + fromAddress);
Logger.println("to " + toAddress);
fromNameAddress = addressFactory.createAddress(fromName, fromAddress);
fromHeader = headerFactory.createFromHeader(fromNameAddress, new Integer((int)(Math.random() * 10000)).toString());
/* create To Header
* e.g. "Willie Walker"<sip:30039@152.70.1.28:5060>
* where "Willie Walker" == cp.getName()
* 30039 == cp.getNumber()
* 152.70.1.28 == cp.getIpAddress()
* 5060 == cp.getPort()
*/
Logger.println("XXXX gatewayRequired 6");
if (Bridge.getPrivateHost().startsWith("127.") &&
voipGateway.equals("127.0.0.1") == false) {
throw new SipException("The bridge's ip address is "
+ Bridge.getPrivateHost()
+ ". It is not possible to initiate a call to " + voipGateway);
}
if (Bridge.getPrivateHost().startsWith("127.") == false &&
voipGateway.startsWith("127.") == true) {
throw new SipException("The bridge's ip address must be "
+ Bridge.getPrivateHost()
+ " in order to issue a call to " + voipGateway);
}
Logger.writeFile("Call " + cp + " voip gateway / proxy " + voipGateway
+ " port " + toSipPort);
/*
* Don't do this because port should be that of the toNumber if specified
* otherwise that of the voipGateway
*/
// toAddress.setPort(toSipPort);
toNameAddress = addressFactory.createAddress(toNumber, toAddress);
toHeader = headerFactory.createToHeader(toNameAddress, null);
/* create request URI (the first line of the request)
* e.g. INVITE sip:61202@129.145.176.239:5060;transport=udp SIP/2.0
* where INVITE == (specfied later)
* (requestURI) == (same as toAddress)
* transport=udp SIP/2.0 == (transport)
*/
int ix = toNumber.indexOf("@");
if (ix >= 0) {
toNumber = toNumber.substring(0, ix);
}
Logger.println("XXXX gatewayRequired 7");
requestURI = addressFactory.createSipURI(toNumber, voipGateway);
requestURI.setPort(toSipPort);
requestURI.setTransportParam
(sipProvider.getListeningPoint(transport).getTransport());
/* create Via headers
* e.g. Via: SIP/2.0/UDP 152.70.1.43:5060;branch=z9hG4bK5
* where SIP/2.0/UDP == (transport)
* 152.70.1.43:5060 == (local address and SIP port)
* branch=z9hG4bk5 == (auto generated branch id)
*/
viaHeader = headerFactory.createViaHeader(ourIpAddress, ourSipPort, sipProvider.getListeningPoint(transport).getTransport(), null);
//viaHeader.setBranch(MessageFactoryImpl.generateBranchId());
viaHeaders = new ArrayList();
viaHeaders.add(viaHeader);
/* create CallId header
* e.g. Call-Id: 7727452ebac7ff5ac0c65baa7250e2f5@152.70.1.43
* where 77274.... == (globally unique identifier)
*/
callIdHeader = sipProvider.getNewCallId();
/* create Seq header
* e.g. CSeq: 1 INVITE
* where 1 == (CSeq number - motonically increasing within
* each SIP callId)
* INVITE == (request method)
*/
cSeqHeader = headerFactory.createCSeqHeader(1, Request.INVITE);
// Create a new MaxForwardsHeader
MaxForwardsHeader maxForwards =
headerFactory.createMaxForwardsHeader(70);
// create INVITE message. Put everything together
invite = messageFactory.createRequest(requestURI,
Request.INVITE, callIdHeader, cSeqHeader,
fromHeader, toHeader, viaHeaders, maxForwards);
Logger.println("XXXX gatewayRequired 10");
if (SdpManager.useTelephoneEvent() == true) {
allowEventsHeader =
headerFactory.createAllowEventsHeader("telephone-event");
invite.addHeader(allowEventsHeader);
}
/* Contact Header (where subsequent requests should be sent to)
* e.g. Contact: "Awarenex" <sip:Awarenex@152.70.1.43:5060>;
* where "Awarenex" <sip:... == (local Address)
*/
SipURI contactURI = null;
if (fromNumber.startsWith("sip:"))
contactURI = (SipURI)addressFactory.createAddress(fromNumber).getURI();
else
contactURI = addressFactory.createSipURI(fromNumber, ourPublicIpAddress);
Logger.println("XXXX gatewayRequired 12");
contactURI.setPort(ourPublicSipPort);
Address contactAddress =
addressFactory.createAddress(contactURI);
contactAddress.setDisplayName(fromName);
ContactHeader contactHeader =
headerFactory.createContactHeader(contactAddress);
invite.addHeader(contactHeader);
Logger.println("XXXX gatewayRequired 14");
if (obProxy != null)
{
try {
SipURI routeURI = (SipURI) addressFactory.createURI("sip:" + obProxy + ";lr");
RouteHeader routeHeader = headerFactory.createRouteHeader(addressFactory.createAddress(routeURI));
invite.addHeader(routeHeader);
} catch (Exception e) {
Logger.error("Creating registration route error " + e);
}
}
Logger.println("XXXX gatewayRequired 16");
if (cp.isAutoAnswer())
{
Logger.println("Call " + cp + " alert-info added");
try {
SIPAlertInfo alertInfo = new SIPAlertInfo();
alertInfo.setNamePair("info=alert-autoanswer") ;
invite.addHeader(alertInfo) ;
} catch (Exception e) {
Logger.error("Creating alert info error " + e);
}
}
Logger.println("XXXX gatewayRequired 18");
if (sdp != null) {
contentTypeHeader =
headerFactory.createContentTypeHeader("application", "sdp");
invite.setContent(sdp, contentTypeHeader);
}
// Create the client transaction.
ClientTransaction clientTransaction;
Logger.writeFile("Invite\n" + invite);
try {
clientTransaction =
sipProvider.getNewClientTransaction(invite);
} catch (Exception e) {
Logger.println("Call " + cp + " sendInvite failed: " + e.getMessage());
return null;
}
Logger.println("XXXX gatewayRequired 19");
clientTransaction.sendRequest();
Logger.println("XXXX gatewayRequired 20");
return clientTransaction;
}
public static boolean isSipUri(String phoneNumber) {
if (phoneNumber == null || phoneNumber.indexOf("sip:") != 0) {
return false;
}
Address address = null;
SipURI sipURI = null;
String host = null;
String user = null;
try {
address = addressFactory.createAddress(phoneNumber);
sipURI = (SipURI)address.getURI();
host = sipURI.getHost();
user = sipURI.getUser();
} catch (ParseException e) {
return false;
}
return user != null;
}
/**
* builds and sends a standard ACK message with the TPC
* server's address and port in the sdp.
*
* @param clientTransaction ClientTransaction for this call
* @param sdpBody String sdp body for this call
* @param isa InetSocketAddress of conference receiver
* @throws ParsException if message cannot be parsed
* @throws SipException if general sip exception occurs.
* @throws TransactionDoesNotExistException if transaction can
* not be found.
*/
public void sendAckWithTPCAddress(ClientTransaction clientTransaction, String sdpBody, InetSocketAddress isa)
throws TransactionDoesNotExistException, ParseException,
SipException {
int start = sdpBody.indexOf("c=IN IP4 ");
int finish = sdpBody.indexOf("\r", start);
if (Logger.logLevel >= Logger.LOG_SIP) {
Logger.println("modifying sdp with IP " +
isa.getAddress() + " port " + isa.getPort());
}
String newSdp = sdpBody.substring(0, start+9) + isa.getAddress().getHostAddress() + sdpBody.substring(finish);
start = newSdp.indexOf("m=audio ");
if (start > - 1) {
newSdp = newSdp.substring(0, start + 8) + isa.getPort() + newSdp.substring(newSdp.indexOf(" RTP/AVP"));
//only return PCMU 8000
start = newSdp.indexOf("RTP/AVP ");
String pcmu = "RTP/AVP 0 13 101\r\n" + "a=rtpmap:0 PCMU/8000\r\n";
newSdp = newSdp.substring(0, start) + pcmu ;
}
if (Logger.logLevel >= Logger.LOG_SIP) {
Logger.println("sdp 1\n" + newSdp);
}
/**
* Build and send a standard ACK message, based on the sdpBody
* given and the previous transaction of the call participant.
*/
Dialog dialog = clientTransaction.getDialog();
Request ackRequest = dialog.createRequest(Request.ACK);
ContentTypeHeader contentTypeHeader = headerFactory.createContentTypeHeader("application", "sdp");
ackRequest.setContent(newSdp, contentTypeHeader);
Logger.writeFile(ackRequest.toString());
dialog.sendAck(ackRequest);
return;
}
/**
* builds and sends a standard ACK message with no SDP.
*
* @param clientTransaction ClientTransaction for this call
* @throws ParsException if message cannot be parsed
* @throws SipException if general sip exception occurs.
* @throws TransactionDoesNotExistException if transaction can
* not be found.
*/
public void sendAck(ClientTransaction clientTransaction)
throws TransactionDoesNotExistException, ParseException,
SipException {
/**
* Build and send a standard ACK message
*/
Dialog dialog = clientTransaction.getDialog();
//Request ackRequest = dialog.createRequest(Request.ACK);
Request ackRequest = clientTransaction.createAck();
dialog.sendAck(ackRequest);
return;
}
/**
* builds and sends a CANCEL message starting with an message.
* @param clientTransaction most recent client transaction for call
* @return transaction id of the request
* @throws ParsEexception if message cannot be parsed
* @throws SipException if general sip exception occurs.
* @throws TransactionDoesNotExistException if transaction can
* not be found.
*/
public void sendCancel(ClientTransaction clientTransaction)
throws TransactionDoesNotExistException, ParseException,
SipException {
Request cancel = clientTransaction.createCancel();
clientTransaction = sipProvider.getNewClientTransaction(cancel);
clientTransaction.sendRequest();
}
public void sendCancel(ServerTransaction st)
throws TransactionDoesNotExistException, ParseException,
SipException {
Dialog dialog = st.getDialog();
dialog.incrementLocalSequenceNumber();
Request cancelRequest = dialog.createRequest(Request.CANCEL);
dialog.sendRequest(sipProvider.getNewClientTransaction(cancelRequest));
}
/**
* builds and sends a standard BYE message.
* @param clientTransaction Most recent client transaction for call
* @throws ParseException if message cannot be parsed
* @throws SipException if general sip exception occurs.
* @throws TransactionDoesNotExistException if transaction can
* not be found.
*/
public void sendBye(ClientTransaction clientTransaction)
throws TransactionDoesNotExistException, ParseException,
SipException, InvalidArgumentException {
Dialog dialog = clientTransaction.getDialog();
/*
* Sip stack takes care of this.
*/
//dialog.incrementLocalSequenceNumber();
Request byeRequest = dialog.createRequest(Request.BYE);
dialog.sendRequest(sipProvider.getNewClientTransaction(byeRequest));
}
/**
* builds and sends a standard BYE message.
* @param serverTransaction
*/
public void sendBye(ServerTransaction st)
throws TransactionDoesNotExistException, ParseException,
SipException, InvalidArgumentException {
Dialog dialog = st.getDialog();
/*
* Sip stack takes care of this.
*/
//dialog.incrementLocalSequenceNumber();
Request byeRequest = dialog.createRequest(Request.BYE);
Logger.writeFile(byeRequest.toString());
dialog.sendRequest(sipProvider.getNewClientTransaction(byeRequest));
}
/**
* builds and sends a standard OK message with SDP.
* @return serverTransaction ServerTransaction for call
* @param isa InetSocketAddress of conference receiver
* @throws ParsEexception if message cannot be parsed
* @throws SipException if general sip exception occurs.
* @throws TransactionDoesNotExistException if transaction can
* not be found.
*/
public void sendOkWithSdp(Request request,
ServerTransaction st, InetSocketAddress isa, SdpInfo remoteSdpInfo)
throws TransactionDoesNotExistException, ParseException,
SipException {
Response response = messageFactory.createResponse(Response.OK, request);
ToHeader to = (ToHeader) response.getHeader(ToHeader.NAME);
if (to == null) {
Logger.println("something is wrong, no ToHeader...");
return;
}
try {
if (to.getTag() == null || to.getTag().trim().length() == 0) {
Dialog dialog = st.getDialog();
to.setTag(Integer.toString(dialog.hashCode()));
}
} catch (ParseException ex) {
Logger.println("can't set to tag");
return;
}
/*
* Contact Header (where subsequent requests should be sent to)
* e.g. Contact: "Awarenex" <sip:Awarenex@152.70.1.43:5060>;
* where "Awarenex" <sip:... == (local Address)
*/
Address address = (Address) to.getAddress();
SipURI toURI = (SipURI) address.getURI();
SipURI contactURI =
addressFactory.createSipURI(toURI.getUser(), ourPublicIpAddress);
contactURI.setPort(ourPublicSipPort);
Address contactAddress = addressFactory.createAddress(contactURI);
contactAddress.setDisplayName(to.getName());
ContactHeader contactHeader =
headerFactory.createContactHeader(contactAddress);
response.addHeader(contactHeader);
String mySdp;
try {
mySdp = sdpManager.generateSdp("MeetingCentral", isa, remoteSdpInfo);
} catch (IOException e) {
throw new SipException("Failed to generate sdp "
+ remoteSdpInfo.getMediaInfo());
}
ContentTypeHeader contentTypeHeader = headerFactory.
createContentTypeHeader("application", "sdp");
response.setContent(mySdp, contentTypeHeader);
try {
Logger.writeFile(response.toString());
st.sendResponse(response);
} catch (InvalidArgumentException e) {
Logger.println("SendOKWithSdp: " + e.getMessage());
throw new SipException("Failed to send response: " + e.getMessage());
}
}
/*
* Send an OK with no SDP
*/
public void sendOK(Request request, ServerTransaction st)
throws TransactionDoesNotExistException, ParseException,
SipException {
Response response = messageFactory.createResponse(Response.OK,
request);
ToHeader to = (ToHeader) response.getHeader(ToHeader.NAME);
if (to == null) {
Logger.println("something is wrong, no to header...");
return;
}
try {
if (to.getTag() == null || to.getTag().trim().length() == 0) {
Dialog dialog = st.getDialog();
to.setTag(Integer.toString(dialog.hashCode()));
}
} catch (ParseException ex) {
Logger.println("can't set to tag");
return;
}
/*
* Contact Header (where subsequent requests should be sent to)
* e.g. Contact: "Awarenex" <sip:Awarenex@152.70.1.43:5060>;
* where "Awarenex" <sip:... == (local Address)
*/
Address address = (Address) to.getAddress();
SipURI toURI = (SipURI) address.getURI();
SipURI contactURI =
addressFactory.createSipURI(toURI.getUser(), ourPublicIpAddress);
contactURI.setPort(ourPublicSipPort);
Address contactAddress = addressFactory.createAddress(contactURI);
contactAddress.setDisplayName(to.getName());
ContactHeader contactHeader =
headerFactory.createContactHeader(contactAddress);
response.addHeader(contactHeader);
try {
st.sendResponse(response);
} catch (InvalidArgumentException e) {
Logger.println("SendOk: " + e.getMessage());
throw new SipException("Failed to send response: " + e.getMessage());
}
}
/**
* builds and sends a BUSY message.
* @param clientTransaction ClientTransaction for call
* @return serverTransaction ServerTransaction for call
* @throws ParsEexception if message cannot be parsed
* @throws SipException if general sip exception occurs.
* @throws TransactionDoesNotExistException if transaction can
* not be found.
*/
public void sendBusy(Request request,
ServerTransaction serverTransaction)
throws TransactionDoesNotExistException, ParseException,
SipException {
Response response = messageFactory.createResponse(Response.BUSY_HERE,
request);
/*
* Contact Header (where subsequent requests should be sent to)
* e.g. Contact: "Awarenex" <sip:Awarenex@152.70.1.43:5060>;
* where "Awarenex" <sip:... == (local Address)
*/
//SipURI contactUrl =
// addressFactory.createSipURI(cp.getPhoneNumber(), ourPublicIpAddress);
//contactUrl.setPort(ourPublicSipPort);
//SipURI contactURI =
// addressFactory.createSipURI(cp.getPhoneNumber(), ourPublicIpAddress);
//contactURI.setPort(port);
//Address contactAddress =
// addressFactory.createAddress(contactURI);
//contactAddress.setDisplayName(cp.getName());
//ContactHeader contactHeader =
// headerFactory.createContactHeader(contactAddress);
//response.addHeader(contactHeader);
try {
serverTransaction.sendResponse(response);
} catch (InvalidArgumentException e) {
Logger.println("SendBusy: " + e.getMessage());
throw new SipException("Failed to send response: " + e.getMessage());
}
}
public SdpInfo getSdpInfo(String sdpBody) throws ParseException {
return getSdpInfo(sdpBody, true);
}
public SdpInfo getSdpInfo(String sdpBody, boolean isRequest) throws ParseException
{
SdpInfo remoteSdpInfo = sdpManager.parseSdp(sdpBody);
MediaInfo myPreferredMediaInfo = sdpManager.getPreferredMediaInfo();
byte payload;
Logger.writeFile("My preferred media " + myPreferredMediaInfo);
/*
* If this is a remote SIP REQUEST and the remote side supports our
* preferred mediaInfo, we will reply selecting our preferred media.
* Otherwise, we reply using the remote's media choice, which is
* either the remote's preferred or the "best" choice.
*/
if (isRequest && remoteSdpInfo.isSupported(myPreferredMediaInfo)) {
payload = myPreferredMediaInfo.getPayload();
remoteSdpInfo.setMediaInfo(myPreferredMediaInfo);
Logger.println("My preferred payload being used " + payload);
} else {
if (isRequest) {
Logger.writeFile("My preferred media " + myPreferredMediaInfo + " not supported...");
}
try {
payload = remoteSdpInfo.getMediaInfo().getPayload();
remoteSdpInfo.setMediaInfo(sdpManager.findMediaInfo(payload));
Logger.writeFile("media setting is " + remoteSdpInfo.getMediaInfo());
} catch (ParseException e) {
remoteSdpInfo.setMediaInfo(new MediaInfo((byte)0, RtpPacket.PCMU_ENCODING, 8000, 1, false));
}
}
return remoteSdpInfo;
}
/*
* We add an attribute to the sdp data when we send a request
* to a sip phone number
*/
public static String getCallIdFromSdp(Request request) {
byte[] rawContent = request.getRawContent();
if (rawContent == null) {
return null;
}
String sdpBody = new String(rawContent);
SdpInfo sdpInfo;
try {
sdpInfo = SdpManager.parseSdp(sdpBody);
} catch (ParseException e) {
return null;
}
return sdpInfo.getCallId();
}
/*
* We add an attribute to the sdp data when we send a request
* to a sip phone number
*/
public static String getConferenceIdFromSdp(Request request) {
byte[] rawContent = request.getRawContent();
if (rawContent == null) {
return null;
}
String sdpBody = new String(rawContent);
SdpInfo sdpInfo;
try {
sdpInfo = SdpManager.parseSdp(sdpBody);
} catch (ParseException e) {
return null;
}
return sdpInfo.getConferenceId();
}
public static String getUserNameFromSdp(Request request) {
byte[] rawContent = request.getRawContent();
if (rawContent == null) {
return null;
}
String sdpBody = new String(rawContent);
SdpInfo sdpInfo;
try {
sdpInfo = SdpManager.parseSdp(sdpBody);
} catch (ParseException e) {
return null;
}
return sdpInfo.getUserName();
}
public static boolean getDistributedBridgeFromSdp(Request request) {
byte[] rawContent = request.getRawContent();
if (rawContent == null) {
return false;
}
String sdpBody = new String(rawContent);
SdpInfo sdpInfo;
try {
sdpInfo = SdpManager.parseSdp(sdpBody);
} catch (ParseException e) {
return false;
}
return sdpInfo.isDistributedBridge();
}
/*
* Utility method to parse a request and get the requestor's phone number
*/
public static String getFromPhoneNumber(Object requestEvent) {
Request request = ((RequestEvent)requestEvent).getRequest();
FromHeader from = (FromHeader) request.getHeader(FromHeader.NAME);
Address address = from.getAddress();
SipURI uri = (SipURI)address.getURI();
if (uri.toString().indexOf("@") >= 0) {
String s = uri.getUser() + "@" + uri.getHost();
if (uri.getPort() != -1) {
s += ":" + uri.getPort();
}
return s;
}
return ((SipURI)address.getURI()).getUser();
}
public static String getRequest(Object requestEvent) {
Request request = ((RequestEvent)requestEvent).getRequest();
return request.toString();
}
/*
* Utility method to parse a request and get the To phone number
*/
public static String getToPhoneNumber(Object requestEvent) {
Request request = ((RequestEvent)requestEvent).getRequest();
ToHeader to = (ToHeader) request.getHeader(ToHeader.NAME);
Address address = to.getAddress();
return ((SipURI)address.getURI()).getUser();
}
public static String getPhoneNumber(String phoneNumber) {
if (SipUtil.isSipUri(phoneNumber) == false) {
return phoneNumber;
}
try {
Address address = addressFactory.createAddress(phoneNumber);
SipURI sipURI = (SipURI)address.getURI();
return sipURI.getUser();
} catch (ParseException e) {
Logger.println("parse exception: " + phoneNumber);
return phoneNumber;
}
}
/*
* Utility method to parse a request and get the requestor's host address
*/
public static String getFromHost(Object requestEvent) {
Request request = ((RequestEvent)requestEvent).getRequest();
FromHeader from = (FromHeader) request.getHeader(FromHeader.NAME);
Address address = (Address) from.getAddress();
return ((SipURI)address.getURI()).getHost();
}
/*
* Utility method to parse a request and get the requestor's name
*/
public static String getFromName(Object requestEvent) {
Request request = ((RequestEvent)requestEvent).getRequest();
FromHeader from = (FromHeader) request.getHeader(FromHeader.NAME);
Address address = (Address) from.getAddress();
String name = address.getDisplayName();
if (name == null) {
name = address.getURI().toString();
}
return name;
}
public static void sendAckWithSDP(ClientTransaction ct, String sdp)
throws ParseException, SipException
{
Dialog dialog = ct.getDialog();
Request ackRequest = dialog.createRequest(Request.ACK);
if(sdp != null){
ContentTypeHeader contentTypeHeader;
contentTypeHeader =
headerFactory.createContentTypeHeader("application", "sdp");
ackRequest.setContent(sdp, contentTypeHeader);
}
dialog.sendAck(ackRequest);
return;
}
}