src/main/java/com/genersoft/iot/vmp/gb28181/auth/DigestServerAuthenticationHelper.java
@@ -241,4 +241,59 @@ return mdString.equals(response); } public static void main(String[] args) throws NoSuchAlgorithmException { String realm = "4401000000"; String username = "44010000001110008008"; String nonce = "0074b397f86fc263b1b7f9eb72553267"; String uri = "sip:44010000002000000001@4401000000"; // qop 保护质量 包含auth(默认的)和auth-int(增加了报文完整性检测)两种策略 String qop = null; // 客户端随机数,这是一个不透明的字符串值,由客户端提供,并且客户端和服务器都会使用,以避免用明文文本。 // 这使得双方都可以查验对方的身份,并对消息的完整性提供一些保护 //String cNonce = authHeader.getCNonce(); // nonce计数器,是一个16进制的数值,表示同一nonce下客户端发送出请求的数量 int nc = -1; String ncStr = new DecimalFormat("00000000").format(nc); // String ncStr = new DecimalFormat("00000000").format(Integer.parseInt(nc + "", 16)); MessageDigest messageDigest = MessageDigest.getInstance(DEFAULT_ALGORITHM); String A1 = username + ":" + realm + ":" + "crservice@123"; String A2 = "REGISTER" + ":" + uri.toString(); byte mdbytes[] = messageDigest.digest(A1.getBytes()); String HA1 = toHexString(mdbytes); System.out.println("A1: " + A1); System.out.println("A2: " + A2); mdbytes = messageDigest.digest(A2.getBytes()); String HA2 = toHexString(mdbytes); System.out.println("HA1: " + HA1); System.out.println("HA2: " + HA2); String cnonce = null; System.out.println("nonce: " + nonce); System.out.println("nc: " + ncStr); System.out.println("cnonce: " + cnonce); System.out.println("qop: " + qop); String KD = HA1 + ":" + nonce; if (qop != null && qop.equals("auth") ) { if (nc != -1) { KD += ":" + ncStr; } if (cnonce != null) { KD += ":" + cnonce; } KD += ":" + qop; } KD += ":" + HA2; System.out.println("KD: " + KD); mdbytes = messageDigest.digest(KD.getBytes()); String mdString = toHexString(mdbytes); System.out.println("mdString: " + mdString); String response = "fdb1608a7a3b96f0598f40b8ba78d6a9"; System.out.println("response: " + response); } } src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java
@@ -89,7 +89,7 @@ } // 未携带授权头或者密码错误 回复401 if (authorhead == null || !passwordCorrect) { if (authorhead == null ) { if (authorhead == null) { logger.info("[{}] 未携带授权头 回复401", requestAddress); @@ -98,65 +98,71 @@ } response = getMessageFactory().createResponse(Response.UNAUTHORIZED, request); new DigestServerAuthenticationHelper().generateChallenge(getHeaderFactory(), response, sipConfig.getSipDomain()); } // 携带授权头并且密码正确 else if (passwordCorrect) { response = getMessageFactory().createResponse(Response.OK, request); // 添加date头 SIPDateHeader dateHeader = new SIPDateHeader(); // 使用自己修改的 WvpSipDate wvpSipDate = new WvpSipDate(Calendar.getInstance(Locale.ENGLISH).getTimeInMillis()); dateHeader.setDate(wvpSipDate); response.addHeader(dateHeader); }else { if (!passwordCorrect){ // 注册失败 response = getMessageFactory().createResponse(Response.FORBIDDEN, request); response.setReasonPhrase("wrong password"); }else { // 携带授权头并且密码正确 response = getMessageFactory().createResponse(Response.OK, request); // 添加date头 SIPDateHeader dateHeader = new SIPDateHeader(); // 使用自己修改的 WvpSipDate wvpSipDate = new WvpSipDate(Calendar.getInstance(Locale.ENGLISH).getTimeInMillis()); dateHeader.setDate(wvpSipDate); response.addHeader(dateHeader); ExpiresHeader expiresHeader = (ExpiresHeader) request.getHeader(Expires.NAME); if (expiresHeader == null) { response = getMessageFactory().createResponse(Response.BAD_REQUEST, request); getServerTransaction(evt).sendResponse(response); return; } // 添加Contact头 response.addHeader(request.getHeader(ContactHeader.NAME)); // 添加Expires头 response.addHeader(request.getExpires()); // 获取到通信地址等信息 ViaHeader viaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME); String received = viaHeader.getReceived(); int rPort = viaHeader.getRPort(); // 解析本地地址替代 if (StringUtils.isEmpty(received) || rPort == -1) { received = viaHeader.getHost(); rPort = viaHeader.getPort(); } // if (device == null) { device = new Device(); device.setStreamMode("UDP"); device.setDeviceId(deviceId); } device.setIp(received); device.setPort(rPort); device.setHostAddress(received.concat(":").concat(String.valueOf(rPort))); // 注销成功 if (expiresHeader.getExpires() == 0) { registerFlag = 2; } // 注册成功 else { device.setExpires(expiresHeader.getExpires()); registerFlag = 1; // 判断TCP还是UDP boolean isTcp = false; ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME); String transport = reqViaHeader.getTransport(); if (transport.equals("TCP")) { isTcp = true; ExpiresHeader expiresHeader = (ExpiresHeader) request.getHeader(Expires.NAME); if (expiresHeader == null) { response = getMessageFactory().createResponse(Response.BAD_REQUEST, request); getServerTransaction(evt).sendResponse(response); return; } device.setTransport(isTcp ? "TCP" : "UDP"); // 添加Contact头 response.addHeader(request.getHeader(ContactHeader.NAME)); // 添加Expires头 response.addHeader(request.getExpires()); // 获取到通信地址等信息 ViaHeader viaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME); String received = viaHeader.getReceived(); int rPort = viaHeader.getRPort(); // 解析本地地址替代 if (StringUtils.isEmpty(received) || rPort == -1) { received = viaHeader.getHost(); rPort = viaHeader.getPort(); } // if (device == null) { device = new Device(); device.setStreamMode("UDP"); device.setDeviceId(deviceId); } device.setIp(received); device.setPort(rPort); device.setHostAddress(received.concat(":").concat(String.valueOf(rPort))); // 注销成功 if (expiresHeader.getExpires() == 0) { registerFlag = 2; } // 注册成功 else { device.setExpires(expiresHeader.getExpires()); registerFlag = 1; // 判断TCP还是UDP boolean isTcp = false; ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME); String transport = reqViaHeader.getTransport(); if (transport.equals("TCP")) { isTcp = true; } device.setTransport(isTcp ? "TCP" : "UDP"); } } } getServerTransaction(evt).sendResponse(response); // 注册成功 // 保存到redis src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
@@ -4,7 +4,6 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.genersoft.iot.vmp.conf.MediaConfig; import com.genersoft.iot.vmp.conf.SipConfig; import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import com.genersoft.iot.vmp.service.IStreamProxyService; src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerConfig.java
@@ -41,7 +41,7 @@ private String streamIp; private long updateTime; private String updateTime; @JSONField(name = "hls.fileBufSize") private String hlsFileBufSize; @@ -732,11 +732,11 @@ this.shellPhell = shellPhell; } public long getUpdateTime() { public String getUpdateTime() { return updateTime; } public void setUpdateTime(long updateTime) { public void setUpdateTime(String updateTime) { this.updateTime = updateTime; } src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
@@ -24,7 +24,7 @@ @Update(value = {" <script>" + "UPDATE device_channel " + "SET updateTime=datetime('now','localtime'))" + "SET updateTime=datetime('now','localtime')" + "<if test=\"name != null\">, name='${name}'</if>" + "<if test=\"manufacture != null\">, manufacture='${manufacture}'</if>" + "<if test=\"model != null\">, model='${model}'</if>" + src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
@@ -10,6 +10,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.text.SimpleDateFormat; import java.util.*; @SuppressWarnings("rawtypes") @@ -22,6 +23,7 @@ @Autowired private DeviceChannelMapper deviceChannelMapper; private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); /** * 开始播放时将流存入redis @@ -91,7 +93,7 @@ */ @Override public boolean updateMediaInfo(ZLMServerConfig ZLMServerConfig) { ZLMServerConfig.setUpdateTime(System.currentTimeMillis()); ZLMServerConfig.setUpdateTime(format.format(new Date(System.currentTimeMillis()))); return redis.set(VideoManagerConstants.MEDIA_SERVER_PREFIX, ZLMServerConfig); }