package test.unit.gov.nist.javax.sip.stack.dialog.b2bua.reinvite;
import gov.nist.javax.sip.DialogTimeoutEvent;
import gov.nist.javax.sip.ListeningPointExt;
import gov.nist.javax.sip.SipListenerExt;
import gov.nist.javax.sip.SipProviderExt;
import java.text.ParseException;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Properties;
import java.util.Random;
import javax.sip.ClientTransaction;
import javax.sip.Dialog;
import javax.sip.DialogTerminatedEvent;
import javax.sip.IOExceptionEvent;
import javax.sip.InvalidArgumentException;
import javax.sip.ListeningPoint;
import javax.sip.RequestEvent;
import javax.sip.ResponseEvent;
import javax.sip.ServerTransaction;
import javax.sip.SipException;
import javax.sip.SipFactory;
import javax.sip.SipProvider;
import javax.sip.SipStack;
import javax.sip.TimeoutEvent;
import javax.sip.TransactionAlreadyExistsException;
import javax.sip.TransactionTerminatedEvent;
import javax.sip.TransactionUnavailableException;
import javax.sip.address.AddressFactory;
import javax.sip.address.SipURI;
import javax.sip.header.CSeqHeader;
import javax.sip.header.ContactHeader;
import javax.sip.header.FromHeader;
import javax.sip.header.HeaderFactory;
import javax.sip.header.RouteHeader;
import javax.sip.header.ViaHeader;
import javax.sip.message.MessageFactory;
import javax.sip.message.Request;
import javax.sip.message.Response;
import test.tck.msgflow.callflows.ProtocolObjects;
public class BackToBackUserAgent implements SipListenerExt {
private HashSet<Dialog> dialogs = new HashSet<Dialog>();
private ListeningPoint[] listeningPoints = new ListeningPoint[2];
private SipProvider[] providers = new SipProvider[2];
private MessageFactory messageFactory;
private Hashtable<Dialog,Response> lastResponseTable = new Hashtable<Dialog,Response>();
private ProtocolObjects protocolObjects;
private HeaderFactory headerFactory;
private AddressFactory addressFactory;
private boolean inviteOkSeen;
private boolean dialogTimedOut;
public Dialog getPeer(Dialog dialog) {
Object[] dialogArray = dialogs.toArray();
if ( dialogArray.length < 2) return null;
if ( dialogArray[0] == dialog) return (Dialog) dialogArray[1];
else if ( dialogArray[1] == dialog) return (Dialog) dialogArray[0];
else return null;
}
public SipProvider getPeerProvider (SipProvider provider) {
if ( providers[0] == provider) return providers[1];
else return providers[0];
}
public void addDialog(Dialog dialog) {
this.dialogs.add(dialog);
System.out.println("Dialogs " + this.dialogs);
}
public void forwardRequest(RequestEvent requestEvent,
ServerTransaction serverTransaction) throws SipException, ParseException, InvalidArgumentException {
SipProvider provider = (SipProvider) requestEvent.getSource();
Dialog dialog = serverTransaction.getDialog();
Dialog peerDialog = this.getPeer(dialog);
Request request = requestEvent.getRequest();
System.out.println("Dialog " + dialog);
Request newRequest = null;
if ( peerDialog != null ) {
newRequest = peerDialog.createRequest(request.getMethod());
} else {
newRequest = (Request) request.clone();
((SipURI)newRequest.getRequestURI()).setPort(5090);
newRequest.removeHeader(RouteHeader.NAME);
FromHeader fromHeader = (FromHeader) newRequest.getHeader(FromHeader.NAME);
fromHeader.setTag(Long.toString(Math.abs(new Random().nextLong())));
SipProvider peerProvider = getPeerProvider(provider);
ViaHeader viaHeader = ((ListeningPointExt) ((SipProviderExt)
getPeerProvider(provider)).getListeningPoint("udp")).createViaHeader();
newRequest.setHeader(viaHeader);
}
ContactHeader contactHeader = ((ListeningPointExt) ((SipProviderExt)
getPeerProvider(provider)).getListeningPoint("udp")).createContactHeader();
newRequest.setHeader(contactHeader);
ClientTransaction clientTransaction = provider.getNewClientTransaction(newRequest);
clientTransaction.setApplicationData(serverTransaction);
if (request.getMethod().equals(Request.INVITE)) {
this.addDialog(clientTransaction.getDialog());
}
if ( peerDialog != null ) {
peerDialog.sendRequest(clientTransaction);
} else {
clientTransaction.sendRequest();
}
}
public void processDialogTimeout(DialogTimeoutEvent timeoutEvent) {
this.dialogTimedOut = true;
}
public void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) {
}
public void processIOException(IOExceptionEvent exceptionEvent) {
// TODO Auto-generated method stub
}
public void processRequest(RequestEvent requestEvent) {
try {
Request request = requestEvent.getRequest();
SipProvider provider = (SipProvider) requestEvent.getSource();
if (request.getMethod().equals(Request.INVITE)) {
if (requestEvent.getServerTransaction() == null) {
try {
ServerTransaction serverTx = provider.getNewServerTransaction(request);
this.addDialog(serverTx.getDialog());
this.forwardRequest(requestEvent,serverTx);
} catch (TransactionAlreadyExistsException ex) {
System.err.println("Transaction exists -- ignoring");
} catch (Exception ex) {
ex.printStackTrace();
BackToBackUserAgentTest.fail("Unepxected exception");
}
} else {
this.forwardRequest(requestEvent,requestEvent.getServerTransaction());
}
} else if ( request.getMethod().equals(Request.BYE)) {
ServerTransaction serverTransaction = requestEvent.getServerTransaction();
if ( serverTransaction == null ) {
serverTransaction = provider.getNewServerTransaction(request);
}
this.forwardRequest(requestEvent, serverTransaction);
} else if (request.getMethod().equals(Request.ACK)) {
Dialog dialog = requestEvent.getDialog();
Dialog peer = this.getPeer(dialog);
Response response = this.lastResponseTable.get(peer);
CSeqHeader cseqHeader = (CSeqHeader) response.getHeader(CSeqHeader.NAME);
String method = cseqHeader.getMethod();
long seqno = cseqHeader.getSeqNumber();
Request ack = peer.createAck(seqno);
peer.sendAck(ack);
}
} catch ( Exception ex) {
ex.printStackTrace();
BackToBackUserAgentTest.fail("Unexpected exception forwarding request");
}
}
public void processResponse(ResponseEvent responseEvent) {
try {
Response response = responseEvent.getResponse();
Dialog dialog = responseEvent.getDialog();
this.lastResponseTable.put(dialog, response);
ServerTransaction serverTransaction = (ServerTransaction)responseEvent.getClientTransaction().getApplicationData();
if ( serverTransaction != null ) {
Request stRequest = serverTransaction.getRequest();
Response newResponse = this.messageFactory.createResponse(response.getStatusCode(),stRequest);
SipProvider provider = (SipProvider)responseEvent.getSource();
SipProvider peerProvider = this.getPeerProvider(provider);
ListeningPoint peerListeningPoint = peerProvider.getListeningPoint("udp");
ContactHeader peerContactHeader = ((ListeningPointExt)peerListeningPoint).createContactHeader();
newResponse.setHeader(peerContactHeader);
serverTransaction.sendResponse(newResponse);
if ( ((CSeqHeader)response.getHeader(CSeqHeader.NAME)).getMethod().equals(Request.INVITE) &&
response.getStatusCode() == 200 ) {
Request newRequest = dialog.createRequest(Request.INVITE);
ListeningPointExt listeningPoint = (ListeningPointExt) provider.getListeningPoint("udp");
ContactHeader contact = listeningPoint.createContactHeader();
newRequest.setHeader(contact);
ClientTransaction clientTransaction = provider.getNewClientTransaction(newRequest);
// Send without waiting for ACK.
dialog.sendRequest(clientTransaction);
}
} else {
this.inviteOkSeen = true;
if ( ((CSeqHeader)response.getHeader(CSeqHeader.NAME)).getMethod().equals(Request.INVITE) &&
response.getStatusCode() == 200){
long cseqno = ((CSeqHeader)response.getHeader(CSeqHeader.NAME)).getSeqNumber();
Request ack = dialog.createAck(cseqno);
dialog.sendAck(ack);
} else {
if ( !((CSeqHeader)response.getHeader(CSeqHeader.NAME)).getMethod().equals(Request.INVITE)) {
System.out.println("Unexpected response " + response);
BackToBackUserAgentTest.fail("Unexpected response");
}
}
}
} catch (Exception ex) {
ex.printStackTrace();
BackToBackUserAgentTest.fail("Unexpected exception");
}
}
public void processTimeout(TimeoutEvent timeoutEvent) {
// TODO Auto-generated method stub
}
public void processTransactionTerminated(TransactionTerminatedEvent transactionTerminatedEvent) {
}
public BackToBackUserAgent(int port1, int port2) {
SipFactory sipFactory = null;
sipFactory = SipFactory.getInstance();
sipFactory.setPathName("gov.nist");
Properties properties = new Properties();
this.protocolObjects = new ProtocolObjects("backtobackua","gov.nist","udp",true,true, false);
try {
headerFactory = protocolObjects.headerFactory;
addressFactory = protocolObjects.addressFactory;
messageFactory = protocolObjects.messageFactory;
SipStack sipStack = protocolObjects.sipStack;
ListeningPoint lp1 = sipStack.createListeningPoint("127.0.0.1", port1, "udp");
ListeningPoint lp2 = sipStack.createListeningPoint("127.0.0.1", port2, "udp");
SipProvider sp1 = sipStack.createSipProvider(lp1);
SipProvider sp2 = sipStack.createSipProvider(lp2);
this.listeningPoints[0] = lp1;
this.listeningPoints[1] = lp2;
this.providers[0] = sp1;
this.providers[1] = sp2;
sp1.addSipListener(this);
sp2.addSipListener(this);
} catch (Exception ex) {
}
}
public void checkState() {
BackToBackUserAgentTest.assertTrue("INVITE OK not seen", this.inviteOkSeen);
BackToBackUserAgentTest.assertFalse("Dialog timed out ", this.dialogTimedOut);
}
}