国标28181 学习篇-part2

国标28181 学习篇-part2

 

1、国标协议处理实现业务类

package com.srymy.gb28181.part1.sip;

import com.srymy.gb28181.part1.util.MD5Util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.sip.*;
import javax.sip.address.AddressFactory;
import javax.sip.address.SipURI;
import javax.sip.address.URI;
import javax.sip.header.*;
import javax.sip.message.MessageFactory;
import javax.sip.message.Request;
import javax.sip.message.Response;
import java.text.ParseException;
import java.util.Calendar;
import java.util.UUID;

/**
 * @Author: cth
 * @Date: 2019/5/16 17:47
 * @Description: 国标协议处理实现业务类
 */
@Slf4j
@Service
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SipSrymyMessageProcessorImpl implements SipSrymyMessageProcessor {

    @Value("${gb28181.password:12345678}")
    String password;

    @Autowired
    SipSrymyMessageProcessorImpl(){
    }


    @Override
    public void processRequest(RequestEvent requestEvent, AddressFactory addressFactory, MessageFactory messageFactory, HeaderFactory headerFactory, SipProvider sipProvider) {
        Request request = requestEvent.getRequest();
        if (null == request) {
            log.error("processRequest RequestEvent is null");
            return;
        }
        switch (request.getMethod().toUpperCase()) {
            case Request.MESSAGE:
                log.debug("收到MESSAGE的请求");
                doRequestMessage(requestEvent, addressFactory,messageFactory, headerFactory, sipProvider);
                break;
            case Request.REGISTER:
                log.info("收到下级域REGISTER的请求");
                doRequestRegister(requestEvent, addressFactory, messageFactory, headerFactory, sipProvider);
                break;
            case Request.ACK:
                log.info("收到ACK的请求");
                doRequestAsk(requestEvent, addressFactory, messageFactory, headerFactory, sipProvider);
                break;
            case Request.BYE:
                log.info("收到BYE的请求");
                doRequestBye(requestEvent, addressFactory,messageFactory, headerFactory, sipProvider);
                break;
            case Request.INVITE:
                log.info("收到上级域INVITE的请求");

                doRequestInvite(requestEvent, addressFactory, messageFactory, headerFactory, sipProvider);
                break;
            default:
                log.info("不处理的requestMethod:" + request.getMethod().toUpperCase());
        }
    }

    @Override
    public void processResponse(ResponseEvent responseEvent, AddressFactory addressFactory, MessageFactory messageFactory, HeaderFactory headerFactory, SipProvider sipProvider) throws InvalidArgumentException {
        Response response = responseEvent.getResponse();
        try {
            CSeqHeader cSeqHeader = (CSeqHeader) response.getHeader(CSeqHeader.NAME);
            switch (cSeqHeader.getMethod().toUpperCase()) {
                case Request.MESSAGE:
                    log.debug("收到MESSAGE的请求");
                    doResponseMessage(responseEvent, messageFactory, headerFactory, sipProvider);
                    break;
                case Request.REGISTER:
                    log.info("收到REGISTER的返回");
                    doResponseRegister(responseEvent, addressFactory, messageFactory, headerFactory, sipProvider, response);
                    break;
                case Request.INVITE:
                    log.info("收到INVITE的返回");
                    doResponseInvite(responseEvent, addressFactory, messageFactory, headerFactory, sipProvider, response, cSeqHeader);
                    break;
                case Request.ACK:
                    log.info("收到ACK的返回");
                    break;
                case Request.BYE:
                    log.info("收到BYE的返回");
                    doResponseBye(responseEvent, addressFactory, messageFactory, headerFactory, sipProvider, response);
                    break;
                default:
                    log.info("不处理的requestMethod:" + cSeqHeader.getMethod().toUpperCase());
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private void doResponseInvite(ResponseEvent responseEvent, AddressFactory addressFactory, MessageFactory messageFactory, HeaderFactory headerFactory, SipProvider sipProvider, Response response, CSeqHeader cSeqHeader) {
    }

    private void doRequestInvite(RequestEvent requestEvent, AddressFactory addressFactory, MessageFactory messageFactory, HeaderFactory headerFactory, SipProvider sipProvider) {
    }

    private void doRequestBye(RequestEvent requestEvent, AddressFactory addressFactory, MessageFactory messageFactory, HeaderFactory headerFactory, SipProvider sipProvider) {
    }

    private void doResponseRegister(ResponseEvent responseEvent, AddressFactory addressFactory, MessageFactory messageFactory, HeaderFactory headerFactory, SipProvider sipProvider, Response response) {
    }

    private void doResponseMessage(ResponseEvent responseEvent, MessageFactory messageFactory, HeaderFactory headerFactory, SipProvider sipProvider) {
    }

    @Override
    public void processError(String errorMessage) {

    }

    private void doResponseBye(ResponseEvent responseEvent, AddressFactory addressFactory, MessageFactory messageFactory, HeaderFactory headerFactory, SipProvider sipProvider, Response response) {
    }

    private void doRequestAsk(RequestEvent requestEvent, AddressFactory addressFactory, MessageFactory messageFactory, HeaderFactory headerFactory, SipProvider sipProvider) {
    }

    private void doRequestRegister(RequestEvent requestEvent, AddressFactory addressFactory, MessageFactory messageFactory, HeaderFactory headerFactory, SipProvider sipProvider) {
        Request request = requestEvent.getRequest();
        try {
            String deviceId = getDeviceIdByRequest(request);
            log.info("Register deviceId is {}, toURI is {}", deviceId);
            if (StringUtils.isEmpty(deviceId)) {
                log.error("Register error, deviceId is empty!");
                return;
            }
            //无需鉴权或者鉴权判断通过 是否校验鉴权通过
            if (isAuthClosed(deviceId) || isAuthorizationPass(request)) {
                //返回成功 返回Response.OK
                log.info("Register doSuccess!");
                System.out.println("---------------注册到服务器,返回200 ok--------------------");
                doSuccess(requestEvent, addressFactory, messageFactory, headerFactory, sipProvider);
            }
            // 有Auth信息,一般在第二次Register的时候,这个时候会带着第一次服务端返回的Digest信息
            else if (isRegisterWithoutAuth(request)) {
                doUnAuthorized401(requestEvent, messageFactory, headerFactory, sipProvider, request, deviceId);
            } else {
                doLoginFail403(requestEvent, addressFactory, messageFactory, headerFactory, sipProvider);
            }
        } catch (Exception e) {
            log.error("处理Register请求的时候出错 error, {}", e.getMessage());
            e.printStackTrace();
        }
    }

    private void doRequestMessage(RequestEvent requestEvent, AddressFactory addressFactory, MessageFactory messageFactory, HeaderFactory headerFactory, SipProvider sipProvider) {
    }

    /**
     * 组装登录成功200的Response
     * @return
     */
    private void doSuccess(RequestEvent requestEvent, AddressFactory addressFactory, MessageFactory messageFactory, HeaderFactory headerFactory, SipProvider sipProvider) throws ParseException, SipException, InvalidArgumentException {
        Request request = requestEvent.getRequest();
        Response response = messageFactory.createResponse(Response.OK, request);
        DateHeader dateHeader = headerFactory.createDateHeader(Calendar.getInstance());
        response.addHeader(dateHeader);
        ServerTransaction serverTransactionId = requestEvent.getServerTransaction() == null ? sipProvider.getNewServerTransaction(request) : requestEvent.getServerTransaction();
        serverTransactionId.sendResponse(response);
    }

    /**
     * 组装登录失败403的Response
     * @return
     */
    private void doLoginFail403(RequestEvent requestEvent, AddressFactory addressFactory, MessageFactory messageFactory, HeaderFactory headerFactory, SipProvider sipProvider) throws ParseException, SipException, InvalidArgumentException {
        Request request = requestEvent.getRequest();
        Response response = messageFactory.createResponse(Response.FORBIDDEN, request);
        DateHeader dateHeader = headerFactory.createDateHeader(Calendar.getInstance());
        response.addHeader(dateHeader);
        ServerTransaction serverTransactionId = requestEvent.getServerTransaction() == null ? sipProvider.getNewServerTransaction(request) : requestEvent.getServerTransaction();
        serverTransactionId.sendResponse(response);
    }

    private String getDeviceIdByRequest(Request request) {
        ToHeader toHead = (ToHeader) request.getHeader(ToHeader.NAME);
        SipURI toUri =(SipURI) toHead.getAddress().getURI();
        return toUri.getUser();
    }

    /**
     * 判断鉴权是否关闭
     * @param deviceId 设备ID
     * @return
     */
    private boolean isAuthClosed(String deviceId) {
//        return ("34020000001110000001".equals(deviceId));
        // 设备ID和服务器ID相同则不鉴权
        return ("34020000002000000001".equals(deviceId));
    }

    /**
     * 有鉴权,判断是否校验鉴权通过
     * @param request
     * @return true 通过
     */
    private boolean isAuthorizationPass(Request request) {
        if (isRegisterWithoutAuth(request)) {
            return false;
        }
        AuthorizationHeader authorizationHeader = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
        String username = authorizationHeader.getUsername();
        String realm = authorizationHeader.getRealm();
        String nonce = authorizationHeader.getNonce();
        URI uri = authorizationHeader.getURI();
        String res = authorizationHeader.getResponse();
        String algorithm = authorizationHeader.getAlgorithm();
        log.info("Authorization信息:username=" + username + ",realm=" + realm + ",nonce=" + nonce + ",uri=" + uri + ",response=" + res + ",algorithm=" + algorithm);
        if (null == username || null == realm || null == nonce || null == uri || null == res || null == algorithm) {
            log.info("Authorization信息不全,无法认证。");
            return false;
        } else {
            // 比较Authorization信息正确性
            String A1 = MD5Util.MD5(username +":"+ realm +":"+ password);
            String A2 = MD5Util.MD5("REGISTER" +":"+  uri);
            String resStr = MD5Util.MD5(A1 +":"+  nonce +":"+  A2);
            return resStr.equals(res);
        }
    }


    /**
     * 第一次请求服务器后,服务器返回401
     * @param requestEvent
     * @param messageFactory
     * @param headerFactory
     * @param sipProvider
     * @param request
     * @param deviceId
     * @throws ParseException
     * @throws SipException
     * @throws InvalidArgumentException
     */
    private void doUnAuthorized401(RequestEvent requestEvent, MessageFactory messageFactory, HeaderFactory headerFactory, SipProvider sipProvider, Request request, String deviceId) throws ParseException, SipException, InvalidArgumentException {
        Response response;
        response = messageFactory.createResponse(Response.UNAUTHORIZED, request);
        String realm = generateShortUUID();

        String callId = getCallIdFromRequest(request);
        String nonce = MD5Util.MD5(callId + deviceId);
        WWWAuthenticateHeader wwwAuthenticateHeader = headerFactory.createWWWAuthenticateHeader("Digest realm=\"" + realm + "\",nonce=\"" + nonce + "\",algorithm=MD5");
        response.setHeader(wwwAuthenticateHeader);
        ServerTransaction serverTransactionId = requestEvent.getServerTransaction() == null ? sipProvider.getNewServerTransaction(request) : requestEvent.getServerTransaction();
        serverTransactionId.sendResponse(response);
    }


    /**
     * 没有Auth信息,一般在第一次Register的时候
     *
     * @param request
     * @return
     */
    private boolean isRegisterWithAuth(Request request) {
        int expires = request.getExpires().getExpires();
        AuthorizationHeader authorizationHeader = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
        return expires > 0 && authorizationHeader != null;
    }

    /**
     * 有Auth信息,一般在第二次Register的时候,这个时候会带着第一次服务端返回的Digest信息
     *
     * @param request
     * @return
     */
    private boolean isRegisterWithoutAuth(Request request) {
        int expires = request.getExpires().getExpires();
        AuthorizationHeader authorizationHeader = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
        // expires == 0是注销码
        return expires >= 0 && authorizationHeader == null;
    }

    private String getCallIdFromRequest(Request request) {
        CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME);
        return callIdHeader.getCallId();
    }


    public static String generateShortUUID() {
        StringBuffer shortBuffer = new StringBuffer();
        String uuid = UUID.randomUUID().toString().replace("-", "");
        for (int i = 0; i < 8; i++) {
            String str = uuid.substring(i * 4, i * 4 + 4);
            int x = Integer.parseInt(str, 16);
            shortBuffer.append(chars[x % 0x3E]);
        }
        return shortBuffer.toString();
    }

    public static String[] chars = new String[]{"a", "b", "c", "d", "e", "f",
            "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
            "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5",
            "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I",
            "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
            "W", "X", "Y", "Z"};
}

2、MD5加密

 public static String MD5(String text) {
        //加密后的字符串
        String encodeStr = DigestUtils.md5Hex(text);
        return encodeStr;
    }

实现以上代码即可实现注册和注销

上一篇:891. Sum of Subsequence Widths


下一篇:秀++视频联网四:社会面视频接入*网解决方案