/* * 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.testsuite; import java.io.IOException; import java.io.Serializable; import javax.annotation.Resource; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.sip.Address; import javax.servlet.sip.AuthInfo; import javax.servlet.sip.Parameterable; import javax.servlet.sip.ServletParseException; import javax.servlet.sip.ServletTimer; import javax.servlet.sip.SipApplicationSession; import javax.servlet.sip.SipErrorEvent; import javax.servlet.sip.SipErrorListener; import javax.servlet.sip.SipFactory; import javax.servlet.sip.SipServlet; import javax.servlet.sip.SipServletRequest; import javax.servlet.sip.SipServletResponse; import javax.servlet.sip.SipSession; import javax.servlet.sip.SipURI; import javax.servlet.sip.TimerListener; import javax.servlet.sip.TimerService; import javax.servlet.sip.SipSession.State; import org.apache.log4j.Logger; public class SimpleSipServlet extends SipServlet implements SipErrorListener, TimerListener { private static final long serialVersionUID = 1L; private static final String TEST_REGISTER_C_SEQ = "testRegisterCSeq"; private static final String TEST_REGISTER_SAVED_SESSION = "testRegisterSavedSession"; private static final String TEST_SUBSCRIBER_URI = "testSubscriberUri"; private static final String TEST_EXTERNAL_ROUTING = "testExternalRouting"; private static final String TEST_EXTERNAL_ROUTING_NO_INFO = "testExternalRoutingNoInfo"; private static final String TEST_NON_EXISTING_HEADER = "TestNonExistingHeader"; private static final String TEST_ALLOW_HEADER = "TestAllowHeader"; private static final String TEST_TO_TAG = "TestToTag"; private static final String CONTENT_TYPE = "text/plain;charset=UTF-8"; private static final String CANCEL_RECEIVED = "cancelReceived"; private static final String SUBSCRIBER_URI = "sip:testSubscriberUri@sip-servlets.com"; @Resource SipFactory sipFactory; @Resource TimerService timerService; SipSession registerSipSession; @Override protected void doBranchResponse(SipServletResponse resp) throws ServletException, IOException { resp.getApplicationSession().setAttribute("doBranchResponse", "true"); super.doBranchResponse(resp); } private static transient Logger logger = Logger.getLogger(SimpleSipServlet.class); private static String TEST_REINVITE_USERNAME = "reinvite"; private static String TEST_IS_SEND_REINVITE_USERNAME = "isendreinvite"; private static String TEST_CANCEL_USERNAME = "cancel"; /** Creates a new instance of SimpleProxyServlet */ public SimpleSipServlet() { } @Override public void init(ServletConfig servletConfig) throws ServletException { logger.info("the simple sip servlet has been started"); super.init(servletConfig); } /** * {@inheritDoc} */ protected void doInvite(SipServletRequest request) throws ServletException, IOException { logger.info("from : " + request.getFrom()); logger.info("Got request: " + request.getMethod()); if(request.getParameterableHeader("additionalParameterableHeader") != null) { request.getParameterableHeader("additionalParameterableHeader").setParameter("dsfds", "value"); boolean error = false; try { request.getParameterableHeader("nonParameterableHeader").setParameter("dsfds", "value"); } catch (ServletParseException e) { error = true; } if(error) { // Success only if nonParameterable headers thow excpetion when treated as parametereable request.createResponse(200).send(); } return; } request.createResponse(SipServletResponse.SC_TRYING).send(); String fromString = request.getFrom().toString(); if(fromString.contains(TEST_EXTERNAL_ROUTING_NO_INFO)) { SipServletResponse sipServletResponse = request.createResponse(SipServletResponse.SC_OK); timerService.createTimer(request.getApplicationSession(), 1000, false, (Serializable)sipServletResponse); return; } if(fromString.contains(TEST_EXTERNAL_ROUTING)) { SipServletResponse sipServletResponse = request.createResponse(SipServletResponse.SC_RINGING); sipServletResponse.send(); sipServletResponse = request.createResponse(SipServletResponse.SC_OK); timerService.createTimer(request.getApplicationSession(), 1000, false, (Serializable)sipServletResponse); return; } if(fromString.contains(TEST_ALLOW_HEADER)) { SipServletResponse sipServletResponse = request.createResponse(SipServletResponse.SC_METHOD_NOT_ALLOWED); sipServletResponse.setHeader("Allow", "INVITE, ACK, CANCEL, OPTIONS, BYE"); sipServletResponse.addHeader("Allow", "SUBSCRIBE, NOTIFY"); sipServletResponse.addHeader("Allow", "REFER"); sipServletResponse.send(); return; } logger.info("Subscriber URI received : " + request.getSubscriberURI()); if(fromString.contains(TEST_SUBSCRIBER_URI) && !SUBSCRIBER_URI.equalsIgnoreCase(request.getSubscriberURI().toString())) { SipServletResponse sipServletResponse = request.createResponse(SipServletResponse.SC_SERVER_INTERNAL_ERROR); sipServletResponse.send(); return; } if(fromString.contains(TEST_TO_TAG)) { //checking if the to tag is not Address fromAddress = request.getFrom(); Address toAddress = sipFactory.createAddress(request.getRequestURI(), request.getTo().getDisplayName()); SipServletRequest newRequest = sipFactory.createRequest(request.getApplicationSession(), "INVITE", fromAddress, toAddress); if(newRequest.getTo().getParameter("tag") != null) { logger.error("the ToTag should be empty, sending 500 response"); SipServletResponse sipServletResponse = request.createResponse(SipServletResponse.SC_SERVER_INTERNAL_ERROR); sipServletResponse.send(); return; } } request.getAddressHeader(TEST_NON_EXISTING_HEADER); request.getHeader(TEST_NON_EXISTING_HEADER); request.getHeaders(TEST_NON_EXISTING_HEADER); request.getParameterableHeader("Reply-To"); request.getParameterableHeaders("Reply-To"); // Test register cseq issue http://groups.google.com/group/mobicents-public/browse_thread/thread/70f472ca111baccf if(fromString.contains(TEST_REGISTER_C_SEQ)) { SipServletResponse sipServletResponse = request.createResponse(SipServletResponse.SC_RINGING); sipServletResponse.send(); sipServletResponse = request.createResponse(SipServletResponse.SC_OK); sipServletResponse.send(); sendRegister(null); return; } if(fromString.contains(TEST_REGISTER_SAVED_SESSION)) { SipServletResponse sipServletResponse = request.createResponse(SipServletResponse.SC_RINGING); sipServletResponse.send(); sipServletResponse = request.createResponse(SipServletResponse.SC_OK); sipServletResponse.send(); sendRegister(); return; } if(!TEST_CANCEL_USERNAME.equalsIgnoreCase(((SipURI)request.getFrom().getURI()).getUser())) { SipServletResponse sipServletResponse = request.createResponse(SipServletResponse.SC_RINGING); sipServletResponse.send(); sipServletResponse = request.createResponse(SipServletResponse.SC_OK); sipServletResponse.send(); } else { SipServletResponse sipServletResponse = request.createResponse(SipServletResponse.SC_RINGING); sipServletResponse.send(); try { Thread.sleep(2000); } catch (InterruptedException e) { logger.error("unexpected exception while waiting ", e); } sipServletResponse = request.createResponse(SipServletResponse.SC_OK); sipServletResponse.send(); } } @Override protected void doAck(SipServletRequest req) throws ServletException, IOException { if(req.getFrom().getURI() instanceof SipURI) { if(TEST_REINVITE_USERNAME.equalsIgnoreCase(((SipURI)req.getFrom().getURI()).getUser())) { SipServletRequest reInvite = req.getSession(false).createRequest("INVITE"); if(reInvite.getHeader("Contact").contains("0.0.0.0")) { logger.error("Reinvite doesn't add correct address. We must not see 0.0.0.0 here"); return; } if(req.getSession(false) == reInvite.getSession(false)) { reInvite.send(); } else { logger.error("the newly created subsequent request doesn't have " + "the same session instance as the one it has been created from"); } } else if(TEST_IS_SEND_REINVITE_USERNAME.equalsIgnoreCase(((SipURI)req.getFrom().getURI()).getUser())) { Integer nbOfAcks = (Integer) req.getSession().getAttribute("nbAcks"); if(nbOfAcks == null) { nbOfAcks = Integer.valueOf(1); } else { nbOfAcks = Integer.valueOf(nbOfAcks.intValue() + 1); } req.getSession().setAttribute("nbAcks", nbOfAcks); } } } @Override protected void doSuccessResponse(SipServletResponse resp) throws ServletException, IOException { // This is for the REGISTER CSeq test if(resp.getMethod().equalsIgnoreCase("REGISTER")) { int cseq = Integer.parseInt(resp.getRequest().getHeader("CSeq").substring(0,1)); if(cseq < 4) { try { // Put some delay as per http://groups.google.com/group/mobicents-public/browse_thread/thread/70f472ca111baccf Thread.sleep(15000); } catch (InterruptedException e) { logger.error("Unexpected exception", e); } // Check if the session remains in INITIAL state, if not, the test will fail for missing registers if(resp.getSession().getState().equals(State.INITIAL)) { String fromString = resp.getFrom().toString(); if(fromString.contains(TEST_REGISTER_SAVED_SESSION)) { // registerSipSession = resp.getSession(); sendRegister(); } else { sendRegister(resp.getSession()); } } } return; } if(!"BYE".equalsIgnoreCase(resp.getMethod())) { resp.createAck().send(); resp.getSession(false).createRequest("BYE").send(); } } @Override protected void doErrorResponse(SipServletResponse response) throws ServletException, IOException { SipFactory sipFactory = (SipFactory) getServletContext().getAttribute(SIP_FACTORY); if(response.getStatus() == SipServletResponse.SC_UNAUTHORIZED || response.getStatus() == SipServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED) { // Avoid re-sending if the auth repeatedly fails. if(!"true".equals(getServletContext().getAttribute("FirstResponseRecieved"))) { getServletContext().setAttribute("FirstResponseRecieved", "true"); AuthInfo authInfo = sipFactory.createAuthInfo(); authInfo.addAuthInfo(response.getStatus(), "sip-servlets-realm", "user", "pass"); SipServletRequest challengeRequest = null; String fromString = response.getFrom().toString(); if(fromString.contains(TEST_REGISTER_SAVED_SESSION)) { // registerSipSession = response.getSession(); challengeRequest = registerSipSession.createRequest( response.getMethod()); } else { challengeRequest = response.getSession().createRequest( response.getMethod()); } challengeRequest.addAuthHeader(response, authInfo); challengeRequest.send(); } } logger.info("Got response: " + response); } /** * {@inheritDoc} */ protected void doBye(SipServletRequest request) throws ServletException, IOException { int statusCode = SipServletResponse.SC_OK; logger.info("Got BYE request: " + request); if(TEST_IS_SEND_REINVITE_USERNAME.equalsIgnoreCase(((SipURI)request.getFrom().getURI()).getUser())) { Integer nbOfAcks = (Integer) request.getSession().getAttribute("nbAcks"); if(nbOfAcks == null || nbOfAcks.intValue() != 2) { statusCode = SipServletResponse.SC_DECLINE; } } SipServletResponse sipServletResponse = request.createResponse(statusCode); // Force fail by not sending OK if the doBranchResponse is called. In non-proxy app // this would be wrong. if(!"true".equals(request.getApplicationSession().getAttribute("doBranchResponse"))) sipServletResponse.send(); } @Override protected void doCancel(SipServletRequest request) throws ServletException, IOException { logger.info("Got CANCEL request: " + request); SipFactory sipFactory = (SipFactory)getServletContext().getAttribute(SIP_FACTORY); try { SipServletRequest sipServletRequest = sipFactory.createRequest( sipFactory.createApplicationSession(), "MESSAGE", "sip:sender@sip-servlets.com", "sip:receiver@sip-servlets.com"); SipURI sipUri=sipFactory.createSipURI("receiver", "127.0.0.1:5080"); sipServletRequest.setRequestURI(sipUri); sipServletRequest.setContentLength(CANCEL_RECEIVED.length()); sipServletRequest.setContent(CANCEL_RECEIVED, CONTENT_TYPE); sipServletRequest.send(); } catch (ServletParseException e) { logger.error("Exception occured while parsing the addresses",e); } catch (IOException e) { logger.error("Exception occured while sending the request",e); } } @Override protected void doRegister(SipServletRequest req) throws ServletException, IOException { Address contact = req.getAddressHeader("Contact"); contact.setExpires(3600); logger.info("REGISTER Contact Address.toString = " + contact.toString()); int response = SipServletResponse.SC_OK; if(!"<sip:sender@127.0.0.1:5080;transport=udp;lr>;expires=3600".equals(contact.toString())) { response = SipServletResponse.SC_SERVER_INTERNAL_ERROR; } SipServletResponse resp = req.createResponse(response); resp.send(); } @Override protected void doInfo(SipServletRequest req) throws ServletException, IOException { String content = (String) req.getContent(); req.getSession().setAttribute("mutable", content); try { Thread.sleep(5000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } int response = SipServletResponse.SC_OK; if(!content.equals(req.getSession().getAttribute("mutable"))) response = SipServletResponse.SC_SERVER_INTERNAL_ERROR; SipServletResponse resp = req.createResponse(response); resp.send(); } // SipErrorListener methods /** * {@inheritDoc} */ public void noAckReceived(SipErrorEvent ee) { logger.error("noAckReceived."); } /** * {@inheritDoc} */ public void noPrackReceived(SipErrorEvent ee) { logger.error("noPrackReceived."); } public void timeout(ServletTimer timer) { SipServletResponse sipServletResponse = (SipServletResponse)timer.getInfo(); try { sipServletResponse.send(); } catch (IOException e) { logger.error("Unexpected exception while sending the OK", e); } } private void sendRegister() throws ServletParseException, IOException { SipServletRequest register = null; if (registerSipSession != null) { logger.info("saved session instance : " + registerSipSession); logger.info("session attribute is : " + registerSipSession.getAttribute("attribute")); register = registerSipSession.createRequest("REGISTER"); } else { SipApplicationSession app = sipFactory.createApplicationSession(); register = sipFactory.createRequest(app, "REGISTER", "sip:testRegisterSavedSession@simple-servlet.com", "sip:you@localhost:5058"); Parameterable contact = sipFactory.createParameterable("sip:john@127.0.0.1:6090;expires=900"); register.addParameterableHeader("Contact", contact, true); registerSipSession = register.getSession(); logger.info("saved session instance : " + registerSipSession); registerSipSession.setAttribute("attribute", "value"); } register.setHeader("Expires", "3600"); register.setHeader("test", "test"); register.send(); } private void sendRegister(SipSession sipSession) throws ServletParseException, IOException { SipServletRequest register = null; if (sipSession != null) { register = sipSession.createRequest("REGISTER"); } else { SipApplicationSession app = sipFactory.createApplicationSession(); register = sipFactory.createRequest(app, "REGISTER", "sip:testRegisterCSeq@simple-servlet.com", "sip:you@localhost:5058"); Parameterable contact = sipFactory.createParameterable("sip:john@127.0.0.1:6090;expires=900"); register.addParameterableHeader("Contact", contact, true); } register.setHeader("Expires", "3600"); register.setHeader("test", "test"); register.send(); } }