基于JAINSIP协议栈的一个简单SIP服务器实现流程

来源:互联网 发布:普通话标准发音软件 编辑:程序博客网 时间:2024/06/06 01:49
SIP服务器采用B2BUA,sip呼叫控制实现流程
TAG:


SIP服务器采用B2BUA,sip呼叫控制实现流程: 

INVITE的请求: 
收到INVITE后,克隆INVITE消息。替换Request URI被叫注册的地址。 
替换VIA头为服务器地址。通过该INVITE请求得到客户端事务并通过 
该事务来发送INVITE请求。 

180,200 OK响应的处理: 
根据返回的响应码创建新的响应。 
替换CONTACT头地址为服务器的地址。 
拷贝原响应中的媒体内容至新的响应中。 
通过INVITE中保存下来的服务端事务发送响应消息。 

ACK的处理: 
从ACK请求中得到序列数。 
通过被叫对话来创建新的ACK请求。 
通过被叫对话发送ACK请求。 

BYE的处理流程: 
根据被叫端的客户端事务得到发送给被叫的INVITE请求,根据INVITE请求创建BYE消息。 
BYE响应消息处理流程: 
根据DIALOG得到服务端事务,并由此得到BYE请求。根据BYE请求创建响应。 

CANCEL的处理流程: 
向主叫响应CANCEL 200 OK。 
根据客户端事务得到发送给主叫的INVITE请求中的URI,CALLID,FROM,TO,VIA头域来创建CANCEL请求。 

注:非200 OK的ACK响应是由协议栈来实现的,不需要应用层来发送。也就是说,ACK消息不会经过应用层。 

