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

时间:2025-01-31 12:29:56


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 ; 
import ; 
import ; 
import ; 
import ; 
import ; 
import ; 
import ; 
import ; 
import ; 
import ; 
import ; 
import ; 
import ; 
import .*; 
import ; 
import ; 
import ; 
import ; 
import ; 
import ; 
import ; 
import ; 
import ; 
import ; 
import ; 
import ; 
import ; 
import ; 
import ; 
import ; 
public class SipPhone implements SipListener  
{ 
 public void processDialogTerminated(DialogTerminatedEvent arg0) { 
  // TODO Auto-generated method stub 
  ("processDialogTerminated " + ()); 
 } 
 public void processIOException(IOExceptionEvent arg0) { 
  // TODO Auto-generated method stub 
  ("processIOException " + ()); 
 } 
  
 /** 
  * 保存当前注册的用户 
  */ 
 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) 
  { 
   ("processInvite request is null."); 
   return; 
  } 
  //("Request " + ()); 
  ServerTransaction serverTransactionId = (); 
   
  try  
  { 
   Response response = null; 
   ToHeader head = (ToHeader)(); 
   Address toAddress = (); 
   URI toURI = (); 
   ContactHeader contactHeader = (ContactHeader) ("Contact"); 
   Address contactAddr = (); 
   URI contactURI = (); 
   ("processRegister from: " + toURI + " request str: " + contactURI); 
   int expires = ().getExpires(); 
   // 如果expires不等于0,则为注册,否则为注销。 
   if (expires != 0 || () != 0) 
   { 
    (toURI, contactURI); 
    ("register user " + toURI); 
   } 
   else 
   {   
    (toURI); 
    ("unregister user " + toURI); 
   } 
    
   response = (200, request); 
   ("send register response  : " + ());    
    
   if(serverTransactionId == null) 
   { 
    serverTransactionId = (request); 
    (response); 
    //(); 
    ("register serverTransaction: " + serverTransactionId); 
   } 
   else 
   { 
    ("processRequest serverTransactionId is null."); 
   } 
    
  } 
  catch (ParseException e) 
  { 
   // TODO Auto-generated catch block 
   (); 
  } 
  catch (SipException e)  
  { 
   // TODO Auto-generated catch block 
   (); 
  } 
  catch (InvalidArgumentException e) 
  { 
   // TODO Auto-generated catch block 
   (); 
  } 
 } 
  
 /** 
  * 处理invite请求 
  * @param request 请求消息 
  */ 
 private void processInvite(Request request, RequestEvent requestEvent) 
 { 
  if (null == request) 
  { 
   ("processInvite request is null."); 
   return; 
  } 
  try 
  {  
   // 发送100 Trying 
   serverTransactionId = (); 
   if (serverTransactionId == null) 
   { 
    serverTransactionId = (request); 
    callerDialog = (); 
    Response response = (, request); 
    (response); 
   } 
   //查询目标地址 
   URI reqUri = (); 
   URI contactURI = (reqUri); 
    
   ("processInvite rqStr=" + reqUri + " contact=" + contactURI); 
    
   //根据Request uri来路由,后续的响应消息通过VIA来路由 
   Request cliReq = (()); 
   (contactURI); 
       
   Via callerVia = (Via)(); 
   Via via = (Via) (ipAddr, port, "UDP", ()+"sipphone"); 
    
   // FIXME 需要测试是否能够通过设置VIA头域来修改VIA头域值 
   (); 
   (via); 
    
   // 更新contact的地址 
   ContactHeader contactHeader = (); 
   Address address = ("sip:sipsoft@" + ipAddr +":"+ port); 
   (address); 
   (3600); 
   (contactHeader); 
    
   clientTransactionId = (cliReq); 
   (); 
    
   ("processInvite clientTransactionId=" + ()); 
    
   ("send invite to callee: " + cliReq);       
  } 
  catch (TransactionUnavailableException e1) 
  { 
   // TODO Auto-generated catch block 
   (); 
  } 
  catch (SipException e) 
  { 
   // TODO Auto-generated catch block 
   (); 
  } 
  catch (ParseException e) 
  { 
   (); 
  } 
  catch (Exception e) 
  { 
   (); 
  } 
 } 
  
 /** 
  * 处理SUBSCRIBE请求 
  * @param request 请求消息 
  */ 
 private void processSubscribe(Request request) 
 { 
  if (null == request) 
  { 
   ("processSubscribe request is null."); 
   return; 
  } 
  ServerTransaction serverTransactionId = null; 
  try  
  { 
   serverTransactionId = (request); 
  } 
  catch (TransactionAlreadyExistsException e1) 
  { 
   // TODO Auto-generated catch block 
   (); 
  } catch (TransactionUnavailableException e1) 
  { 
   // TODO Auto-generated catch block 
   (); 
  } 
   
  try  
  { 
   Response response = null; 
   response = (200, request); 
   if (response != null) 
   { 
    ExpiresHeader expireHeader = (30); 
    (expireHeader); 
   } 
   ("response : " + ()); 
    
   if(serverTransactionId != null) 
   { 
    (response); 
    ();      
   } 
   else 
   { 
    ("processRequest serverTransactionId is null."); 
   } 
    
  } 
  catch (ParseException e) 
  { 
   // TODO Auto-generated catch block 
   (); 
  } 
  catch (SipException e)  
  { 
   // TODO Auto-generated catch block 
   (); 
  } 
  catch (InvalidArgumentException e) 
  { 
   // TODO Auto-generated catch block 
   (); 
  } 
 } 
 /** 
  * 处理BYE请求 
  * @param request 请求消息 
  */ 
 private void processBye(Request request, RequestEvent requestEvent) 
 { 
  if (null == request || null == requestEvent) 
  { 
   ("processBye request is null."); 
   return; 
  } 
  Request byeReq = null; 
  Dialog dialog = (); 
  ("calleeDialog : " + calleeDialog); 
  ("callerDialog : " + callerDialog); 
  try 
  { 
   if ((calleeDialog)) 
   { 
    byeReq = (()); 
    ClientTransaction clientTran = (byeReq); 
    (clientTran); 
    (()); 
   } 
   else if ((callerDialog)) 
   { 
    byeReq = (()); 
    ClientTransaction clientTran = (byeReq); 
    (clientTran);  
    (()); 
   } 
   else 
   { 
    (""); 
   } 
    
   ("send bye to peer:" + ()); 
  } 
  catch (SipException e) 
  { 
   // TODO Auto-generated catch block 
   (); 
  }     
   
 } 
  
 /** 
  * 处理CANCEL请求 
  * @param request 请求消息 
  */ 
 private void processCancel(Request request) 
 { 
  if (null == request) 
  { 
   ("processCancel request is null."); 
   return; 
  } 
 } 
  
 /** 
  * 处理INFO请求 
  * @param request 请求消息 
  */ 
 private void processInfo(Request request) 
 { 
  if (null == request) 
  { 
   ("processInfo request is null."); 
   return; 
  } 
 } 
  
  
 /** 
  * 处理ACK请求 
  * @param request 请求消息 
  */ 
 private void processAck(Request request, RequestEvent requestEvent) 
 { 
  if (null == request) 
  { 
   ("processAck request is null."); 
   return; 
  } 
   
  try  
  { 
   Request ackRequest = null; 
   CSeq csReq = (CSeq)();    
   ackRequest = (()); 
   (ackRequest);    
   ("send ack to callee:" + ()); 
  } 
  catch (SipException e) 
  { 
   // TODO Auto-generated catch block 
   (); 
  }  
  catch (InvalidArgumentException e)  
  { 
   // TODO Auto-generated catch block 
   (); 
  } 
   
   
 } 
  
 /** 
  * 处理CANCEL消息 
  * @param request 
  * @param requestEvent 
  */ 
 private void processCancel(Request request, RequestEvent requestEvent) 
 { 
  // 判断参数是否有效 
  if (request == null || requestEvent == null) 
  { 
   ("processCancel input parameter invalid."); 
   return; 
  } 
     
  try 
  { 
   // 发送CANCEL 200 OK消息 
   Response response = (, request); 
   ServerTransaction cancelServTran = (); 
   if (cancelServTran == null) 
   { 
    cancelServTran = (request); 
   } 
   (response); 
    
   // 向对端发送CANCEL消息    
   Request cancelReq = null; 
   Request inviteReq = (); 
   List list = new ArrayList(); 
   Via viaHeader = (Via)(); 
   (viaHeader); 
    
   CSeq cseq = (CSeq)(); 
   CSeq cancelCSeq = (CSeq)((), ); 
   cancelReq = ((), 
     (), 
     (CallIdHeader)(), 
     cancelCSeq, 
     (FromHeader)(), 
     (ToHeader)(), 
     list,  
     (MaxForwardsHeader)()); 
   ClientTransaction cancelClientTran = (cancelReq); 
   (); 
  } 
  catch (ParseException e) 
  { 
   // TODO Auto-generated catch block 
   (); 
  }  
  catch (TransactionAlreadyExistsException e) 
  { 
   // TODO Auto-generated catch block 
   (); 
  } 
  catch (TransactionUnavailableException e) 
  { 
   // TODO Auto-generated catch block 
   (); 
  }  
  catch (SipException e) 
  { 
   // TODO Auto-generated catch block 
   (); 
  } 
  catch (InvalidArgumentException e) 
  { 
   // TODO Auto-generated catch block 
   (); 
  } 
 } 
  
  
 private ServerTransaction serverTransactionId = null; 
 /* (non-Javadoc) 
  * @see #processRequest() 
  */ 
 public void processRequest(RequestEvent arg0)  
 { 
  Request request = (); 
  if (null == request) 
  { 
   ("processRequest request is null."); 
   return; 
  } 
  ("processRequest:" + ()); 
  if ((())) 
  {       
   processInvite(request, arg0); 
  } 
  else if ((())) 
  { 
   processRegister(request, arg0); 
  } 
  else if ((())) 
  { 
   processSubscribe(request); 
  } 
  else if ((())) 
  { 
   processAck(request, arg0); 
  } 
  else if ((())) 
  { 
   processBye(request, arg0); 
  } 
  else if ((())) 
  { 
   processCancel(request, arg0); 
  } 
  else 
  { 
   ("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 = (); 
   
  try 
  { 
   Response byeResp = null; 
   if ((dialog)) 
   { 
    ServerTransaction servTran = (ServerTransaction)(); 
    byeResp = ((), ()); 
    (byeResp); 
   } 
   else if ((dialog)) 
   { 
    ServerTransaction servTran = (ServerTransaction)(); 
    byeResp = ((), ()); 
    (byeResp); 
   } 
   else 
   { 
     
   } 
   ("send bye response to peer:" + ()); 
  } 
  catch (ParseException e) 
  { 
   // TODO Auto-generated catch block 
   (); 
  } catch (SipException e) 
  { 
   // TODO Auto-generated catch block 
   (); 
  } catch (InvalidArgumentException e)  
  { 
   // TODO Auto-generated catch block 
   (); 
  } 
 } 
 /* (non-Javadoc) 
  * @see #processResponse() 
  *  
  */ 
 public void processResponse(ResponseEvent arg0) 
 { 
  // FIXME 需要判断各个响应对应的是什么请求 
  Response response = (); 
   
  ("recv the response :" +  ()); 
  ("respone to request : " + ().getRequest()); 
   
  if (() == ) 
  { 
   ("The response is 100 response."); 
   return; 
  } 
   
  try 
  { 
   ClientTransaction clientTran = (ClientTransaction) (); 
    
   if ((().getMethod())) 
   { 
    int statusCode = ();    
    Response callerResp = null; 
  
    callerResp = (statusCode, ()); 
  
    // 更新contact头域值,因为后面的消息是根据该URI来路由的 
    ContactHeader contactHeader = (); 
    Address address = ("sip:sipsoft@"+ipAddr+":"+port);    
    (address); 
    (3600); 
    (contactHeader); 
     
    // 拷贝to头域 
    ToHeader toHeader = (ToHeader)(); 
    (toHeader); 
     
    // 拷贝相应的消息体 
    ContentLength contentLen = (ContentLength)(); 
    if (contentLen != null && () != 0) 
    { 
     ContentType contentType = (ContentType)(); 
     ("the sdp contenttype is " + contentType); 
      
     (contentLen); 
     //(contentType); 
     ((), contentType); 
    } 
    else 
    { 
     ("sdp is null."); 
    } 
    if (serverTransactionId != null) 
    { 
     callerDialog = (); 
     calleeDialog = (); 
     (callerResp); 
     ("callerDialog=" + callerDialog); 
     ("=" + ());      
    } 
    else 
    { 
     ("serverTransactionId is null."); 
    }    
     
    ("send response to caller : " + ()); 
   } 
   else if ((().getMethod())) 
   { 
    doByeResponse(response, arg0); 
   } 
   else if ((().getMethod())) 
   { 
    //doCancelResponse(response, arg0); 
   } 
   else  
   { 
     
   } 
    
    
  } 
  catch (ParseException e) 
  { 
   // TODO Auto-generated catch block 
   (); 
  } 
  catch (SipException e) 
  { 
   // TODO Auto-generated catch block 
   (); 
  } 
  catch (InvalidArgumentException e) 
  { 
   // TODO Auto-generated catch block 
   (); 
  } 
  catch (Exception ex) 
  { 
   (); 
  } 
   
 } 
  
 private void doCancelResponse(Response response, ResponseEvent responseEvent) 
 { 
  //FIXME  需要验证参数的有效性 
  ServerTransaction servTran = (ServerTransaction)(); 
  Response cancelResp; 
  try  
  { 
   cancelResp = ((), ()); 
   (cancelResp); 
  } 
  catch (ParseException e) 
  { 
   // TODO Auto-generated catch block 
   (); 
  }  
  catch (SipException e) 
  { 
   // TODO Auto-generated catch block 
   (); 
  }  
  catch (InvalidArgumentException e) 
  { 
   // TODO Auto-generated catch block 
   (); 
  } 
   
 } 
 public void processTimeout(TimeoutEvent arg0) 
 { 
  // TODO Auto-generated method stub 
  (" processTimeout " + ()); 
 } 
 public void processTransactionTerminated(TransactionTerminatedEvent arg0) { 
  // TODO Auto-generated method stub 
  (" processTransactionTerminated " + ().getBranchId()  
        + " " + ().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 = (); 
  if (null == sipFactory) 
  { 
   ("init sipFactory is null."); 
   return; 
  } 
   
  (""); 
  Properties properties = new Properties(); 
  (".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. 
  (".TRACE_LEVEL", "32"); 
  (".DEBUG_LOG", 
    ""); 
  (".SERVER_LOG", 
    ""); 
  try  
  { 
   sipStack = (properties); 
  } 
  catch (PeerUnavailableException e) 
  { 
   // TODO Auto-generated catch block 
   (); 
   return; 
  } 
   
  try 
  { 
   headerFactory = (); 
   addressFactory = (); 
   msgFactory = (); 
   ListeningPoint lp = ("192.168.0.20", 
     5060, "udp"); 
   SipPhone listener = this; 
    
   sipProvider = (lp); 
   ("udp provider " + ()); 
   (listener); 
  } 
  catch (Exception ex) 
  { 
   (); 
   return; 
  } 
   
 } 
  
 /** 
  * 程序入口 
  * @param args 
  */ 
 public static void main(String []args) 
 { 
  new SipPhone().init(); 
 } 
  
}