Java SIP Client

采用JAIN SIP API实现一个SIP客户端实现向SIP服务器注册。SIP服务器可以为FreeSWITCH也可以为满足GB28181的SIP平台。话不多说直接看注册流程图:

在这里插入图片描述

代码实现:

  1. 创建maven工程添加依赖

    <dependencies>
        <dependency>
          <groupId>javax.sip</groupId>
          <artifactId>jain-sip-ri</artifactId>
          <version>1.3.0-91</version>
        </dependency>
    
        <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-log4j12</artifactId>
          <version>1.7.25</version>
        </dependency>
      </dependencies>
    
  2. 构造SIP协议栈

       	private static final String USERNAME = "1001";
    	private static final String PASSWORD = "1234";
    	private static final String IP = "xx.xx.xx.xx";
    	private static final Integer PORT = 5061;
    	private static final String SIP_SERVER_IP = "192.168.130.131";
    	private static final Integer SIP_SERVER_PORT = 5060;
        public SipLayer()
    	    throws PeerUnavailableException, TransportNotSupportedException,
    	    InvalidArgumentException, ObjectInUseException,
    	    TooManyListenersException {
    		sipFactory = SipFactory.getInstance();
    		sipFactory.setPathName("gov.nist");
    		Properties properties = new Properties();
    		properties.setProperty("javax.sip.STACK_NAME", "TextClient");
    		properties.setProperty("javax.sip.IP_ADDRESS", IP);
    		//DEBUGGING: Information will go to files
    		properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "32");
    		properties.setProperty("gov.nist.javax.sip.SERVER_LOG",
    			"freeswitch_sip_client.txt");
    		properties.setProperty("gov.nist.javax.sip.DEBUG_LOG",
    			"freeswitch_sip_client.log");
    		// 成员属性初始化
    		sipStack = sipFactory.createSipStack(properties);
    		headerFactory = sipFactory.createHeaderFactory();
    		addressFactory = sipFactory.createAddressFactory();
    		messageFactory = sipFactory.createMessageFactory();
    		// ListeningPoint此接口封装传输/端口对(例如 UDP/5060)。
    		ListeningPoint tcp = sipStack.createListeningPoint(PORT, "tcp");
    		ListeningPoint udp = sipStack.createListeningPoint(PORT, "udp");
    		// 此接口用于发送 SIP消息
    		sipProvider = sipStack.createSipProvider(tcp);
    		// 为传入 SIP消息注册侦听器
    		sipProvider.addSipListener(this);
    		sipProvider = sipStack.createSipProvider(udp);
    		sipProvider.addSipListener(this);
        }
    
  3. 发起REGISTER请求

    public void register() throws Exception {
    		Request request = createRequest(null);
    		messageProcessor.processInfo(request.toString());
    		sipProvider.sendRequest(request);
        }
    
    
    private Request createRequest(AuthorizationHeader authorizationHeader) throws Exception{
    		// 组装sip协议消息
    		SipURI from = addressFactory.createSipURI(USERNAME, IP);
    		Address fromNameAddress = addressFactory.createAddress(from);
    		// fromNameAddress.setDisplayName(getUsername());
    		fromNameAddress.setDisplayName(USERNAME);
    		// Address address, String tag
    		FromHeader fromHeader = headerFactory.createFromHeader(fromNameAddress,
    				USERNAME + "v1.0");
    		SipURI toAddress = addressFactory.createSipURI(USERNAME, IP);
    		Address toNameAddress = addressFactory.createAddress(toAddress);
    		toNameAddress.setDisplayName(USERNAME);
    		ToHeader toHeader = headerFactory.createToHeader(toNameAddress, null);
    		// Request-URL
    		SipURI requestURI = addressFactory.createSipURI(null, SIP_SERVER_IP + ":" + SIP_SERVER_PORT);
    		REQUEST_URL = requestURI.toString();
    		requestURI.setTransportParam("udp");
    		ArrayList viaHeaders = new ArrayList();
    		// Via头域是被服务器插入request中,用来检查路由环的,并且可以使response根据via找到返回的路
    		ViaHeader viaHeader = headerFactory.createViaHeader(IP, PORT, "udp", "z9hG4bK");
    		viaHeaders.add(viaHeader);
    		// 由本地设备(Client)生成,全局唯一,每次呼叫这个值唯一不变
    		CallIdHeader callIdHeader;
    		if(CALL_ID == null){
    			callIdHeader = sipProvider.getNewCallId();
    			CALL_ID = callIdHeader.getCallId();
    		}else {
    			callIdHeader = sipFactory.createHeaderFactory().createCallIdHeader(CALL_ID);
    		}
    		CSeqHeader cSeqHeader = headerFactory.createCSeqHeader(CSEQ++,
    				Request.REGISTER);
    		// 用于表示这个包最多可以传送多少跳,每经过一跳都会减一当Max-Forwards==0系统会返回483。默认为70
    		MaxForwardsHeader maxForwards = headerFactory
    				.createMaxForwardsHeader(70);
    		// 状态行(请求行)+消息头(请求头)
    		Request request = messageFactory.createRequest(requestURI,
    				Request.REGISTER, callIdHeader, cSeqHeader, fromHeader,
    				toHeader, viaHeaders, maxForwards);
    
    		SipURI contactURI = addressFactory.createSipURI(USERNAME, IP);
    		contactURI.setPort(PORT);
    		Address contactAddress = addressFactory.createAddress(contactURI);
    		contactAddress.setDisplayName(USERNAME);
    		ContactHeader contactHeader = headerFactory
    				.createContactHeader(contactAddress);
    		request.addHeader(contactHeader);
    		ExpiresHeader expiresHeader = sipFactory.createHeaderFactory().createExpiresHeader(3600);
    		request.addHeader(expiresHeader);
    		List<String> agentParam = new ArrayList<String>(1);
    		agentParam.add(USERNAME);
    		UserAgentHeader userAgentHeader = sipFactory.createHeaderFactory().createUserAgentHeader(agentParam);
    		request.addHeader(userAgentHeader);
    		if(authorizationHeader != null){
    			request.addHeader(authorizationHeader);
    		}
    		System.out.println(request.toString());
    		return request;
    	}
    
  4. 处理401响应

       public void processResponse(ResponseEvent evt) {
    		Response response = evt.getResponse();
    		System.out.println(response.toString());
    		messageProcessor.processInfo(response.toString());
    		int status = response.getStatusCode();
    
    		if ((status >= 200) && (status < 300)) { //Success!
    			messageProcessor.processInfo("Register Success!");
    			System.out.println("注册成功");
    			return;
    		}
    		if(status == 401){
    			// 获取相应中的认证信息
    			WWWAuthenticateHeader wwwAuthenticateHeader = (WWWAuthenticateHeader)response.getHeader(WWWAuthenticateHeader.NAME);
    			String realm = wwwAuthenticateHeader.getRealm();
    			String nonce = wwwAuthenticateHeader.getNonce();
    			String algorithm = wwwAuthenticateHeader.getAlgorithm(); // 通常为MD5
    			String qop = wwwAuthenticateHeader.getQop();
    			// 计算Digest响应
    			String ncStr = String.format("%08x", NC_VALUE++).toUpperCase();
    			try {
    			// 处理401根据响应生成认证信息
    			} catch (Exception e) {
    				e.printStackTrace();
    			}
            }
        }
    
  5. 重新发起REGISTER请求

    	String cnonce = Utils.generateCnonce();
        String responseDigest = new DigestServerAuthenticationHelper().doAuthenticatePlainTextPassword(realm,
        USERNAME, PASSWORD,
        nonce, REQUEST_URL, qop, cnonce, ncStr, Request.REGISTER);
        // 构造Authorization头字段
        AuthorizationHeader authorizationHeader = headerFactory.createAuthorizationHeader("Digest");
        authorizationHeader.setUsername(USERNAME);
        authorizationHeader.setRealm(realm);
        authorizationHeader.setNonce(nonce);
        authorizationHeader.setURI(addressFactory.createSipURI(null, SIP_SERVER_IP + ":" + SIP_SERVER_PORT));
        authorizationHeader.setResponse(responseDigest);
        authorizationHeader.setAlgorithm(algorithm);
        authorizationHeader.setCNonce(cnonce);
        authorizationHeader.setNonceCount(Integer.parseInt(ncStr));
        authorizationHeader.setQop(qop);
        Request request = createRequest(authorizationHeader);
        messageProcessor.processInfo(request.toString());
        sipProvider.sendRequest(request);
    
  6. 接收200响应

    if ((status >= 200) && (status < 300)) { //Success!
    			messageProcessor.processInfo("Register Success!");
    			System.out.println("注册成功");
    			return;
    		}
    
  7. 向FreeSWITCH注册

    REGISTER sip:192.168.130.131:5060;transport=udp SIP/2.0
    Call-ID: da961718177def46838dcc0d422cb013@192.168.130.1
    CSeq: 1 REGISTER
    From: "1001" <sip:1001@192.168.130.1>;tag=1001v1.0
    To: "1001" <sip:1001@192.168.130.1>
    Via: SIP/2.0/UDP 192.168.130.1:5061;branch=z9hG4bK
    Max-Forwards: 70
    Contact: "1001" <sip:1001@192.168.130.1:5061>
    Expires: 3600
    User-Agent: 1001
    Content-Length: 0
    
    
    SIP/2.0 401 Unauthorized
    Via: SIP/2.0/UDP 192.168.130.1:5061;branch=z9hG4bK
    From: "1001" <sip:1001@192.168.130.1>;tag=1001v1.0
    To: "1001" <sip:1001@192.168.130.1>;tag=gX8c37XjH661g
    Call-ID: da961718177def46838dcc0d422cb013@192.168.130.1
    CSeq: 1 REGISTER
    User-Agent: FreeSWITCH-mod_sofia/1.10.2-release~64bit
    Allow: INVITE,ACK,BYE,CANCEL,OPTIONS,MESSAGE,INFO,UPDATE,REGISTER,REFER,NOTIFY,PUBLISH,SUBSCRIBE
    Supported: timer,path,replaces
    WWW-Authenticate: Digest realm="192.168.130.1",nonce="b23ac718-7363-4c71-bf2d-cbaa24b75dde",algorithm=MD5,qop="auth"
    Content-Length: 0
    
    
    REGISTER sip:192.168.130.131:5060;transport=udp SIP/2.0
    Call-ID: da961718177def46838dcc0d422cb013@192.168.130.1
    CSeq: 2 REGISTER
    From: "1001" <sip:1001@192.168.130.1>;tag=1001v1.0
    To: "1001" <sip:1001@192.168.130.1>
    Via: SIP/2.0/UDP 192.168.130.1:5061;branch=z9hG4bK
    Max-Forwards: 70
    Contact: "1001" <sip:1001@192.168.130.1:5061>
    Expires: 3600
    User-Agent: 1001
    Authorization: Digest username="1001",realm="192.168.130.1",nonce="b23ac718-7363-4c71-bf2d-cbaa24b75dde",uri="sip:192.168.130.131:5060",response="818dc5bca39bdbaffa8520244be01511",algorithm=MD5,cnonce="zVWY34UveCSzehKlMiLqag==",nc=00000001,qop=auth
    Content-Length: 0
    
    
    SIP/2.0 200 OK
    Via: SIP/2.0/UDP 192.168.130.1:5061;branch=z9hG4bK
    From: "1001" <sip:1001@192.168.130.1>;tag=1001v1.0
    To: "1001" <sip:1001@192.168.130.1>;tag=H61542epeFXmc
    Call-ID: da961718177def46838dcc0d422cb013@192.168.130.1
    CSeq: 2 REGISTER
    Contact: <sip:1001@192.168.130.1:5061>;expires=3600
    Date: Tue, 13 Aug 2024 06:58:45 GMT
    User-Agent: FreeSWITCH-mod_sofia/1.10.2-release~64bit
    Allow: INVITE,ACK,BYE,CANCEL,OPTIONS,MESSAGE,INFO,UPDATE,REGISTER,REFER,NOTIFY,PUBLISH,SUBSCRIBE
    Supported: timer,path,replaces
    Content-Length: 0
    
    
    注册成功
    
    

    在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

倔强的初学者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值