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,56 @@
1
+ # NOTE: Extracted from https://github.com/schmurfy/fiber_pool.
2
+
3
+ module OverSIP
4
+ class FiberPool
5
+
6
+ # Prepare a list of fibers that are able to run different blocks of code
7
+ # every time. Once a fiber is done with its block, it attempts to fetch
8
+ # another one from the queue.
9
+ def initialize count = 100
10
+ @fibers,@busy_fibers,@queue = [],{},[]
11
+
12
+ count.times do |i|
13
+ add_fiber()
14
+ end
15
+ end
16
+
17
+ def add_fiber
18
+ fiber = ::Fiber.new do |block|
19
+ loop do
20
+ block.call
21
+ unless @queue.empty?
22
+ block = @queue.shift
23
+ else
24
+ @busy_fibers.delete ::Fiber.current.object_id
25
+ @fibers.unshift ::Fiber.current
26
+ block = ::Fiber.yield
27
+ end
28
+ end
29
+ end
30
+
31
+ @fibers << fiber
32
+ fiber
33
+ end
34
+ private :add_fiber
35
+
36
+ # If there is an available fiber use it, otherwise, leave it to linger
37
+ # in a queue.
38
+ def spawn &block
39
+ # resurrect dead fibers
40
+ @busy_fibers.values.reject(&:alive?).each do |f|
41
+ @busy_fibers.delete f.object_id
42
+ add_fiber()
43
+ end
44
+
45
+ if (fiber = @fibers.shift)
46
+ @busy_fibers[fiber.object_id] = fiber
47
+ fiber.resume block
48
+ else
49
+ @queue << block
50
+ end
51
+
52
+ fiber
53
+ end
54
+
55
+ end # class FiberPool
56
+ end
@@ -0,0 +1,507 @@
1
+ module OverSIP::Launcher
2
+
3
+ extend ::OverSIP::Logger
4
+
5
+ READY_PIPE_TIMEOUT = 6
6
+
7
+ @log_id = "launcher"
8
+
9
+
10
+ def self.daemonize!(options)
11
+ $stdin.reopen("/dev/null")
12
+
13
+ # grandparent (launcher) : Reads pipe, exits when master is ready.
14
+ # \_ parent : Exits immediately ASAP.
15
+ # \_ master : Writes to pipe when ready.
16
+
17
+ rd, wr = IO.pipe
18
+ grandparent = $$
19
+ if fork
20
+ wr.close # Grandparent does not write in the ready_pipe.
21
+ else
22
+ rd.close # Parent (so also future master) does not read from the ready_pipe.
23
+ ::Process.setsid
24
+ exit if fork # Parent dies now.
25
+ end
26
+
27
+ # I'm grandparent (launcher) process.
28
+ if grandparent == $$
29
+ # Master process will inmediatelly write in the ready_pipe its PID so we get
30
+ # its PID.
31
+ master_pid = nil
32
+ begin
33
+ ::Timeout::timeout(READY_PIPE_TIMEOUT/2) do
34
+ master_pid = rd.gets("\n").to_i rescue nil
35
+ end
36
+ rescue ::Timeout::Error
37
+ fatal "master process didn't notify its PID within #{READY_PIPE_TIMEOUT/2} seconds"
38
+ end
39
+ unless master_pid
40
+ fatal "master process failed to start"
41
+ end
42
+
43
+ # This will block until OverSIP::Launcher.run ends succesfully (so master process
44
+ # writes "ok" in the ready_pipe) or until the pipe is closes without writting into it
45
+ # (so the master process has died).
46
+ # It can also occur that master process blocks forever and never writes into the
47
+ # ready pipe neither closes it. In this case a timeout is raised and master process
48
+ # is killed.
49
+ master_ok = nil
50
+ begin
51
+ ::Timeout::timeout(READY_PIPE_TIMEOUT/2) do
52
+ master_ok = (rd.read(2) rescue nil)
53
+ end
54
+ rescue ::Timeout::Error
55
+ begin
56
+ ::Process.kill(:TERM, master_pid)
57
+ 10.times do |i|
58
+ sleep 0.05
59
+ ::Process.wait(master_pid, ::Process::WNOHANG) rescue nil
60
+ ::Process.kill(0, master_pid) rescue break
61
+ end
62
+ ::Process.kill(0, master_pid)
63
+ ::Process.kill(:KILL, master_pid) rescue nil
64
+ rescue ::Errno::ESRCH
65
+ end
66
+ fatal "master process is not ready within #{READY_PIPE_TIMEOUT/2} seconds, killing it"
67
+ end
68
+ unless master_ok == "ok"
69
+ fatal "master process failed to start"
70
+ end
71
+
72
+ # Grandparent can die now with honor.
73
+ exit 0
74
+
75
+ # I'm master process.
76
+ else
77
+ options[:ready_pipe] = wr
78
+ end
79
+ end
80
+
81
+
82
+ def self.run(options)
83
+ configuration = ::OverSIP.configuration
84
+
85
+ # Store the master process PID.
86
+ ::OverSIP.master_pid = $$
87
+
88
+ begin
89
+ # Inmediatelly write into the ready_pipe so grandparent process reads it
90
+ # and knowns which PID we have.
91
+ ready_pipe = options.delete(:ready_pipe)
92
+ ready_pipe.write($$.to_s + "\n") if ready_pipe
93
+
94
+ # I'm master process.
95
+ if syslogger_pid = fork
96
+ ::OverSIP.syslogger_pid = syslogger_pid
97
+ log_system_info "starting syslogger process (PID #{syslogger_pid})..."
98
+ ::OverSIP::Logger.load_methods
99
+
100
+ # Load all the libraries for the master process.
101
+ require "oversip/master_process.rb"
102
+
103
+ ::OverSIP::TLS.module_init
104
+ ::OverSIP::SIP.module_init
105
+ ::OverSIP::SIP::RFC3263.module_init
106
+ ::OverSIP::WebSocket::WsFraming.class_init
107
+ ::OverSIP::WebSocket::WsApp.class_init
108
+
109
+ # I'm the sysloger process.
110
+ else
111
+ # Close the pipe in the syslogger process.
112
+ ready_pipe.close rescue nil
113
+ ready_pipe = nil
114
+
115
+ require "oversip/syslogger_process.rb"
116
+ ::OverSIP::SysLoggerProcess.run options
117
+ exit
118
+ end
119
+
120
+ ::EM.run do
121
+
122
+ log_system_info "using Ruby #{RUBY_VERSION}p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE} revision #{RUBY_REVISION}) [#{RUBY_PLATFORM}]"
123
+ log_system_info "using EventMachine-LE #{::EM::VERSION}"
124
+ log_system_info "starting event reactor..."
125
+
126
+ # DNS resolver.
127
+ ::OverSIP::SIP::RFC3263.run
128
+
129
+ if configuration[:sip][:sip_udp]
130
+ # SIP UDP IPv4 server.
131
+ if configuration[:sip][:enable_ipv4]
132
+ ::OverSIP::SIP::Launcher.run true, :ipv4, configuration[:sip][:listen_ipv4],
133
+ configuration[:sip][:listen_port], :udp
134
+ end
135
+
136
+ # SIP IPv6 UDP server.
137
+ if configuration[:sip][:enable_ipv6]
138
+ ::OverSIP::SIP::Launcher.run true, :ipv6, configuration[:sip][:listen_ipv6],
139
+ configuration[:sip][:listen_port], :udp
140
+ end
141
+ end
142
+
143
+ if configuration[:sip][:sip_tcp]
144
+ # SIP IPv4 TCP server.
145
+ if configuration[:sip][:enable_ipv4]
146
+ ::OverSIP::SIP::Launcher.run true, :ipv4, configuration[:sip][:listen_ipv4],
147
+ configuration[:sip][:listen_port], :tcp
148
+ end
149
+
150
+ # SIP IPv6 TCP server.
151
+ if configuration[:sip][:enable_ipv6]
152
+ ::OverSIP::SIP::Launcher.run true, :ipv6, configuration[:sip][:listen_ipv6],
153
+ configuration[:sip][:listen_port], :tcp
154
+ end
155
+ end
156
+
157
+ if configuration[:sip][:sip_tls]
158
+ unless configuration[:sip][:use_tls_tunnel]
159
+ # SIP IPv4 TLS server (native).
160
+ if configuration[:sip][:enable_ipv4]
161
+ ::OverSIP::SIP::Launcher.run true, :ipv4, configuration[:sip][:listen_ipv4],
162
+ configuration[:sip][:listen_port_tls], :tls
163
+ end
164
+
165
+ # SIP IPv6 TLS server (native).
166
+ if configuration[:sip][:enable_ipv6]
167
+ ::OverSIP::SIP::Launcher.run true, :ipv6, configuration[:sip][:listen_ipv6],
168
+ configuration[:sip][:listen_port_tls], :tls
169
+ end
170
+ else
171
+ # SIP IPv4 TLS server (Stud).
172
+ if configuration[:sip][:enable_ipv4]
173
+ ::OverSIP::SIP::Launcher.run true, :ipv4, "127.0.0.1",
174
+ configuration[:sip][:listen_port_tls_tunnel], :tls_tunnel,
175
+ configuration[:sip][:listen_ipv4],
176
+ configuration[:sip][:listen_port_tls]
177
+ ::OverSIP::SIP::Launcher.run false, :ipv4, configuration[:sip][:listen_ipv4],
178
+ configuration[:sip][:listen_port_tls], :tls
179
+
180
+ # Spawn a Stud process.
181
+ spawn_stud_process options,
182
+ configuration[:sip][:listen_ipv4], configuration[:sip][:listen_port_tls],
183
+ "127.0.0.1", configuration[:sip][:listen_port_tls_tunnel],
184
+ ssl = false
185
+ end
186
+
187
+ # SIP IPv6 TLS server (Stud).
188
+ if configuration[:sip][:enable_ipv6]
189
+ ::OverSIP::SIP::Launcher.run true, :ipv6, "::1",
190
+ configuration[:sip][:listen_port_tls_tunnel], :tls_tunnel,
191
+ configuration[:sip][:listen_ipv6],
192
+ configuration[:sip][:listen_port_tls]
193
+ ::OverSIP::SIP::Launcher.run false, :ipv6, configuration[:sip][:listen_ipv6],
194
+ configuration[:sip][:listen_port_tls], :tls
195
+
196
+ # Spawn a Stud process.
197
+ spawn_stud_process options,
198
+ configuration[:sip][:listen_ipv6], configuration[:sip][:listen_port_tls],
199
+ "::1", configuration[:sip][:listen_port_tls_tunnel],
200
+ ssl = false
201
+ end
202
+ end
203
+ end
204
+
205
+ if configuration[:websocket][:sip_ws]
206
+ # WebSocket IPv4 TCP SIP server.
207
+ if configuration[:websocket][:enable_ipv4]
208
+ ::OverSIP::WebSocket::Launcher.run true, :ipv4, configuration[:websocket][:listen_ipv4],
209
+ configuration[:websocket][:listen_port], :tcp,
210
+ ::OverSIP::WebSocket::WS_SIP_PROTOCOL
211
+ end
212
+
213
+ # WebSocket IPv6 TCP SIP server.
214
+ if configuration[:websocket][:enable_ipv6]
215
+ ::OverSIP::WebSocket::Launcher.run true, :ipv6, configuration[:websocket][:listen_ipv6],
216
+ configuration[:websocket][:listen_port], :tcp,
217
+ ::OverSIP::WebSocket::WS_SIP_PROTOCOL
218
+ end
219
+ end
220
+
221
+ if configuration[:websocket][:sip_wss]
222
+ unless configuration[:websocket][:use_tls_tunnel]
223
+ # WebSocket IPv4 TLS SIP server (native).
224
+ if configuration[:websocket][:enable_ipv4]
225
+ ::OverSIP::WebSocket::Launcher.run true, :ipv4, configuration[:websocket][:listen_ipv4],
226
+ configuration[:websocket][:listen_port_tls], :tls,
227
+ ::OverSIP::WebSocket::WS_SIP_PROTOCOL
228
+ end
229
+
230
+ # WebSocket IPv6 TLS SIP server (native).
231
+ if configuration[:websocket][:enable_ipv6]
232
+ ::OverSIP::WebSocket::Launcher.run true, :ipv6, configuration[:websocket][:listen_ipv6],
233
+ configuration[:websocket][:listen_port_tls], :tls,
234
+ ::OverSIP::WebSocket::WS_SIP_PROTOCOL
235
+ end
236
+ else
237
+ # WebSocket IPv4 TLS SIP server (Stud).
238
+ if configuration[:websocket][:enable_ipv4]
239
+ ::OverSIP::WebSocket::Launcher.run true, :ipv4, "127.0.0.1",
240
+ configuration[:websocket][:listen_port_tls_tunnel], :tls_tunnel,
241
+ ::OverSIP::WebSocket::WS_SIP_PROTOCOL,
242
+ configuration[:websocket][:listen_ipv4],
243
+ configuration[:websocket][:listen_port_tls]
244
+ ::OverSIP::WebSocket::Launcher.run false, :ipv4, configuration[:websocket][:listen_ipv4],
245
+ configuration[:websocket][:listen_port_tls], :tls,
246
+ ::OverSIP::WebSocket::WS_SIP_PROTOCOL
247
+
248
+ # Spawn a Stud process.
249
+ spawn_stud_process options,
250
+ configuration[:websocket][:listen_ipv4], configuration[:websocket][:listen_port_tls],
251
+ "127.0.0.1", configuration[:websocket][:listen_port_tls_tunnel],
252
+ ssl = true
253
+ end
254
+
255
+ # WebSocket IPv6 TLS SIP server (Stud).
256
+ if configuration[:sip][:enable_ipv6]
257
+ ::OverSIP::WebSocket::Launcher.run true, :ipv6, "::1",
258
+ configuration[:websocket][:listen_port_tls_tunnel], :tls_tunnel,
259
+ ::OverSIP::WebSocket::WS_SIP_PROTOCOL,
260
+ configuration[:websocket][:listen_ipv6],
261
+ configuration[:websocket][:listen_port_tls]
262
+ ::OverSIP::WebSocket::Launcher.run false, :ipv6, configuration[:websocket][:listen_ipv6],
263
+ configuration[:websocket][:listen_port_tls], :tls,
264
+ ::OverSIP::WebSocket::WS_SIP_PROTOCOL
265
+
266
+ # Spawn a Stud process.
267
+ spawn_stud_process options,
268
+ configuration[:websocket][:listen_ipv6], configuration[:websocket][:listen_port_tls],
269
+ "::1", configuration[:websocket][:listen_port_tls_tunnel],
270
+ ssl = true
271
+ end
272
+ end
273
+ end
274
+
275
+
276
+ # TEST: WebSocket Autobahn server.
277
+ #if configuration[:websocket][:sip_ws]
278
+ # if configuration[:websocket][:enable_ipv4]
279
+ # ::OverSIP::WebSocket::Launcher.run true, :ipv4, configuration[:websocket][:listen_ipv4],
280
+ # 9001, :tcp,
281
+ # ::OverSIP::WebSocket::WS_AUTOBAHN_PROTOCOL
282
+ # end
283
+ #end
284
+ #
285
+ #if configuration[:websocket][:sip_wss]
286
+ # if configuration[:websocket][:enable_ipv4]
287
+ # ::OverSIP::WebSocket::Launcher.run true, :ipv4, configuration[:websocket][:listen_ipv4],
288
+ # 9002, :tls,
289
+ # ::OverSIP::WebSocket::WS_AUTOBAHN_PROTOCOL
290
+ # end
291
+ #end
292
+
293
+
294
+ # Change process permissions if requested.
295
+ set_user_group(options[:user], options[:group])
296
+
297
+ # Create PID file.
298
+ create_pid_file(options[:pid_file])
299
+
300
+ log_system_info "reactor running"
301
+ log_system_info "master process (PID #{$$}) ready"
302
+ log_system_info "#{::OverSIP::PROGRAM_NAME} #{::OverSIP::VERSION} running in background"
303
+
304
+ # Write "ok" into the ready_pipe so grandparent process (launcher)
305
+ # exits with status 0.
306
+ if ready_pipe
307
+ ready_pipe.write("ok")
308
+ ready_pipe.close rescue nil
309
+ ready_pipe = nil
310
+ end
311
+
312
+ # Stop writting into standard output/error.
313
+ $stdout.reopen("/dev/null")
314
+ $stderr.reopen("/dev/null")
315
+ ::OverSIP.daemonized = true
316
+
317
+ ::OverSIP::Logger.load_methods
318
+
319
+ ::EM.error_handler do |e|
320
+ log_system_error "error raised during event loop and rescued by EM.error_handler:"
321
+ log_system_error e
322
+ end
323
+
324
+ trap_signals
325
+
326
+ end # ::EM.run
327
+
328
+ rescue => e
329
+ fatal e
330
+ end
331
+
332
+ end # def self.run
333
+
334
+
335
+ def self.create_pid_file(path)
336
+ # Check that the PID file is accesible.
337
+ begin
338
+ assert_file_is_writable_readable_deletable(path)
339
+ rescue ::OverSIP::Error => e
340
+ fatal "cannot create PID file: #{e.message}"
341
+ end
342
+ # If the PID file exists (it shouldn't) check if it's stale.
343
+ if wpid = valid_pid?(path) and wpid != $$
344
+ fatal "already running on PID #{wpid} (or '#{path}' is stale)"
345
+ end
346
+ # Delete the PID file if it exists.
347
+ ::File.unlink(path) rescue nil
348
+ # Create the PID file.
349
+ ::File.open(path, "w", 0644) do |f|
350
+ f.syswrite("#$$\n")
351
+ end
352
+ ::OverSIP.pid_file = path
353
+ end
354
+
355
+
356
+ def self.assert_file_is_writable_readable_deletable(path)
357
+ # File already exists.
358
+ if ::File.exist?(path)
359
+ if not ::File.file?(path)
360
+ raise ::OverSIP::Error, "'#{path}' exits and is not a regular file"
361
+ elsif not ::File.readable?(path)
362
+ raise ::OverSIP::Error, "'#{path}' is not readable"
363
+ elsif not ::File.writable?(path)
364
+ raise ::OverSIP::Error, "'#{path}' is not writable"
365
+ end
366
+ end
367
+ # Check if the parent directory is writeable.
368
+ if not ::File.writable? ::File.dirname(path)
369
+ raise ::OverSIP::Error, "directory '#{::File.dirname(path)}' is not writable"
370
+ end
371
+ end
372
+
373
+
374
+ # Returns a PID if a given path contains a non-stale PID file,
375
+ # false otherwise.
376
+ def self.valid_pid?(path)
377
+ begin
378
+ wpid = ::File.read(path).to_i
379
+ wpid <= 0 and return false
380
+ # If the process exists return its PID.
381
+ ::Process.kill(0, wpid)
382
+ return wpid
383
+ # If the process exists but we don't have permissions over it, return its PID.
384
+ rescue ::Errno::EPERM
385
+ return wpid
386
+ # If the PID file (path) doesn't exist or the process is not running return false.
387
+ rescue ::Errno::ENOENT, ::Errno::ESRCH
388
+ return false
389
+ end
390
+ end
391
+
392
+
393
+ def self.trap_signals
394
+ # This should never occur, but maybe if I've missed trapping a signal.
395
+ at_exit do
396
+ log_system_crit "exiting due to an unknown cause ($! = #{$!.inspect})..."
397
+ terminate
398
+ end
399
+
400
+ # Signals that cause OverSIP to terminate.
401
+ exit_signals = [:TERM, :QUIT]
402
+ exit_signals.each do |signal|
403
+ trap signal do
404
+ log_system_notice "#{signal} signal received, exiting..."
405
+ terminate
406
+ end
407
+ end
408
+
409
+ # Signals that must be ignored.
410
+ ignore_signals = [:ALRM, :INT, :PIPE, :POLL, :PROF, :USR1, :USR2, :VTALRM, :WINCH]
411
+ ignore_signals.each do |signal|
412
+ begin
413
+ trap signal do
414
+ log_system_notice "#{signal.to_s.upcase} signal received, ignored"
415
+ end
416
+ rescue ::ArgumentError
417
+ log_system_notice "cannot trap signal #{signal.to_s.upcase}, it could not exist in this system, ignoring it"
418
+ end
419
+ end
420
+
421
+ # Signal HUP reloads logic.
422
+ # TODO: Reload proxies (so purge DNS cache in all of them), reload websocket policy.
423
+ trap :HUP do
424
+ log_system_info "HUP signal received, reloading logic..."
425
+ ::OverSIP::Config.reload_logic
426
+ end
427
+
428
+ # Signal CHLD is sent by syslogger process if it dies.
429
+ trap :CHLD do
430
+ # TODO: This won't be logged since syslogger process has died!
431
+ log_system_crit "CHLD signal received, syslogger process could be death"
432
+ end
433
+ end
434
+
435
+ def self.terminate error=false
436
+ unless error
437
+ log_system_info "exiting, thank you for tasting #{::OverSIP::PROGRAM_NAME}"
438
+ end
439
+
440
+ # Wait a bit so pending log messages in the Posix MQ can be queued.
441
+ sleep 0.05
442
+ delete_pid_file
443
+ ::OverSIP::Logger.close
444
+ kill_syslogger_process
445
+
446
+ # Kill Stud processes.
447
+ pid = Process.spawn "killall oversip_stud 2>/dev/null"
448
+ Process.wait(pid)
449
+
450
+ # Exit by preventing any exception.
451
+ exit!( error ? false : true )
452
+ end
453
+
454
+
455
+ def self.delete_pid_file
456
+ return false unless ::OverSIP.master_pid
457
+
458
+ ::File.delete(::OverSIP.pid_file) rescue nil
459
+ end
460
+
461
+
462
+ def self.kill_syslogger_process
463
+ return false unless ::OverSIP.master_pid
464
+
465
+ begin
466
+ ::Process.kill(:TERM, ::OverSIP.syslogger_pid)
467
+ 10.times do |i|
468
+ sleep 0.05
469
+ ::Process.wait(::OverSIP.syslogger_pid, ::Process::WNOHANG) rescue nil
470
+ ::Process.kill(0, ::OverSIP.syslogger_pid) rescue break
471
+ end
472
+ ::Process.kill(0, ::OverSIP.syslogger_pid)
473
+ ::Process.kill(:KILL, ::OverSIP.syslogger_pid) rescue nil
474
+ rescue ::Errno::ESRCH
475
+ end
476
+ end
477
+
478
+
479
+ def self.set_user_group(user, group)
480
+ uid = ::Etc.getpwnam(user).uid if user
481
+ gid = ::Etc.getgrnam(group).gid if group
482
+ if uid or gid
483
+ if gid && ::Process.egid != gid
484
+ ::Process.initgroups(user, gid) if user
485
+ ::Process::GID.change_privilege(gid)
486
+ end
487
+ if uid
488
+ ::Process.euid != uid and ::Process::UID.change_privilege(uid)
489
+ end
490
+ end
491
+ end
492
+
493
+
494
+ def self.spawn_stud_process(options, listen_ip, listen_port, bg_ip, bg_port, ssl=false)
495
+ stud_user_group = ""
496
+ stud_user_group << "-u #{options[:user]}" if options[:user]
497
+ stud_user_group << " -g #{options[:group]}" if options[:group]
498
+ ssl_option = ( ssl ? "--ssl" : "" )
499
+
500
+ bin_dir = ::File.join(::File.absolute_path(::File.dirname(__FILE__)), "../../bin/")
501
+ Dir.chdir(bin_dir) do
502
+ 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]}"
503
+ Process.waitpid(pid)
504
+ end
505
+ end
506
+
507
+ end