oversip_p 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (132) hide show
  1. checksums.yaml +7 -0
  2. data/AUTHORS +22 -0
  3. data/LICENSE +25 -0
  4. data/README.md +43 -0
  5. data/Rakefile +54 -0
  6. data/bin/oversip +184 -0
  7. data/etc/oversip.conf +274 -0
  8. data/etc/proxies.conf +145 -0
  9. data/etc/server.rb +315 -0
  10. data/etc/tls/ca/cacert.pem +3894 -0
  11. data/etc/tls/demo-tls.oversip.net.crt +17 -0
  12. data/etc/tls/demo-tls.oversip.net.key +15 -0
  13. data/etc/tls/upgrade-cacert.sh +12 -0
  14. data/etc/tls/utils/create-cert.rb +162 -0
  15. data/etc/tls/utils/get-sip-identities.rb +95 -0
  16. data/ext/common/c_util.h +74 -0
  17. data/ext/common/ruby_c_util.h +88 -0
  18. data/ext/sip_parser/common_headers.h +210 -0
  19. data/ext/sip_parser/ext_help.h +18 -0
  20. data/ext/sip_parser/extconf.rb +3 -0
  21. data/ext/sip_parser/sip_message_parser.c +29741 -0
  22. data/ext/sip_parser/sip_parser.h +250 -0
  23. data/ext/sip_parser/sip_parser_ruby.c +1370 -0
  24. data/ext/sip_parser/sip_uri_parser.c +39699 -0
  25. data/ext/stud/extconf.rb +43 -0
  26. data/ext/stun/ext_help.h +16 -0
  27. data/ext/stun/extconf.rb +3 -0
  28. data/ext/stun/stun_ruby.c +394 -0
  29. data/ext/utils/ext_help.h +14 -0
  30. data/ext/utils/extconf.rb +3 -0
  31. data/ext/utils/haproxy_protocol.c +6163 -0
  32. data/ext/utils/haproxy_protocol.h +27 -0
  33. data/ext/utils/ip_utils.c +5952 -0
  34. data/ext/utils/ip_utils.h +64 -0
  35. data/ext/utils/outbound_utils.c +3227 -0
  36. data/ext/utils/outbound_utils.h +27 -0
  37. data/ext/utils/utils_ruby.c +392 -0
  38. data/ext/utils/utils_ruby.h +76 -0
  39. data/ext/websocket_framing_utils/ext_help.h +18 -0
  40. data/ext/websocket_framing_utils/extconf.rb +3 -0
  41. data/ext/websocket_framing_utils/ws_framing_utils.h +47 -0
  42. data/ext/websocket_framing_utils/ws_framing_utils_ruby.c +135 -0
  43. data/ext/websocket_http_parser/ext_help.h +18 -0
  44. data/ext/websocket_http_parser/extconf.rb +3 -0
  45. data/ext/websocket_http_parser/ws_http_parser.c +1635 -0
  46. data/ext/websocket_http_parser/ws_http_parser.h +87 -0
  47. data/ext/websocket_http_parser/ws_http_parser_ruby.c +630 -0
  48. data/lib/oversip/config.rb +597 -0
  49. data/lib/oversip/config_validators.rb +126 -0
  50. data/lib/oversip/default_server.rb +52 -0
  51. data/lib/oversip/errors.rb +10 -0
  52. data/lib/oversip/fiber_pool.rb +56 -0
  53. data/lib/oversip/launcher.rb +635 -0
  54. data/lib/oversip/logger.rb +84 -0
  55. data/lib/oversip/modules/outbound_mangling.rb +56 -0
  56. data/lib/oversip/modules/user_assertion.rb +73 -0
  57. data/lib/oversip/proxies_config.rb +189 -0
  58. data/lib/oversip/ruby_ext/eventmachine.rb +38 -0
  59. data/lib/oversip/sip/client.rb +428 -0
  60. data/lib/oversip/sip/client_transaction.rb +586 -0
  61. data/lib/oversip/sip/constants.rb +88 -0
  62. data/lib/oversip/sip/core.rb +217 -0
  63. data/lib/oversip/sip/launcher.rb +221 -0
  64. data/lib/oversip/sip/listeners/connection.rb +54 -0
  65. data/lib/oversip/sip/listeners/ipv4_tcp_client.rb +21 -0
  66. data/lib/oversip/sip/listeners/ipv4_tcp_server.rb +22 -0
  67. data/lib/oversip/sip/listeners/ipv4_tls_client.rb +21 -0
  68. data/lib/oversip/sip/listeners/ipv4_tls_server.rb +22 -0
  69. data/lib/oversip/sip/listeners/ipv4_tls_tunnel_server.rb +22 -0
  70. data/lib/oversip/sip/listeners/ipv4_udp_server.rb +21 -0
  71. data/lib/oversip/sip/listeners/ipv6_tcp_client.rb +21 -0
  72. data/lib/oversip/sip/listeners/ipv6_tcp_server.rb +22 -0
  73. data/lib/oversip/sip/listeners/ipv6_tls_client.rb +21 -0
  74. data/lib/oversip/sip/listeners/ipv6_tls_server.rb +22 -0
  75. data/lib/oversip/sip/listeners/ipv6_tls_tunnel_server.rb +22 -0
  76. data/lib/oversip/sip/listeners/ipv6_udp_server.rb +21 -0
  77. data/lib/oversip/sip/listeners/tcp_client.rb +97 -0
  78. data/lib/oversip/sip/listeners/tcp_connection.rb +202 -0
  79. data/lib/oversip/sip/listeners/tcp_server.rb +71 -0
  80. data/lib/oversip/sip/listeners/tls_client.rb +125 -0
  81. data/lib/oversip/sip/listeners/tls_server.rb +88 -0
  82. data/lib/oversip/sip/listeners/tls_tunnel_connection.rb +89 -0
  83. data/lib/oversip/sip/listeners/tls_tunnel_server.rb +61 -0
  84. data/lib/oversip/sip/listeners/udp_connection.rb +214 -0
  85. data/lib/oversip/sip/listeners.rb +24 -0
  86. data/lib/oversip/sip/message.rb +177 -0
  87. data/lib/oversip/sip/message_processor.rb +213 -0
  88. data/lib/oversip/sip/name_addr.rb +51 -0
  89. data/lib/oversip/sip/proxy.rb +324 -0
  90. data/lib/oversip/sip/request.rb +179 -0
  91. data/lib/oversip/sip/response.rb +37 -0
  92. data/lib/oversip/sip/rfc3263.rb +643 -0
  93. data/lib/oversip/sip/server_transaction.rb +295 -0
  94. data/lib/oversip/sip/sip.rb +76 -0
  95. data/lib/oversip/sip/tags.rb +39 -0
  96. data/lib/oversip/sip/timers.rb +55 -0
  97. data/lib/oversip/sip/transport_manager.rb +130 -0
  98. data/lib/oversip/sip/uac.rb +89 -0
  99. data/lib/oversip/sip/uac_request.rb +84 -0
  100. data/lib/oversip/sip/uri.rb +208 -0
  101. data/lib/oversip/syslog.rb +68 -0
  102. data/lib/oversip/system_callbacks.rb +45 -0
  103. data/lib/oversip/tls.rb +172 -0
  104. data/lib/oversip/utils.rb +30 -0
  105. data/lib/oversip/version.rb +21 -0
  106. data/lib/oversip/websocket/constants.rb +55 -0
  107. data/lib/oversip/websocket/http_request.rb +59 -0
  108. data/lib/oversip/websocket/launcher.rb +183 -0
  109. data/lib/oversip/websocket/listeners/connection.rb +51 -0
  110. data/lib/oversip/websocket/listeners/ipv4_ws_server.rb +22 -0
  111. data/lib/oversip/websocket/listeners/ipv4_wss_server.rb +22 -0
  112. data/lib/oversip/websocket/listeners/ipv4_wss_tunnel_server.rb +22 -0
  113. data/lib/oversip/websocket/listeners/ipv6_ws_server.rb +22 -0
  114. data/lib/oversip/websocket/listeners/ipv6_wss_server.rb +22 -0
  115. data/lib/oversip/websocket/listeners/ipv6_wss_tunnel_server.rb +22 -0
  116. data/lib/oversip/websocket/listeners/ws_server.rb +331 -0
  117. data/lib/oversip/websocket/listeners/wss_server.rb +88 -0
  118. data/lib/oversip/websocket/listeners/wss_tunnel_server.rb +133 -0
  119. data/lib/oversip/websocket/listeners.rb +13 -0
  120. data/lib/oversip/websocket/websocket.rb +13 -0
  121. data/lib/oversip/websocket/ws_framing.rb +545 -0
  122. data/lib/oversip/websocket/ws_sip_app.rb +120 -0
  123. data/lib/oversip.rb +127 -0
  124. data/test/oversip_test_helper.rb +19 -0
  125. data/test/test_http_parser.rb +73 -0
  126. data/test/test_name_addr.rb +27 -0
  127. data/test/test_name_addr_parser.rb +24 -0
  128. data/test/test_sip_message_parser.rb +168 -0
  129. data/test/test_sip_uri_parser.rb +56 -0
  130. data/test/test_uri.rb +68 -0
  131. data/thirdparty/stud/stud.tar.gz +0 -0
  132. metadata +334 -0
