-
Notifications
You must be signed in to change notification settings - Fork 17
/
ysipchan.cpp
10892 lines (10410 loc) · 331 KB
/
ysipchan.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/**
* ysipchan.cpp
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Sip Channel
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2023 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
* information for this specific distribution.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#include <yatephone.h>
#include <yatesip.h>
#include <yatesdp.h>
#include <string.h>
using namespace TelEngine;
namespace { // anonymous
class YateSIPListener; // Base class for listeners (need binding)
class YateSIPPartyHolder; // A SIPParty holder
class YateSIPTransport; // SIP transport: keeps a socket, read/send data
class YateSIPUDPTransport; // UDP transport
class YateSIPTCPTransport; // TCP/TLS transport
class YateSIPTransportWorker; // A transport worker
class YateSIPTCPListener; // A TCP listener
class YateSipParty; // Module SIP party
class YateUDPParty; // A SIP UDP party
class YateTCPParty; // A SIP TCP/TLS party
class YateSIPEngine; // The SIP engine
class YateSIPLine; // A line
class YateSIPEndPoint; // Endpoint processor
class SIPDriver;
#define EXPIRES_MIN 60
#define EXPIRES_DEF 600
#define EXPIRES_MAX 3600
// Parameters for PRACK 18x retransmission and 2xx waiting
#define PRACK_TIMER 2000000
#define PRACK_TRIES 4
#define PRACK_MWAIT 10000000
// TCP transport idle values in seconds
// Outgoing: interval to send keep alive
// Incoming: interval allowed to stay with refcounter=1 and no data received/sent
#define TCP_IDLE_MIN 32
#define TCP_IDLE_DEF 120
#define TCP_IDLE_MAX 600
// Maximum allowed value for bind retry interval in milliseconds
// 1 minute
#define BIND_RETRY_MAX 60000
static const TokenDict dict_errors[] = {
{ "incomplete", 484 },
{ "noroute", 404 },
{ "noroute", 604 },
{ "noconn", 503 },
{ "noconn", 408 },
{ "noauth", 401 },
{ "noautoauth", 401 },
{ "nomedia", 415 },
{ "nocall", 481 },
{ "busy", 486 },
{ "busy", 600 },
{ "noanswer", 480 },
{ "noanswer", 487 },
{ "rejected", 406 },
{ "rejected", 606 },
{ "forbidden", 403 },
{ "forbidden", 603 },
{ "offline", 404 },
{ "congestion", 480 },
{ "unallocated", 410 },
{ "moved", 410 },
{ "failure", 500 },
{ "pending", 491 },
{ "looping", 483 },
{ "timeout", 408 },
{ "timeout", 504 },
{ "postdialdelay", 504 },
{ "service-not-implemented", 501 },
{ "unimplemented", 501 },
{ "service-unavailable", 503 },
{ "unacceptable", 488 },
{ "noresource", 503 },
{ "interworking", 500 },
{ "interworking", 400 },
{ "invalid-message", 400 },
{ "protocol-error", 400 },
{ 0, 0 },
};
static const char s_dtmfs[] = "0123456789*#ABCDF";
static const TokenDict info_signals[] = {
{ "*", 10 },
{ "#", 11 },
{ "A", 12 },
{ "B", 13 },
{ "C", 14 },
{ "D", 15 },
{ 0, 0 },
};
class BodyTrace : public String
{
public:
inline BodyTrace(const String& body)
: m_hash(body.hash()), m_length(body.length())
{}
inline bool sameBody(const String& body) const
{ return body.hash() == m_hash && body.length() == m_length; }
unsigned int m_hash;
unsigned int m_length;
};
// Protocol definition
class ProtocolHolder
{
public:
enum Protocol {
Unknown = 0,
Udp,
Tcp,
Tls
};
inline ProtocolHolder(int p)
: m_proto(p)
{}
// Retrieve protocol
inline int protocol() const
{ return m_proto; }
inline const char* protoName(bool upperCase = true) const
{ return lookupProtoName(protocol(),upperCase); }
static inline const char* lookupProtoName(int proto, bool upperCase = true)
{ return lookup(proto,upperCase ? s_protoUC : s_protoLC); }
static inline int lookupProto(const char* name, bool upperCase = true,
int def = Unknown)
{ return lookup(name,upperCase ? s_protoUC : s_protoLC,def); }
static inline int lookupProtoAny(const String& name, int def = Unknown) {
String tmp = name;
return lookupProto(tmp.toLower(),false,def);
}
static const TokenDict s_protoLC[]; // Lower case proto name
static const TokenDict s_protoUC[]; // Upper case proto name
protected:
int m_proto;
private:
ProtocolHolder() {} // No default
};
class DtmfMethods
{
public:
enum Method {
Info,
Rfc2833,
Inband,
MethodCount
};
inline DtmfMethods()
{ setDefault(); }
inline void set(int _0 = MethodCount, int _1 = MethodCount, int _2 = MethodCount) {
m_methods[0] = _0;
m_methods[1] = _1;
m_methods[2] = _2;
}
inline void setDefault()
{ set(Rfc2833,Info,Inband); }
// Replace all methods from comma separated list
// If no method is set use other or setDefEmpty (reset to default)
// Return false if methods contain unknown methods
bool set(const String& methods, const DtmfMethods* other, bool setDefEmpty = true,
bool intersectOther = false);
// Intersect with other methods
void intersect(const DtmfMethods& other);
// Retrieve a method from deperecated parameters
// Reset the method if the parameter is false
// Display a message anyway if warn is not false
// Return true if the parameter was found
bool getDeprecatedDtmfMethod(const NamedList& list, const char* param, int method, bool* warn);
// Reset a method
void reset(int method);
// Build a string list from methods
void buildMethods(String& buf, const char* sep = ",");
bool hasMethod(int method) const;
inline void printMethods(DebugEnabler* enabler, int level, const String& str) {
String tmp;
buildMethods(tmp);
Debug(enabler,level,"Built DTMF methods '%s' from '%s'",tmp.safe(),str.safe());
}
inline int operator[](unsigned int index) {
if (index < MethodCount)
return m_methods[index];
return MethodCount;
}
inline DtmfMethods& operator=(const DtmfMethods& other) {
for (int i = 0; i < MethodCount; i++)
m_methods[i] = other.m_methods[i];
return *this;
}
static const TokenDict s_methodName[];
protected:
int m_methods[MethodCount];
};
class CaptureFilter : virtual public SocketFilter, public RefObject
{
public:
CaptureFilter(const char* name = 0)
:m_name(name), m_lock("CaptureFilter"), m_captureAgent(0), m_warned(false)
{
DDebug(DebugAll,"CaptureFilter(%s) [%p]",TelEngine::c_safe(name),this);
}
virtual ~CaptureFilter()
{
DDebug(DebugAll,"~CaptureFilter(%s) [%p]",m_name.c_str(),this);
TelEngine::destruct(m_captureAgent);
}
inline void setLocalAddr(const SocketAddr& lAddr)
{
WLock l(m_lock);
m_local = lAddr;
}
inline void setRemoteAddr(const SocketAddr& rAddr)
{
WLock l(m_lock);
m_remote = rAddr;
}
virtual void destruct()
{ RefObject::destruct(); }
bool init(YateSIPTransport* transp, const NamedList& params, const SocketAddr& lAddr, const SocketAddr& rAddr);
virtual void* getObject(const String& name) const;
virtual bool received(const void* buffer, int length, int flags, const struct sockaddr* addr, socklen_t adrlen);
virtual bool sent(const void* buffer, int length, int flags, const struct sockaddr* addr, socklen_t adrlen);
private:
String m_name;
RWLock m_lock;
SocketAddr m_local;
SocketAddr m_remote;
Capture* m_captureAgent;
bool m_warned;
};
// A SIP party holder
class YateSIPPartyHolder : public ProtocolHolder
{
public:
inline YateSIPPartyHolder(DebugEnabler* enabler, Mutex* mutex = 0, const String& traceId = String::empty())
: ProtocolHolder(Udp),
m_party(0), m_partyMutex(mutex), m_sips(false), m_transLocalPort(0), m_transRemotePort(0),
m_capture(false), m_captZipped(false), m_enabler(enabler), m_traceId(traceId)
{}
virtual ~YateSIPPartyHolder()
{ setParty(); }
// Retrieve a referrenced pointer to the held party
inline SIPParty* party() {
Lock lock(m_partyMutex);
return (m_party && m_party->ref()) ? m_party : 0;
}
// Retrieve the transport from party
YateSIPTransport* transport(bool ref = false);
// Check if a transport is used by our party
inline bool isTransport(YateSIPTransport* trans)
{ return trans == transport(); }
// Set the held party. Referrence it before
void setParty(SIPParty* party = 0);
// Set the held party if remote address changed
// Return true if holder party was set to given party
bool setPartyChanged(SIPParty* party);
// Set the party of a non answer message. Return true on success
bool setSipParty(SIPMessage* message, const YateSIPLine* line = 0,
bool useEp = false, const char* host = 0, int port = 0) const;
// (Re)Build party. Return true on success
bool buildParty(bool force = true, bool isTemp = false);
// Change party and its transport if the parameter list contains a transport
// Set force to true to try building a party anyway
// Return true on success
bool setParty(const NamedList& params, bool force,
const String& prefix = String::empty(),
const String& defRemoteAddr = String::empty(), int defRemotePort = 0,
bool isTemp = false);
// SIPS URI usage
inline bool sips() const
{ return m_sips; }
inline bool sips(bool on)
{ return change(m_sips,on); }
// Transport status changed notification
virtual void transportChangedStatus(int stat, const String& reason);
// Check if transport config params are present in parameters list
static inline bool haveTransParams(const NamedList& params,
const String& prefix = String::empty()) {
return params[prefix + "connection_id"] ||
params.getParam(prefix + "ip_transport") ||
params.getBoolValue(prefix + "ip_transport_tcp");
}
protected:
// Change a parameter, notify descendents
bool change(String& dest, const String& src);
bool change(int& dest, int src);
bool change(bool& dest, bool src);
// Changing notification for descendents
virtual void changing();
// Update transport type. Return true if changed
bool updateProto(const NamedList& params, const String& prefix = String::empty());
// Update transport remote addr/port. Return true if changed
bool updateRemoteAddr(const NamedList& params, const String& prefix = String::empty(),
const String& defRemoteAddr = String::empty(), int defRemotePort = 0);
// Update transport local addr/port. Return true if changed
bool updateLocalAddr(const NamedList& params, const String& prefix = String::empty());
// Update RTP local address
void setRtpLocalAddr(String& addr, Message* m = 0);
SIPParty* m_party; // Held party
Mutex* m_partyMutex; // Mutex protecting the party pointer
bool m_sips; // SIPS URI is used
// Data used to (re)build the transport
String m_transId;
String m_transLocalAddr;
int m_transLocalPort;
String m_transRemoteAddr;
int m_transRemotePort;
// Failure
String m_partyInvalidRemote;
bool m_capture;
String m_captAgent;
String m_captServer;
bool m_captZipped;
private:
DebugEnabler* m_enabler;
String m_traceId;
};
// Base class for listeners (need binding)
class YateSIPListener
{
public:
YateSIPListener(const char* name, int proto, const String& addr = String::empty(),
int port = 0);
inline const String& listenerName() const
{ return m_name; }
inline const char* lName() const
{ return m_name; }
inline const String& address() const
{ return m_address; }
inline int port() const
{ return m_port; }
inline bool ipv6() const
{ return m_ipv6; }
inline bool ipv6Support() const
{ return m_ipv6Support; }
// Check if address would change
inline bool addrWouldChange(Mutex* mutex, const String& addr, int port) {
Lock lck(mutex);
return m_port != port || m_cfgAddr != addr;
}
protected:
// Check bind now flag
bool bindNow(Mutex* mutex);
// Set addr/port/IPv6 support. Set bind flag if changed
void setAddr(const String& addr, int port, bool ipv6);
// Update IPv6 support from global. Set bind flag if changed and we must use IPv6
void updateIPv6Support();
// Update rtp address. Return true if set rtp addr flag changed
bool updateRtpAddr(const NamedList& params, String& buf, Mutex* mutex = 0);
// Initialize a socket
Socket* initSocket(SocketAddr& addr, Mutex* mutex, int backLogBuffer, bool forceBind,
String& reason);
void initialize(const NamedList& params, bool first);
unsigned int m_bindInterval; // Interval to try binding
u_int64_t m_nextBind; // Next time to bind
bool m_bind; // Re-bind flag
String m_cfgAddr; // Configured address
String m_address; // Address to bind
int m_port; // Port to bind
bool m_ipv6; // Listen on IPv6 address(es)
bool m_ipv6Support; // IPv6 supported
bool m_setRtpAddr; // Set rtp address from bind address
String m_bindRtpLocalAddr; // Rtp local address set from bind address
uint64_t m_warnBindFailDelay; // Delay failed to bind debug message
private:
String m_name; // Listener name
int m_proto; // Listener protocol
};
// SIP transport: keeps a socket, read data from it, send data through it
class YateSIPTransport : public Mutex, public RefObject, public ProtocolHolder
{
YCLASS(YateSIPTransport,RefObject);
YNOCOPY(YateSIPTransport);
friend class SIPDriver;
friend class YateSIPEndPoint;
friend class YateSIPTransportWorker;
public:
enum Status {
Idle = 0,
Connected,
Terminating,
Terminated
};
// (Re)Initialize the transport
bool init(const NamedList& params, const NamedList& defs, bool first,
Thread::Priority prio = Thread::Normal);
// Retrieve status
inline int status() const
{ return m_status; }
// Check if valid (connected)
inline bool valid() const
{ return status() == Connected; }
// Check if VIA header should be ignored
inline bool ignoreVia() const
{ return m_ignoreVia; }
// Retrieve local address for this transport
// This method is not thread safe for outgoing TCP
inline const SocketAddr& local() const
{ return m_local; }
// Retrieve remote address for this transport
// This method is not thread safe for outgoing TCP
inline const SocketAddr& remote() const
{ return m_remote; }
// Safely retrieve RTP local address
inline void rtpAddr(String& buf) {
Lock lock(this);
buf = m_rtpLocalAddr;
}
// Safely retrieve RTP external NAT address, only if set
inline void rtpNatAddr(String& buf) {
Lock lock(this);
if (m_rtpNatAddr)
buf = m_rtpNatAddr;
}
// Print sent messages to output
void printSendMsg(const SIPMessage* msg, const SocketAddr* addr = 0);
// Print received messages to output
// For TCP transports the function will assume 'buf' is not null terminated
void printRecvMsg(const char* buf, int len, const String& traceId = String::empty());
// Add transport data yate message
void fillMessage(Message& msg, bool addRoute = false);
// Transport descendents
virtual YateSIPUDPTransport* udpTransport()
{ return 0; }
virtual YateSIPTCPTransport* tcpTransport()
{ return 0; }
// Stop the worker. Change status
void terminate(const char* reason = 0);
// Process data (read/send).
// Return 0 to continue processing, positive to sleep (usec),
// negative to terminate and destroy
virtual int process() = 0;
// Retrieve the transport id
virtual const String& toString() const;
// Reset and delete a socket
static void resetSocket(Socket*& sock, int linger);
// Status names
static inline const char* statusName(int stat, const char* defVal = "Unknown")
{ return lookup(stat,s_statusName,defVal); }
static const TokenDict s_statusName[];
protected:
YateSIPTransport(int proto, const String& id, Socket* sock, int stat = Connected);
virtual void destroyed();
// Status changed notification for descendents
virtual void statusChanged()
{}
// Start the worker thread
bool startWorker(Thread::Priority prio);
// Change transport status. Notify it
void changeStatus(int stat);
// Handle received messages, set party, add to engine
// Consume the message
void receiveMsg(SIPMessage*& msg);
// Print socket read error to output
void printReadError();
// Print socket write error to output
void printWriteError(int res, unsigned int len, bool alarm = false);
// Set m_protoAddr from local/remote ip/port or reset it
void setProtoAddr(bool set);
String m_id; // Transport id
int m_status; // Transport status
unsigned int m_statusChgTime; // Last status changed time (seconds)
String m_reason; // Termination reason
Socket* m_sock; // The socket
unsigned int m_maxpkt; // Max receive packet length
DataBlock m_buffer; // Read buffer
SocketAddr m_local; // Local ip/port
SocketAddr m_remote; // Remote ip/port
String m_rtpLocalAddr; // RTP local address
String m_rtpNatAddr; // NAT IP to override RTP local address
YateSIPTransportWorker* m_worker; // Transport worker
bool m_initialized; // Flag reset when initializing by the module and set in init()
String m_protoAddr; // Proto + addr: used for debug (send/recv msg)
String m_role;
bool m_ignoreVia; // Ignore VIA header (override from global)
CaptureFilter* m_capture;
private:
YateSIPTransport() : ProtocolHolder(Udp) {} // No default constructor
};
// UDP transport
class YateSIPUDPTransport : public YateSIPTransport, public YateSIPListener
{
YCLASS(YateSIPUDPTransport,YateSIPTransport);
friend class YateSIPTransport;
public:
YateSIPUDPTransport(const String& id);
inline bool isDefault() const
{ return m_default; }
virtual YateSIPUDPTransport* udpTransport()
{ return this; }
// (Re)Initialize the transport
bool init(const NamedList& params, const NamedList& defs, bool first,
Thread::Priority prio = Thread::Normal);
// Send data
bool send(const void* data, unsigned int len, const SocketAddr& addr);
// Process data (read)
virtual int process();
protected:
bool m_default;
bool m_forceBind;
bool m_errored;
int m_bufferReq;
};
// TCP/TLS transport
class YateSIPTCPTransport : public YateSIPTransport
{
YCLASS(YateSIPTCPTransport,YateSIPTransport);
friend class YateTCPParty;
public:
// Build an outgoing transport
YateSIPTCPTransport(bool tls, const String& laddr, const String& raddr, int rport);
// Build an incoming transport
YateSIPTCPTransport(Socket* sock, bool tls);
inline bool outgoing() const
{ return m_outgoing; }
inline bool tls() const
{ return protocol() == Tls; }
inline const String& remoteAddr() const
{ return m_remoteAddr; }
inline int remotePort() const
{ return m_remotePort; }
inline const String& localAddr() const
{ return m_localAddr; }
// Safely return a reference to party
YateTCPParty* getParty();
virtual YateSIPTCPTransport* tcpTransport()
{ return this; }
// (Re)Initialize the transport
bool init(const NamedList& params, bool first, Thread::Priority prio = Thread::Normal);
// Set flow timer flag and idle interval (in seconds)
// Reset idle timeout
void setFlowTimer(bool on, unsigned int interval);
// Send an event
bool send(SIPEvent* event);
// Process data (read/send)
virtual int process();
protected:
virtual void destroyed();
// Status changed notification
virtual void statusChanged();
// Reset transport's party
void resetParty(YateTCPParty* party, bool set);
// Connect an outgoing transport. Terminate the socket before it
// Return: 1: OK, 0: retry connect, -1: stop the transport
int connect(u_int64_t connToutUs = 60000000);
// Send pending messages or keepalive, return false on failure
bool sendPending(const Time& time, bool& sent);
// Read data
bool readData(const Time& time, bool& read);
// Reset socket and connection related data
void resetConnection(Socket* sock = 0);
// Set transport idle timeout
void setIdleTimeout(u_int64_t time = Time::now());
// Send keep alive (or response to keep alive)
bool sendKeepAlive(bool request);
// Capture SIP TCP messages
void capture(const void* data, unsigned int len, bool rx);
inline bool sendPendingKeepAlive() {
if (!m_keepAlivePending)
return true;
m_keepAlivePending = false;
return sendKeepAlive(false);
}
bool m_outgoing; // Direction
YateTCPParty* m_party; // Transport party
ObjList m_queue; // Pending message queue
int m_sent; // Sent bytes from first message in queue
// -1 to dequeue a new message and print it
unsigned int m_firstKeepalive; // Outgoing: first keep alive interval
bool m_firstKeepaliveSent; // First keep alive used
unsigned int m_idleInterval; // Incoming: interval allowed to stay with a reference
// counter=1 without receiving any data
// Outgoing: keep alive interval
u_int64_t m_idleTimeout; // Idle timeout: check state or send keep alive
bool m_flowTimer; // Flow timer flag (RFC5626)
bool m_keepAlivePending; // Pending keep alive response
SIPMessage* m_msg; // Partially received SIP message (expecting body)
DataBlock m_sipBuffer; // Accumulated read data
unsigned int m_sipBufOffs; // Offset in sip buffer for partial sip message
unsigned int m_contentLen; // Expected content length for partial sip message
// Outgoing (re-connect info)
String m_remoteAddr; // Remote party address
int m_remotePort; // Remote port
String m_localAddr; // Optional local address to bind to
unsigned int m_connectRetry; // Number of re-connect
u_int64_t m_nextConnect; // Interval to try ro re-connect
};
// Transport worker
class YateSIPTransportWorker : public Thread
{
friend class YateSIPTransport;
public:
YateSIPTransportWorker(YateSIPTransport* trans, Thread::Priority prio);
~YateSIPTransportWorker();
virtual void run();
private:
void cleanupTransport(bool final, bool terminate = false);
YateSIPTransport* m_transport;
};
class YateSIPTCPListener : public Thread, public GenObject, public ProtocolHolder, public YateSIPListener
{
friend class SIPDriver;
friend class YateSIPEndPoint;
public:
YateSIPTCPListener(int proto, const String& name, const NamedList& params);
~YateSIPTCPListener();
void init(const NamedList& params, bool first);
inline bool tls() const
{ return protocol() == Tls; }
inline bool listening() const
{ return m_socket != 0; }
// Retrieve local address for this transport
// This method is not thread safe
inline const SocketAddr& local() const
{ return m_local; }
inline void setReason(const char* reason) {
if (!reason)
return;
Lock lck(m_mutex);
m_reason = reason;
}
virtual void run();
virtual const String& toString() const
{ return listenerName(); }
private:
// Close the socket. Remove from endpoint list
void cleanup(bool final);
// Reset socket
void stopListening(const char* reason = 0, int level = DebugNote);
Mutex m_mutex; // Mutex protecting transport parameters and bind ip/port
String m_reason; // Last error (state change) string
bool m_sslContextChanged; // SSL context changed flag
bool m_sslContextCheck; // Check SSL context availability
bool m_transParamsChanged; // Transport parameters changed flag
Socket* m_socket; // The socket
SocketAddr m_local; // Local ip/port
unsigned int m_backlog; // Pending connections queue length
String m_sslContext; // SSL/TLS context
NamedList m_transParams; // Parameters for created transports
bool m_initialized; // Flag reset when initializing by the module and set in init()
};
class YateSipParty : public SIPParty
{
YCLASS(YateSipParty,SIPParty)
public:
void fill(Message& params, bool transAddRoute = false);
protected:
YateSipParty(bool reliable);
virtual YateUDPParty* udpParty()
{ return 0; }
};
class YateUDPParty : public YateSipParty
{
public:
YateUDPParty(YateSIPUDPTransport* trans, const SocketAddr& addr, int* localPort = 0,
const char* localAddr = 0);
~YateUDPParty();
inline const SocketAddr& addr() const
{ return m_addr; }
inline const String& recvParty() const
{ return m_recvParty; }
inline int recvPort() const
{ return m_recvPort; }
virtual bool transmit(SIPEvent* event);
virtual const char* getProtoName() const;
virtual bool setParty(const URI& uri);
virtual void* getTransport();
// Get an object from this one
virtual void* getObject(const String& name) const;
protected:
virtual YateUDPParty* udpParty()
{ return this; }
YateSIPUDPTransport* m_transport;
SocketAddr m_addr;
String m_recvParty;
int m_recvPort;
};
class YateTCPParty : public YateSipParty
{
public:
YateTCPParty(YateSIPTCPTransport* trans);
~YateTCPParty();
virtual bool transmit(SIPEvent* event);
virtual const char* getProtoName() const;
virtual bool setParty(const URI& uri);
virtual void* getTransport();
// Get an object from this one
virtual void* getObject(const String& name) const;
// Update party local/remote addr/port from transport
void updateAddrs();
protected:
virtual void destroyed();
YateSIPTCPTransport* m_transport;
};
class SipHandler;
class YateSIPEngine : public SIPEngine
{
public:
YateSIPEngine(YateSIPEndPoint* ep);
// Initialize the engine
void initialize(NamedList* params);
virtual bool buildParty(SIPMessage* message);
virtual void allocTraceId(String& id);
virtual void traceMsg(SIPMessage* message, bool incoming = true);
virtual bool checkUser(String& username, const String& realm, const String& nonce,
const String& method, const String& uri, const String& response,
const SIPMessage* message, const MimeHeaderLine* authLine, GenObject* userData);
virtual SIPTransaction* forkInvite(SIPMessage* answer, SIPTransaction* trans);
// Transport status changed notification
void transportChangedStatus(YateSIPTransport* trans, int stat, const String& reason);
// Check if the engine has an active transaction using a given transport
bool hasActiveTransaction(YateSIPTransport* trans);
// Check if the engine has pending transactions
bool hasInitialTransaction();
// Clear transactions
inline void clearTransactions() {
Lock lck(this);
m_transList.clear();
}
inline bool update() const
{ return m_update; }
inline bool prack() const
{ return m_prack; }
inline bool info() const
{ return m_info; }
inline bool foreignAuth() const
{ return m_foreignAuth; }
private:
static bool copyAuthParams(NamedList* dest, const NamedList& src, bool ok = true);
YateSIPEndPoint* m_ep;
bool m_update;
bool m_prack;
bool m_info;
bool m_fork;
bool m_forkEarly;
bool m_foreignAuth;
uint64_t m_traceIds;
};
class YateSIPLine : public String, public Mutex, public CallAccount, public YateSIPPartyHolder
{
YCLASS(YateSIPLine,String)
public:
YateSIPLine(const String& name);
virtual ~YateSIPLine();
bool matchInbound(const String& addr, int port, const String& user) const;
void setupAuth(SIPMessage* msg) const;
SIPMessage* buildRegister(int expires);
void login();
void logout(bool sendLogout = true, const char* reason = 0);
bool process(SIPEvent* ev);
void timer(const Time& when);
bool update(const Message& msg);
// Transport status changed notification
virtual void transportChangedStatus(int stat, const String& reason);
inline const String& getLocalAddr() const
{ return m_localAddr; }
inline const String& getPartyAddr() const
{ return m_partyAddr ? m_partyAddr : m_transRemoteAddr; }
inline int getLocalPort() const
{ return m_localPort; }
inline int getPartyPort() const
{ return m_partyPort ? m_partyPort : m_transRemotePort; }
inline bool localDetect() const
{ return m_localDetect; }
inline const String& getFullName() const
{ return m_display; }
inline const String& getUserName() const
{ return m_username; }
inline const String& getAuthName() const
{ return m_authname ? m_authname : m_username; }
inline const String& regDomain() const
{ return m_registrar ? m_registrar : m_transRemoteAddr; }
inline const String& domain() const
{ return m_domain ? m_domain : regDomain(); }
inline const char* domain(const char* defDomain) const
{ return m_domain ? m_domain.c_str() :
(TelEngine::null(defDomain) ? regDomain().c_str() : defDomain); }
inline bool valid() const
{ return m_valid; }
inline bool marked() const
{ return m_marked; }
inline void marked(bool mark)
{ m_marked = mark; }
private:
void clearTransaction();
void detectLocal(const SIPMessage* msg);
void keepalive();
void setValid(bool valid, const char* reason = 0, const char* error = 0);
virtual void changing();
String m_registrar;
String m_username;
String m_authname;
String m_password;
String m_domain;
String m_display;
u_int64_t m_resend;
u_int64_t m_keepalive;
int m_interval;
int m_alive;
int m_flags;
int m_trans;
SIPTransaction* m_tr;
RefPointer<SIPSequence> m_seq;
bool m_marked;
bool m_valid;
String m_callid;
String m_localAddr;
String m_partyAddr;
int m_localPort;
int m_partyPort;
bool m_localDetect;
bool m_keepTcpOffline; // Don't reset party when offline
bool m_matchPort;
bool m_matchUser;
bool m_forceNotify;
};
class YateSIPEndPoint : public Thread
{
friend class SIPDriver;
friend class YateSIPTCPListener;
public:
YateSIPEndPoint(Thread::Priority prio = Thread::Normal,
unsigned int partyMutexCount = 5);
~YateSIPEndPoint();
bool Init(void);
void run(void);
bool incoming(SIPEvent* e, SIPTransaction* t);
void invite(SIPEvent* e, SIPTransaction* t);
void regReq(SIPEvent* e, SIPTransaction* t);
void regRun(const SIPMessage* message, SIPTransaction* t);
void options(SIPEvent* e, SIPTransaction* t);
bool generic(SIPEvent* e, SIPTransaction* t, int defErr = 405, bool async = false);
bool generic(const SIPMessage* message, SIPTransaction* t, const String& meth, bool autoAuth, bool isMsg);
bool buildParty(SIPMessage* message, const char* host = 0, int port = 0, const YateSIPLine* line = 0);
inline void addTcpTransport(YateSIPTCPTransport* trans) {
if (!trans)
return;
Lock lock(m_mutex);
m_transports.append(trans)->setDelete(false);
}
// Retrieve the default transport. Return a referrenced object
inline YateSIPUDPTransport* defTransport() {
Lock lock(m_mutex);
return (m_defTransport && m_defTransport->ref()) ? m_defTransport : 0;
}
// (re)set default UDP transport
void updateDefUdpTransport();
// Retrieve a transport by name (name can be a prefix).
// Return a referrenced object
YateSIPTransport* findTransport(const String& name);
// Retrieve an UDP transport. Return a referrenced object
YateSIPUDPTransport* findUdpTransport(const String& name);
// Retrieve an UDP transport by addr/port. Return a referrenced object
YateSIPUDPTransport* findUdpTransport(const String& addr, int port);
// Build or delete an UDP transport (re-init existing). Start the thread
bool setupUdpTransport(const String& name, bool enabled, const NamedList& params,
const NamedList& defs = NamedList::empty(), const char* reason = 0);
// Delete an UDP transport
bool removeUdpTransport(const String& name, const char* reason);
// Remove a transport from list without deleting it. Notify termination.
// Return true if found
bool removeTransport(YateSIPTransport* trans, bool updDef = true);
// Clear all transports
void clearUdpTransports(const char* reason);
// Transport status changed notification
void transportChangedStatus(YateSIPTransport* trans, int stat, const String& reason);
// Build or delete a TCP listener. Start the thread
bool setupListener(int proto, const String& name, bool enabled, const NamedList& params);
// Remove a listener from list without deleting it. Return true if found
bool removeListener(YateSIPTCPListener* listener);
// Remove a listener from list. Remove all if name is empty. Wait for termination
void cancelListener(const String& name = String::empty(), const char* reason = 0);
// This method is called by the driver when start/end initializing
void initializing(bool start);
// Complete transport names
void completeTransports(Message& msg, const String& partWord,
bool udp = true, bool tcp = true, bool tls = true);
inline YateSIPEngine* engine() const
{ return m_engine; }
inline void incFailedAuths()
{ m_failedAuths++; }
inline unsigned int failedAuths()
{
unsigned int tmp = m_failedAuths;
m_failedAuths = 0;
return tmp;
}
inline unsigned int timedOutTrs()
{
unsigned int tmp = m_timedOutTrs;
m_timedOutTrs = 0;
return tmp;
}
inline unsigned int timedOutByes()
{
unsigned int tmp = m_timedOutByes;
m_timedOutByes = 0;
return tmp;
}
RWLockPool m_partyMutexPool; // SIPParty mutex pool
// Check if data is allowed to be read from socket(s) and processed
static bool canRead();
static int s_evCount;
private:
YateSIPEngine *m_engine;
Mutex m_mutex; // Protect transports and listeners
ObjList m_transports; // All transports (non UDP are not owned)
YateSIPUDPTransport* m_defTransport; // Default transport (pointer to object in m_transports)
ObjList m_listeners; // Listeners list
unsigned int m_failedAuths;
unsigned int m_timedOutTrs;
unsigned int m_timedOutByes;
};
// Handle transfer requests
// Respond to the enclosed transaction
class YateSIPRefer : public Thread
{
public:
YateSIPRefer(const String& transferorID, const String& transferredID,
Driver* transferredDrv, Message* msg, SIPMessage* sipNotify,
SIPTransaction* transaction, Message* validate);
virtual void run(void);
virtual void cleanup(void)
{ release(true); }
private:
inline void setSuccess() {
m_rspCode = 202;
m_notifyCode = 200;
}
inline bool setFailure(int code) {
m_rspCode = m_notifyCode = code;
return false;
}
// Check success after message dispatch
// Return true if succeeded. Set response on failure
bool checkSuccess(const Message& msg, bool ok, void* chan);
// Respond the transaction and deref() it
void setTrResponse(int code);