@@ -16,10 +16,14 @@ package sip
1616
1717import (
1818 "context"
19+ "crypto/tls"
20+ "errors"
1921 "fmt"
22+ "io"
2023 "log/slog"
2124 "net"
2225 "net/netip"
26+ "os"
2327 "strings"
2428 "sync"
2529 "sync/atomic"
@@ -45,12 +49,13 @@ type ServiceConfig struct {
4549}
4650
4751type Service struct {
48- conf * config.Config
49- sconf * ServiceConfig
50- log logger.Logger
51- mon * stats.Monitor
52- cli * Client
53- srv * Server
52+ conf * config.Config
53+ sconf * ServiceConfig
54+ log logger.Logger
55+ mon * stats.Monitor
56+ cli * Client
57+ srv * Server
58+ closers []io.Closer
5459
5560 mu sync.Mutex
5661 pendingTransfers map [transferKey ]chan struct {}
@@ -168,6 +173,9 @@ func (s *Service) Stop() {
168173 s .cli .Stop ()
169174 s .srv .Stop ()
170175 s .mon .Stop ()
176+ for _ , c := range s .closers {
177+ _ = c .Close ()
178+ }
171179}
172180
173181func (s * Service ) SetHandler (handler Handler ) {
@@ -194,10 +202,47 @@ func (s *Service) Start() error {
194202 //
195203 // Routers are smart, they usually keep the UDP "session" open for a few moments, and may allow INVITE handshake
196204 // to pass even without forwarding rules on the firewall. ut it will inevitably fail later on follow-up requests like BYE.
197- ua , err := sipgo .NewUA (
205+ var opts = [] sipgo.UserAgentOption {
198206 sipgo .WithUserAgent (UserAgent ),
199207 sipgo .WithUserAgentLogger (slog .New (logger .ToSlogHandler (s .log ))),
200- )
208+ }
209+ var tlsConf * tls.Config
210+ if tconf := s .conf .TLS ; tconf != nil {
211+ if len (tconf .Certs ) == 0 {
212+ return errors .New ("TLS certificate required" )
213+ }
214+ var certs []tls.Certificate
215+ for _ , c := range tconf .Certs {
216+ cert , err := tls .LoadX509KeyPair (c .CertFile , c .KeyFile )
217+ if err != nil {
218+ return err
219+ }
220+ certs = append (certs , cert )
221+ }
222+ var keyLog io.Writer
223+ if tconf .KeyLog != "" {
224+ f , err := os .OpenFile (tconf .KeyLog , os .O_APPEND | os .O_CREATE | os .O_WRONLY , 0600 )
225+ if err != nil {
226+ return err
227+ }
228+ s .closers = append (s .closers , f )
229+ keyLog = f
230+ go func () {
231+ ticker := time .NewTicker (30 * time .Second )
232+ defer ticker .Stop ()
233+ for range ticker .C {
234+ f .Sync ()
235+ }
236+ }()
237+ }
238+ tlsConf = & tls.Config {
239+ NextProtos : []string {"sip" },
240+ Certificates : certs ,
241+ KeyLogWriter : keyLog ,
242+ }
243+ opts = append (opts , sipgo .WithUserAgenTLSConfig (tlsConf ))
244+ }
245+ ua , err := sipgo .NewUA (opts ... )
201246 if err != nil {
202247 return err
203248 }
@@ -206,7 +251,7 @@ func (s *Service) Start() error {
206251 }
207252 // Server is responsible for answering all transactions. However, the client may also receive some (e.g. BYE).
208253 // Thus, all unhandled transactions will be checked by the client.
209- if err := s .srv .Start (ua , s .sconf , s .cli .OnRequest ); err != nil {
254+ if err := s .srv .Start (ua , s .sconf , tlsConf , s .cli .OnRequest ); err != nil {
210255 return err
211256 }
212257 s .log .Debugw ("sip service ready" )
@@ -223,7 +268,7 @@ func (s *Service) CreateSIPParticipantAffinity(ctx context.Context, req *rpc.Int
223268}
224269
225270func (s * Service ) TransferSIPParticipant (ctx context.Context , req * rpc.InternalTransferSIPParticipantRequest ) (* emptypb.Empty , error ) {
226- s .log .Infow ("transfering SIP call" , "callID" , req .SipCallId , "transferTo" , req .TransferTo )
271+ s .log .Infow ("transferring SIP call" , "callID" , req .SipCallId , "transferTo" , req .TransferTo )
227272
228273 var transferResult atomic.Pointer [error ]
229274
0 commit comments