@@ -0,0 +1,586 @@
1
+ module OverSIP::SIP
2
+
3
+ class ClientTransaction
4
+
5
+ include ::OverSIP::Logger
6
+
7
+ def self.get_class request
8
+ case request.sip_method
9
+ when :INVITE ; ::OverSIP::SIP::InviteClientTransaction
10
+ when :ACK ; ::OverSIP::SIP::Ack2xxForwarder
11
+ else ; ::OverSIP::SIP::NonInviteClientTransaction
12
+ end
13
+ end
14
+
15
+ attr_reader :core, :request, :state, :connection
16
+
17
+ # In case _transport_ is a String, it's an Outbound flow token.
18
+ def initialize core, request, transaction_conf, transport, ip=nil, ip_type=nil, port=nil
19
+ @core = core
20
+ @request = request
21
+ @transaction_conf = transaction_conf || {}
22
+ @transaction_id = ::SecureRandom.hex(4) << @request.antiloop_id
23
+
24
+ # A client transaction for using an existing Outbound connection.
25
+ if transport.is_a? ::String
26
+ @connection, @ip, @port = ::OverSIP::SIP::TransportManager.get_outbound_connection transport
27
+ if @connection
28
+ @server_klass = @connection.class
29
+ @transport = @server_klass.transport
30
+ end
31
+
32
+ # A client transaction based on procedures of RFC 3263. The connection could exist (so reuse it)
33
+ # or not (so try to create it).
34
+ else
35
+ @transport = transport
36
+ @ip = ip
37
+ @ip_type = ip_type
38
+ @port = port
39
+
40
+ @server_klass = case @transport
41
+ when :udp
42
+ case @ip_type
43
+ when :ipv4 ; ::OverSIP::SIP::IPv4UdpServer
44
+ when :ipv6 ; ::OverSIP::SIP::IPv6UdpServer
45
+ end
46
+ when :tcp
47
+ case @ip_type
48
+ when :ipv4 ; ::OverSIP::SIP::IPv4TcpServer
49
+ when :ipv6 ; ::OverSIP::SIP::IPv6TcpServer
50
+ end
51
+ when :tls
52
+ case @ip_type
53
+ when :ipv4 ; ::OverSIP::SIP::IPv4TlsServer
54
+ when :ipv6 ; ::OverSIP::SIP::IPv6TlsServer
55
+ end
56
+ end
57
+
58
+ @connection = ::OverSIP::SIP::TransportManager.get_connection @server_klass, @ip, @port, self, transaction_conf[:callback_on_server_tls_handshake]
59
+ end
60
+
61
+ # Ensure the request has Content-Length. Add it otherwise.
62
+ # NOTE: Don't do this for UAcRequest instances!
63
+ if @request.is_a? ::OverSIP::SIP::Request
64
+ if @request.body
65
+ @request.headers["Content-Length"] = [ @request.body.bytesize.to_s ]
66
+ else
67
+ @request.headers["Content-Length"] = HDR_ARRAY_CONTENT_LENGTH_0
68
+ end
69
+ end
70
+
71
+ end # def initialize
72
+
73
+ end # class ClientTransaction
74
+
75
+
76
+ class InviteClientTransaction < ClientTransaction
77
+
78
+ def initialize core, request, transaction_conf, transport, ip=nil, ip_type=nil, port=nil
79
+ super
80
+ @log_id = "ICT #{@transaction_id}"
81
+
82
+ # Can be :calling, :proceeding, :completed, :accepted or :terminated.
83
+ @state = :calling
84
+ end
85
+
86
+ def send_request
87
+ @client_transactions = @server_klass.invite_client_transactions
88
+ # Store the new client transaction.
89
+ @client_transactions[@transaction_id] = self
90
+
91
+ @top_via = "#{@server_klass.via_core};branch=z9hG4bK#{@transaction_id};rport"
92
+ @request.insert_header "Via", @top_via
93
+
94
+ case @request.in_rr
95
+ # Add a second Record-Route just in case there is transport change.
96
+ when :rr
97
+ unless @request.connection.is_a?(@server_klass)
98
+ @out_rr = :rr
99
+ @request.insert_header "Record-Route", @server_klass.record_route
100
+ end
101
+ # When there is outgoing Outbound always add a second Record-Route header.
102
+ when :outgoing_outbound_rr
103
+ @out_rr = :rr
104
+ @request.insert_header "Record-Route", @server_klass.record_route
105
+ # When there is incoming Outbound always add a second Record-Route header containing the flow token.
106
+ when :incoming_outbound_rr
107
+ @out_rr = :rr
108
+ @request.insert_header "Record-Route", "<sip:" << @request.route_outbound_flow_token << @server_klass.outbound_record_route_fragment
109
+ # When there is both incoming and outgoing Outbound always add a second Record-Route header containing the flow token.
110
+ when :both_outbound_rr
111
+ @out_rr = :rr
112
+ @request.insert_header "Record-Route", "<sip:" << @request.route_outbound_flow_token << @server_klass.outbound_record_route_fragment
113
+ end if @request.in_rr
114
+
115
+ @outgoing_request_str = @request.to_s
116
+
117
+ @request.delete_header_top "Via"
118
+ # TODO: I think this should be removed
119
+ # https://github.com/versatica/OverSIP/issues/76
120
+ if @out_rr == :rr
121
+ @request.delete_header_top "Record-Route"
122
+ end
123
+
124
+ @connection.send_sip_msg @outgoing_request_str, @ip, @port
125
+
126
+ start_timer_A if @transport == :udp
127
+ start_timer_B
128
+ start_timer_C
129
+ end
130
+
131
+ def start_timer_A
132
+ @timer_A_interval = TIMER_A
133
+ @timer_A = ::EM::PeriodicTimer.new(@timer_A_interval) do
134
+ log_system_debug "timer A expires, retransmitting request" if $oversip_debug
135
+ retransmit_request
136
+ @timer_A_interval = @timer_A.interval = 2*@timer_A_interval
137
+ end
138
+ end
139
+
140
+ def start_timer_B
141
+ @timer_B = ::EM::Timer.new(@transaction_conf[:timer_B] || TIMER_B) do
142
+ log_system_debug "timer B expires, transaction timeout" if $oversip_debug
143
+ @timer_A.cancel if @timer_A
144
+ @timer_C.cancel
145
+ terminate_transaction
146
+ @core.client_timeout
147
+ end
148
+ end
149
+
150
+ def start_timer_C
151
+ @timer_C = ::EM::Timer.new(@transaction_conf[:timer_C] || TIMER_C) do
152
+ log_system_debug "timer C expires, transaction timeout" if $oversip_debug
153
+ @timer_A.cancel if @timer_A
154
+ @timer_B.cancel
155
+ do_cancel
156
+ @core.invite_timeout
157
+ end
158
+ end
159
+
160
+ def start_timer_D
161
+ ::EM.add_timer(TIMER_D_UDP) do
162
+ log_system_debug "timer D expires, transaction terminated" if $oversip_debug
163
+ terminate_transaction
164
+ end
165
+ end
166
+
167
+ def start_timer_M
168
+ ::EM.add_timer(TIMER_M) do
169
+ log_system_debug "timer M expires, transaction terminated" if $oversip_debug
170
+ terminate_transaction
171
+ end
172
+ end
173
+
174
+ # Terminate current transaction and delete from the list of transactions.
175
+ def terminate_transaction
176
+ @state = :terminated
177
+ @client_transactions.delete(@transaction_id)
178
+ end
179
+
180
+ def retransmit_request
181
+ @connection.send_sip_msg @outgoing_request_str, @ip, @port
182
+ end
183
+
184
+ def receive_response response
185
+ # Set the request attribute to the response so we can access the related outgoing request.
186
+ response.request = @request
187
+
188
+ # Set server transaction variables to the response.
189
+ response.tvars = @request.tvars
190
+
191
+ # Provisional response
192
+ if response.status_code < 200
193
+ case @state
194
+ when :calling
195
+ @state = :proceeding
196
+ @timer_A.cancel if @timer_A
197
+ @timer_B.cancel
198
+ @core.receive_response(response) unless response.status_code == 100
199
+ # RFC 3261 - 9.1 states that a CANCEL must be sent after receiving a 1XX response.
200
+ send_cancel if @cancel
201
+ return true
202
+ when :proceeding
203
+ @core.receive_response(response) unless response.status_code == 100
204
+ return true
205
+ else
206
+ log_system_notice "received a provisional response #{response.status_code} while in #{@state} state"
207
+ return false
208
+ end
209
+
210
+ # [3456]XX final response.
211
+ elsif response.status_code >= 300
212
+ case @state
213
+ when :calling, :proceeding
214
+ @state = :completed
215
+ @timer_A.cancel if @timer_A
216
+ @timer_B.cancel
217
+ @timer_C.cancel
218
+ if @transport == :udp
219
+ start_timer_D
220
+ else
221
+ terminate_transaction
222
+ end
223
+ send_ack(response)
224
+ @core.receive_response(response)
225
+ return true
226
+ when :completed
227
+ send_ack(response)
228
+ return false
229
+ when :accepted
230
+ log_system_notice "received a [3456]XX response while in accepted state, ignoring it"
231
+ return false
232
+ end
233
+
234
+ # 2XX final response.
235
+ else
236
+ case @state
237
+ when :calling, :proceeding
238
+ @state = :accepted
239
+ @timer_A.cancel if @timer_A
240
+ @timer_B.cancel
241
+ @timer_C.cancel
242
+ start_timer_M
243
+ @core.receive_response(response)
244
+ return true
245
+ when :accepted
246
+ @core.receive_response(response)
247
+ return true
248
+ when :completed
249
+ ### NOTE: It could be accepted and bypassed to the UAC, but makes no sense.
250
+ log_system_notice "received 2XX response while in completed state, ignoring it"
251
+ return false
252
+ end
253
+
254
+ end
255
+ end
256
+
257
+ def connection_failed
258
+ # This avoid the case in which the TCP connection timeout raises after the transaction timeout.
259
+ # Neither we react if the transaction has been canceled and the CANCEL cannot be sent due to
260
+ # TCP disconnection.
261
+ return unless @state == :calling or not @cancel
262
+
263
+ @timer_A.cancel if @timer_A
264
+ @timer_B.cancel
265
+ @timer_C.cancel
266
+ terminate_transaction
267
+
268
+ @core.connection_failed
269
+ end
270
+
271
+ def tls_validation_failed
272
+ return unless @state == :calling or not @cancel
273
+
274
+ @timer_A.cancel if @timer_A
275
+ @timer_B.cancel
276
+ @timer_C.cancel
277
+ terminate_transaction
278
+
279
+ @core.tls_validation_failed
280
+ end
281
+
282
+ def send_ack response
283
+ unless @ack
284
+ @ack = "ACK #{@request.ruri} SIP/2.0\r\n"
285
+ @ack << "Via: #{@top_via}\r\n"
286
+
287
+ @request.hdr_route.each do |route|
288
+ @ack << "Route: " << route << CRLF
289
+ end if @request.hdr_route
290
+
291
+ @ack << "From: " << @request.hdr_from << CRLF
292
+ @ack << "To: " << @request.hdr_to
293
+ unless @request.to_tag
294
+ @ack << ";tag=#{response.to_tag}" if response.to_tag
295
+ end
296
+ @ack << CRLF
297
+
298
+ @ack << "Call-ID: " << @request.call_id << CRLF
299
+ @ack << "CSeq: " << @request.cseq.to_s << " ACK\r\n"
300
+ @ack << "Content-Length: 0\r\n"
301
+ @ack << HDR_USER_AGENT << CRLF
302
+ @ack << CRLF
303
+ end
304
+
305
+ log_system_debug "sending ACK for [3456]XX response" if $oversip_debug
306
+ @connection.send_sip_msg @ack, @ip, @port
307
+ end
308
+
309
+ # It receives the received CANCEL request as parameter so it can check the existence of
310
+ # Reason header and act according (RFC 3326).
311
+ # This method is also called (without argument) when Timer C expires (INVITE).
312
+ def do_cancel cancel=nil
313
+ return if @cancel
314
+
315
+ @cancel = "CANCEL #{@request.ruri} SIP/2.0\r\n"
316
+ @cancel << "Via: #{@top_via}\r\n"
317
+
318
+ @request.hdr_route.each do |route|
319
+ @cancel << "Route: " << route << CRLF
320
+ end if @request.hdr_route
321
+
322
+ # RFC 3326. Copy Reason headers if present in the received CANCEL.
323
+ cancel.header_all("Reason").each do |reason|
324
+ @cancel << "Reason: " << reason << CRLF
325
+ end if cancel
326
+
327
+ @cancel << "From: " << @request.hdr_from << CRLF
328
+ @cancel << "To: " << @request.hdr_to << CRLF
329
+ @cancel << "Call-ID: " << @request.call_id << CRLF
330
+ @cancel << "CSeq: " << @request.cseq.to_s << " CANCEL\r\n"
331
+ @cancel << "Content-Length: 0\r\n"
332
+ @cancel << HDR_USER_AGENT << CRLF
333
+ @cancel << CRLF
334
+
335
+ # Just send the ACK inmediately if the branch has replied a 1XX response.
336
+ send_cancel if @state == :proceeding
337
+ end
338
+
339
+ def send_cancel
340
+ log_system_debug "sending CANCEL" if $oversip_debug
341
+
342
+ @connection.send_sip_msg @cancel, @ip, @port
343
+
344
+ start_timer_E_cancel if @transport == :udp
345
+ start_timer_F_cancel
346
+ end
347
+
348
+ def start_timer_E_cancel
349
+ @timer_E_cancel_interval = TIMER_E
350
+ @timer_E_cancel = ::EM::PeriodicTimer.new(@timer_E_cancel_interval) do
351
+ log_system_debug "timer E expires, retransmitting CANCEL" if $oversip_debug
352
+ retransmit_cancel
353
+ @timer_E_cancel_interval = @timer_E_cancel.interval = [2*@timer_E_cancel_interval, T2].min
354
+ end
355
+ end
356
+
357
+ def start_timer_F_cancel
358
+ @timer_F_cancel = ::EM::Timer.new(@transaction_conf[:timer_F] || TIMER_F) do
359
+ unless @state == :terminated
360
+ log_system_debug "timer F expires, CANCEL timeout, transaction terminated" if $oversip_debug
361
+ @timer_E_cancel.cancel if @timer_E_cancel
362
+ terminate_transaction
363
+ end
364
+ end
365
+ end
366
+
367
+ def retransmit_cancel
368
+ @connection.send_sip_msg @cancel, @ip, @port
369
+ end
370
+
371
+ def receive_response_to_cancel(response)
372
+ unless @state == :terminated
373
+ log_system_debug "our CANCEL got a #{response.status_code} response, transaction terminated" if $oversip_debug
374
+
375
+ @timer_E_cancel.cancel if @timer_E_cancel
376
+ @timer_F_cancel.cancel
377
+ # We MUST ensure that we end the client transaction, so after sending a CANCEL and get a response
378
+ # for it, ensure the transaction is terminated after a while.
379
+ ::EM.add_timer(4) { terminate_transaction }
380
+ end
381
+ end
382
+
383
+ end # class InviteClientTransaction
384
+
385
+
386
+ class NonInviteClientTransaction < ClientTransaction
387
+
388
+ def initialize core, request, transaction_conf, transport, ip=nil, ip_type=nil, port=nil
389
+ super
390
+ @log_id = "NICT #{@transaction_id}"
391
+
392
+ # Can be :trying, :proceeding, :completed or :terminated.
393
+ @state = :trying
394
+ end
395
+
396
+ def send_request
397
+ @client_transactions = @server_klass.non_invite_client_transactions
398
+ # Store the new client transaction.
399
+ @client_transactions[@transaction_id] = self
400
+
401
+ @top_via = "#{@server_klass.via_core};branch=z9hG4bK#{@transaction_id};rport"
402
+ @request.insert_header "Via", @top_via
403
+
404
+ case @request.in_rr
405
+ # Add a second Record-Route just in case there is transport change.
406
+ when :rr
407
+ unless @request.connection.is_a?(@server_klass)
408
+ @out_rr = :rr
409
+ @request.insert_header "Record-Route", @server_klass.record_route
410
+ end
411
+ # When there is outgoing Outbound always add a second Record-Route header.
412
+ when :outgoing_outbound_rr
413
+ @out_rr = :rr
414
+ @request.insert_header "Record-Route", @server_klass.record_route
415
+ # When there is incoming Outbound always add a second Record-Route header containing the flow token.
416
+ when :incoming_outbound_rr
417
+ @out_rr = :rr
418
+ @request.insert_header "Record-Route", "<sip:" << @request.route_outbound_flow_token << @server_klass.outbound_record_route_fragment
419
+ # When there is both outgoing/incoming Outbound always add a second Record-Route header containing the flow token.
420
+ when :both_outbound_rr
421
+ @out_rr = :rr
422
+ @request.insert_header "Record-Route", "<sip:" << @request.route_outbound_flow_token << @server_klass.outbound_record_route_fragment
423
+ # Add a second Path just in case there is transport change.
424
+ when :path
425
+ unless @request.connection.is_a?(@server_klass)
426
+ @out_rr = :path
427
+ @request.insert_header "Path", @server_klass.record_route
428
+ end
429
+ # When there is outgoing Outbound always add a second Path header.
430
+ when :outgoing_outbound_path
431
+ @out_rr = :path
432
+ @request.insert_header "Path", @server_klass.record_route
433
+ # When there is incoming Outbound always add a second Path header containing the flow token.
434
+ when :incoming_outbound_path
435
+ @out_rr = :path
436
+ @request.insert_header "Path", "<sip:" << @request.route_outbound_flow_token << @server_klass.outbound_path_fragment
437
+ # When there is both outgoing/incoming Outbound always add a second Path header containing the flow token.
438
+ when :both_outbound_path
439
+ @out_rr = :rr
440
+ @request.insert_header "Path", "<sip:" << @request.route_outbound_flow_token << @server_klass.outbound_path_fragment
441
+ end if @core.is_a? ::OverSIP::SIP::Proxy
442
+
443
+ @outgoing_request_str = @request.to_s
444
+
445
+ @request.delete_header_top "Via"
446
+ # TODO: I think this should be removed
447
+ # https://github.com/versatica/OverSIP/issues/76
448
+ case @out_rr
449
+ when :rr
450
+ @request.delete_header_top "Record-Route"
451
+ when :path
452
+ @request.delete_header_top "Path"
453
+ end
454
+
455
+ @connection.send_sip_msg @outgoing_request_str, @ip, @port
456
+
457
+ start_timer_E if @transport == :udp
458
+ start_timer_F
459
+ end
460
+
461
+ def start_timer_E
462
+ @timer_E_interval = TIMER_E
463
+ @timer_E = ::EM::PeriodicTimer.new(@timer_E_interval) do
464
+ log_system_debug "timer E expires, retransmitting request" if $oversip_debug
465
+ retransmit_request
466
+ if @state == :trying
467
+ @timer_E_interval = @timer_E.interval = [2*@timer_E_interval, T2].min
468
+ else
469
+ @timer_E_interval = @timer_E.interval = T2
470
+ end
471
+ end
472
+ end
473
+
474
+ def start_timer_F
475
+ @timer_F = ::EM::Timer.new(@transaction_conf[:timer_F] || TIMER_F) do
476
+ log_system_debug "timer F expires, transaction timeout" if $oversip_debug
477
+ @timer_E.cancel if @timer_E
478
+ terminate_transaction
479
+ @core.client_timeout
480
+ end
481
+ end
482
+
483
+ def start_timer_K
484
+ ::EM.add_timer(TIMER_K_UDP) do
485
+ log_system_debug "timer K expires, transaction terminated" if $oversip_debug
486
+ terminate_transaction
487
+ end
488
+ end
489
+
490
+ # Terminate current transaction and delete from the list of transactions.
491
+ def terminate_transaction
492
+ @state = :terminated
493
+ @client_transactions.delete(@transaction_id)
494
+ end
495
+
496
+ def retransmit_request
497
+ @connection.send_sip_msg @outgoing_request_str, @ip, @port
498
+ end
499
+
500
+ def receive_response response
501
+ # Set the request attribute to the response so we can access the related outgoing request.
502
+ response.request = @request
503
+
504
+ # Set server transaction variables to the response.
505
+ response.tvars = @request.tvars
506
+
507
+ # Provisional response
508
+ if response.status_code < 200
509
+ case @state
510
+ when :trying
511
+ @state = :proceeding
512
+ @core.receive_response(response) unless response.status_code == 100
513
+ return true
514
+ when :proceeding
515
+ @core.receive_response(response) unless response.status_code == 100
516
+ return true
517
+ else
518
+ log_system_notice "received a provisional response #{response.status_code} while in #{@state} state"
519
+ return false
520
+ end
521
+
522
+ # [23456]XX final response.
523
+ elsif response.status_code >= 200
524
+ case @state
525
+ when :trying, :proceeding
526
+ @state = :completed
527
+ @timer_F.cancel
528
+ @timer_E.cancel if @timer_E
529
+ if @transport == :udp
530
+ start_timer_K
531
+ else
532
+ terminate_transaction
533
+ end
534
+ @core.receive_response(response)
535
+ return true
536
+ else
537
+ log_system_notice "received a final response #{response.status_code} while in #{@state} state"
538
+ return false
539
+ end
540
+
541
+ end
542
+ end
543
+
544
+ def connection_failed
545
+ @timer_F.cancel
546
+ @timer_E.cancel if @timer_E
547
+ terminate_transaction
548
+
549
+ @core.connection_failed
550
+ end
551
+
552
+ def tls_validation_failed
553
+ @timer_F.cancel
554
+ @timer_E.cancel if @timer_E
555
+ terminate_transaction
556
+
557
+ @core.tls_validation_failed
558
+ end
559
+
560
+ end # class NonInviteClientTransaction
561
+
562
+
563
+ class Ack2xxForwarder < ClientTransaction
564
+
565
+ def initialize core, request, transaction_conf, transport, ip=nil, ip_type=nil, port=nil
566
+ super
567
+ @log_id = "ICT #{@transaction_id}"
568
+ end
569
+
570
+ def send_request
571
+ @request.insert_header "Via", "#{@server_klass.via_core};branch=z9hG4bK#{@transaction_id}"
572
+
573
+ @connection.send_sip_msg @request.to_s, @ip, @port
574
+ end
575
+
576
+ def connection_failed
577
+ # Do nothing.
578
+ end
579
+
580
+ def tls_validation_failed
581
+ # Do nothing.
582
+ end
583
+
584
+ end # class Ack2xxForwarder
585
+
586
+ end
@@ -0,0 +1,88 @@
1
+ module OverSIP::SIP
2
+
3
+ CRLF = "\r\n"
4
+ DOUBLE_CRLF = "\r\n\r\n"
5
+
6
+ # DOC: http://www.iana.org/assignments/sip-parameters
7
+ REASON_PHRASE = {
8
+ 100 => "Trying",
9
+ 180 => "Ringing",
10
+ 181 => "Call Is Being Forwarded",
11
+ 182 => "Queued",
12
+ 183 => "Session Progress",
13
+ 199 => "Early Dialog Terminated", # draft-ietf-sipcore-199
14
+ 200 => "OK",
15
+ 202 => "Accepted", # RFC 3265
16
+ 204 => "No Notification", #RFC 5839
17
+ 300 => "Multiple Choices",
18
+ 301 => "Moved Permanently",
19
+ 302 => "Moved Temporarily",
20
+ 305 => "Use Proxy",
21
+ 380 => "Alternative Service",
22
+ 400 => "Bad Request",
23
+ 401 => "Unauthorized",
24
+ 402 => "Payment Required",
25
+ 403 => "Forbidden",
26
+ 404 => "Not Found",
27
+ 405 => "Method Not Allowed",
28
+ 406 => "Not Acceptable",
29
+ 407 => "Proxy Authentication Required",
30
+ 408 => "Request Timeout",
31
+ 410 => "Gone",
32
+ 412 => "Conditional Request Failed", # RFC 3903
33
+ 413 => "Request Entity Too Large",
34
+ 414 => "Request-URI Too Long",
35
+ 415 => "Unsupported Media Type",
36
+ 416 => "Unsupported URI Scheme",
37
+ 417 => "Unknown Resource-Priority", # RFC 4412
38
+ 420 => "Bad Extension",
39
+ 421 => "Extension Required",
40
+ 422 => "Session Interval Too Small", # RFC 4028
41
+ 423 => "Interval Too Brief",
42
+ 424 => "Bad Location Information", # RFC 6442
43
+ 428 => "Use Identity Header", # RFC 4474
44
+ 429 => "Provide Referrer Identity", # RFC 3892
45
+ 430 => "Flow Failed", # RFC 5626
46
+ 433 => "Anonymity Disallowed", # RFC 5079
47
+ 436 => "Bad Identity-Info", # RFC 4474
48
+ 437 => "Unsupported Certificate", # RFC 4744
49
+ 438 => "Invalid Identity Header", # RFC 4744
50
+ 439 => "First Hop Lacks Outbound Support", # RFC 5626
51
+ 440 => "Max-Breadth Exceeded", # RFC 5393
52
+ 469 => "Bad Info Package", # draft-ietf-sipcore-info-events
53
+ 470 => "Consent Needed", # RF C5360
54
+ 478 => "Unresolvable Destination", # Custom code copied from Kamailio.
55
+ 480 => "Temporarily Unavailable",
56
+ 481 => "Call/Transaction Does Not Exist",
57
+ 482 => "Loop Detected",
58
+ 483 => "Too Many Hops",
59
+ 484 => "Address Incomplete",
60
+ 485 => "Ambiguous",
61
+ 486 => "Busy Here",
62
+ 487 => "Request Terminated",
63
+ 488 => "Not Acceptable Here",
64
+ 489 => "Bad Event", # RFC 3265
65
+ 491 => "Request Pending",
66
+ 493 => "Undecipherable",
67
+ 494 => "Security Agreement Required", # RFC 3329
68
+ 500 => "Server Internal Error",
69
+ 501 => "Not Implemented",
70
+ 502 => "Bad Gateway",
71
+ 503 => "Service Unavailable",
72
+ 504 => "Server Time-out",
73
+ 505 => "Version Not Supported",
74
+ 513 => "Message Too Large",
75
+ 580 => "Precondition Failure", # RFC 3312
76
+ 600 => "Busy Everywhere",
77
+ 603 => "Decline",
78
+ 604 => "Does Not Exist Anywhere",
79
+ 606 => "Not Acceptable"
80
+ }
81
+
82
+ REASON_PHRASE_NOT_SET = "Reason Phrase Not Set"
83
+
84
+ HDR_SERVER = "Server: #{::OverSIP::PROGRAM_NAME}/#{::OverSIP::VERSION}".freeze
85
+ HDR_USER_AGENT = "User-Agent: #{::OverSIP::PROGRAM_NAME}/#{::OverSIP::VERSION}".freeze
86
+ HDR_ARRAY_CONTENT_LENGTH_0 = [ "0" ].freeze
87
+
88
+ end