oversip_p 1.0.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 (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