主动发起注册 未完
This commit is contained in:
parent
6d280daed8
commit
68f5964a42
@ -0,0 +1,31 @@
|
||||
package cn.skcks.docking.gb28181.mocking.api.gb28181;
|
||||
|
||||
import cn.skcks.docking.gb28181.annotation.web.methods.GetJson;
|
||||
import cn.skcks.docking.gb28181.common.json.JsonResponse;
|
||||
import cn.skcks.docking.gb28181.mocking.config.SwaggerConfig;
|
||||
import cn.skcks.docking.gb28181.mocking.service.gb28181.register.RegisterService;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springdoc.core.models.GroupedOpenApi;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@Slf4j
|
||||
@Tag(name = "设备信息")
|
||||
@RestController
|
||||
@RequestMapping("/gb28181")
|
||||
@RequiredArgsConstructor
|
||||
public class Gb28181Controller {
|
||||
private final RegisterService registerService;
|
||||
@Bean
|
||||
public GroupedOpenApi gb28181Api() {
|
||||
return SwaggerConfig.api("GB28181 Api", "/gb28181");
|
||||
}
|
||||
|
||||
@GetJson("/register")
|
||||
public JsonResponse<Boolean> register(){
|
||||
return JsonResponse.success(registerService.register());
|
||||
}
|
||||
}
|
@ -5,6 +5,8 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sip.ListeningPoint;
|
||||
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "gb28181.server", ignoreInvalidFields = true)
|
||||
@Order(0)
|
||||
@ -15,4 +17,5 @@ public class ServerConfig {
|
||||
private String ip;
|
||||
private int port;
|
||||
private String password;
|
||||
private String transport = ListeningPoint.UDP;
|
||||
}
|
||||
|
@ -26,6 +26,8 @@ public class SipConfig {
|
||||
|
||||
private String password;
|
||||
|
||||
private int expire = 3600;
|
||||
|
||||
Integer ptzSpeed = 50;
|
||||
|
||||
Integer registerTimeInterval = 120;
|
||||
|
@ -0,0 +1,5 @@
|
||||
package cn.skcks.docking.gb28181.mocking.core.sip.message.register.request;
|
||||
|
||||
|
||||
public class RegisterRequest {
|
||||
}
|
@ -0,0 +1,176 @@
|
||||
package cn.skcks.docking.gb28181.mocking.core.sip.request;
|
||||
|
||||
import cn.skcks.docking.gb28181.core.sip.message.MessageHelper;
|
||||
import cn.skcks.docking.gb28181.core.sip.utils.SipUtil;
|
||||
import cn.skcks.docking.gb28181.mocking.config.sip.ServerConfig;
|
||||
import cn.skcks.docking.gb28181.mocking.config.sip.SipConfig;
|
||||
import cn.skcks.docking.gb28181.mocking.orm.mybatis.dynamic.model.MockingDevice;
|
||||
import cn.skcks.docking.gb28181.orm.mybatis.dynamic.model.DockingDevice;
|
||||
import lombok.SneakyThrows;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.DigestUtils;
|
||||
|
||||
import javax.sip.SipFactory;
|
||||
import javax.sip.address.Address;
|
||||
import javax.sip.address.SipURI;
|
||||
import javax.sip.header.*;
|
||||
import javax.sip.message.Request;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@DependsOn("serverConfig")
|
||||
@Component
|
||||
public class SipRequestBuilder implements ApplicationContextAware {
|
||||
private static ServerConfig serverConfig;
|
||||
|
||||
private static SipConfig sipConfig;
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
serverConfig = applicationContext.getBean(ServerConfig.class);
|
||||
sipConfig = applicationContext.getBean(SipConfig.class);
|
||||
}
|
||||
|
||||
private static SipFactory getSipFactory(){
|
||||
return SipFactory.getInstance();
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static SipURI getSipURI(String id, String address){
|
||||
return MessageHelper.createSipURI(id, address);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static Address getAddress(SipURI uri){
|
||||
return MessageHelper.createAddress(uri);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static FromHeader getFromHeader(Address fromAddress, String fromTag){
|
||||
return MessageHelper.createFromHeader(fromAddress, fromTag);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static ToHeader getToHeader(Address toAddress, String toTag){
|
||||
return MessageHelper.createToHeader(toAddress, toTag);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static MaxForwardsHeader getMaxForwardsHeader(int maxForwards){
|
||||
return getSipFactory().createHeaderFactory().createMaxForwardsHeader(maxForwards);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static List<ViaHeader> getDeviceViaHeaders(DockingDevice device, String viaTag){
|
||||
ViaHeader viaHeader = getSipFactory().createHeaderFactory().createViaHeader(device.getLocalIp(), serverConfig.getPort(), device.getTransport(), viaTag);
|
||||
viaHeader.setRPort();
|
||||
return Collections.singletonList(viaHeader);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static List<ViaHeader> getViaHeaders(String ip,int port, String transport, String viaTag){
|
||||
ViaHeader viaHeader = getSipFactory().createHeaderFactory().createViaHeader(ip, port, transport, viaTag);
|
||||
viaHeader.setRPort();
|
||||
return Collections.singletonList(viaHeader);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static CSeqHeader getCSeqHeader(long cSeq, String method){
|
||||
return getSipFactory().createHeaderFactory().createCSeqHeader(cSeq, method);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static Request createRegisterRequest(MockingDevice device, String ip, int port, long cSeq, String fromTag, String viaTag, CallIdHeader callIdHeader) {
|
||||
String target = StringUtils.joinWith(":", serverConfig.getIp(), serverConfig.getPort());
|
||||
SipURI requestURI = getSipURI(serverConfig.getId(), target);
|
||||
// via
|
||||
List<ViaHeader> viaHeaders = getViaHeaders(serverConfig.getIp(), serverConfig.getPort(), serverConfig.getTransport(), viaTag);
|
||||
|
||||
// from
|
||||
String from = StringUtils.joinWith(":", ip, port);
|
||||
SipURI fromSipURI = getSipURI(device.getGbDeviceId(), from);
|
||||
Address fromAddress = getAddress(fromSipURI);
|
||||
FromHeader fromHeader = getFromHeader(fromAddress, fromTag);
|
||||
|
||||
// to
|
||||
ToHeader toHeader = getToHeader(fromAddress, null);
|
||||
|
||||
// forwards
|
||||
MaxForwardsHeader maxForwardsHeader = getMaxForwardsHeader(70);
|
||||
|
||||
// ceq
|
||||
CSeqHeader cSeqHeader = getCSeqHeader(cSeq, Request.REGISTER);
|
||||
|
||||
SipFactory sipFactory = getSipFactory();
|
||||
Request request = sipFactory.createMessageFactory().createRequest(requestURI, Request.REGISTER, callIdHeader,
|
||||
cSeqHeader, fromHeader, toHeader, viaHeaders, maxForwardsHeader);
|
||||
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory()
|
||||
.createSipURI(device.getGbDeviceId(), from));
|
||||
request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
|
||||
ExpiresHeader expires = sipFactory.createHeaderFactory().createExpiresHeader(sipConfig.getExpire());
|
||||
request.addHeader(expires);
|
||||
UserAgentHeader userAgentHeader = SipUtil.createUserAgentHeader();
|
||||
request.addHeader(userAgentHeader);
|
||||
return request;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static Request createRegisterRequestWithAuthorization(MockingDevice device, String ip, int port, long cSeq, String fromTag, String viaTag, CallIdHeader callIdHeader, String callId, WWWAuthenticateHeader www) {
|
||||
Request request = createRegisterRequest(device, ip, port, cSeq, fromTag, viaTag, callIdHeader);
|
||||
String realm = www.getRealm();
|
||||
String nonce = www.getNonce();
|
||||
String scheme = www.getScheme();
|
||||
String qop = www.getQop();
|
||||
|
||||
String target = StringUtils.joinWith(":", serverConfig.getIp(), serverConfig.getPort());
|
||||
SipURI requestURI = getSipURI(serverConfig.getId(), target);
|
||||
String cNonce = null;
|
||||
String nc = "00000001";
|
||||
if (qop != null) {
|
||||
if ("auth".equals(qop)) {
|
||||
// 客户端随机数,这是一个不透明的字符串值,由客户端提供,并且客户端和服务器都会使用,以避免用明文文本。
|
||||
// 这使得双方都可以查验对方的身份,并对消息的完整性提供一些保护
|
||||
cNonce = UUID.randomUUID().toString();
|
||||
} else if ("auth-int".equals(qop)) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
String HA1 = DigestUtils.md5DigestAsHex((device.getGbDeviceId() + ":" + realm + ":" + serverConfig.getPassword()).getBytes());
|
||||
String HA2 = DigestUtils.md5DigestAsHex((Request.REGISTER + ":" + requestURI.toString()).getBytes());
|
||||
StringBuffer reStr = new StringBuffer(200);
|
||||
reStr.append(HA1);
|
||||
reStr.append(":");
|
||||
reStr.append(nonce);
|
||||
reStr.append(":");
|
||||
if (qop != null) {
|
||||
reStr.append(nc);
|
||||
reStr.append(":");
|
||||
reStr.append(cNonce);
|
||||
reStr.append(":");
|
||||
reStr.append(qop);
|
||||
reStr.append(":");
|
||||
}
|
||||
reStr.append(HA2);
|
||||
String response = DigestUtils.md5DigestAsHex(reStr.toString().getBytes());
|
||||
AuthorizationHeader authorizationHeader = getSipFactory().createHeaderFactory().createAuthorizationHeader(scheme);
|
||||
authorizationHeader.setUsername(device.getGbDeviceId());
|
||||
authorizationHeader.setRealm(realm);
|
||||
authorizationHeader.setNonce(nonce);
|
||||
authorizationHeader.setURI(requestURI);
|
||||
authorizationHeader.setResponse(response);
|
||||
authorizationHeader.setAlgorithm("MD5");
|
||||
if (qop != null) {
|
||||
authorizationHeader.setQop(qop);
|
||||
authorizationHeader.setCNonce(cNonce);
|
||||
authorizationHeader.setNonceCount(1);
|
||||
}
|
||||
request.addHeader(authorizationHeader);
|
||||
return request;
|
||||
}
|
||||
}
|
@ -119,6 +119,10 @@ public class DeviceService {
|
||||
return deviceMapper.updateByPrimaryKey(device) > 0;
|
||||
}
|
||||
|
||||
public List<MockingDevice> getAllDevice(){
|
||||
return deviceMapper.select(u -> u.orderBy(MockingDeviceDynamicSqlSupport.id.descending()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询设备
|
||||
* @param page 页数
|
||||
|
@ -0,0 +1,47 @@
|
||||
package cn.skcks.docking.gb28181.mocking.service.gb28181.register;
|
||||
|
||||
|
||||
import cn.skcks.docking.gb28181.core.sip.listener.SipListener;
|
||||
import cn.skcks.docking.gb28181.core.sip.service.SipService;
|
||||
import cn.skcks.docking.gb28181.core.sip.utils.SipUtil;
|
||||
import cn.skcks.docking.gb28181.mocking.config.sip.SipConfig;
|
||||
import cn.skcks.docking.gb28181.mocking.core.sip.request.SipRequestBuilder;
|
||||
import cn.skcks.docking.gb28181.mocking.service.device.DeviceService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.sip.ListeningPoint;
|
||||
import javax.sip.SipException;
|
||||
import javax.sip.SipProvider;
|
||||
import javax.sip.message.Request;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class RegisterService {
|
||||
private final SipConfig sipConfig;
|
||||
private final SipListener sipListener;
|
||||
private final SipService sipService;
|
||||
|
||||
private final DeviceService deviceService;
|
||||
|
||||
public boolean register(){
|
||||
deviceService.getAllDevice().parallelStream().forEach(device -> {
|
||||
sipConfig.getIp().parallelStream().forEach(ip->{
|
||||
SipProvider provider = sipService.getProvider(ListeningPoint.UDP, ip);
|
||||
if(provider == null){
|
||||
return;
|
||||
}
|
||||
Request request = SipRequestBuilder.createRegisterRequest(device,ip, sipConfig.getPort(),1, SipUtil.generateFromTag(),null, provider.getNewCallId());
|
||||
try {
|
||||
provider.sendRequest(request);
|
||||
} catch (SipException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ import cn.skcks.docking.gb28181.mocking.config.sip.SipConfig;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.SmartLifecycle;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
@ -16,6 +17,7 @@ import org.springframework.util.CollectionUtils;
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
@DependsOn("mockingOrmInitService")
|
||||
@ComponentScan("cn.skcks.docking.gb28181.core.sip.executor")
|
||||
public class SipStarter implements SmartLifecycle {
|
||||
private final SipService sipService;
|
||||
private final SipConfig sipConfig;
|
||||
|
@ -11,6 +11,7 @@ import org.springframework.context.annotation.ComponentScan;
|
||||
"cn.skcks.docking.gb28181.annotation",
|
||||
"cn.skcks.docking.gb28181.common",
|
||||
"cn.skcks.docking.gb28181.mocking",
|
||||
"cn.skcks.docking.gb28181.core.sip.utils",
|
||||
})
|
||||
public class Gb28181MockingStarter {
|
||||
public static void main(String[] args) {
|
||||
|
@ -48,8 +48,10 @@ gb28181:
|
||||
id: 44050100002000000002
|
||||
# [可选] 默认设备认证密码,后续扩展使用设备单独密码, 移除密码将不进行校验
|
||||
password: 123456
|
||||
expire: 3600
|
||||
server:
|
||||
ip: 192.168.10.241
|
||||
ip: 192.168.10.32
|
||||
# ip: 192.168.3.12
|
||||
port: 5060
|
||||
password: 123456
|
||||
domain: 4405010000
|
||||
|
Loading…
Reference in New Issue
Block a user