From 838d64ebffb7bf2e5e643f37ac6c1c24845fea9e Mon Sep 17 00:00:00 2001 From: shikong <919411476@qq.com> Date: Sat, 25 Jan 2025 17:47:00 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E5=90=AF=E5=8A=A8=E6=97=B6?= =?UTF-8?q?=E6=B3=A8=E5=86=8C=20register?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/client/main.go | 17 +++--- pkg/services/device/keepalive.go | 1 + pkg/services/device/register.go | 99 ++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 7 deletions(-) create mode 100644 pkg/services/device/register.go diff --git a/cmd/client/main.go b/cmd/client/main.go index b7135ac..9bb86b7 100644 --- a/cmd/client/main.go +++ b/cmd/client/main.go @@ -60,16 +60,11 @@ func main() { // 服务端, 接受 SIP 指令 srv, _ := sipgo.NewServer(ua, sipgo.WithServerLogger(logger)) - message.SetupMessageHandler(srv, client, clientConfig) - keepalive.SetupKeepalive(client, clientConfig) - device.StartKeepAlive(client) - defer device.StopKeepAlive() - quit := make(chan os.Signal, 1) go func() { defer func() { if err := recover(); err != nil { - logger.Fatal().Any("%s", err) + logger.Error().Msgf("%s", err) quit <- syscall.SIGKILL } }() @@ -77,11 +72,19 @@ func main() { // 暂时 默认 udp // 启动 SIP 服务 if err := srv.ListenAndServe(ctx, "udp", addr); err != nil { - logger.Error().Err(err) + logger.Error().Msgf("%s", err) quit <- syscall.SIGTERM } }() + time.Sleep(1 * time.Second) + + device.Register(client, clientConfig) + message.SetupMessageHandler(srv, client, clientConfig) + keepalive.SetupKeepalive(client, clientConfig) + device.StartKeepAlive(client) + defer device.StopKeepAlive() + signal.Notify(quit, syscall.SIGINT, syscall.SIGKILL, syscall.SIGTERM) <-quit } diff --git a/pkg/services/device/keepalive.go b/pkg/services/device/keepalive.go index 8c64fe5..0b8af3b 100644 --- a/pkg/services/device/keepalive.go +++ b/pkg/services/device/keepalive.go @@ -18,6 +18,7 @@ func AddKeepaliveSender(deviceId string, sender SendKeepAlive) { } // StartKeepAlive 启动 keepalive 定时器 +// // 每 30 秒发送一次 keepalive 消息到服务器 func StartKeepAlive(client *sipgo.Client) { keepaliveTimer = time.NewTicker(time.Second * 30) diff --git a/pkg/services/device/register.go b/pkg/services/device/register.go new file mode 100644 index 0000000..bd704f3 --- /dev/null +++ b/pkg/services/device/register.go @@ -0,0 +1,99 @@ +package device + +import ( + "context" + "fmt" + "git.skcks.cn/Shikong/go-gb28181/pkg/config" + "git.skcks.cn/Shikong/go-gb28181/pkg/log" + "github.com/emiago/sipgo" + "github.com/emiago/sipgo/sip" + "github.com/icholy/digest" + "time" +) + +func Register(client *sipgo.Client, clientConfig *config.ClientConfig) { + target := sip.Uri{ + User: clientConfig.ServerId, + Host: clientConfig.ServerIp, + Port: clientConfig.ServerPort, + Headers: sip.NewParams(), + } + uri := sip.Uri{User: clientConfig.DeviceId, Host: clientConfig.ListenIp, Port: clientConfig.ServerPort} + req := sip.NewRequest(sip.REGISTER, target) + req.AppendHeader(sip.NewHeader("X-GB-Ver", "2.0")) + req.AppendHeader(sip.NewHeader("Contact", uri.String())) + req.AppendHeader(sip.NewHeader("Expires", "3600")) + + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + + tx, err := client.TransactionRequest(ctx, req) + defer tx.Terminate() + if err != nil { + log.Log().Error().Msgf("%v", err) + return + } + + resp, err := getResponse(tx) + if err != nil { + log.Log().Error().Msgf("%v", err) + return + } + + headers := resp.Headers() + for _, h := range headers { + log.Log().Info().Msgf("%v => %v", h.Name(), h.Value()) + } + log.Log().Info().Msgf(resp.String()) + + // 如果状态码是401,则需要验证 + if resp.StatusCode == 401 { + wwwAuth := resp.GetHeader("WWW-Authenticate") + chal, err := digest.ParseChallenge(wwwAuth.Value()) + if err != nil { + log.Log().Error().Msgf("Fail to parse challenge %v", err) + return + } + + // Reply with digest + cred, _ := digest.Digest(chal, digest.Options{ + Method: req.Method.String(), + Username: clientConfig.ServerId, + URI: target.String(), + Password: clientConfig.Password, + }) + + newReq := req.Clone() + newReq.RemoveHeader("Via") // Must be regenerated by tranport layer + newReq.AppendHeader(sip.NewHeader("Authorization", cred.String())) + + ctx := context.Background() + tx, err := client.TransactionRequest(ctx, newReq, sipgo.ClientRequestAddVia) + if err != nil { + log.Log().Error().Msgf("Fail to create transaction") + return + } + + resp, err = getResponse(tx) + defer tx.Terminate() + if err != nil { + log.Log().Error().Msgf("Fail to get response") + return + } + + if resp.StatusCode != 403 { + log.Log().Info().Msgf("设备:%s 注册成功", clientConfig.DeviceId) + } + + log.Log().Info().Msgf(resp.String()) + } +} + +func getResponse(tx sip.ClientTransaction) (*sip.Response, error) { + select { + case <-tx.Done(): + return nil, fmt.Errorf("transaction died") + case res := <-tx.Responses(): + return res, nil + } +}