oversip_p 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (132) hide show
  1. checksums.yaml +7 -0
  2. data/AUTHORS +22 -0
  3. data/LICENSE +25 -0
  4. data/README.md +43 -0
  5. data/Rakefile +54 -0
  6. data/bin/oversip +184 -0
  7. data/etc/oversip.conf +274 -0
  8. data/etc/proxies.conf +145 -0
  9. data/etc/server.rb +315 -0
  10. data/etc/tls/ca/cacert.pem +3894 -0
  11. data/etc/tls/demo-tls.oversip.net.crt +17 -0
  12. data/etc/tls/demo-tls.oversip.net.key +15 -0
  13. data/etc/tls/upgrade-cacert.sh +12 -0
  14. data/etc/tls/utils/create-cert.rb +162 -0
  15. data/etc/tls/utils/get-sip-identities.rb +95 -0
  16. data/ext/common/c_util.h +74 -0
  17. data/ext/common/ruby_c_util.h +88 -0
  18. data/ext/sip_parser/common_headers.h +210 -0
  19. data/ext/sip_parser/ext_help.h +18 -0
  20. data/ext/sip_parser/extconf.rb +3 -0
  21. data/ext/sip_parser/sip_message_parser.c +29741 -0
  22. data/ext/sip_parser/sip_parser.h +250 -0
  23. data/ext/sip_parser/sip_parser_ruby.c +1370 -0
  24. data/ext/sip_parser/sip_uri_parser.c +39699 -0
  25. data/ext/stud/extconf.rb +43 -0
  26. data/ext/stun/ext_help.h +16 -0
  27. data/ext/stun/extconf.rb +3 -0
  28. data/ext/stun/stun_ruby.c +394 -0
  29. data/ext/utils/ext_help.h +14 -0
  30. data/ext/utils/extconf.rb +3 -0
  31. data/ext/utils/haproxy_protocol.c +6163 -0
  32. data/ext/utils/haproxy_protocol.h +27 -0
  33. data/ext/utils/ip_utils.c +5952 -0
  34. data/ext/utils/ip_utils.h +64 -0
  35. data/ext/utils/outbound_utils.c +3227 -0
  36. data/ext/utils/outbound_utils.h +27 -0
  37. data/ext/utils/utils_ruby.c +392 -0
  38. data/ext/utils/utils_ruby.h +76 -0
  39. data/ext/websocket_framing_utils/ext_help.h +18 -0
  40. data/ext/websocket_framing_utils/extconf.rb +3 -0
  41. data/ext/websocket_framing_utils/ws_framing_utils.h +47 -0
  42. data/ext/websocket_framing_utils/ws_framing_utils_ruby.c +135 -0
  43. data/ext/websocket_http_parser/ext_help.h +18 -0
  44. data/ext/websocket_http_parser/extconf.rb +3 -0
  45. data/ext/websocket_http_parser/ws_http_parser.c +1635 -0
  46. data/ext/websocket_http_parser/ws_http_parser.h +87 -0
  47. data/ext/websocket_http_parser/ws_http_parser_ruby.c +630 -0
  48. data/lib/oversip/config.rb +597 -0
  49. data/lib/oversip/config_validators.rb +126 -0
  50. data/lib/oversip/default_server.rb +52 -0
  51. data/lib/oversip/errors.rb +10 -0
  52. data/lib/oversip/fiber_pool.rb +56 -0
  53. data/lib/oversip/launcher.rb +635 -0
  54. data/lib/oversip/logger.rb +84 -0
  55. data/lib/oversip/modules/outbound_mangling.rb +56 -0
  56. data/lib/oversip/modules/user_assertion.rb +73 -0
  57. data/lib/oversip/proxies_config.rb +189 -0
  58. data/lib/oversip/ruby_ext/eventmachine.rb +38 -0
  59. data/lib/oversip/sip/client.rb +428 -0
  60. data/lib/oversip/sip/client_transaction.rb +586 -0
  61. data/lib/oversip/sip/constants.rb +88 -0
  62. data/lib/oversip/sip/core.rb +217 -0
  63. data/lib/oversip/sip/launcher.rb +221 -0
  64. data/lib/oversip/sip/listeners/connection.rb +54 -0
  65. data/lib/oversip/sip/listeners/ipv4_tcp_client.rb +21 -0
  66. data/lib/oversip/sip/listeners/ipv4_tcp_server.rb +22 -0
  67. data/lib/oversip/sip/listeners/ipv4_tls_client.rb +21 -0
  68. data/lib/oversip/sip/listeners/ipv4_tls_server.rb +22 -0
  69. data/lib/oversip/sip/listeners/ipv4_tls_tunnel_server.rb +22 -0
  70. data/lib/oversip/sip/listeners/ipv4_udp_server.rb +21 -0
  71. data/lib/oversip/sip/listeners/ipv6_tcp_client.rb +21 -0
  72. data/lib/oversip/sip/listeners/ipv6_tcp_server.rb +22 -0
  73. data/lib/oversip/sip/listeners/ipv6_tls_client.rb +21 -0
  74. data/lib/oversip/sip/listeners/ipv6_tls_server.rb +22 -0
  75. data/lib/oversip/sip/listeners/ipv6_tls_tunnel_server.rb +22 -0
  76. data/lib/oversip/sip/listeners/ipv6_udp_server.rb +21 -0
  77. data/lib/oversip/sip/listeners/tcp_client.rb +97 -0
  78. data/lib/oversip/sip/listeners/tcp_connection.rb +202 -0
  79. data/lib/oversip/sip/listeners/tcp_server.rb +71 -0
  80. data/lib/oversip/sip/listeners/tls_client.rb +125 -0
  81. data/lib/oversip/sip/listeners/tls_server.rb +88 -0
  82. data/lib/oversip/sip/listeners/tls_tunnel_connection.rb +89 -0
  83. data/lib/oversip/sip/listeners/tls_tunnel_server.rb +61 -0
  84. data/lib/oversip/sip/listeners/udp_connection.rb +214 -0
  85. data/lib/oversip/sip/listeners.rb +24 -0
  86. data/lib/oversip/sip/message.rb +177 -0
  87. data/lib/oversip/sip/message_processor.rb +213 -0
  88. data/lib/oversip/sip/name_addr.rb +51 -0
  89. data/lib/oversip/sip/proxy.rb +324 -0
  90. data/lib/oversip/sip/request.rb +179 -0
  91. data/lib/oversip/sip/response.rb +37 -0
  92. data/lib/oversip/sip/rfc3263.rb +643 -0
  93. data/lib/oversip/sip/server_transaction.rb +295 -0
  94. data/lib/oversip/sip/sip.rb +76 -0
  95. data/lib/oversip/sip/tags.rb +39 -0
  96. data/lib/oversip/sip/timers.rb +55 -0
  97. data/lib/oversip/sip/transport_manager.rb +130 -0
  98. data/lib/oversip/sip/uac.rb +89 -0
  99. data/lib/oversip/sip/uac_request.rb +84 -0
  100. data/lib/oversip/sip/uri.rb +208 -0
  101. data/lib/oversip/syslog.rb +68 -0
  102. data/lib/oversip/system_callbacks.rb +45 -0
  103. data/lib/oversip/tls.rb +172 -0
  104. data/lib/oversip/utils.rb +30 -0
  105. data/lib/oversip/version.rb +21 -0
  106. data/lib/oversip/websocket/constants.rb +55 -0
  107. data/lib/oversip/websocket/http_request.rb +59 -0
  108. data/lib/oversip/websocket/launcher.rb +183 -0
  109. data/lib/oversip/websocket/listeners/connection.rb +51 -0
  110. data/lib/oversip/websocket/listeners/ipv4_ws_server.rb +22 -0
  111. data/lib/oversip/websocket/listeners/ipv4_wss_server.rb +22 -0
  112. data/lib/oversip/websocket/listeners/ipv4_wss_tunnel_server.rb +22 -0
  113. data/lib/oversip/websocket/listeners/ipv6_ws_server.rb +22 -0
  114. data/lib/oversip/websocket/listeners/ipv6_wss_server.rb +22 -0
  115. data/lib/oversip/websocket/listeners/ipv6_wss_tunnel_server.rb +22 -0
  116. data/lib/oversip/websocket/listeners/ws_server.rb +331 -0
  117. data/lib/oversip/websocket/listeners/wss_server.rb +88 -0
  118. data/lib/oversip/websocket/listeners/wss_tunnel_server.rb +133 -0
  119. data/lib/oversip/websocket/listeners.rb +13 -0
  120. data/lib/oversip/websocket/websocket.rb +13 -0
  121. data/lib/oversip/websocket/ws_framing.rb +545 -0
  122. data/lib/oversip/websocket/ws_sip_app.rb +120 -0
  123. data/lib/oversip.rb +127 -0
  124. data/test/oversip_test_helper.rb +19 -0
  125. data/test/test_http_parser.rb +73 -0
  126. data/test/test_name_addr.rb +27 -0
  127. data/test/test_name_addr_parser.rb +24 -0
  128. data/test/test_sip_message_parser.rb +168 -0
  129. data/test/test_sip_uri_parser.rb +56 -0
  130. data/test/test_uri.rb +68 -0
  131. data/thirdparty/stud/stud.tar.gz +0 -0
  132. metadata +334 -0
