Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  package examples.subsnotify;
  
  import javax.sip.*;
  import javax.sip.header.*;
  
  
 
 
 import java.util.*;

This implements a simple forking proxy to test proper handling of multiple NOTIFYs. An initial SUBSCRIBE request (i.e. without to-tag) is forked two times to the same destination. Each response should have a different to-tag; this proxy only passes the first 2xx response through, and discards the second NOTIFYs should go directly to the Contact announced in the SUBSCRIBE, hence this proxy won't see them

Author(s):
Jeroen van Bemmel
 
 
 public class Forker implements SipListener {
 
     private static AddressFactory addressFactory;
 
     private static MessageFactory messageFactory;
 
     private static HeaderFactory headerFactory;
 
     private static SipStack sipStack;
 
     private SipProvider udpProvider;

    
Flag to test UAC behavior for non-RFC3261 proxies. In particular, they dont set the 'lr' flag and perform strict routing, ie replace the request URI with the topmost Route header
 
     private static boolean nonRFC3261Proxy;
 
     private static Logger logger = Logger.getLogger(Forker.class);
     static {
         try {
             .setLevel(.);
             .addAppender(new ConsoleAppender(new SimpleLayout()));
             .addAppender(new FileAppender(new SimpleLayout(),
                     "forkeroutputlog.txt"));
         } catch (Exception ex) {
             throw new RuntimeException(ex);
         }
     }
 
     private static final String usageString = "java "
             + "examples.subsnotify.Forker \n"
             + ">>>> is your class path set to the root?";
 
     private static void usage() {
         .info();
         System.exit(0);
 
     }

    
Adds a suitable Record-Route header to the given request or response

 
     private void recordRouteMessage mString uniqueId ) throws ParseExceptionSipException {
         Address me = .createAddress"<sip:127.0.0.1:5065;id=" + uniqueId + '>' );
         if (!) ((SipURIme.getURI()).setLrParam();
         m.addFirstrr );
     }
 
     public void processRequest(RequestEvent re) {
         Request request = re.getRequest();
         ServerTransaction st = re.getServerTransaction();
 
         .info("\n\nRequest " + request.getMethod()
                 + " received at " + .getStackName()
                 + " with server transaction id " + st);
 
         try {
             if (request.getMethod().equals(.)) {
                 processSubscribe(rest);
             } else if (request.getMethod().equals(.)) {    // because
                                                                        // of
                                                                        // Record-Routing
                .info"Got NOTIFY, forwarding statelessly...");
                // Forward it without creating a transaction
                // RFC3265 says: "proxy MUST record-route the initial SUBSCRIBE
                // and
                // any dialog-establishing NOTIFY requests
                // Use from tag as unique id, for debugging
                FromHeader from = (FromHeaderrequest.getHeader(.);
                recordRouterequestfrom.getTag() );
                doForwardStatelessrequestst );
            } else {
                Response notImplemented = .createResponse.request );
                ((SipProvider)re.getSource()).sendResponsenotImplemented );
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    
Process the invite request.
    public void processSubscribeRequestEvent reServerTransaction st) {
        Request request = re.getRequest();
        try {
            .info("forker: got an Subscribe -> forking or forwarding");
            // Check if it is in-dialog or not
            ToHeader to = (ToHeaderrequest.getHeader(.);
            if (to.getTag()==null) {
                .info("forker: got a dialog-creating Subscribe forking twice");
                if (st==null) {
                    st = ((SipProvider)re.getSource()).getNewServerTransaction(request);
                }
              // Subscriber added a Route to us; remove it could check its 'id' here)
              request.removeFirst. );
                doForkrequestst, 5070 );
                doForkrequestst, 5071 );
            } else {
                ..println("forker: got a mid-dialog Subscribe, forwarding statelessly...");
                // Forward it statelessly
                doForwardStatelessrequestst );
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    
Mapping of Via branch IDs to the corresponding ServerTransaction, used for forwarding responses
    private final Map CTtoST = new HashMap();
    private void doForkRequest origServerTransaction stint port ) throws Exception {
        ViaHeader myVia = .createViaHeader"127.0.0.1",
                .getListeningPoint("udp").getPort(), "udp"null );
        Request forked = (Requestorig.clone();
        forked.addHeadermyVia );
        // Note: BIG Gotcha: Need to do this before creating the
        // ClientTransaction!
        if () {
            SipURI suri = .createSipURInull"127.0.0.1" );
            suri.setPortport );
            forked.setRequestURIsuri );
        } else {
            RouteHeader route = .createRouteHeader(
                .createAddress"<sip:127.0.0.1;lr>" )
            );
            ((SipURI)route.getAddress().getURI()).setPortport );
            forked.addHeaderroute );
        }
        // Add a Record-Route header, to test that separate dialog instances are
        // correctly created at the subscriber
        // This causes us to receive NOTIFYs too
        recordRouteforked, Integer.toString(port) );
        ClientTransaction ct = .getNewClientTransactionforked );
        .putctst );
        ct.sendRequest();// gets sent to the outbound proxy == Notifier
    }
    private void doForwardStatelessRequest origServerTransaction st ) throws ParseException,
        // To forward statelessly, we need to keep the stack from
        // creating a ST for us.
        // Internally a dialog is created for the SUBSCRIBE, unless
        // dialog support
        // XXX bug: if I use branch==null here, the stack assigns a random int
        // without magic cookie
        //
        // Latest wisdom from RFC3261 says to simply copy branch from current top via
        // when forwarding statelessly
        //
        ViaHeader top = (ViaHeaderorig.getHeader. );
        ViaHeader myVia = .createViaHeader("127.0.0.1",
                5065, "udp"top.getBranch() );
        orig.addFirstmyVia );
        if () {
            RouteHeader route = (RouteHeaderorig.getHeader"Route" );
            if (route!=null) {
                orig.removeFirst"Route" );
                orig.setRequestURIroute.getAddress().getURI() );
            }
        } else {
            orig.removeFirst. );// points at us
        }
        // To forward statelessly, we need to keep the stack from creating a ST for us.
        // Internally a dialog is created for the SUBSCRIBE, unless dialog support
        // is switched off (see initialization)
        if (st!=null) {
            .info"Would like to forward statelessly, but ST!=null! Problem...");
            .info("st == " + st);
        }
        .sendRequestorig );
    }
    public void processResponse(ResponseEvent responseReceivedEvent) {
        .info("Got a response");
        Response response = (ResponseresponseReceivedEvent.getResponse();
        ClientTransaction ct = responseReceivedEvent.getClientTransaction();
        .info("Dialog = " + responseReceivedEvent.getDialog());
        .info("Response received with client transaction id "
                + ct + ": " + response.getStatusCode() );
        if (ct==null) {
            .info"Assuming NOTIFY response, forwarding...");
            // NOTIFYs are forwarded without transaction, do the same for their
            // responses
            response.removeFirst. );
            try {
                .sendResponseresponse );
            } catch (SipException e) {
                e.printStackTrace();
            }
        } else {
            ServerTransaction st = (ServerTransaction.get(ct);
            if (st!=null) {
                // only forward the first response
                synchronized (st) {
                    if (st.getState() == .) {
                        response.removeFirst. );
                        try {
                            st.sendResponseresponse );
                        } catch (SipException e) {
                            e.printStackTrace();
                        } catch (InvalidArgumentException e) {
                            e.printStackTrace();
                        }
                    } else {
                        .info"Discarding second response" );
                    }
                    .removect );
                }
            } else {
                .info"No ST found");
            }
        }
    }
    public void processTimeout(javax.sip.TimeoutEvent timeoutEvent) {
        Transaction transaction;
        if (timeoutEvent.isServerTransaction()) {
            transaction = timeoutEvent.getServerTransaction();
        } else {
            transaction = timeoutEvent.getClientTransaction();
        }
        .info("state = " + transaction.getState());
        .info("Transaction Time out");
    }
    private static void initFactories () {
        SipFactory sipFactory = null;
         = null;
        sipFactory = SipFactory.getInstance();
        sipFactory.setPathName("gov.nist");
        Properties properties = new Properties();
        String name = "forker";
        if (name += "_nonRFC3261";
        properties.setProperty("javax.sip.STACK_NAME"name );
        // You need 16 for logging traces. 32 for debug + traces.
        // Your code will limp at 32 but it is best for debugging.
        properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL""32");
        properties.setProperty("gov.nist.javax.sip.DEBUG_LOG",
                "forkerdebug.txt");
        properties.setProperty("gov.nist.javax.sip.SERVER_LOG",
                "forkerlog.txt");
        // Switch OFF automatic dialog support. We dont want dialogs in a proxy!
        properties.setProperty("javax.sip.AUTOMATIC_DIALOG_SUPPORT""off");
        try {
            // Create SipStack object
             = sipFactory.createSipStack(properties);
            .info("sipStack = " + );
        } catch (PeerUnavailableException e) {
            // could not find
            // gov.nist.jain.protocol.ip.sip.SipStackImpl
            // in the classpath
            e.printStackTrace();
            ..println(e.getMessage());
            if (e.getCause() != null)
                e.getCause().printStackTrace();
            System.exit(0);
        }
        try {
             = sipFactory.createHeaderFactory();
             = sipFactory.createAddressFactory();
             = sipFactory.createMessageFactory();
        } catch  (Exception ex) {
            ex.printStackTrace();
        }
    }
    public void init() {
        try {
            ListeningPoint lp = .createListeningPoint("127.0.0.1", 5065, "udp");
            this. = .createSipProvider(lp);
            .info("udp provider " + );
        } catch (Exception ex) {
            .error(ex.getMessage());
            ex.printStackTrace();
            usage();
        }
    }
    public static void main(String args[]) throws Exception {
         = args.length > 0;
        initFactories();
        Forker f = new Forker();
        f.init();
        f.udpProvider.addSipListener(f);
    }
    public void processIOException(IOExceptionEvent exceptionEvent) {
        // TODO Auto-generated method stub
    }
    public void processTransactionTerminated(
            TransactionTerminatedEvent transactionTerminatedEvent) {
        // TODO Auto-generated method stub
    }
    public void processDialogTerminated(
            DialogTerminatedEvent dialogTerminatedEvent) {
        // TODO Auto-generated method stub
    }
New to GrepCode? Check out our FAQ X