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,541 @@
1
+ module OverSIP
2
+
3
+ module Config
4
+
5
+ # Pre-declaration of Validators module (defined in other file).
6
+ module Config::Validators ; end
7
+
8
+ extend ::OverSIP::Logger
9
+ extend ::OverSIP::Config::Validators
10
+
11
+ DEFAULT_CONFIG_DIR = "/etc/oversip/"
12
+ DEFAULT_TLS_DIR = "tls/"
13
+ DEFAULT_TLS_CA_DIR = "tls/ca/"
14
+ CONF_FILE = "oversip.conf"
15
+ PROXIES_FILE = "proxies.conf"
16
+ LOGIC_FILE = "logic.rb"
17
+ WEBSOCKET_POLICY_FILE = "websocket_policy.rb"
18
+
19
+ def self.log_id
20
+ @log_id ||= "Config"
21
+ end
22
+
23
+ def self.conf_file
24
+ @conf_file ||= ::File.join(@conf_dir, CONF_FILE)
25
+ end
26
+
27
+ def self.proxies_file
28
+ @proxies_file ||= ::File.join(@conf_dir, PROXIES_FILE)
29
+ end
30
+
31
+ def self.logic_file
32
+ @logic_file ||= ::File.join(@conf_dir, LOGIC_FILE)
33
+ end
34
+
35
+ def self.websocket_policy_file
36
+ @websocket_policy_file ||= ::File.join(@conf_dir, WEBSOCKET_POLICY_FILE)
37
+ end
38
+
39
+ @configuration = {
40
+ :core => {
41
+ :nameservers => nil,
42
+ :syslog_facility => "user",
43
+ :syslog_level => "info"
44
+ },
45
+ :sip => {
46
+ :sip_udp => true,
47
+ :sip_tcp => true,
48
+ :sip_tls => false,
49
+ :enable_ipv4 => true,
50
+ :listen_ipv4 => nil,
51
+ :enable_ipv6 => true,
52
+ :listen_ipv6 => nil,
53
+ :listen_port => 5060,
54
+ :listen_port_tls => 5061,
55
+ :use_tls_tunnel => false,
56
+ :listen_port_tls_tunnel => 5062,
57
+ :local_domains => nil,
58
+ :tcp_keepalive_interval => nil,
59
+ :record_route_hostname_tls_ipv4 => nil,
60
+ :record_route_hostname_tls_ipv6 => nil
61
+ },
62
+ :websocket => {
63
+ :sip_ws => false,
64
+ :sip_wss => false,
65
+ :enable_ipv4 => true,
66
+ :listen_ipv4 => nil,
67
+ :enable_ipv6 => true,
68
+ :listen_ipv6 => nil,
69
+ :listen_port => 10080,
70
+ :listen_port_tls => 10443,
71
+ :use_tls_tunnel => false,
72
+ :listen_port_tls_tunnel => 10444,
73
+ :max_ws_message_size => 65536,
74
+ :max_ws_frame_size => 65536,
75
+ :ws_keepalive_interval => nil
76
+ },
77
+ :tls => {
78
+ :public_cert => nil,
79
+ :private_cert => nil,
80
+ :ca_dir => nil
81
+ }
82
+ }
83
+
84
+ CONFIG_VALIDATIONS = {
85
+ :core => {
86
+ :nameservers => [ :ipv4, :multi_value ],
87
+ :syslog_facility => [
88
+ [ :choices,
89
+ %w{ kern user daemon local0 local1 local2 local3 local4 local5 local6 local7 } ]
90
+ ],
91
+ :syslog_level => [
92
+ [ :choices,
93
+ %w{ debug info notice warn error crit } ]
94
+ ],
95
+ },
96
+ :sip => {
97
+ :sip_udp => :boolean,
98
+ :sip_tcp => :boolean,
99
+ :sip_tls => :boolean,
100
+ :enable_ipv4 => :boolean,
101
+ :listen_ipv4 => :ipv4,
102
+ :enable_ipv6 => :boolean,
103
+ :listen_ipv6 => :ipv6,
104
+ :listen_port => :port,
105
+ :listen_port_tls => :port,
106
+ :use_tls_tunnel => :boolean,
107
+ # TODO, si use_tls_tunnel es yes entonces listen_port_tls_tunnel debe estar puesto.
108
+ :listen_port_tls_tunnel => :port,
109
+ :local_domains => [ :domain, :multi_value ],
110
+ :tcp_keepalive_interval => [ :fixnum, [ :greater_equal_than, 180 ] ],
111
+ :record_route_hostname_tls_ipv4 => :domain,
112
+ :record_route_hostname_tls_ipv6 => :domain,
113
+ },
114
+ :websocket => {
115
+ :sip_ws => :boolean,
116
+ :sip_wss => :boolean,
117
+ :enable_ipv4 => :boolean,
118
+ :listen_ipv4 => :ipv4,
119
+ :enable_ipv6 => :boolean,
120
+ :listen_ipv6 => :ipv6,
121
+ :listen_port => :port,
122
+ :listen_port_tls => :port,
123
+ :use_tls_tunnel => :boolean,
124
+ :listen_port_tls_tunnel => :port,
125
+ :max_ws_message_size => [ :fixnum, [ :minor_than, 1048576 ] ],
126
+ :max_ws_frame_size => [ :fixnum, [ :minor_than, 1048576 ] ],
127
+ :ws_keepalive_interval => [ :fixnum, [ :greater_equal_than, 180 ] ]
128
+ },
129
+ :tls => {
130
+ :public_cert => [ :readable_file, :tls_pem_chain ],
131
+ :private_cert => [ :readable_file, :tls_pem_private ],
132
+ :ca_dir => :readable_dir
133
+ }
134
+ }
135
+
136
+
137
+ def self.load conf_dir = nil
138
+ @conf_dir ||= DEFAULT_CONFIG_DIR
139
+
140
+ begin
141
+ conf_yaml = ::YAML.load_file conf_file
142
+ rescue => e
143
+ fatal "error loading configuration file '#{conf_file}': #{e.message} (#{e.class})"
144
+ end
145
+
146
+ begin
147
+ proxies_yaml = ::YAML.load_file proxies_file
148
+ rescue => e
149
+ fatal "error loading proxies configuration file '#{proxies_file}': #{e.message} (#{e.class})"
150
+ end
151
+
152
+ begin
153
+ Kernel.load logic_file
154
+ rescue LoadError => e
155
+ fatal "error loading logic file '#{logic_file}': #{e.message} (#{e.class})"
156
+ end
157
+
158
+ begin
159
+ Kernel.load websocket_policy_file
160
+ rescue LoadError => e
161
+ log_system_warn "cannot load WebSocket Policy file '#{websocket_policy_file}': #{e.message} (#{e.class}), using default policy (allow all)"
162
+ end
163
+
164
+ begin
165
+ pre_check(conf_yaml)
166
+
167
+ CONFIG_VALIDATIONS.each_key do |section|
168
+ CONFIG_VALIDATIONS[section].each do |parameter, validations|
169
+ values = conf_yaml[section.to_s][parameter.to_s] rescue nil
170
+ validations = [ validations ] unless validations.is_a?(Array)
171
+
172
+ if values == nil
173
+ if validations.include? :required
174
+ fatal "#{section}[#{parameter}] requires a value"
175
+ end
176
+ next
177
+ end
178
+
179
+ if values.is_a? Array
180
+ unless validations.include? :multi_value
181
+ fatal "#{section}[#{parameter}] does not allow multiple values"
182
+ end
183
+
184
+ if validations.include? :non_empty and values.empty?
185
+ fatal "#{section}[#{parameter}] does not allow empty values"
186
+ end
187
+ end
188
+
189
+ values = ( values.is_a?(Array) ? values : [ values ] )
190
+
191
+ values.each do |value|
192
+ validations.each do |validation|
193
+
194
+ if validation.is_a? Symbol
195
+ args = []
196
+ elsif validation.is_a? Array
197
+ args = validation[1..-1]
198
+ validation = validation[0]
199
+ end
200
+
201
+ next if [:required, :multi_value, :non_empty].include? validation
202
+
203
+ unless send validation, value, *args
204
+ fatal "#{section}[#{parameter}] has invalid value '#{humanize_value value}' (does not satisfy '#{validation}' validation requirement)"
205
+ end
206
+ end
207
+
208
+ @configuration[section][parameter] = ( validations.include?(:multi_value) ? values : values[0] )
209
+ end
210
+
211
+ end # CONFIG_VALIDATIONS[section].each
212
+ end # CONFIG_VALIDATIONS.each_key
213
+
214
+ post_process
215
+ post_check
216
+
217
+ rescue OverSIP::ConfigurationError => e
218
+ fatal "configuration error: #{e.message}"
219
+ rescue => e
220
+ fatal e
221
+ end
222
+
223
+ ::OverSIP.configuration = @configuration
224
+
225
+ ::OverSIP::ProxiesConfig.load proxies_yaml
226
+ end
227
+
228
+
229
+ def self.pre_check conf_yaml
230
+ # If TLS files/directories are given as relative path, convert them into absolute paths.
231
+
232
+ tls_public_cert = conf_yaml["tls"]["public_cert"] rescue nil
233
+ tls_private_cert = conf_yaml["tls"]["private_cert"] rescue nil
234
+ tls_ca_dir = conf_yaml["tls"]["ca_dir"] rescue nil
235
+
236
+ if tls_public_cert.is_a?(String) and tls_public_cert[0] != "/"
237
+ conf_yaml["tls"]["public_cert"] = ::File.join(@conf_dir, DEFAULT_TLS_DIR, tls_public_cert)
238
+ end
239
+
240
+ if tls_private_cert.is_a?(String) and tls_private_cert[0] != "/"
241
+ conf_yaml["tls"]["private_cert"] = ::File.join(@conf_dir, DEFAULT_TLS_DIR, tls_private_cert)
242
+ end
243
+
244
+ if tls_ca_dir.is_a?(String) and tls_ca_dir[0] != "/"
245
+ conf_yaml["tls"]["ca_dir"] = ::File.join(@conf_dir, DEFAULT_TLS_DIR, tls_ca_dir)
246
+ end
247
+ end
248
+
249
+ def self.post_process
250
+ if @configuration[:tls][:public_cert] and @configuration[:tls][:private_cert]
251
+ @use_tls = true
252
+ # Generate a full PEM file containing both the public and private certificate (for Stud).
253
+ full_cert = Tempfile.new("oversip_full_cert_")
254
+ full_cert.puts File.read(@configuration[:tls][:public_cert])
255
+ full_cert.puts File.read(@configuration[:tls][:private_cert])
256
+ @configuration[:tls][:full_cert] = full_cert.path
257
+ full_cert.close
258
+ else
259
+ @configuration[:sip][:sip_tls] = false
260
+ @configuration[:websocket][:sip_wss] = false
261
+ end
262
+
263
+ if @configuration[:sip][:sip_udp] or @configuration[:sip][:sip_tcp]
264
+ @use_sip_udp_or_tcp = true
265
+ else
266
+ @configuration[:sip][:listen_port] = nil
267
+ end
268
+
269
+ if @configuration[:sip][:sip_tls] and @use_tls
270
+ @use_sip_tls = true
271
+ else
272
+ @configuration[:sip][:listen_port_tls] = nil
273
+ end
274
+
275
+ unless @use_sip_udp_or_tcp or @use_sip_tls
276
+ @configuration[:sip][:listen_ipv4] = nil
277
+ @configuration[:sip][:listen_ipv6] = nil
278
+ @configuration[:sip][:enable_ipv4] = nil
279
+ @configuration[:sip][:enable_ipv6] = nil
280
+ end
281
+
282
+ unless @configuration[:sip][:enable_ipv4]
283
+ @configuration[:sip][:listen_ipv4] = nil
284
+ end
285
+
286
+ unless @configuration[:sip][:enable_ipv6]
287
+ @configuration[:sip][:listen_ipv6] = nil
288
+ end
289
+
290
+ if @configuration[:websocket][:sip_ws]
291
+ @use_sip_ws = true
292
+ else
293
+ @configuration[:websocket][:listen_port] = nil
294
+ end
295
+
296
+ if @configuration[:websocket][:sip_wss] and @use_tls
297
+ @use_sip_wss = true
298
+ else
299
+ @configuration[:websocket][:listen_port_tls] = nil
300
+ end
301
+
302
+ unless @use_sip_ws or @use_sip_wss
303
+ @configuration[:websocket][:listen_ipv4] = nil
304
+ @configuration[:websocket][:listen_ipv6] = nil
305
+ @configuration[:websocket][:enable_ipv4] = nil
306
+ @configuration[:websocket][:enable_ipv6] = nil
307
+ end
308
+
309
+ if ( @use_sip_udp_or_tcp or @use_sip_tls ) and @configuration[:sip][:listen_ipv4] == nil and @configuration[:sip][:enable_ipv4]
310
+ unless (@configuration[:sip][:listen_ipv4] = discover_local_ip(:ipv4))
311
+ log_system_warn "dissabling IPv4 for SIP"
312
+ @configuration[:sip][:listen_ipv4] = nil
313
+ @configuration[:sip][:enable_ipv4] = false
314
+ end
315
+ end
316
+
317
+ if ( @use_sip_udp_or_tcp or @use_sip_tls ) and @configuration[:sip][:listen_ipv6] == nil and @configuration[:sip][:enable_ipv6]
318
+ unless (@configuration[:sip][:listen_ipv6] = discover_local_ip(:ipv6))
319
+ log_system_warn "dissabling IPv6 for SIP"
320
+ @configuration[:sip][:listen_ipv6] = nil
321
+ @configuration[:sip][:enable_ipv6] = false
322
+ end
323
+ end
324
+
325
+ if ( @use_sip_ws or @use_sip_wss ) and @configuration[:websocket][:listen_ipv4] == nil and @configuration[:websocket][:enable_ipv4]
326
+ unless (@configuration[:websocket][:listen_ipv4] = discover_local_ip(:ipv4))
327
+ log_system_warn "dissabling IPv4 for WebSocket"
328
+ @configuration[:websocket][:listen_ipv4] = nil
329
+ @configuration[:websocket][:enable_ipv4] = false
330
+ end
331
+ end
332
+
333
+ if ( @use_sip_ws or @use_sip_wss ) and @configuration[:websocket][:listen_ipv6] == nil and @configuration[:websocket][:enable_ipv6]
334
+ unless (@configuration[:websocket][:listen_ipv6] = discover_local_ip(:ipv6))
335
+ log_system_warn "dissabling IPv6 for WebSocket"
336
+ @configuration[:websocket][:listen_ipv6] = nil
337
+ @configuration[:websocket][:enable_ipv6] = false
338
+ end
339
+ end
340
+
341
+ if @configuration[:sip][:local_domains]
342
+ if @configuration[:sip][:local_domains].is_a? String
343
+ @configuration[:sip][:local_domains] = [ @configuration[:sip][:local_domains].downcase ]
344
+ end
345
+ @configuration[:sip][:local_domains].each {|local_domain| local_domain.downcase!}
346
+ end
347
+ end # def self.post_process
348
+
349
+
350
+ def self.post_check
351
+ binds = { :udp => [], :tcp => [] }
352
+
353
+ if @configuration[:sip][:enable_ipv4]
354
+ ipv4 = @configuration[:sip][:listen_ipv4]
355
+
356
+ if @configuration[:sip][:sip_udp]
357
+ binds[:udp] << [ ipv4, @configuration[:sip][:listen_port] ]
358
+ end
359
+
360
+ if @configuration[:sip][:sip_tcp]
361
+ binds[:tcp] << [ ipv4, @configuration[:sip][:listen_port] ]
362
+ end
363
+
364
+ if @configuration[:sip][:sip_tls]
365
+ unless @configuration[:sip][:use_tls_tunnel]
366
+ binds[:tcp] << [ ipv4, @configuration[:sip][:listen_port_tls] ]
367
+ else
368
+ binds[:tcp] << [ "127.0.0.1", @configuration[:sip][:listen_port_tls_tunnel] ]
369
+ end
370
+ end
371
+ end
372
+
373
+ if @configuration[:sip][:enable_ipv6]
374
+ ipv6 = @configuration[:sip][:listen_ipv6]
375
+
376
+ if @configuration[:sip][:sip_udp]
377
+ binds[:udp] << [ ipv6, @configuration[:sip][:listen_port] ]
378
+ end
379
+
380
+ if @configuration[:sip][:sip_tcp]
381
+ binds[:tcp] << [ ipv6, @configuration[:sip][:listen_port] ]
382
+ end
383
+
384
+ if @configuration[:sip][:sip_tls]
385
+ unless @configuration[:sip][:use_tls_tunnel]
386
+ binds[:tcp] << [ ipv6, @configuration[:sip][:listen_port_tls] ]
387
+ else
388
+ binds[:tcp] << [ "::1", @configuration[:sip][:listen_port_tls_tunnel] ]
389
+ end
390
+ end
391
+ end
392
+
393
+ if @configuration[:websocket][:enable_ipv4]
394
+ ipv4 = @configuration[:websocket][:listen_ipv4]
395
+
396
+ if @configuration[:websocket][:sip_ws]
397
+ binds[:tcp] << [ ipv4, @configuration[:websocket][:listen_port] ]
398
+ end
399
+
400
+ if @configuration[:websocket][:sip_wss]
401
+ unless @configuration[:sip][:use_tls_tunnel]
402
+ binds[:tcp] << [ ipv4, @configuration[:websocket][:listen_port_tls] ]
403
+ else
404
+ binds[:tcp] << [ "127.0.0.1", @configuration[:websocket][:listen_port_tls_tunnel] ]
405
+ end
406
+ end
407
+ end
408
+
409
+ if @configuration[:websocket][:enable_ipv6]
410
+ ipv6 = @configuration[:websocket][:listen_ipv6]
411
+
412
+ if @configuration[:websocket][:sip_ws]
413
+ binds[:tcp] << [ ipv6, @configuration[:websocket][:listen_port] ]
414
+ end
415
+
416
+ if @configuration[:websocket][:sip_wss]
417
+ unless @configuration[:sip][:use_tls_tunnel]
418
+ binds[:tcp] << [ ipv6, @configuration[:websocket][:listen_port_tls] ]
419
+ else
420
+ binds[:tcp] << [ "::1", @configuration[:websocket][:listen_port_tls_tunnel] ]
421
+ end
422
+ end
423
+ end
424
+
425
+ [:udp, :tcp].each do |transport|
426
+ transport_str = transport.to_s.upcase
427
+ binds[transport].each do |ip, port|
428
+ begin
429
+ unless (ip_type = ::OverSIP::Utils.ip_type(ip))
430
+ raise ::OverSIP::ConfigurationError, "given IP '#{ip}' is not IPv4 nor IPv6"
431
+ end
432
+
433
+ case transport
434
+ when :udp
435
+ case ip_type
436
+ when :ipv4
437
+ socket = ::UDPSocket.new ::Socket::AF_INET
438
+ when :ipv6
439
+ socket = ::UDPSocket.new ::Socket::AF_INET6
440
+ end
441
+ socket.bind ip, port
442
+ when :tcp
443
+ socket = ::TCPServer.open ip, port
444
+ end
445
+
446
+ socket.close
447
+
448
+ rescue ::Errno::EADDRNOTAVAIL
449
+ raise ::OverSIP::ConfigurationError, "cannot bind in #{transport_str} IP '#{ip}', address not available"
450
+ rescue ::Errno::EADDRINUSE
451
+ raise ::OverSIP::ConfigurationError, "#{transport_str} IP '#{ip}' and port #{port} already in use"
452
+ rescue ::Errno::EACCES
453
+ raise ::OverSIP::ConfigurationError, "no permission to bind in #{transport_str} IP '#{ip}' and port #{port}"
454
+ rescue => e
455
+ raise e.class, "error binding in #{transport_str} IP '#{ip}' and port #{port} (#{e.class}: #{e.message})"
456
+ end
457
+ end
458
+ end
459
+ end # def self.post_check
460
+
461
+
462
+ def self.print colorize=true
463
+ color = Term::ANSIColor if colorize
464
+
465
+ puts
466
+ @configuration.each_key do |section|
467
+ if colorize
468
+ puts " #{color.bold(section.to_s)}:"
469
+ else
470
+ puts " #{section.to_s}:"
471
+ end
472
+ @configuration[section].each do |parameter, value|
473
+ humanized_value = humanize_value value
474
+ color_value = case value
475
+ when TrueClass
476
+ colorize ? color.bold(color.green(humanized_value)) : humanized_value
477
+ when FalseClass
478
+ colorize ? color.bold(color.red(humanized_value)) : humanized_value
479
+ when NilClass
480
+ humanized_value
481
+ when String, Symbol
482
+ colorize ? color.yellow(humanized_value) : humanized_value
483
+ when Array
484
+ colorize ? color.yellow(humanized_value) : humanized_value
485
+ when Fixnum, Float
486
+ colorize ? color.bold(color.blue(humanized_value)) : humanized_value
487
+ else
488
+ humanized_value
489
+ end
490
+ printf(" %-32s: %s\n", parameter, color_value)
491
+ end
492
+ puts
493
+ end
494
+ end
495
+
496
+ def self.humanize_value value
497
+ case value
498
+ when TrueClass ; "yes"
499
+ when FalseClass ; "no"
500
+ when NilClass ; "null"
501
+ when String ; value
502
+ when Symbol ; value.to_s
503
+ when Array ; value.join(", ")
504
+ when Fixnum, Float ; value.to_s
505
+ else ; value.to_s
506
+ end
507
+ end
508
+
509
+ def self.discover_local_ip(type)
510
+ begin
511
+ if type == :ipv4
512
+ socket = ::UDPSocket.new ::Socket::AF_INET
513
+ socket.connect("1.2.3.4", 1)
514
+ elsif type == :ipv6
515
+ socket = ::UDPSocket.new ::Socket::AF_INET6
516
+ socket.connect("2001::1", 1)
517
+ end
518
+ ip = socket.local_address.ip_address
519
+ socket.close
520
+ return ip
521
+ rescue => e
522
+ log_system_warn "cannot autodiscover local #{type == :ipv4 ? "IPv4" : "IPv6"}: #{e.message} (#{e.class})"
523
+ return false
524
+ end
525
+ end
526
+
527
+ def self.reload_logic
528
+ begin
529
+ Kernel.load logic_file
530
+ log_system_info "logic reloaded"
531
+ true
532
+ rescue Exception => e
533
+ log_system_crit "error reloading logic"
534
+ log_system_crit e
535
+ false
536
+ end
537
+ end
538
+
539
+ end
540
+
541
+ end
@@ -0,0 +1,126 @@
1
+ require "openssl"
2
+
3
+
4
+ module OverSIP
5
+
6
+ module Config
7
+
8
+ module Validators
9
+
10
+ extend ::OverSIP::Logger
11
+
12
+ DOMAIN_REGEXP = /^(([0-9a-zA-Z\-_])+\.)*([0-9a-zA-Z\-_])+$/
13
+ TLS_PEM_CHAIN_REGEXP = /-{5}BEGIN CERTIFICATE-{5}\n.*?-{5}END CERTIFICATE-{5}\n/m
14
+
15
+ def boolean value
16
+ value == true or value == false
17
+ end
18
+
19
+ def string value
20
+ value.is_a? String
21
+ end
22
+
23
+ def fixnum value
24
+ value.is_a? Fixnum
25
+ end
26
+
27
+ def port value
28
+ fixnum(value) and value.between?(1,65536)
29
+ end
30
+
31
+ def ipv4 value
32
+ return false unless value.is_a? String
33
+ ::OverSIP::Utils.ip_type(value) == :ipv4 and value != "0.0.0.0"
34
+ end
35
+
36
+ def ipv6 value
37
+ return false unless value.is_a? String
38
+ ::OverSIP::Utils.ip_type(value) == :ipv6 and ::OverSIP::Utils.normalize_ipv6(value) != "::"
39
+ end
40
+
41
+ def ipv4_any value
42
+ return false unless value.is_a? String
43
+ ::OverSIP::Utils.ip_type(value) == :ipv4
44
+ end
45
+
46
+ def ipv6_any value
47
+ return false unless value.is_a? String
48
+ ::OverSIP::Utils.ip_type(value) == :ipv6
49
+ end
50
+
51
+ def domain value
52
+ value =~ DOMAIN_REGEXP
53
+ end
54
+
55
+ def choices value, choices
56
+ choices.include? value
57
+ end
58
+
59
+ def greater_than value, minimum
60
+ value > minimum rescue false
61
+ end
62
+
63
+ def greater_equal_than value, minimum
64
+ value >= minimum rescue false
65
+ end
66
+
67
+ def minor_than value, maximum
68
+ value < maximum rescue false
69
+ end
70
+
71
+ def minor_equal_than value, maximum
72
+ value <= maximum rescue false
73
+ end
74
+
75
+ def readable_file file
76
+ ::File.file?(file) and ::File.readable?(file)
77
+ end
78
+
79
+ def readable_dir dir
80
+ ::File.directory?(dir) and ::File.readable?(dir)
81
+ end
82
+
83
+ def tls_pem_chain file
84
+ chain = ::File.read file
85
+ pems = chain.scan(TLS_PEM_CHAIN_REGEXP).flatten
86
+ pem_found = nil
87
+
88
+ begin
89
+ pems.each do |pem|
90
+ ::OpenSSL::X509::Certificate.new pem
91
+ pem_found = true
92
+ end
93
+ rescue => e
94
+ log_system_error "#{e.class}: #{e.message}"
95
+ return false
96
+ end
97
+
98
+ if pem_found
99
+ return true
100
+ else
101
+ log_system_error "no valid X509 PEM found in the file"
102
+ return false
103
+ end
104
+ end
105
+
106
+ def tls_pem_private file
107
+ pem = ::File.read file
108
+ key_classes = [::OpenSSL::PKey::RSA, ::OpenSSL::PKey::DSA]
109
+
110
+ begin
111
+ key_class = key_classes.shift
112
+ key_class.new pem
113
+ return true
114
+ rescue => e
115
+ retry if key_classes.any?
116
+ log_system_error e.message
117
+ end
118
+
119
+ return false
120
+ end
121
+
122
+ end # module Validators
123
+
124
+ end # module Config
125
+
126
+ end
@@ -0,0 +1,7 @@
1
+ module OverSIP
2
+
3
+ class Error < StandardError ; end
4
+ class ConfigurationError < Error ; end
5
+ class LogicError < Error ; end
6
+
7
+ end