oversip_p 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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