@@ -16,10 +16,14 @@ package sip
16
16
17
17
import (
18
18
"context"
19
+ "crypto/tls"
20
+ "errors"
19
21
"fmt"
22
+ "io"
20
23
"log/slog"
21
24
"net"
22
25
"net/netip"
26
+ "os"
23
27
"strings"
24
28
"sync"
25
29
"sync/atomic"
@@ -45,12 +49,13 @@ type ServiceConfig struct {
45
49
}
46
50
47
51
type 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
54
59
55
60
mu sync.Mutex
56
61
pendingTransfers map [transferKey ]chan struct {}
@@ -168,6 +173,9 @@ func (s *Service) Stop() {
168
173
s .cli .Stop ()
169
174
s .srv .Stop ()
170
175
s .mon .Stop ()
176
+ for _ , c := range s .closers {
177
+ _ = c .Close ()
178
+ }
171
179
}
172
180
173
181
func (s * Service ) SetHandler (handler Handler ) {
@@ -194,10 +202,47 @@ func (s *Service) Start() error {
194
202
//
195
203
// Routers are smart, they usually keep the UDP "session" open for a few moments, and may allow INVITE handshake
196
204
// 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 {
198
206
sipgo .WithUserAgent (UserAgent ),
199
207
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 ... )
201
246
if err != nil {
202
247
return err
203
248
}
@@ -206,7 +251,7 @@ func (s *Service) Start() error {
206
251
}
207
252
// Server is responsible for answering all transactions. However, the client may also receive some (e.g. BYE).
208
253
// 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 {
210
255
return err
211
256
}
212
257
s .log .Debugw ("sip service ready" )
@@ -223,7 +268,7 @@ func (s *Service) CreateSIPParticipantAffinity(ctx context.Context, req *rpc.Int
223
268
}
224
269
225
270
func (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 )
227
272
228
273
var transferResult atomic.Pointer [error ]
229
274
0 commit comments