Commit 91bfbc36f10382434a9e8c79eeeaf07a531b08b5

Authored by 648540858
1 parent 58d1f0ea

优化设备注册,支持到期续订,优化国标级联到期续订。

Showing 19 changed files with 205 additions and 90 deletions
... ... @@ -11,7 +11,7 @@
11 11  
12 12 <groupId>com.genersoft</groupId>
13 13 <artifactId>wvp-pro</artifactId>
14   - <version>2.6.7</version>
  14 + <version>2.6.8</version>
15 15 <name>web video platform</name>
16 16 <description>国标28181视频平台</description>
17 17 <packaging>${project.packaging}</packaging>
... ...
src/main/java/com/genersoft/iot/vmp/conf/SipPlatformRunner.java
... ... @@ -40,17 +40,20 @@ public class SipPlatformRunner implements CommandLineRunner {
40 40 List<ParentPlatform> parentPlatforms = storager.queryEnableParentPlatformList(true);
41 41  
42 42 for (ParentPlatform parentPlatform : parentPlatforms) {
  43 +
  44 + ParentPlatformCatch parentPlatformCatchOld = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId());
  45 +
43 46 // 更新缓存
44 47 ParentPlatformCatch parentPlatformCatch = new ParentPlatformCatch();
45 48 parentPlatformCatch.setParentPlatform(parentPlatform);
46 49 parentPlatformCatch.setId(parentPlatform.getServerGBId());
47 50 redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
48   - // 设置所有平台离线
49   - platformService.offline(parentPlatform, true);
50 51 // 取消订阅
51   - sipCommanderForPlatform.unregister(parentPlatform, null, (eventResult)->{
  52 + sipCommanderForPlatform.unregister(parentPlatform, parentPlatformCatchOld.getSipTransactionInfo(), null, (eventResult)->{
52 53 platformService.login(parentPlatform);
53 54 });
  55 + // 设置所有平台离线
  56 + platformService.offline(parentPlatform, true);
54 57 }
55 58 }
56 59 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
... ... @@ -191,6 +191,9 @@ public class Device {
191 191 @Schema(description = "是否作为消息通道")
192 192 private boolean asMessageChannel;
193 193  
  194 + @Schema(description = "设备注册的事务信息")
  195 + private SipTransactionInfo sipTransactionInfo;
  196 +
194 197  
195 198 public String getDeviceId() {
196 199 return deviceId;
... ... @@ -439,4 +442,12 @@ public class Device {
439 442 public void setAsMessageChannel(boolean asMessageChannel) {
440 443 this.asMessageChannel = asMessageChannel;
441 444 }
  445 +
  446 + public SipTransactionInfo getSipTransactionInfo() {
  447 + return sipTransactionInfo;
  448 + }
  449 +
  450 + public void setSipTransactionInfo(SipTransactionInfo sipTransactionInfo) {
  451 + this.sipTransactionInfo = sipTransactionInfo;
  452 + }
442 453 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatformCatch.java
... ... @@ -16,6 +16,8 @@ public class ParentPlatformCatch {
16 16  
17 17 private ParentPlatform parentPlatform;
18 18  
  19 + private SipTransactionInfo sipTransactionInfo;
  20 +
19 21 public String getId() {
20 22 return id;
21 23 }
... ... @@ -55,4 +57,12 @@ public class ParentPlatformCatch {
55 57 public void setCallId(String callId) {
56 58 this.callId = callId;
57 59 }
  60 +
  61 + public SipTransactionInfo getSipTransactionInfo() {
  62 + return sipTransactionInfo;
  63 + }
  64 +
  65 + public void setSipTransactionInfo(SipTransactionInfo sipTransactionInfo) {
  66 + this.sipTransactionInfo = sipTransactionInfo;
  67 + }
58 68 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/task/SipRunner.java
... ... @@ -63,7 +63,7 @@ public class SipRunner implements CommandLineRunner {
63 63 if (deviceService.expire(device)){
64 64 deviceService.offline(device.getDeviceId(), "注册已过期");
65 65 }else {
66   - deviceService.online(device);
  66 + deviceService.online(device, null);
67 67 }
68 68 }
69 69 // 重置cseq计数
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java
... ... @@ -18,14 +18,16 @@ public interface ISIPCommanderForPlatform {
18 18 * @return
19 19 */
20 20 void register(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException;
21   - void register(ParentPlatform parentPlatform, String callId, WWWAuthenticateHeader www, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent, boolean registerAgain, boolean isRegister) throws SipException, InvalidArgumentException, ParseException;
  21 +
  22 + void register(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException;
  23 + void register(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo, WWWAuthenticateHeader www, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent, boolean registerAgain, boolean isRegister) throws SipException, InvalidArgumentException, ParseException;
22 24  
23 25 /**
24 26 * 向上级平台注销
25 27 * @param parentPlatform
26 28 * @return
27 29 */
28   - void unregister(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException;
  30 + void unregister(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException;
29 31  
30 32  
31 33 /**
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java
... ... @@ -14,7 +14,8 @@ import org.springframework.beans.factory.annotation.Autowired;
14 14 import org.springframework.stereotype.Component;
15 15 import org.springframework.util.DigestUtils;
16 16  
17   -import javax.sip.*;
  17 +import javax.sip.InvalidArgumentException;
  18 +import javax.sip.PeerUnavailableException;
18 19 import javax.sip.address.Address;
19 20 import javax.sip.address.SipURI;
20 21 import javax.sip.header.*;
... ... @@ -22,7 +23,6 @@ import javax.sip.message.Request;
22 23 import javax.validation.constraints.NotNull;
23 24 import java.text.ParseException;
24 25 import java.util.ArrayList;
25   -import java.util.List;
26 26 import java.util.UUID;
27 27  
28 28 /**
... ... @@ -45,7 +45,7 @@ public class SIPRequestHeaderPlarformProvider {
45 45 @Autowired
46 46 private IRedisCatchStorage redisCatchStorage;
47 47  
48   - public Request createRegisterRequest(@NotNull ParentPlatform parentPlatform, long CSeq, String fromTag, String viaTag, CallIdHeader callIdHeader, boolean isRegister) throws ParseException, InvalidArgumentException, PeerUnavailableException {
  48 + public Request createRegisterRequest(@NotNull ParentPlatform parentPlatform, long CSeq, String fromTag, String toTag, CallIdHeader callIdHeader, boolean isRegister) throws ParseException, InvalidArgumentException, PeerUnavailableException {
49 49 Request request = null;
50 50 String sipAddress = parentPlatform.getDeviceIp() + ":" + parentPlatform.getDevicePort();
51 51 //请求行
... ... @@ -53,7 +53,8 @@ public class SIPRequestHeaderPlarformProvider {
53 53 parentPlatform.getServerIP() + ":" + parentPlatform.getServerPort());
54 54 //via
55 55 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
56   - ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(parentPlatform.getServerIP(), parentPlatform.getServerPort(), parentPlatform.getTransport(), viaTag);
  56 + ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(parentPlatform.getServerIP(),
  57 + parentPlatform.getServerPort(), parentPlatform.getTransport(), SipUtils.getNewViaTag());
57 58 viaHeader.setRPort();
58 59 viaHeaders.add(viaHeader);
59 60 //from
... ... @@ -63,7 +64,7 @@ public class SIPRequestHeaderPlarformProvider {
63 64 //to
64 65 SipURI toSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(parentPlatform.getDeviceGBId(), sipConfig.getDomain());
65 66 Address toAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(toSipURI);
66   - ToHeader toHeader = sipLayer.getSipFactory().createHeaderFactory().createToHeader(toAddress,null);
  67 + ToHeader toHeader = sipLayer.getSipFactory().createHeaderFactory().createToHeader(toAddress,toTag);
67 68  
68 69 //Forwards
69 70 MaxForwardsHeader maxForwards = sipLayer.getSipFactory().createHeaderFactory().createMaxForwardsHeader(70);
... ... @@ -85,11 +86,11 @@ public class SIPRequestHeaderPlarformProvider {
85 86 return request;
86 87 }
87 88  
88   - public Request createRegisterRequest(@NotNull ParentPlatform parentPlatform, String fromTag, String viaTag,
89   - String callId, WWWAuthenticateHeader www , CallIdHeader callIdHeader, boolean isRegister) throws ParseException, PeerUnavailableException, InvalidArgumentException {
  89 + public Request createRegisterRequest(@NotNull ParentPlatform parentPlatform, String fromTag, String toTag,
  90 + WWWAuthenticateHeader www , CallIdHeader callIdHeader, boolean isRegister) throws ParseException, PeerUnavailableException, InvalidArgumentException {
90 91  
91 92  
92   - Request registerRequest = createRegisterRequest(parentPlatform, redisCatchStorage.getCSEQ(), fromTag, viaTag, callIdHeader, isRegister);
  93 + Request registerRequest = createRegisterRequest(parentPlatform, redisCatchStorage.getCSEQ(), fromTag, toTag, callIdHeader, isRegister);
93 94 SipURI requestURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(parentPlatform.getServerGBId(), parentPlatform.getServerIP() + ":" + parentPlatform.getServerPort());
94 95 if (www == null) {
95 96 AuthorizationHeader authorizationHeader = sipLayer.getSipFactory().createHeaderFactory().createAuthorizationHeader("Digest");
... ... @@ -107,8 +108,6 @@ public class SIPRequestHeaderPlarformProvider {
107 108 // qop 保护质量 包含auth(默认的)和auth-int(增加了报文完整性检测)两种策略
108 109 String qop = www.getQop();
109 110  
110   - callIdHeader.setCallId(callId);
111   -
112 111 String cNonce = null;
113 112 String nc = "00000001";
114 113 if (qop != null) {
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
... ... @@ -75,20 +75,40 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
75 75 }
76 76  
77 77 @Override
78   - public void unregister(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException {
79   - register(parentPlatform, null, null, errorEvent, okEvent, false, false);
  78 + public void register(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException {
  79 +
  80 + register(parentPlatform, sipTransactionInfo, null, errorEvent, okEvent, false, true);
  81 + }
  82 +
  83 + @Override
  84 + public void unregister(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException {
  85 + register(parentPlatform, sipTransactionInfo, null, errorEvent, okEvent, false, false);
80 86 }
81 87  
82 88 @Override
83   - public void register(ParentPlatform parentPlatform, @Nullable String callId, @Nullable WWWAuthenticateHeader www,
  89 + public void register(ParentPlatform parentPlatform, @Nullable SipTransactionInfo sipTransactionInfo, @Nullable WWWAuthenticateHeader www,
84 90 SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent, boolean registerAgain, boolean isRegister) throws SipException, InvalidArgumentException, ParseException {
85 91 Request request;
86   - if (!registerAgain ) {
87   - CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(parentPlatform.getDeviceIp(),parentPlatform.getTransport());
88 92  
  93 + CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(parentPlatform.getDeviceIp(),parentPlatform.getTransport());
  94 + String fromTag = SipUtils.getNewFromTag();
  95 + String toTag = null;
  96 + if (sipTransactionInfo != null ) {
  97 + if (sipTransactionInfo.getCallId() != null) {
  98 + callIdHeader.setCallId(sipTransactionInfo.getCallId());
  99 + }
  100 + if (sipTransactionInfo.getFromTag() != null) {
  101 + fromTag = sipTransactionInfo.getFromTag();
  102 + }
  103 + if (sipTransactionInfo.getToTag() != null) {
  104 + toTag = sipTransactionInfo.getToTag();
  105 + }
  106 + }
  107 +
  108 + if (!registerAgain ) {
89 109 request = headerProviderPlatformProvider.createRegisterRequest(parentPlatform,
90   - redisCatchStorage.getCSEQ(), SipUtils.getNewFromTag(),
91   - SipUtils.getNewViaTag(), callIdHeader, isRegister);
  110 + redisCatchStorage.getCSEQ(), fromTag,
  111 + toTag, callIdHeader, isRegister);
92 112 // 将 callid 写入缓存, 等注册成功可以更新状态
93 113 String callIdFromHeader = callIdHeader.getCallId();
94 114 redisCatchStorage.updatePlatformRegisterInfo(callIdFromHeader, PlatformRegisterInfo.getInstance(parentPlatform.getServerGBId(), isRegister));
... ... @@ -106,8 +126,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
106 126 });
107 127  
108 128 }else {
109   - CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(parentPlatform.getDeviceIp(),parentPlatform.getTransport());
110   - request = headerProviderPlatformProvider.createRegisterRequest(parentPlatform, SipUtils.getNewFromTag(), null, callId, www, callIdHeader, isRegister);
  129 + request = headerProviderPlatformProvider.createRegisterRequest(parentPlatform, fromTag, toTag, www, callIdHeader, isRegister);
111 130 }
112 131  
113 132 sipSender.transmitRequest(parentPlatform.getDeviceIp(), request, null, okEvent);
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java
... ... @@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.conf.UserSetting;
5 5 import com.genersoft.iot.vmp.gb28181.auth.DigestServerAuthenticationHelper;
6 6 import com.genersoft.iot.vmp.gb28181.bean.Device;
7 7 import com.genersoft.iot.vmp.gb28181.bean.RemoteAddressInfo;
  8 +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo;
8 9 import com.genersoft.iot.vmp.gb28181.bean.WvpSipDate;
9 10 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
10 11 import com.genersoft.iot.vmp.gb28181.transmit.SIPSender;
... ... @@ -18,6 +19,7 @@ import gov.nist.javax.sip.address.AddressImpl;
18 19 import gov.nist.javax.sip.address.SipUri;
19 20 import gov.nist.javax.sip.header.SIPDateHeader;
20 21 import gov.nist.javax.sip.message.SIPRequest;
  22 +import gov.nist.javax.sip.message.SIPResponse;
21 23 import org.slf4j.Logger;
22 24 import org.slf4j.LoggerFactory;
23 25 import org.springframework.beans.factory.InitializingBean;
... ... @@ -31,6 +33,7 @@ import javax.sip.header.AuthorizationHeader;
31 33 import javax.sip.header.ContactHeader;
32 34 import javax.sip.header.FromHeader;
33 35 import javax.sip.header.ViaHeader;
  36 +import javax.sip.message.Request;
34 37 import javax.sip.message.Response;
35 38 import java.security.NoSuchAlgorithmException;
36 39 import java.text.ParseException;
... ... @@ -102,6 +105,30 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
102 105 SipUri uri = (SipUri) address.getURI();
103 106 String deviceId = uri.getUser();
104 107 Device device = deviceService.getDevice(deviceId);
  108 +
  109 + RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request,
  110 + userSetting.getSipUseSourceIpAsRemoteAddress());
  111 +
  112 + if (device != null &&
  113 + device.getSipTransactionInfo() != null &&
  114 + request.getCallIdHeader().getCallId().equals(device.getSipTransactionInfo().getCallId())) {
  115 + logger.info("[注册请求] 注册续订: {}", device.getDeviceId());
  116 + device.setExpires(request.getExpires().getExpires());
  117 + device.setIp(remoteAddressInfo.getIp());
  118 + device.setPort(remoteAddressInfo.getPort());
  119 + device.setHostAddress(remoteAddressInfo.getIp().concat(":").concat(String.valueOf(remoteAddressInfo.getPort())));
  120 + device.setLocalIp(request.getLocalAddress().getHostAddress());
  121 + Response registerOkResponse = getRegisterOkResponse(request);
  122 + // 判断TCP还是UDP
  123 + ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
  124 + String transport = reqViaHeader.getTransport();
  125 + device.setTransport("TCP".equalsIgnoreCase(transport) ? "TCP" : "UDP");
  126 + sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), registerOkResponse);
  127 + device.setRegisterTime(DateUtil.getNow());
  128 + SipTransactionInfo sipTransactionInfo = new SipTransactionInfo((SIPResponse)registerOkResponse);
  129 + deviceService.online(device, sipTransactionInfo);
  130 + return;
  131 + }
105 132 String password = (device != null && !ObjectUtils.isEmpty(device.getPassword()))? device.getPassword() : sipConfig.getPassword();
106 133 AuthorizationHeader authHead = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
107 134 if (authHead == null && !ObjectUtils.isEmpty(password)) {
... ... @@ -144,9 +171,6 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
144 171 // 添加Expires头
145 172 response.addHeader(request.getExpires());
146 173  
147   - RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request,
148   - userSetting.getSipUseSourceIpAsRemoteAddress());
149   -
150 174 if (device == null) {
151 175 device = new Device();
152 176 device.setStreamMode("UDP");
... ... @@ -179,7 +203,8 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
179 203 if (registerFlag) {
180 204 logger.info("[注册成功] deviceId: {}->{}", deviceId, requestAddress);
181 205 device.setRegisterTime(DateUtil.getNow());
182   - deviceService.online(device);
  206 + SipTransactionInfo sipTransactionInfo = new SipTransactionInfo((SIPResponse)response);
  207 + deviceService.online(device, sipTransactionInfo);
183 208 } else {
184 209 logger.info("[注销成功] deviceId: {}->{}" ,deviceId, requestAddress);
185 210 deviceService.offline(deviceId, "主动注销");
... ... @@ -188,4 +213,23 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
188 213 logger.error("未处理的异常 ", e);
189 214 }
190 215 }
  216 +
  217 + private Response getRegisterOkResponse(Request request) throws ParseException {
  218 + // 携带授权头并且密码正确
  219 + Response response = getMessageFactory().createResponse(Response.OK, request);
  220 + // 添加date头
  221 + SIPDateHeader dateHeader = new SIPDateHeader();
  222 + // 使用自己修改的
  223 + WvpSipDate wvpSipDate = new WvpSipDate(Calendar.getInstance(Locale.ENGLISH).getTimeInMillis());
  224 + dateHeader.setDate(wvpSipDate);
  225 + response.addHeader(dateHeader);
  226 +
  227 + // 添加Contact头
  228 + response.addHeader(request.getHeader(ContactHeader.NAME));
  229 + // 添加Expires头
  230 + response.addHeader(request.getExpires());
  231 +
  232 + return response;
  233 +
  234 + }
191 235 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java
... ... @@ -73,35 +73,38 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
73 73 String channelId = getText(rootElement, "DeviceID");
74 74 // 远程启动功能
75 75 if (!ObjectUtils.isEmpty(getText(rootElement, "TeleBoot"))) {
76   - if (parentPlatform.getServerGBId().equals(targetGBId)) {
77   - // 远程启动本平台:需要在重新启动程序后先对SipStack解绑
78   - logger.info("执行远程启动本平台命令");
79   - try {
80   - cmderFroPlatform.unregister(parentPlatform, null, null);
81   - } catch (InvalidArgumentException | ParseException | SipException e) {
82   - logger.error("[命令发送失败] 国标级联 注销: {}", e.getMessage());
83   - }
84   - taskExecutor.execute(() -> {
85   - // 远程启动
86   -// try {
87   -// Thread.sleep(3000);
88   -// SipProvider up = (SipProvider) SpringBeanFactory.getBean("udpSipProvider");
89   -// SipStackImpl stack = (SipStackImpl)up.getSipStack();
90   -// stack.stop();
91   -// Iterator listener = stack.getListeningPoints();
92   -// while (listener.hasNext()) {
93   -// stack.deleteListeningPoint((ListeningPoint) listener.next());
94   -// }
95   -// Iterator providers = stack.getSipProviders();
96   -// while (providers.hasNext()) {
97   -// stack.deleteSipProvider((SipProvider) providers.next());
98   -// }
99   -// VManageBootstrap.restart();
100   -// } catch (InterruptedException | ObjectInUseException e) {
101   -// logger.error("[任务执行失败] 服务重启: {}", e.getMessage());
102   -// }
103   - });
104   - }
  76 + // TODO 拒绝远程启动命令
  77 + logger.warn("[国标级联]收到平台的远程启动命令, 不处理");
  78 +
  79 +// if (parentPlatform.getServerGBId().equals(targetGBId)) {
  80 +// // 远程启动本平台:需要在重新启动程序后先对SipStack解绑
  81 +// logger.info("执行远程启动本平台命令");
  82 +// try {
  83 +// cmderFroPlatform.unregister(parentPlatform, null, null);
  84 +// } catch (InvalidArgumentException | ParseException | SipException e) {
  85 +// logger.error("[命令发送失败] 国标级联 注销: {}", e.getMessage());
  86 +// }
  87 +// taskExecutor.execute(() -> {
  88 +// // 远程启动
  89 +//// try {
  90 +//// Thread.sleep(3000);
  91 +//// SipProvider up = (SipProvider) SpringBeanFactory.getBean("udpSipProvider");
  92 +//// SipStackImpl stack = (SipStackImpl)up.getSipStack();
  93 +//// stack.stop();
  94 +//// Iterator listener = stack.getListeningPoints();
  95 +//// while (listener.hasNext()) {
  96 +//// stack.deleteListeningPoint((ListeningPoint) listener.next());
  97 +//// }
  98 +//// Iterator providers = stack.getSipProviders();
  99 +//// while (providers.hasNext()) {
  100 +//// stack.deleteSipProvider((SipProvider) providers.next());
  101 +//// }
  102 +//// VManageBootstrap.restart();
  103 +//// } catch (InterruptedException | ObjectInUseException e) {
  104 +//// logger.error("[任务执行失败] 服务重启: {}", e.getMessage());
  105 +//// }
  106 +// });
  107 +// }
105 108 }
106 109 DeviceControlType deviceControlType = DeviceControlType.typeOf(rootElement);
107 110 logger.info("[接受deviceControl命令] 命令: {}", deviceControlType);
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java
... ... @@ -88,7 +88,7 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp
88 88 // 对于已经离线的设备判断他的注册是否已经过期
89 89 if (!deviceService.expire(device)){
90 90 device.setOnline(0);
91   - deviceService.online(device);
  91 + deviceService.online(device, null);
92 92 }
93 93 }
94 94 // 刷新过期任务
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceStatusResponseMessageHandler.java
... ... @@ -71,7 +71,7 @@ public class DeviceStatusResponseMessageHandler extends SIPRequestProcessorParen
71 71 }
72 72 String text = onlineElement.getText();
73 73 if ("ONLINE".equalsIgnoreCase(text.trim())) {
74   - deviceService.online(device);
  74 + deviceService.online(device, null);
75 75 }else {
76 76 deviceService.offline(device.getDeviceId(), "设备状态查询结果:" + text.trim());
77 77 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/RegisterResponseProcessor.java
... ... @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.response.impl;
2 2  
3 3 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
4 4 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
  5 +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo;
5 6 import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder;
6 7 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
7 8 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
... ... @@ -10,6 +11,7 @@ import com.genersoft.iot.vmp.service.IPlatformService;
10 11 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
11 12 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
12 13 import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo;
  14 +import gov.nist.javax.sip.message.SIPResponse;
13 15 import org.slf4j.Logger;
14 16 import org.slf4j.LoggerFactory;
15 17 import org.springframework.beans.factory.annotation.Autowired;
... ... @@ -18,7 +20,6 @@ import org.springframework.stereotype.Component;
18 20 import javax.sip.InvalidArgumentException;
19 21 import javax.sip.ResponseEvent;
20 22 import javax.sip.SipException;
21   -import javax.sip.header.CallIdHeader;
22 23 import javax.sip.header.WWWAuthenticateHeader;
23 24 import javax.sip.message.Response;
24 25 import java.text.ParseException;
... ... @@ -65,9 +66,8 @@ public class RegisterResponseProcessor extends SIPResponseProcessorAbstract {
65 66 */
66 67 @Override
67 68 public void process(ResponseEvent evt) {
68   - Response response = evt.getResponse();
69   - CallIdHeader callIdHeader = (CallIdHeader) response.getHeader(CallIdHeader.NAME);
70   - String callId = callIdHeader.getCallId();
  69 + SIPResponse response = (SIPResponse)evt.getResponse();
  70 + String callId = response.getCallIdHeader().getCallId();
71 71 PlatformRegisterInfo platformRegisterInfo = redisCatchStorage.queryPlatformRegisterInfo(callId);
72 72 if (platformRegisterInfo == null) {
73 73 logger.info(String.format("[国标级联]未找到callId: %s 的注册/注销平台id", callId ));
... ... @@ -90,15 +90,17 @@ public class RegisterResponseProcessor extends SIPResponseProcessorAbstract {
90 90  
91 91 if (response.getStatusCode() == Response.UNAUTHORIZED) {
92 92 WWWAuthenticateHeader www = (WWWAuthenticateHeader)response.getHeader(WWWAuthenticateHeader.NAME);
  93 + SipTransactionInfo sipTransactionInfo = new SipTransactionInfo(response);
93 94 try {
94   - sipCommanderForPlatform.register(parentPlatform, callId, www, null, null, true, platformRegisterInfo.isRegister());
  95 + sipCommanderForPlatform.register(parentPlatform, sipTransactionInfo, www, null, null, true, platformRegisterInfo.isRegister());
95 96 } catch (SipException | InvalidArgumentException | ParseException e) {
96 97 logger.error("[命令发送失败] 国标级联 再次注册: {}", e.getMessage());
97 98 }
98 99 }else if (response.getStatusCode() == Response.OK){
99 100  
100 101 if (platformRegisterInfo.isRegister()) {
101   - platformService.online(parentPlatform);
  102 + SipTransactionInfo sipTransactionInfo = new SipTransactionInfo(response);
  103 + platformService.online(parentPlatform, sipTransactionInfo);
102 104 }else {
103 105 platformService.offline(parentPlatform, false);
104 106 }
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
... ... @@ -116,7 +116,7 @@ public class ZLMHttpHookListener {
116 116 @PostMapping(value = "/on_server_keepalive", produces = "application/json;charset=UTF-8")
117 117 public HookResult onServerKeepalive(@RequestBody OnServerKeepaliveHookParam param) {
118 118  
119   - logger.info("[ZLM HOOK] 收到zlm心跳:" + param.getMediaServerId());
  119 +// logger.info("[ZLM HOOK] 收到zlm心跳:" + param.getMediaServerId());
120 120  
121 121 taskExecutor.execute(() -> {
122 122 List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_keepalive);
... ...
src/main/java/com/genersoft/iot/vmp/service/IDeviceService.java
... ... @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.service;
2 2  
3 3 import com.genersoft.iot.vmp.gb28181.bean.Device;
4 4 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
  5 +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo;
5 6 import com.genersoft.iot.vmp.gb28181.bean.SyncStatus;
6 7 import com.genersoft.iot.vmp.vmanager.bean.BaseTree;
7 8 import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo;
... ... @@ -18,7 +19,7 @@ public interface IDeviceService {
18 19 * 设备上线
19 20 * @param device 设备信息
20 21 */
21   - void online(Device device);
  22 + void online(Device device, SipTransactionInfo sipTransactionInfo);
22 23  
23 24 /**
24 25 * 设备下线
... ...
src/main/java/com/genersoft/iot/vmp/service/IPlatformService.java
1 1 package com.genersoft.iot.vmp.service;
2 2  
3 3 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
  4 +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo;
4 5 import com.github.pagehelper.PageInfo;
5 6  
6 7 /**
... ... @@ -35,7 +36,7 @@ public interface IPlatformService {
35 36 * 平台上线
36 37 * @param parentPlatform 平台信息
37 38 */
38   - void online(ParentPlatform parentPlatform);
  39 + void online(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo);
39 40  
40 41 /**
41 42 * 平台离线
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
... ... @@ -89,7 +89,7 @@ public class DeviceServiceImpl implements IDeviceService {
89 89 private IMediaServerService mediaServerService;
90 90  
91 91 @Override
92   - public void online(Device device) {
  92 + public void online(Device device, SipTransactionInfo sipTransactionInfo) {
93 93 logger.info("[设备上线] deviceId:{}->{}:{}", device.getDeviceId(), device.getIp(), device.getPort());
94 94 Device deviceInRedis = redisCatchStorage.getDevice(device.getDeviceId());
95 95 Device deviceInDb = deviceMapper.getDeviceByDeviceId(device.getDeviceId());
... ... @@ -104,6 +104,14 @@ public class DeviceServiceImpl implements IDeviceService {
104 104 // 默认心跳间隔60
105 105 device.setKeepaliveIntervalTime(60);
106 106 }
  107 + if (sipTransactionInfo != null) {
  108 + device.setSipTransactionInfo(sipTransactionInfo);
  109 + }else {
  110 + if (deviceInRedis != null) {
  111 + device.setSipTransactionInfo(deviceInRedis.getSipTransactionInfo());
  112 + }
  113 + }
  114 +
107 115 // 第一次上线 或则设备之前是离线状态--进行通道同步和设备信息查询
108 116 if (device.getCreateTime() == null) {
109 117 device.setOnline(1);
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java
... ... @@ -123,8 +123,10 @@ public class PlatformServiceImpl implements IPlatformService {
123 123  
124 124 @Override
125 125 public boolean update(ParentPlatform parentPlatform) {
  126 + logger.info("[国标级联]更新平台 {}", parentPlatform.getDeviceGBId());
126 127 parentPlatform.setCharacterSet(parentPlatform.getCharacterSet().toUpperCase());
127 128 ParentPlatform parentPlatformOld = platformMapper.getParentPlatById(parentPlatform.getId());
  129 + ParentPlatformCatch parentPlatformCatchOld = redisCatchStorage.queryPlatformCatchInfo(parentPlatformOld.getServerGBId());
128 130 parentPlatform.setUpdateTime(DateUtil.getNow());
129 131 if (!parentPlatformOld.getTreeType().equals(parentPlatform.getTreeType())) {
130 132 // 目录结构发生变化,清空之前的关联关系
... ... @@ -134,6 +136,7 @@ public class PlatformServiceImpl implements IPlatformService {
134 136 platformGbStreamMapper.delByPlatformId(parentPlatformOld.getServerGBId());
135 137 }
136 138  
  139 +
137 140 // 停止心跳定时
138 141 final String keepaliveTaskKey = KEEPALIVE_KEY_PREFIX + parentPlatformOld.getServerGBId();
139 142 dynamicTask.stop(keepaliveTaskKey);
... ... @@ -142,9 +145,13 @@ public class PlatformServiceImpl implements IPlatformService {
142 145 dynamicTask.stop(registerTaskKey);
143 146 // 注销旧的
144 147 try {
145   - commanderForPlatform.unregister(parentPlatformOld, null, eventResult -> {
146   - logger.info("[国标级联] 注销成功, 平台:{}", parentPlatformOld.getServerGBId());
147   - });
  148 + if (parentPlatformOld.isStatus()) {
  149 + logger.info("保存平台{}时发现救平台在线,发送注销命令", parentPlatform.getDeviceGBId());
  150 + commanderForPlatform.unregister(parentPlatformOld, parentPlatformCatchOld.getSipTransactionInfo(), null, eventResult -> {
  151 + logger.info("[国标级联] 注销成功, 平台:{}", parentPlatformOld.getServerGBId());
  152 + });
  153 + }
  154 +
148 155 } catch (InvalidArgumentException | ParseException | SipException e) {
149 156 logger.error("[命令发送失败] 国标级联 注销: {}", e.getMessage());
150 157 }
... ... @@ -185,36 +192,36 @@ public class PlatformServiceImpl implements IPlatformService {
185 192  
186 193  
187 194 @Override
188   - public void online(ParentPlatform parentPlatform) {
189   - logger.info("[国标级联]:{}, 平台上线/更新注册", parentPlatform.getServerGBId());
  195 + public void online(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo) {
  196 + logger.info("[国标级联]:{}, 平台上线", parentPlatform.getServerGBId());
190 197 platformMapper.updateParentPlatformStatus(parentPlatform.getServerGBId(), true);
191 198 ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId());
192   - if (parentPlatformCatch != null) {
193   - parentPlatformCatch.getParentPlatform().setStatus(true);
194   - redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
195   - }else {
  199 + if (parentPlatformCatch == null) {
196 200 parentPlatformCatch = new ParentPlatformCatch();
197 201 parentPlatformCatch.setParentPlatform(parentPlatform);
198 202 parentPlatformCatch.setId(parentPlatform.getServerGBId());
199 203 parentPlatform.setStatus(true);
200 204 parentPlatformCatch.setParentPlatform(parentPlatform);
201   - redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
202 205 }
203 206  
  207 + parentPlatformCatch.getParentPlatform().setStatus(true);
  208 + parentPlatformCatch.setSipTransactionInfo(sipTransactionInfo);
  209 + redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
  210 +
204 211 final String registerTaskKey = REGISTER_KEY_PREFIX + parentPlatform.getServerGBId();
205 212 if (!dynamicTask.isAlive(registerTaskKey)) {
  213 + logger.info("[国标级联]:{}, 添加定时注册任务", parentPlatform.getServerGBId());
206 214 // 添加注册任务
207 215 dynamicTask.startCron(registerTaskKey,
208 216 // 注册失败(注册成功时由程序直接调用了online方法)
209   - ()-> {
210   - registerTask(parentPlatform);
211   - },
212   - (parentPlatform.getExpires()) *1000);
  217 + ()-> registerTask(parentPlatform, sipTransactionInfo),
  218 + parentPlatform.getExpires() * 1000);
213 219 }
214 220  
215 221  
216 222 final String keepaliveTaskKey = KEEPALIVE_KEY_PREFIX + parentPlatform.getServerGBId();
217 223 if (!dynamicTask.contains(keepaliveTaskKey)) {
  224 + logger.info("[国标级联]:{}, 添加定时心跳任务", parentPlatform.getServerGBId());
218 225 // 添加心跳任务
219 226 dynamicTask.startCron(keepaliveTaskKey,
220 227 ()-> {
... ... @@ -259,7 +266,7 @@ public class PlatformServiceImpl implements IPlatformService {
259 266 }
260 267 }
261 268  
262   - private void registerTask(ParentPlatform parentPlatform){
  269 + private void registerTask(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo){
263 270 try {
264 271 // 设置超时重发, 后续从底层支持消息重发
265 272 String key = KEEPALIVE_KEY_PREFIX + parentPlatform.getServerGBId() + "_timeout";
... ... @@ -267,10 +274,10 @@ public class PlatformServiceImpl implements IPlatformService {
267 274 return;
268 275 }
269 276 dynamicTask.startDelay(key, ()->{
270   - registerTask(parentPlatform);
  277 + registerTask(parentPlatform, sipTransactionInfo);
271 278 }, 1000);
272   - logger.info("[国标级联] 平台:{}注册即将到期,重新注册", parentPlatform.getServerGBId());
273   - commanderForPlatform.register(parentPlatform, eventResult -> {
  279 + logger.info("[国标级联] 平台:{}注册即将到期,开始续订", parentPlatform.getServerGBId());
  280 + commanderForPlatform.register(parentPlatform, sipTransactionInfo, eventResult -> {
274 281 dynamicTask.stop(key);
275 282 offline(parentPlatform, false);
276 283 },eventResult -> {
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java
... ... @@ -7,6 +7,7 @@ import com.genersoft.iot.vmp.conf.DynamicTask;
7 7 import com.genersoft.iot.vmp.conf.UserSetting;
8 8 import com.genersoft.iot.vmp.conf.exception.ControllerException;
9 9 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
  10 +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
10 11 import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog;
11 12 import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder;
12 13 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
... ... @@ -229,12 +230,16 @@ public class PlatformController {
229 230 throw new ControllerException(ErrorCode.ERROR400);
230 231 }
231 232 ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(serverGBId);
  233 + ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(serverGBId);
232 234 if (parentPlatform == null) {
233 235 throw new ControllerException(ErrorCode.ERROR100.getCode(), "平台不存在");
234 236 }
  237 + if (parentPlatformCatch == null) {
  238 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "平台不存在");
  239 + }
235 240 // 发送离线消息,无论是否成功都删除缓存
236 241 try {
237   - commanderForPlatform.unregister(parentPlatform, (event -> {
  242 + commanderForPlatform.unregister(parentPlatform, parentPlatformCatch.getSipTransactionInfo(), (event -> {
238 243 // 清空redis缓存
239 244 redisCatchStorage.delPlatformCatchInfo(parentPlatform.getServerGBId());
240 245 redisCatchStorage.delPlatformKeepalive(parentPlatform.getServerGBId());
... ...