oversip 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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