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