package com.voip.sipphone; import gov.nist.javax.sip.address.SipUri; import gov.nist.javax.sip.header.CSeq; import gov.nist.javax.sip.header.Contact; import gov.nist.javax.sip.header.ContentLength; import gov.nist.javax.sip.header.ContentType; import gov.nist.javax.sip.header.From; import gov.nist.javax.sip.header.Via; import java.text.ParseException; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; import java.util.Properties; import java.util.Timer; import javax.sip.*; import javax.sip.address.Address; import javax.sip.address.AddressFactory; import javax.sip.address.URI; import javax.sip.header.CallIdHeader; import javax.sip.header.ContactHeader; import javax.sip.header.ExpiresHeader; import javax.sip.header.FromHeader; import javax.sip.header.Header; import javax.sip.header.HeaderFactory; import javax.sip.header.MaxForwardsHeader; import javax.sip.header.RecordRouteHeader; import javax.sip.header.ToHeader; import javax.sip.header.ViaHeader; import javax.sip.message.MessageFactory; import javax.sip.message.Request; import javax.sip.message.Response; public class SipPhone implements SipListener  {  public void processDialogTerminated(DialogTerminatedEvent arg0) {   // TODO Auto-generated method stub   System.out.println("processDialogTerminated " + arg0.toString());  }  public void processIOException(IOExceptionEvent arg0) {   // TODO Auto-generated method stub   System.out.println("processIOException " + arg0.toString());  }    /**   * 保存当前注册的用户   */  private static Hashtable<URI, URI> currUser = new Hashtable();      /**   * @author software   * 注册定时器   */  class TimerTask extends Timer  {   /**    * default constructor    */   public TimerTask()   {       }      /**    *  如果定时任务到,则删除该用户的注册信息    */   public void run()   {       }  }      /**   * 服务器侦听IP地址   */  private String ipAddr = "192.168.0.20";      /**   * 服务器侦听端口   */  private int port = 5060;    /**   * 处理register请求   * @param request 请求消息   */  private void processRegister(Request request, RequestEvent requestEvent)  {   if (null == request)   {    System.out.println("processInvite request is null.");    return;   }   //System.out.println("Request " + request.toString());   ServerTransaction serverTransactionId = requestEvent.getServerTransaction();      try    {    Response response = null;    ToHeader head = (ToHeader)request.getHeader(ToHeader.NAME);    Address toAddress = head.getAddress();    URI toURI = toAddress.getURI();    ContactHeader contactHeader = (ContactHeader) request.getHeader("Contact");    Address contactAddr = contactHeader.getAddress();    URI contactURI = contactAddr.getURI();    System.out.println("processRegister from: " + toURI + " request str: " + contactURI);    int expires = request.getExpires().getExpires();    // 如果expires不等于0,则为注册,否则为注销。    if (expires != 0 || contactHeader.getExpires() != 0)    {     currUser.put(toURI, contactURI);     System.out.println("register user " + toURI);    }    else    {       currUser.remove(toURI);     System.out.println("unregister user " + toURI);    }        response = msgFactory.createResponse(200, request);    System.out.println("send register response  : " + response.toString());           if(serverTransactionId == null)    {     serverTransactionId = sipProvider.getNewServerTransaction(request);     serverTransactionId.sendResponse(response);     //serverTransactionId.terminate();     System.out.println("register serverTransaction: " + serverTransactionId);    }    else    {     System.out.println("processRequest serverTransactionId is null.");    }       }   catch (ParseException e)   {    // TODO Auto-generated catch block    e.printStackTrace();   }   catch (SipException e)    {    // TODO Auto-generated catch block    e.printStackTrace();   }   catch (InvalidArgumentException e)   {    // TODO Auto-generated catch block    e.printStackTrace();   }  }    /**   * 处理invite请求   * @param request 请求消息   */  private void processInvite(Request request, RequestEvent requestEvent)  {   if (null == request)   {    System.out.println("processInvite request is null.");    return;   }   try   {     // 发送100 Trying    serverTransactionId = requestEvent.getServerTransaction();    if (serverTransactionId == null)    {     serverTransactionId = sipProvider.getNewServerTransaction(request);     callerDialog = serverTransactionId.getDialog();     Response response = msgFactory.createResponse(Response.TRYING, request);     serverTransactionId.sendResponse(response);    }    //查询目标地址    URI reqUri = request.getRequestURI();    URI contactURI = currUser.get(reqUri);        System.out.println("processInvite rqStr=" + reqUri + " contact=" + contactURI);        //根据Request uri来路由,后续的响应消息通过VIA来路由    Request cliReq = msgFactory.createRequest(request.toString());    cliReq.setRequestURI(contactURI);           Via callerVia = (Via)request.getHeader(Via.NAME);    Via via = (Via) headerFactory.createViaHeader(ipAddr, port, "UDP", callerVia.getBranch()+"sipphone");        // FIXME 需要测试是否能够通过设置VIA头域来修改VIA头域值    cliReq.removeHeader(Via.NAME);    cliReq.addHeader(via);        // 更新contact的地址    ContactHeader contactHeader = headerFactory.createContactHeader();    Address address = addressFactory.createAddress("sip:sipsoft@" + ipAddr +":"+ port);    contactHeader.setAddress(address);    contactHeader.setExpires(3600);    cliReq.setHeader(contactHeader);        clientTransactionId = sipProvider.getNewClientTransaction(cliReq);    clientTransactionId.sendRequest();        System.out.println("processInvite clientTransactionId=" + clientTransactionId.toString());        System.out.println("send invite to callee: " + cliReq);         }   catch (TransactionUnavailableException e1)   {    // TODO Auto-generated catch block    e1.printStackTrace();   }   catch (SipException e)   {    // TODO Auto-generated catch block    e.printStackTrace();   }   catch (ParseException e)   {    e.printStackTrace();   }   catch (Exception e)   {    e.printStackTrace();   }  }    /**   * 处理SUBSCRIBE请求   * @param request 请求消息   */  private void processSubscribe(Request request)  {   if (null == request)   {    System.out.println("processSubscribe request is null.");    return;   }   ServerTransaction serverTransactionId = null;   try    {    serverTransactionId = sipProvider.getNewServerTransaction(request);   }   catch (TransactionAlreadyExistsException e1)   {    // TODO Auto-generated catch block    e1.printStackTrace();   } catch (TransactionUnavailableException e1)   {    // TODO Auto-generated catch block    e1.printStackTrace();   }      try    {    Response response = null;    response = msgFactory.createResponse(200, request);    if (response != null)    {     ExpiresHeader expireHeader = headerFactory.createExpiresHeader(30);     response.setExpires(expireHeader);    }    System.out.println("response : " + response.toString());        if(serverTransactionId != null)    {     serverTransactionId.sendResponse(response);     serverTransactionId.terminate();         }    else    {     System.out.println("processRequest serverTransactionId is null.");    }       }   catch (ParseException e)   {    // TODO Auto-generated catch block    e.printStackTrace();   }   catch (SipException e)    {    // TODO Auto-generated catch block    e.printStackTrace();   }   catch (InvalidArgumentException e)   {    // TODO Auto-generated catch block    e.printStackTrace();   }  }  /**   * 处理BYE请求   * @param request 请求消息   */  private void processBye(Request request, RequestEvent requestEvent)  {   if (null == request || null == requestEvent)   {    System.out.println("processBye request is null.");    return;   }   Request byeReq = null;   Dialog dialog = requestEvent.getDialog();   System.out.println("calleeDialog : " + calleeDialog);   System.out.println("callerDialog : " + callerDialog);   try   {    if (dialog.equals(calleeDialog))    {     byeReq = callerDialog.createRequest(request.getMethod());     ClientTransaction clientTran = sipProvider.getNewClientTransaction(byeReq);     callerDialog.sendRequest(clientTran);     calleeDialog.setApplicationData(requestEvent.getServerTransaction());    }    else if (dialog.equals(callerDialog))    {     byeReq = calleeDialog.createRequest(request.getMethod());     ClientTransaction clientTran = sipProvider.getNewClientTransaction(byeReq);     calleeDialog.sendRequest(clientTran);      callerDialog.setApplicationData(requestEvent.getServerTransaction());    }    else    {     System.out.println("");    }        System.out.println("send bye to peer:" + byeReq.toString());   }   catch (SipException e)   {    // TODO Auto-generated catch block    e.printStackTrace();   }         }    /**   * 处理CANCEL请求   * @param request 请求消息   */  private void processCancel(Request request)  {   if (null == request)   {    System.out.println("processCancel request is null.");    return;   }  }    /**   * 处理INFO请求   * @param request 请求消息   */  private void processInfo(Request request)  {   if (null == request)   {    System.out.println("processInfo request is null.");    return;   }  }      /**   * 处理ACK请求   * @param request 请求消息   */  private void processAck(Request request, RequestEvent requestEvent)  {   if (null == request)   {    System.out.println("processAck request is null.");    return;   }      try    {    Request ackRequest = null;    CSeq csReq = (CSeq)request.getHeader(CSeq.NAME);       ackRequest = calleeDialog.createAck(csReq.getSeqNumber());    calleeDialog.sendAck(ackRequest);       System.out.println("send ack to callee:" + ackRequest.toString());   }   catch (SipException e)   {    // TODO Auto-generated catch block    e.printStackTrace();   }    catch (InvalidArgumentException e)    {    // TODO Auto-generated catch block    e.printStackTrace();   }        }    /**   * 处理CANCEL消息   * @param request   * @param requestEvent   */  private void processCancel(Request request, RequestEvent requestEvent)  {   // 判断参数是否有效   if (request == null || requestEvent == null)   {    System.out.println("processCancel input parameter invalid.");    return;   }        try   {    // 发送CANCEL 200 OK消息    Response response = msgFactory.createResponse(Response.OK, request);    ServerTransaction cancelServTran = requestEvent.getServerTransaction();    if (cancelServTran == null)    {     cancelServTran = sipProvider.getNewServerTransaction(request);    }    cancelServTran.sendResponse(response);        // 向对端发送CANCEL消息       Request cancelReq = null;    Request inviteReq = clientTransactionId.getRequest();    List list = new ArrayList();    Via viaHeader = (Via)inviteReq.getHeader(Via.NAME);    list.add(viaHeader);        CSeq cseq = (CSeq)inviteReq.getHeader(CSeq.NAME);    CSeq cancelCSeq = (CSeq)headerFactory.createCSeqHeader(cseq.getSeqNumber(), Request.CANCEL);    cancelReq = msgFactory.createRequest(inviteReq.getRequestURI(),      inviteReq.getMethod(),      (CallIdHeader)inviteReq.getHeader(CallIdHeader.NAME),      cancelCSeq,      (FromHeader)inviteReq.getHeader(From.NAME),      (ToHeader)inviteReq.getHeader(ToHeader.NAME),      list,       (MaxForwardsHeader)inviteReq.getHeader(MaxForwardsHeader.NAME));    ClientTransaction cancelClientTran = sipProvider.getNewClientTransaction(cancelReq);    cancelClientTran.sendRequest();   }   catch (ParseException e)   {    // TODO Auto-generated catch block    e.printStackTrace();   }    catch (TransactionAlreadyExistsException e)   {    // TODO Auto-generated catch block    e.printStackTrace();   }   catch (TransactionUnavailableException e)   {    // TODO Auto-generated catch block    e.printStackTrace();   }    catch (SipException e)   {    // TODO Auto-generated catch block    e.printStackTrace();   }   catch (InvalidArgumentException e)   {    // TODO Auto-generated catch block    e.printStackTrace();   }  }      private ServerTransaction serverTransactionId = null;  /* (non-Javadoc)   * @see javax.sip.SipListener#processRequest(javax.sip.RequestEvent)   */  public void processRequest(RequestEvent arg0)   {   Request request = arg0.getRequest();   if (null == request)   {    System.out.println("processRequest request is null.");    return;   }   System.out.println("processRequest:" + request.toString());   if (Request.INVITE.equals(request.getMethod()))   {          processInvite(request, arg0);   }   else if (Request.REGISTER.equals(request.getMethod()))   {    processRegister(request, arg0);   }   else if (Request.SUBSCRIBE.equals(request.getMethod()))   {    processSubscribe(request);   }   else if (Request.ACK.equalsIgnoreCase(request.getMethod()))   {    processAck(request, arg0);   }   else if (Request.BYE.equalsIgnoreCase(request.getMethod()))   {    processBye(request, arg0);   }   else if (Request.CANCEL.equalsIgnoreCase(request.getMethod()))   {    processCancel(request, arg0);   }   else   {    System.out.println("no support the method!");   }  }  /**   * 主叫对话   */  private Dialog calleeDialog = null;    /**   * 被叫对话   */  private Dialog callerDialog = null;    /**   *    */  ClientTransaction clientTransactionId = null;    /**   * 处理BYE响应消息   * @param reponseEvent   */  private void doByeResponse(Response response, ResponseEvent responseEvent)  {   Dialog dialog = responseEvent.getDialog();      try   {    Response byeResp = null;    if (callerDialog.equals(dialog))    {     ServerTransaction servTran = (ServerTransaction)calleeDialog.getApplicationData();     byeResp = msgFactory.createResponse(response.getStatusCode(), servTran.getRequest());     servTran.sendResponse(byeResp);    }    else if (calleeDialog.equals(dialog))    {     ServerTransaction servTran = (ServerTransaction)callerDialog.getApplicationData();     byeResp = msgFactory.createResponse(response.getStatusCode(), servTran.getRequest());     servTran.sendResponse(byeResp);    }    else    {         }    System.out.println("send bye response to peer:" + byeResp.toString());   }   catch (ParseException e)   {    // TODO Auto-generated catch block    e.printStackTrace();   } catch (SipException e)   {    // TODO Auto-generated catch block    e.printStackTrace();   } catch (InvalidArgumentException e)    {    // TODO Auto-generated catch block    e.printStackTrace();   }  }  /* (non-Javadoc)   * @see javax.sip.SipListener#processResponse(javax.sip.ResponseEvent)   *    */  public void processResponse(ResponseEvent arg0)  {   // FIXME 需要判断各个响应对应的是什么请求   Response response = arg0.getResponse();      System.out.println("recv the response :" +  response.toString());   System.out.println("respone to request : " + arg0.getClientTransaction().getRequest());      if (response.getStatusCode() == Response.TRYING)   {    System.out.println("The response is 100 response.");    return;   }      try   {    ClientTransaction clientTran = (ClientTransaction) arg0.getClientTransaction();        if (Request.INVITE.equalsIgnoreCase(clientTran.getRequest().getMethod()))    {     int statusCode = response.getStatusCode();        Response callerResp = null;       callerResp = msgFactory.createResponse(statusCode, serverTransactionId.getRequest());       // 更新contact头域值,因为后面的消息是根据该URI来路由的     ContactHeader contactHeader = headerFactory.createContactHeader();     Address address = addressFactory.createAddress("sip:sipsoft@"+ipAddr+":"+port);        contactHeader.setAddress(address);     contactHeader.setExpires(3600);     callerResp.addHeader(contactHeader);          // 拷贝to头域     ToHeader toHeader = (ToHeader)response.getHeader(ToHeader.NAME);     callerResp.setHeader(toHeader);          // 拷贝相应的消息体     ContentLength contentLen = (ContentLength)response.getContentLength();     if (contentLen != null && contentLen.getContentLength() != 0)     {      ContentType contentType = (ContentType)response.getHeader(ContentType.NAME);      System.out.println("the sdp contenttype is " + contentType);            callerResp.setContentLength(contentLen);      //callerResp.addHeader(contentType);      callerResp.setContent(response.getContent(), contentType);     }     else     {      System.out.println("sdp is null.");     }     if (serverTransactionId != null)     {      callerDialog = serverTransactionId.getDialog();      calleeDialog = clientTran.getDialog();      serverTransactionId.sendResponse(callerResp);      System.out.println("callerDialog=" + callerDialog);      System.out.println("serverTransactionId.branch=" + serverTransactionId.getBranchId());          }     else     {      System.out.println("serverTransactionId is null.");     }             System.out.println("send response to caller : " + callerResp.toString());    }    else if (Request.BYE.equalsIgnoreCase(clientTran.getRequest().getMethod()))    {     doByeResponse(response, arg0);    }    else if (Request.CANCEL.equalsIgnoreCase(clientTran.getRequest().getMethod()))    {     //doCancelResponse(response, arg0);    }    else     {         }           }   catch (ParseException e)   {    // TODO Auto-generated catch block    e.printStackTrace();   }   catch (SipException e)   {    // TODO Auto-generated catch block    e.printStackTrace();   }   catch (InvalidArgumentException e)   {    // TODO Auto-generated catch block    e.printStackTrace();   }   catch (Exception ex)   {    ex.printStackTrace();   }     }    private void doCancelResponse(Response response, ResponseEvent responseEvent)  {   //FIXME  需要验证参数的有效性   ServerTransaction servTran = (ServerTransaction)callerDialog.getApplicationData();   Response cancelResp;   try    {    cancelResp = msgFactory.createResponse(response.getStatusCode(), servTran.getRequest());    servTran.sendResponse(cancelResp);   }   catch (ParseException e)   {    // TODO Auto-generated catch block    e.printStackTrace();   }    catch (SipException e)   {    // TODO Auto-generated catch block    e.printStackTrace();   }    catch (InvalidArgumentException e)   {    // TODO Auto-generated catch block    e.printStackTrace();   }     }  public void processTimeout(TimeoutEvent arg0)  {   // TODO Auto-generated method stub   System.out.println(" processTimeout " + arg0.toString());  }  public void processTransactionTerminated(TransactionTerminatedEvent arg0) {   // TODO Auto-generated method stub   System.out.println(" processTransactionTerminated " + arg0.getClientTransaction().getBranchId()          + " " + arg0.getServerTransaction().getBranchId());   }    private static SipStack sipStack = null;    private static AddressFactory addressFactory = null;    private static MessageFactory msgFactory = null;    private static HeaderFactory headerFactory = null;    private static SipProvider sipProvider = null;    private void init()  {   SipFactory sipFactory = null;      sipFactory = SipFactory.getInstance();   if (null == sipFactory)   {    System.out.println("init sipFactory is null.");    return;   }      sipFactory.setPathName("gov.nist");   Properties properties = new Properties();   properties.setProperty("javax.sip.STACK_NAME", "sipphone");   // 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",     "sipphonedebug.txt");   properties.setProperty("gov.nist.javax.sip.SERVER_LOG",     "sipphonelog.txt");   try    {    sipStack = sipFactory.createSipStack(properties);   }   catch (PeerUnavailableException e)   {    // TODO Auto-generated catch block    e.printStackTrace();    return;   }      try   {    headerFactory = sipFactory.createHeaderFactory();    addressFactory = sipFactory.createAddressFactory();    msgFactory = sipFactory.createMessageFactory();    ListeningPoint lp = sipStack.createListeningPoint("192.168.0.20",      5060, "udp");    SipPhone listener = this;        sipProvider = sipStack.createSipProvider(lp);    System.out.println("udp provider " + sipProvider.toString());    sipProvider.addSipListener(listener);   }   catch (Exception ex)   {    ex.printStackTrace();    return;   }     }    /**   * 程序入口   * @param args   */  public static void main(String []args)  {   new SipPhone().init();  }   }
阅读全文
0 0
原创粉丝点击