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,460 @@
1
+ module OverSIP::SIP
2
+
3
+ class Proxy
4
+
5
+ include ::OverSIP::Logger
6
+
7
+ def initialize request, proxy_conf
8
+ @request = request
9
+ @proxy_conf = proxy_conf
10
+ @log_id = "Proxy #{proxy_conf[:name]} #{request.via_branch_id}"
11
+
12
+ # Create the server transaction if it doesn't exist yet.
13
+ @server_transaction = @request.server_transaction or case @request.sip_method
14
+ # Here it can arrive an INVITE, ACK-for-2XX and any method but CANCEL.
15
+ when :INVITE
16
+ InviteServerTransaction.new @request
17
+ when :ACK
18
+ else
19
+ NonInviteServerTransaction.new @request
20
+ end
21
+ @request.server_transaction ||= @server_transaction
22
+
23
+ # Set this core layer to the server transaction.
24
+ @request.server_transaction.core = self if @request.server_transaction
25
+ end # initialize
26
+
27
+
28
+ def on_provisional_response &block
29
+ @on_provisional_response_block = block
30
+ end
31
+
32
+ def on_success_response &block
33
+ @on_success_response_block = block
34
+ end
35
+
36
+ def on_failure_response &block
37
+ @on_failure_response_block = block
38
+ end
39
+
40
+ def on_canceled &block
41
+ @on_canceled_block = block
42
+ end
43
+
44
+ def on_invite_timeout &block
45
+ @on_invite_timeout_block = block
46
+ end
47
+
48
+ def on_error &block
49
+ @on_error_block = block
50
+ end
51
+
52
+ # If called, current response within the called callback won't be forwarded.
53
+ def drop_response
54
+ @drop_response = true
55
+ end
56
+
57
+
58
+ def route dst_host=nil, dst_port=nil, dst_transport=nil
59
+ # NOTE: Routing can be based on incoming request for an Outbound (RFC 5626) connection
60
+ # or based on normal RFC 3263 procedures.
61
+
62
+ # If it's an incoming Outbound connection get the associated connection (but if dst_host is
63
+ # set then don't honor the Outbound connection).
64
+
65
+ if @request.incoming_outbound_requested? and not dst_host
66
+ @client_transaction = (::OverSIP::SIP::ClientTransaction.get_class @request).new self, @request, @proxy_conf, @request.route_outbound_flow_token
67
+
68
+ if @client_transaction.connection
69
+ add_routing_headers
70
+ @client_transaction.send_request
71
+ else
72
+ unless @request.sip_method == :ACK
73
+ log_system_debug "flow failed" if $oversip_debug
74
+
75
+ @on_error_block && @on_error_block.call(430, "Flow Failed")
76
+ unless @drop_response
77
+ @request.reply 430, "Flow Failed"
78
+ else
79
+ @drop_response = false
80
+ end
81
+ else
82
+ log_system_debug "flow failed for received ACK" if $oversip_debug
83
+ end
84
+ end
85
+
86
+ return
87
+ end
88
+
89
+
90
+ # If it's not an incoming Outbound connection (or explicit destination is set),
91
+ # let's perform RFC 3263 procedures.
92
+
93
+ # Check the request destination.
94
+ # If a destination is given use it. If not route based on request headers.
95
+
96
+ # Force the destination.
97
+ if dst_host
98
+ dst_scheme = :sip
99
+ dst_host_type = ::OverSIP::Utils.ip_type(dst_host) || :domain
100
+
101
+ # Or use top Route header.
102
+ elsif @request.routes
103
+ top_route = @request.routes[0]
104
+ dst_scheme = top_route.scheme
105
+ dst_host = top_route.host
106
+ dst_host_type = top_route.host_type
107
+ dst_port = top_route.port
108
+ dst_transport = top_route.transport_param
109
+
110
+ # Or use the Request URI.
111
+ else
112
+ dst_scheme = @request.ruri.scheme
113
+ dst_host = @request.ruri.host
114
+ dst_host_type = @request.ruri.host_type
115
+ dst_port = @request.ruri.port
116
+ dst_transport = @request.ruri.transport_param
117
+ end
118
+
119
+ # If the destination uri_host is an IPv6 reference, convert it to real IPv6.
120
+ if dst_host_type == :ipv6_reference
121
+ dst_host = ::OverSIP::Utils.normalize_ipv6(dst_host, true)
122
+ dst_host_type = :ipv6
123
+ end
124
+
125
+ # Loockup in the DNS cache of this proxy.
126
+ if dst_host_type == :domain and @proxy_conf[:use_dns_cache]
127
+ dns_cache_entry = "#{dst_host}|#{dst_port}|#{dst_transport}|#{dst_scheme}"
128
+ if (result = @proxy_conf[:dns_cache][dns_cache_entry])
129
+ log_system_debug "destination found in the DNS cache" if $oversip_debug
130
+ if result.is_a? ::Symbol
131
+ rfc3263_failed result
132
+ else
133
+ rfc3263_succeeded result
134
+ end
135
+ return
136
+ end
137
+ else
138
+ dns_cache_entry = nil
139
+ end
140
+
141
+ # Perform RFC 3261 procedures.
142
+ dns_query = ::OverSIP::SIP::RFC3263::Query.new @proxy_conf, @request.via_branch_id, dst_scheme, dst_host, dst_host_type, dst_port, dst_transport
143
+ case result = dns_query.resolve
144
+
145
+ # Async result so DNS took place.
146
+ when nil
147
+ # Async success.
148
+ dns_query.callback do |result|
149
+ # Store the result in the DNS cache.
150
+ if dns_cache_entry
151
+ @proxy_conf[:dns_cache][dns_cache_entry] = result
152
+ ::EM.add_timer(@proxy_conf[:dns_cache_time]) { @proxy_conf[:dns_cache].delete dns_cache_entry }
153
+ end
154
+ rfc3263_succeeded result
155
+ end
156
+ # Async error.
157
+ dns_query.errback do |result|
158
+ # Store the result in the DNS cache.
159
+ if dns_cache_entry
160
+ @proxy_conf[:dns_cache][dns_cache_entry] = result
161
+ ::EM.add_timer(@proxy_conf[:dns_cache_time]) { @proxy_conf[:dns_cache].delete dns_cache_entry }
162
+ end
163
+ rfc3263_failed result
164
+ end
165
+ # Instant error.
166
+ when ::Symbol
167
+ # Store the result in the DNS cache.
168
+ if dns_cache_entry
169
+ @proxy_conf[:dns_cache][dns_cache_entry] = result
170
+ ::EM.add_timer(@proxy_conf[:dns_cache_time]) { @proxy_conf[:dns_cache].delete dns_cache_entry }
171
+ end
172
+ rfc3263_failed result
173
+ # Instant success so it's not a domain (no DNS performed).
174
+ else
175
+ rfc3263_succeeded result
176
+ end
177
+
178
+ end # def route
179
+
180
+
181
+ def receive_response response
182
+ log_system_debug "received response #{response.status_code}"
183
+
184
+ response.delete_header_top "Via"
185
+
186
+ if @request.server_transaction.valid_response? response.status_code
187
+ if response.status_code < 200 && ! @canceled
188
+ @on_provisional_response_block && @on_provisional_response_block.call(response)
189
+ elsif response.status_code >= 200 && response.status_code <= 299
190
+ @on_success_response_block && @on_success_response_block.call(response)
191
+ elsif response.status_code >= 300 && ! @canceled
192
+ if response.status_code == 503
193
+ if @proxy_conf[:dns_failover_on_503]
194
+ try_next_target nil, nil, response
195
+ return
196
+ else
197
+ # If the response is 503 convert it into 500 (RFC 3261 16.7).
198
+ response.status_code = 500
199
+ @on_failure_response_block && @on_failure_response_block.call(response)
200
+ end
201
+ else
202
+ @on_failure_response_block && @on_failure_response_block.call(response)
203
+ end
204
+ end
205
+ end
206
+
207
+ unless @drop_response
208
+ @request.reply_full response
209
+ else
210
+ @drop_response = false
211
+ end
212
+ end
213
+
214
+
215
+ # Since we don't implement parallel forking, directly send our CANCEL downstream.
216
+ def receive_cancel cancel
217
+ log_system_debug "server transaction canceled, cancelling pending client transaction" if $oversip_debug
218
+
219
+ @canceled = true
220
+ @on_canceled_block && @on_canceled_block.call
221
+
222
+ @client_transaction.do_cancel cancel
223
+ end
224
+
225
+
226
+ def client_timeout
227
+ try_next_target 408, "Client Timeout"
228
+ end
229
+
230
+
231
+ def connection_failed
232
+ try_next_target 500, "Connection Error"
233
+ end
234
+
235
+
236
+ def tls_validation_failed
237
+ try_next_target 500, "TLS Validation Failed"
238
+ end
239
+
240
+
241
+ # Timer C for INVITE.
242
+ def invite_timeout
243
+ @on_invite_timeout_block && @on_invite_timeout_block.call
244
+
245
+ unless @drop_response
246
+ @request.reply 408, "INVITE Timeout"
247
+ end
248
+ @drop_response = true # Ignore the possible 487 got from the callee.
249
+ end
250
+
251
+
252
+ private
253
+
254
+
255
+ def add_routing_headers
256
+ # Don't add routing headers again if we are in DNS failover within the same Proxy instance.
257
+ # But we must run this method if it's an incoming request asking for Outbound usage (in this
258
+ # case @num_target is nil so the method continues).
259
+ return if @num_target and @num_target > 0
260
+
261
+ add_rr_path = false
262
+ if @request.initial? && @request.loose_record_aware?
263
+ do_loose_routing = @proxy_conf[:do_loose_routing]
264
+
265
+ # Request has no previous RR/Path and current proxy performs loose-routing.
266
+ # So add RR/Path.
267
+ if ! @request.in_rr && do_loose_routing
268
+ add_rr_path = true
269
+
270
+ # Request has previous RR/Path and current proxy does not perform loose-routing.
271
+ # So don't add RR/Path and remove the existing one.
272
+ elsif @request.in_rr && ! do_loose_routing
273
+ case @request.in_rr
274
+ when :rr, :outgoing_outbound_rr, :incoming_outbound_rr, :both_outbound_rr
275
+ @request.delete_header_top "Record-Route"
276
+ when :path, :outgoing_outbound_path, :incoming_outbound_path, :both_outbound_path
277
+ @request.delete_header_top "Path"
278
+ end
279
+ @request.in_rr = nil
280
+
281
+ # Remaining cases are:
282
+ # - Request has previous RR/Path and current proxy performs loose-routing.
283
+ # - Request has no previous RR/Path and current proxy does not perform loose-routing.
284
+ # So don't add RR/Path.
285
+ end
286
+ end
287
+
288
+ unless @request.proxied
289
+ # Indicate that this request has been proxied (at least once).
290
+ @request.proxied = true
291
+
292
+ # Set the Max-Forwards header.
293
+ @request.headers["Max-Forwards"] = [ @request.new_max_forwards.to_s ] if @request.new_max_forwards
294
+ end
295
+
296
+ # Add Record-Route or Path header.
297
+ # Here we only arrive if @request.loose_record_aware?, so method is INVITE, REGISTER, SUBSCRIBE or REFER.
298
+ if add_rr_path
299
+ case @request.sip_method
300
+
301
+ # Path header (RFC 3327) for REGISTER.
302
+ when :REGISTER
303
+ if @request.outgoing_outbound_requested?
304
+ if @request.incoming_outbound_requested?
305
+ @request.in_rr = :both_outbound_path
306
+ else
307
+ @request.in_rr = :outgoing_outbound_path
308
+ end
309
+ @request.insert_header "Path", "<sip:" << @request.connection_outbound_flow_token << @request.connection.class.outbound_path_fragment
310
+ elsif @request.incoming_outbound_requested?
311
+ @request.in_rr = :incoming_outbound_path
312
+ @request.insert_header "Path", @request.connection.class.record_route
313
+ else
314
+ @request.in_rr = :path
315
+ @request.insert_header "Path", @request.connection.class.record_route
316
+ end
317
+
318
+ # Record-Route for INVITE, SUBSCRIBE, REFER.
319
+ else
320
+ if @request.outgoing_outbound_requested?
321
+ if @request.incoming_outbound_requested?
322
+ @request.in_rr = :both_outbound_rr
323
+ else
324
+ @request.in_rr = :outgoing_outbound_rr
325
+ end
326
+ @request.insert_header "Record-Route", "<sip:" << @request.connection_outbound_flow_token << @request.connection.class.outbound_record_route_fragment
327
+ elsif @request.incoming_outbound_requested?
328
+ @request.in_rr = :incoming_outbound_rr
329
+ @request.insert_header "Record-Route", @request.connection.class.record_route
330
+ else
331
+ @request.in_rr = :rr
332
+ @request.insert_header "Record-Route", @request.connection.class.record_route
333
+ end
334
+
335
+ end
336
+ end
337
+
338
+ end # add_routing_headers
339
+
340
+
341
+ def rfc3263_succeeded result
342
+ #log_system_debug "RFC3263 result: #{result.class}: #{result.inspect}" if $oversip_debug
343
+
344
+ # After RFC 3263 (DNS) resolution we get N targets.
345
+ @num_target = 0 # First target is 0 (rather than 1).
346
+
347
+ case result
348
+
349
+ when RFC3263::Target
350
+ @target = result # Single Target.
351
+
352
+ when RFC3263::SrvTargets
353
+ log_system_debug "result is srv targets => randomizing:" if $oversip_debug
354
+ @targets = result.randomize # Array of Targets.
355
+
356
+ # This can contain Target and SrvTargets entries.
357
+ when RFC3263::MultiTargets
358
+ log_system_debug "result is MultiTargets => flatting:" if $oversip_debug
359
+ @targets = result.flatten # Array of Targets.
360
+
361
+ # NOTE: Should never happen.
362
+ else
363
+ raise "rfc3263_succeeded returns a #{result.class}: #{result.inspect}"
364
+
365
+ end
366
+
367
+ try_next_target
368
+ end # rfc3263_succeeded
369
+
370
+
371
+ def try_next_target status=nil, reason=nil, full_response=nil
372
+ # Single target.
373
+ if @target and @num_target == 0
374
+ log_system_debug "using single target: #{@target}" if $oversip_debug
375
+ use_target @target
376
+ @num_target = 1
377
+
378
+ # Multiple targets (so @targets is set).
379
+ elsif @targets and @num_target < @targets.size
380
+ log_system_debug "using target #{@num_target+1} of #{@targets.size}: #{@targets[@num_target]}" if $oversip_debug
381
+ use_target @targets[@num_target]
382
+ @num_target += 1
383
+
384
+ # No more targets.
385
+ else
386
+ # If we have received a [3456]XX response from downstream then run @on_failure_block.
387
+ if full_response
388
+ @on_failure_response_block && @on_failure_response_block.call(full_response)
389
+ unless @drop_response
390
+ # If the response is 503 convert it into 500 (RFC 3261 16.7).
391
+ full_response.status_code = 500 if full_response.status_code == 503
392
+ @request.reply_full full_response
393
+ else
394
+ @drop_response = false
395
+ end
396
+
397
+ # If not, generate the response according to the given status and reason.
398
+ else
399
+ @on_error_block && @on_error_block.call(status, reason)
400
+ unless @drop_response
401
+ @request.reply status, reason
402
+ else
403
+ @drop_response = false
404
+ end
405
+
406
+ end
407
+ end
408
+ end # try_next_target
409
+
410
+
411
+ def use_target target
412
+ @client_transaction = (::OverSIP::SIP::ClientTransaction.get_class @request).new self, @request, @proxy_conf, target.transport, target.ip, target.ip_type, target.port
413
+ add_routing_headers
414
+ @client_transaction.send_request
415
+ end
416
+
417
+
418
+ def rfc3263_failed error
419
+ case error
420
+ when :rfc3263_domain_not_found
421
+ log_system_debug "no resolution" if $oversip_debug
422
+ status = 404
423
+ reason = "No DNS Resolution"
424
+ when :rfc3263_unsupported_scheme
425
+ log_system_debug "unsupported URI scheme" if $oversip_debug
426
+ status = 416
427
+ reason = "Unsupported URI scheme"
428
+ when :rfc3263_unsupported_transport
429
+ log_system_debug "unsupported transport" if $oversip_debug
430
+ status = 478
431
+ reason = "Unsupported Transport"
432
+ when :rfc3263_wrong_transport
433
+ log_system_debug "wrong URI transport" if $oversip_debug
434
+ status = 478
435
+ reason = "Wrong URI Transport"
436
+ when :rfc3263_no_ipv4
437
+ log_system_debug "destination requires unsupported IPv4" if $oversip_debug
438
+ status = 478
439
+ reason = "Destination Requires Unsupported IPv4"
440
+ when :rfc3263_no_ipv6
441
+ log_system_debug "destination requires unsupported IPv6" if $oversip_debug
442
+ status = 478
443
+ reason = "Destination Requires Unsupported IPv6"
444
+ when :rfc3263_no_dns
445
+ log_system_debug "destination requires unsupported DNS query" if $oversip_debug
446
+ status = 478
447
+ reason = "Destination Requires Unsupported DNS Query"
448
+ end
449
+
450
+ @on_error_block && @on_error_block.call(status, reason)
451
+ unless @drop_response
452
+ @request.reply status, reason unless @request.sip_method == :ACK
453
+ else
454
+ @drop_response = false
455
+ end
456
+ end # def rfc3263_failed
457
+
458
+ end # class Proxy
459
+
460
+ end
@@ -0,0 +1,128 @@
1
+ module OverSIP::SIP
2
+
3
+ class Request < Message
4
+
5
+ SECURE_TRANSPORTS = { :tls=>true, :wss=>true }
6
+
7
+ attr_accessor :server_transaction
8
+ attr_reader :ruri
9
+ attr_reader :new_max_forwards
10
+ attr_accessor :antiloop_id
11
+ attr_accessor :route_outbound_flow_token
12
+
13
+ attr_writer :outgoing_outbound_requested, :incoming_outbound_requested
14
+ attr_accessor :proxied # If true it means that this request has been already proxied.
15
+
16
+ # Used for internal purposes when doing proxy and adding the first Record-Route
17
+ # or Path.
18
+ attr_accessor :in_rr
19
+
20
+
21
+ def log_id
22
+ @log_id ||= "SIP Request #{@via_branch_id}"
23
+ end
24
+
25
+ def request? ; true end
26
+ def response? ; false end
27
+
28
+ def initial? ; ! @to_tag end
29
+ def in_dialog? ; @to_tag end
30
+
31
+ def secure?
32
+ SECURE_TRANSPORTS[@transport] || false
33
+ end
34
+
35
+
36
+ def reply status_code, reason_phrase=nil, extra_headers=[], body=nil
37
+ return false unless @server_transaction.receive_response(status_code) if @server_transaction
38
+
39
+ reason_phrase ||= REASON_PHARSE[status_code] || REASON_PHARSE_NOT_SET
40
+
41
+ if status_code > 100
42
+ @internal_to_tag ||= @to_tag || ( @server_transaction ? SecureRandom.hex(6) : OverSIP::SIP::Tags.totag_for_sl_reply )
43
+ end
44
+
45
+ response = "SIP/2.0 #{status_code} #{reason_phrase}\r\n"
46
+
47
+ @hdr_via.each do |hdr|
48
+ response << "Via: " << hdr << "\r\n"
49
+ end
50
+
51
+ response << "From: " << @hdr_from << "\r\n"
52
+
53
+ response << "To: " << @hdr_to
54
+ response << ";tag=#{@internal_to_tag}" if @internal_to_tag
55
+ response << "\r\n"
56
+
57
+ response << "Call-ID: " << @call_id << "\r\n"
58
+ response << "CSeq: " << @cseq.to_s << " " << @sip_method.to_s << "\r\n"
59
+ response << "Content-Length: #{body ? body.bytesize : "0"}\r\n"
60
+
61
+ extra_headers.each do |header|
62
+ response << header.to_s << "\r\n"
63
+ end if extra_headers
64
+
65
+ response << HDR_SERVER << "\r\n"
66
+ response << "\r\n"
67
+
68
+ response << body if body
69
+
70
+ @server_transaction.last_response = response if @server_transaction
71
+
72
+ log_system_debug "replying #{status_code} \"#{reason_phrase}\"" if $oversip_debug
73
+
74
+ send_response(response)
75
+ true
76
+ end
77
+
78
+
79
+ def reply_full response
80
+ return false unless @server_transaction.receive_response(response.status_code) if @server_transaction
81
+
82
+ # Ensure the response has Content-Length. Add it otherwise.
83
+ if response.body
84
+ response.headers["Content-Length"] = [ response.body.bytesize.to_s ]
85
+ else
86
+ response.headers["Content-Length"] = HDR_ARRAY_CONTENT_LENGTH_0
87
+ end
88
+
89
+ response_leg_a = response.to_s
90
+ @server_transaction.last_response = response_leg_a if @server_transaction
91
+
92
+ log_system_debug "forwarding response #{response.status_code} \"#{response.reason_phrase}\"" if $oversip_debug
93
+
94
+ send_response(response_leg_a)
95
+ true
96
+ end
97
+
98
+
99
+ def send_response(response)
100
+ unless (case @transport
101
+ when :udp
102
+ @connection.send_sip_msg response, @source_ip, @via_rport || @via_sent_by_port || 5060
103
+ else
104
+ @connection.send_sip_msg response
105
+ end
106
+ )
107
+ log_system_notice "error sending the SIP response"
108
+ end
109
+ end
110
+
111
+
112
+ def to_s
113
+ msg = "#{@sip_method.to_s} #{self.ruri.uri} SIP/2.0\r\n"
114
+
115
+ @headers.each do |key, values|
116
+ values.each do |value|
117
+ msg << key << ": #{value}\r\n"
118
+ end
119
+ end
120
+
121
+ msg << CRLF
122
+ msg << @body if @body
123
+ msg
124
+ end
125
+
126
+ end # class Request
127
+
128
+ end
@@ -0,0 +1,30 @@
1
+ module OverSIP::SIP
2
+
3
+ class Response < Message
4
+
5
+ attr_accessor :status_code
6
+ attr_accessor :reason_phrase
7
+ attr_accessor :request # The associated request.
8
+
9
+
10
+ def request? ; false end
11
+ def response? ; true end
12
+
13
+
14
+ def to_s
15
+ msg = "SIP/2.0 #{@status_code} #{@reason_phrase}\r\n"
16
+
17
+ @headers.each do |key, values|
18
+ values.each do |value|
19
+ msg << key << ": #{value}\r\n"
20
+ end
21
+ end
22
+
23
+ msg << CRLF
24
+ msg << @body if @body
25
+ msg
26
+ end
27
+
28
+ end # class Response
29
+
30
+ end