@@ -0,0 +1,635 @@
1
+ module OverSIP::Launcher
2
+
3
+ extend ::OverSIP::Logger
4
+
5
+ READY_PIPE_TIMEOUT = 16
6
+
7
+ @log_id = "launcher"
8
+
9
+
10
+ def self.daemonize! options
11
+ @log_id = "launcher (daemonize)"
12
+
13
+ $stdin.reopen("/dev/null")
14
+
15
+ # grandparent (launcher) : Reads pipe, exits when master is ready.
16
+ # \_ parent : Exits immediately ASAP.
17
+ # \_ master : Writes to pipe when ready.
18
+
19
+ rd, wr = IO.pipe
20
+ grandparent = $$
21
+ if fork
22
+ wr.close # Grandparent does not write in the ready_pipe.
23
+ else
24
+ rd.close # Parent (so also future master) does not read from the ready_pipe.
25
+ ::Process.setsid
26
+ exit if fork # Parent dies now.
27
+ end
28
+
29
+ # I'm grandparent (launcher) process.
30
+ if grandparent == $$
31
+ # Master process will inmediatelly write in the ready_pipe its PID so we get
32
+ # its PID.
33
+ pid = nil
34
+ begin
35
+ ::Timeout.timeout(READY_PIPE_TIMEOUT/2) do
36
+ pid = rd.gets("\n").to_i rescue nil
37
+ end
38
+ rescue ::Timeout::Error
39
+ fatal "master process didn't notify its PID within #{READY_PIPE_TIMEOUT/2} seconds"
40
+ end
41
+ unless pid
42
+ fatal "master process failed to start"
43
+ end
44
+
45
+ # This will block until OverSIP::Launcher.run ends succesfully (so master process
46
+ # writes "ok" in the ready_pipe) or until the pipe is closes without writting into it
47
+ # (so the master process has died).
48
+ # It can also occur that master process blocks forever and never writes into the
49
+ # ready pipe neither closes it. In this case a timeout is raised and master process
50
+ # is killed.
51
+ master_ok = nil
52
+ begin
53
+ ::Timeout::timeout(READY_PIPE_TIMEOUT/2) do
54
+ master_ok = (rd.read(2) rescue nil)
55
+ end
56
+ rescue ::Timeout::Error
57
+ log_system_crit "master process is not ready within #{READY_PIPE_TIMEOUT/2} seconds, killing it..."
58
+ begin
59
+ ::Process.kill(:TERM, pid)
60
+ 10.times do |i|
61
+ sleep 0.05
62
+ ::Process.wait(pid, ::Process::WNOHANG) rescue nil
63
+ ::Process.kill(0, pid) rescue break
64
+ end
65
+ ::Process.kill(0, pid)
66
+ ::Process.kill(:KILL, pid) rescue nil
67
+ rescue ::Errno::ESRCH
68
+ end
69
+ fatal "master process killed"
70
+ end
71
+ unless master_ok == "ok"
72
+ fatal "master process failed to start"
73
+ end
74
+
75
+ # Grandparent can die now with honor.
76
+ exit 0
77
+
78
+ # I'm master process.
79
+ else
80
+ options[:ready_pipe] = wr
81
+ end
82
+ end
83
+
84
+
85
+ def self.run options
86
+ @log_id = "launcher (run)"
87
+
88
+ configuration = ::OverSIP.configuration
89
+
90
+ # Store the master process PID.
91
+ ::OverSIP.pid = $$
92
+
93
+ begin
94
+ # Inmediatelly write into the ready_pipe so grandparent process reads it
95
+ # and knowns which PID we have.
96
+ ready_pipe = options.delete(:ready_pipe)
97
+ ready_pipe.write($$.to_s + "\n") if ready_pipe
98
+
99
+ # Init modules.
100
+ ::OverSIP::TLS.module_init
101
+ ::OverSIP::SIP.module_init
102
+ ::OverSIP::SIP::RFC3263.module_init
103
+ ::OverSIP::WebSocket.module_init
104
+ ::OverSIP::WebSocket::WsFraming.class_init
105
+ ::OverSIP::WebSocket::WsSipApp.class_init
106
+
107
+ @log_id = "launcher (master)"
108
+
109
+ ::EM.run do
110
+
111
+ ::OverSIP.is_ready = false
112
+ ::OverSIP.status = :loading
113
+ ::OverSIP.root_fiber = ::Fiber.current
114
+
115
+ log_system_notice "using Ruby #{RUBY_VERSION}p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE} revision #{RUBY_REVISION}) [#{RUBY_PLATFORM}]"
116
+ log_system_notice "using EventMachine #{::EM::VERSION}"
117
+ log_system_notice "starting event reactor..."
118
+
119
+ # Run SIP and WebSocket servers.
120
+ run_servers options
121
+
122
+ # Run DNS resolver.
123
+ ::OverSIP::SIP::RFC3263.run
124
+
125
+ # Change process permissions if requested.
126
+ set_user_group(options[:user], options[:group])
127
+
128
+ # Create PID file.
129
+ create_pid_file(options[:pid_file])
130
+
131
+ trap_signals
132
+
133
+ # Ensure the code in the next SystemEvents and SystemCallbacks are run serially.
134
+ ::Fiber.new do
135
+
136
+ # Run OverSIP::SystemEvents.on_initialize.
137
+ log_system_debug "calling OverSIP::SystemEvents.on_initialize() method..."
138
+ begin
139
+ ::OverSIP::SystemEvents.on_initialize
140
+ rescue ::Exception => e
141
+ log_system_crit "error calling OverSIP::SystemEvents.on_initialize():"
142
+ fatal e
143
+ end
144
+
145
+ # Run all the OverSIP::SystemCallbacks.on_started_callbacks.
146
+ log_system_debug "executing OverSIP::SystemCallbacks.on_started_callbacks..."
147
+ ::OverSIP::SystemCallbacks.on_started_callbacks.each do |cb|
148
+ begin
149
+ cb.call
150
+ rescue ::Exception => e
151
+ log_system_crit "error executing a callback in OverSIP::SystemCallbacks.on_started_callbacks:"
152
+ fatal e
153
+ end
154
+ end
155
+
156
+ # Run OverSIP::SystemEvents.on_started within a fiber.
157
+ log_system_debug "calling OverSIP::SystemEvents.on_started() method..."
158
+ begin
159
+ ::OverSIP::SystemEvents.on_started
160
+ rescue ::Exception => e
161
+ log_system_crit "error calling OverSIP::SystemEvents.on_started():"
162
+ fatal e
163
+ end
164
+
165
+ log_system_notice "#{::OverSIP::PROGRAM_NAME} #{::OverSIP::VERSION} running in background"
166
+
167
+ # Write "ok" into the ready_pipe so grandparent process (launcher)
168
+ # exits with status 0.
169
+ if ready_pipe
170
+ ready_pipe.write("ok")
171
+ ready_pipe.close rescue nil
172
+ ready_pipe = nil
173
+ end
174
+
175
+ # Stop writting into standard output/error.
176
+ $stdout.reopen("/dev/null")
177
+ $stderr.reopen("/dev/null")
178
+ ::OverSIP.daemonized = true
179
+
180
+ # So update the logger to stop writting into stdout.
181
+ ::OverSIP::Logger.load_methods
182
+
183
+ # Set the EventMachine error handler.
184
+ ::EM.error_handler do |e|
185
+ log_system_error "error raised during event loop and rescued by EM.error_handler:"
186
+ log_system_error e
187
+ end
188
+
189
+ ::OverSIP.is_ready = true
190
+ ::OverSIP.status = :running
191
+
192
+ end.resume
193
+
194
+ end # ::EM.run
195
+
196
+ rescue => e
197
+ fatal e
198
+ end
199
+
200
+ end # def self.run
201
+
202
+
203
+ def self.fatal msg
204
+ log_system_crit msg
205
+ log_system_crit "exiting with error status"
206
+
207
+ terminate error=true, fatal=true
208
+ end
209
+
210
+
211
+ def self.create_pid_file path
212
+ # Check that the PID file is accesible.
213
+ begin
214
+ assert_file_is_writable_readable_deletable(path)
215
+ rescue ::OverSIP::Error => e
216
+ fatal "cannot create PID file: #{e.message}"
217
+ end
218
+ # If the PID file exists (it shouldn't) check if it's stale.
219
+ if wpid = valid_pid?(path) and wpid != $$
220
+ fatal "already running on PID #{wpid} (or '#{path}' is stale)"
221
+ end
222
+ # Delete the PID file if it exists.
223
+ ::File.unlink(path) rescue nil
224
+ # Create the PID file.
225
+ ::File.open(path, "w", 0644) do |f|
226
+ f.syswrite("#$$\n")
227
+ end
228
+ ::OverSIP.pid_file = path
229
+ end
230
+
231
+
232
+ def self.assert_file_is_writable_readable_deletable path
233
+ # File already exists.
234
+ if ::File.exist?(path)
235
+ if not ::File.file?(path)
236
+ raise ::OverSIP::Error, "'#{path}' exits and is not a regular file"
237
+ elsif not ::File.readable?(path)
238
+ raise ::OverSIP::Error, "'#{path}' is not readable"
239
+ elsif not ::File.writable?(path)
240
+ raise ::OverSIP::Error, "'#{path}' is not writable"
241
+ end
242
+ end
243
+ # Check if the parent directory is writeable.
244
+ if not ::File.writable? ::File.dirname(path)
245
+ raise ::OverSIP::Error, "directory '#{::File.dirname(path)}' is not writable"
246
+ end
247
+ end
248
+
249
+
250
+ # Returns a PID if a given path contains a non-stale PID file,
251
+ # false otherwise.
252
+ def self.valid_pid? path
253
+ begin
254
+ wpid = ::File.read(path).to_i
255
+ wpid <= 0 and return false
256
+ # If the process exists return its PID.
257
+ ::Process.kill(0, wpid)
258
+ return wpid
259
+ # If the process exists but we don't have permissions over it, return its PID.
260
+ rescue ::Errno::EPERM
261
+ return wpid
262
+ # If the PID file (path) doesn't exist or the process is not running return false.
263
+ rescue ::Errno::ENOENT, ::Errno::ESRCH
264
+ return false
265
+ end
266
+ end
267
+
268
+
269
+ def self.run_servers options
270
+ configuration = ::OverSIP.configuration
271
+
272
+ if configuration[:sip][:sip_udp]
273
+ # SIP UDP IPv4 server.
274
+ if configuration[:sip][:enable_ipv4]
275
+ ::OverSIP::SIP::Launcher.run true, :ipv4, configuration[:sip][:listen_ipv4],
276
+ configuration[:sip][:listen_port], :udp
277
+ end
278
+
279
+ # SIP IPv6 UDP server.
280
+ if configuration[:sip][:enable_ipv6]
281
+ ::OverSIP::SIP::Launcher.run true, :ipv6, configuration[:sip][:listen_ipv6],
282
+ configuration[:sip][:listen_port], :udp
283
+ end
284
+ end
285
+
286
+ if configuration[:sip][:sip_tcp]
287
+ # SIP IPv4 TCP server.
288
+ if configuration[:sip][:enable_ipv4]
289
+ ::OverSIP::SIP::Launcher.run true, :ipv4, configuration[:sip][:listen_ipv4],
290
+ configuration[:sip][:listen_port], :tcp
291
+ end
292
+
293
+ # SIP IPv6 TCP server.
294
+ if configuration[:sip][:enable_ipv6]
295
+ ::OverSIP::SIP::Launcher.run true, :ipv6, configuration[:sip][:listen_ipv6],
296
+ configuration[:sip][:listen_port], :tcp
297
+ end
298
+ end
299
+
300
+ if configuration[:sip][:sip_tls]
301
+ unless configuration[:sip][:use_tls_tunnel]
302
+ # SIP IPv4 TLS server (native).
303
+ if configuration[:sip][:enable_ipv4]
304
+ ::OverSIP::SIP::Launcher.run true, :ipv4, configuration[:sip][:listen_ipv4],
305
+ configuration[:sip][:listen_port_tls], :tls
306
+ end
307
+
308
+ # SIP IPv6 TLS server (native).
309
+ if configuration[:sip][:enable_ipv6]
310
+ ::OverSIP::SIP::Launcher.run true, :ipv6, configuration[:sip][:listen_ipv6],
311
+ configuration[:sip][:listen_port_tls], :tls
312
+ end
313
+ else
314
+ # SIP IPv4 TLS server (Stud).
315
+ if configuration[:sip][:enable_ipv4]
316
+ ::OverSIP::SIP::Launcher.run true, :ipv4, "127.0.0.1",
317
+ configuration[:sip][:listen_port_tls_tunnel], :tls_tunnel,
318
+ configuration[:sip][:listen_ipv4],
319
+ configuration[:sip][:listen_port_tls]
320
+ ::OverSIP::SIP::Launcher.run false, :ipv4, configuration[:sip][:listen_ipv4],
321
+ configuration[:sip][:listen_port_tls], :tls
322
+
323
+ # Spawn a Stud process.
324
+ spawn_stud_process options,
325
+ configuration[:sip][:listen_ipv4], configuration[:sip][:listen_port_tls],
326
+ "127.0.0.1", configuration[:sip][:listen_port_tls_tunnel],
327
+ ssl = false
328
+ end
329
+
330
+ # SIP IPv6 TLS server (Stud).
331
+ if configuration[:sip][:enable_ipv6]
332
+ ::OverSIP::SIP::Launcher.run true, :ipv6, "::1",
333
+ configuration[:sip][:listen_port_tls_tunnel], :tls_tunnel,
334
+ configuration[:sip][:listen_ipv6],
335
+ configuration[:sip][:listen_port_tls]
336
+ ::OverSIP::SIP::Launcher.run false, :ipv6, configuration[:sip][:listen_ipv6],
337
+ configuration[:sip][:listen_port_tls], :tls
338
+
339
+ # Spawn a Stud process.
340
+ spawn_stud_process options,
341
+ configuration[:sip][:listen_ipv6], configuration[:sip][:listen_port_tls],
342
+ "::1", configuration[:sip][:listen_port_tls_tunnel],
343
+ ssl = false
344
+ end
345
+ end
346
+ end
347
+
348
+ if configuration[:websocket][:sip_ws]
349
+ # WebSocket IPv4 TCP SIP server.
350
+ if configuration[:websocket][:enable_ipv4]
351
+ ::OverSIP::WebSocket::Launcher.run true, :ipv4, configuration[:websocket][:listen_ipv4],
352
+ configuration[:websocket][:listen_port], :ws
353
+ end
354
+
355
+ # WebSocket IPv6 TCP SIP server.
356
+ if configuration[:websocket][:enable_ipv6]
357
+ ::OverSIP::WebSocket::Launcher.run true, :ipv6, configuration[:websocket][:listen_ipv6],
358
+ configuration[:websocket][:listen_port], :ws
359
+ end
360
+ end
361
+
362
+ if configuration[:websocket][:sip_wss]
363
+ unless configuration[:websocket][:use_tls_tunnel]
364
+ # WebSocket IPv4 TLS SIP server (native).
365
+ if configuration[:websocket][:enable_ipv4]
366
+ ::OverSIP::WebSocket::Launcher.run true, :ipv4, configuration[:websocket][:listen_ipv4],
367
+ configuration[:websocket][:listen_port_tls], :wss
368
+ end
369
+
370
+ # WebSocket IPv6 TLS SIP server (native).
371
+ if configuration[:websocket][:enable_ipv6]
372
+ ::OverSIP::WebSocket::Launcher.run true, :ipv6, configuration[:websocket][:listen_ipv6],
373
+ configuration[:websocket][:listen_port_tls], :wss
374
+ end
375
+ else
376
+ # WebSocket IPv4 TLS SIP server (Stud).
377
+ if configuration[:websocket][:enable_ipv4]
378
+ ::OverSIP::WebSocket::Launcher.run true, :ipv4, "127.0.0.1",
379
+ configuration[:websocket][:listen_port_tls_tunnel], :wss_tunnel,
380
+ configuration[:websocket][:listen_ipv4],
381
+ configuration[:websocket][:listen_port_tls]
382
+ ::OverSIP::WebSocket::Launcher.run false, :ipv4, configuration[:websocket][:listen_ipv4],
383
+ configuration[:websocket][:listen_port_tls], :wss
384
+
385
+ # Spawn a Stud process.
386
+ spawn_stud_process options,
387
+ configuration[:websocket][:listen_ipv4], configuration[:websocket][:listen_port_tls],
388
+ "127.0.0.1", configuration[:websocket][:listen_port_tls_tunnel],
389
+ ssl = true
390
+ end
391
+
392
+ # WebSocket IPv6 TLS SIP server (Stud).
393
+ if configuration[:sip][:enable_ipv6]
394
+ ::OverSIP::WebSocket::Launcher.run true, :ipv6, "::1",
395
+ configuration[:websocket][:listen_port_tls_tunnel], :wss_tunnel,
396
+ configuration[:websocket][:listen_ipv6],
397
+ configuration[:websocket][:listen_port_tls]
398
+ ::OverSIP::WebSocket::Launcher.run false, :ipv6, configuration[:websocket][:listen_ipv6],
399
+ configuration[:websocket][:listen_port_tls], :wss
400
+
401
+ # Spawn a Stud process.
402
+ spawn_stud_process options,
403
+ configuration[:websocket][:listen_ipv6], configuration[:websocket][:listen_port_tls],
404
+ "::1", configuration[:websocket][:listen_port_tls_tunnel],
405
+ ssl = true
406
+ end
407
+ end
408
+ end
409
+ end
410
+
411
+
412
+ def self.trap_signals
413
+ # This should never occur (unless some not trapped signal is received
414
+ # and causes Ruby to exit, or maybe the user called "exit()" within its
415
+ # custom code).
416
+ at_exit do
417
+ if $!.is_a? ::SystemExit
418
+ log_system_notice "exiting due to SystemExit..."
419
+ terminate error=false
420
+ else
421
+ log_system_crit "exiting due to an unknown cause ($! = #{$!.inspect})..."
422
+ terminate error=true
423
+ end
424
+ end
425
+
426
+ # Signals that cause OverSIP to terminate.
427
+ exit_signals = [:TERM, :QUIT]
428
+ exit_signals.each do |signal|
429
+ trap signal do
430
+ log_system_notice "#{signal} signal received, exiting..."
431
+ terminate error=false
432
+ end
433
+ end
434
+
435
+ # Signals that must be ignored.
436
+ ignore_signals = [:ALRM, :INT, :PIPE, :POLL, :PROF, :USR2, :WINCH]
437
+ ignore_signals.each do |signal|
438
+ begin
439
+ trap signal do
440
+ log_system_notice "#{signal.to_s.upcase} signal received, ignored"
441
+ end
442
+ rescue ::ArgumentError
443
+ log_system_debug "cannot trap signal #{signal.to_s.upcase}, it could not exist in this system, ignoring it"
444
+ end
445
+ end
446
+
447
+ # Ruby 2.0 does not allow trapping VTALRM signal. For other cases ignore it.
448
+ begin
449
+ trap :VTALRM do
450
+ end
451
+ rescue ::ArgumentError
452
+ end
453
+
454
+ # Signal HUP reloads OverSIP system configuration.
455
+ trap :HUP do
456
+ # Ignore another HUP signal until this code is finished.
457
+ original_trap_proc = trap(:HUP){}
458
+
459
+ log_system_notice "HUP signal received, reloading configuration files..."
460
+ ::OverSIP::Config.system_reload
461
+
462
+ # Run all the OverSIP::SystemCallbacks.on_reload_callbacks.
463
+ log_system_info "executing OverSIP::SystemCallbacks.on_reload_callbacks..."
464
+ ::Fiber.new do
465
+ ::OverSIP::SystemCallbacks.on_reload_callbacks.each do |cb|
466
+ begin
467
+ cb.call
468
+ rescue ::Exception => e
469
+ log_system_crit "error executing a callback in OverSIP::SystemCallbacks.on_reload_callbacks:"
470
+ log_system_crit e
471
+ end
472
+ end
473
+
474
+ # Reset the signal handler.
475
+ trap :HUP, original_trap_proc
476
+ end.resume
477
+ end
478
+
479
+ # Signal USR1 reloads custom code provided by the user.
480
+ trap :USR1 do
481
+ # Ignore another HUP signal until this code is finished.
482
+ original_trap_proc = trap(:USR1){}
483
+
484
+ log_system_notice "USR1 signal received, calling OverSIP::SystemEvents.on_user_reload() method..."
485
+ # Run OverSIP::SystemEvents.on_user_reload.
486
+ ::Fiber.new do
487
+ begin
488
+ ::OverSIP::SystemEvents.on_user_reload
489
+ rescue ::Exception => e
490
+ log_system_crit "error calling OverSIP::SystemEvents.on_user_reload():"
491
+ log_system_crit e
492
+ end
493
+
494
+ # Reset the signal handler.
495
+ trap :USR1, original_trap_proc
496
+ end.resume
497
+ end
498
+
499
+ end
500
+
501
+
502
+ def self.terminate error=false, fatal=false
503
+ ::OverSIP.is_ready = false
504
+ ::OverSIP.status = :terminating
505
+
506
+ # Trap TERM/QUIT signals (we are already exiting).
507
+ trap(:TERM) {}
508
+ trap(:QUIT) {}
509
+
510
+ ::Fiber.new do
511
+
512
+ unless fatal
513
+ # Run OverSIP::SystemEvents.on_terminated.
514
+ log_system_info "calling OverSIP::SystemEvents.on_terminated() method..."
515
+ begin
516
+ ::OverSIP::SystemEvents.on_terminated error
517
+ rescue ::Exception => e
518
+ log_system_crit "error calling OverSIP::SystemEvents.on_terminated():"
519
+ log_system_crit e
520
+ end
521
+
522
+ # Run all the SystemCallbacks.on_terminated_callbacks in reverse order.
523
+ log_system_info "executing OverSIP::SystemCallbacks.on_terminated_callbacks..."
524
+ ::OverSIP::SystemCallbacks.on_terminated_callbacks.reverse.each do |cb|
525
+ begin
526
+ cb.call error
527
+ rescue ::Exception => e
528
+ log_system_crit "error executing a callback in OverSIP::SystemCallbacks.on_terminated_callbacks:"
529
+ log_system_crit e
530
+ end
531
+ end
532
+ end
533
+
534
+ unless error
535
+ log_system_info "exiting, thank you for tasting #{::OverSIP::PROGRAM_NAME}"
536
+ end
537
+
538
+ # Kill Stud processes and delete its temporal file with the full certificate.
539
+ kill_stud_processes
540
+ ::File.delete ::OverSIP.configuration[:tls][:full_cert] rescue nil
541
+
542
+ delete_pid_file
543
+
544
+ # Exit by preventing any exception.
545
+ exit!( error ? false : true )
546
+
547
+ end.resume
548
+ end
549
+
550
+
551
+ def self.delete_pid_file
552
+ return false unless ::OverSIP.pid
553
+
554
+ ::File.delete(::OverSIP.pid_file) rescue nil
555
+ end
556
+
557
+
558
+ def self.set_user_group user, group
559
+ uid = ::Etc.getpwnam(user).uid if user
560
+ gid = ::Etc.getgrnam(group).gid if group
561
+ if uid or gid
562
+ if gid and ::Process.egid != gid
563
+ ::Process.initgroups(user, gid) if user
564
+ ::Process::GID.change_privilege(gid)
565
+ end
566
+ if uid
567
+ ::Process.euid != uid and ::Process::UID.change_privilege(uid)
568
+ end
569
+ end
570
+ end
571
+
572
+
573
+ def self.spawn_stud_process options, listen_ip, listen_port, bg_ip, bg_port, ssl=false
574
+ stud_user_group = ""
575
+ stud_user_group << "-u #{options[:user]}" if options[:user]
576
+ stud_user_group << " -g #{options[:group]}" if options[:group]
577
+ ssl_option = ( ssl ? "--ssl" : "" )
578
+
579
+ bin_dir = ::File.join(::File.absolute_path(::File.dirname(__FILE__)), "../../bin/")
580
+ stdout_file = "/tmp/stud.#{listen_ip}:#{listen_port}.out"
581
+ stderr_file = "/tmp/stud.#{listen_ip}:#{listen_port}.err"
582
+
583
+ ::Dir.chdir(bin_dir) do
584
+ pid = ::POSIX::Spawn.spawn "./oversip_stud #{stud_user_group} #{ssl_option} -f '#{listen_ip},#{listen_port}' -b '#{bg_ip},#{bg_port}' -n 2 -s --daemon --write-proxy #{::OverSIP.configuration[:tls][:full_cert]}", :out => stdout_file, :err => stderr_file
585
+ ::Process.waitpid(pid)
586
+ end
587
+
588
+ # Get the PID of the daemonized stud process.
589
+ stdout = ::File.read stdout_file
590
+ pid = nil
591
+ stdout.each_line do |line|
592
+ pid = line.split(" ")[4]
593
+ if pid
594
+ pid = pid.gsub(/\./,"").to_i
595
+ break if pid > 0
596
+ end
597
+ end
598
+ ::File.delete stdout_file rescue nil
599
+
600
+ unless pid
601
+ stderr = ::File.read stderr_file
602
+ ::File.delete stderr_file rescue nil
603
+ log_system_crit "error spawning stud server for listening on #{listen_ip} : #{listen_port}:"
604
+ fatal stderr
605
+ end
606
+ ::File.delete stderr_file rescue nil
607
+
608
+ ::OverSIP.stud_pids ||= []
609
+ ::OverSIP.stud_pids << pid
610
+
611
+ log_system_info "spawned stud server (PID #{pid}) listening on #{listen_ip} : #{listen_port}"
612
+ end
613
+
614
+
615
+ def self.kill_stud_processes
616
+ return false unless ::OverSIP.pid
617
+ return false unless ::OverSIP.stud_pids
618
+
619
+ ::OverSIP.stud_pids.each do |pid|
620
+ begin
621
+ log_system_info "killing stud server with PID #{pid}..."
622
+ ::Process.kill(:TERM, pid)
623
+ 10.times do |i|
624
+ sleep 0.05
625
+ ::Process.wait(pid, ::Process::WNOHANG) rescue nil
626
+ ::Process.kill(0, pid) rescue break
627
+ end
628
+ ::Process.kill(0, pid)
629
+ ::Process.kill(:KILL, pid) rescue nil
630
+ rescue ::Errno::ESRCH
631
+ end
632
+ end
633
+ end
634
+
635
+ end