oversip 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. data/AUTHORS.txt +11 -0
  2. data/LICENSE.txt +22 -0
  3. data/README.md +16 -0
  4. data/Rakefile +55 -0
  5. data/bin/oversip +182 -0
  6. data/ext/common/c_util.h +74 -0
  7. data/ext/common/ruby_c_util.h +88 -0
  8. data/ext/sip_parser/common_headers.h +209 -0
  9. data/ext/sip_parser/ext_help.h +18 -0
  10. data/ext/sip_parser/extconf.rb +3 -0
  11. data/ext/sip_parser/sip_parser.c +29649 -0
  12. data/ext/sip_parser/sip_parser.h +227 -0
  13. data/ext/sip_parser/sip_parser_ruby.c +1292 -0
  14. data/ext/stud/extconf.rb +27 -0
  15. data/ext/stud/stud.tar.gz +0 -0
  16. data/ext/stun/ext_help.h +16 -0
  17. data/ext/stun/extconf.rb +3 -0
  18. data/ext/stun/stun_ruby.c +391 -0
  19. data/ext/utils/ext_help.h +14 -0
  20. data/ext/utils/extconf.rb +3 -0
  21. data/ext/utils/haproxy_protocol.c +6163 -0
  22. data/ext/utils/haproxy_protocol.h +27 -0
  23. data/ext/utils/ip_utils.c +5952 -0
  24. data/ext/utils/ip_utils.h +61 -0
  25. data/ext/utils/outbound_utils.c +3227 -0
  26. data/ext/utils/outbound_utils.h +27 -0
  27. data/ext/utils/utils_ruby.c +384 -0
  28. data/ext/utils/utils_ruby.h +75 -0
  29. data/ext/websocket_framing_utils/ext_help.h +18 -0
  30. data/ext/websocket_framing_utils/extconf.rb +3 -0
  31. data/ext/websocket_framing_utils/ws_framing_utils.h +46 -0
  32. data/ext/websocket_framing_utils/ws_framing_utils_ruby.c +135 -0
  33. data/ext/websocket_http_parser/ext_help.h +18 -0
  34. data/ext/websocket_http_parser/extconf.rb +3 -0
  35. data/ext/websocket_http_parser/ws_http_parser.c +2598 -0
  36. data/ext/websocket_http_parser/ws_http_parser.h +86 -0
  37. data/ext/websocket_http_parser/ws_http_parser_ruby.c +630 -0
  38. data/lib/oversip/config.rb +541 -0
  39. data/lib/oversip/config_validators.rb +126 -0
  40. data/lib/oversip/errors.rb +7 -0
  41. data/lib/oversip/fiber_pool.rb +56 -0
  42. data/lib/oversip/launcher.rb +507 -0
  43. data/lib/oversip/logger.rb +170 -0
  44. data/lib/oversip/master_process.rb +67 -0
  45. data/lib/oversip/posix_mq.rb +121 -0
  46. data/lib/oversip/proxies_config.rb +169 -0
  47. data/lib/oversip/ruby_ext/eventmachine.rb +38 -0
  48. data/lib/oversip/sip/client_transaction.rb +587 -0
  49. data/lib/oversip/sip/constants.rb +87 -0
  50. data/lib/oversip/sip/grammar/name_addr.rb +27 -0
  51. data/lib/oversip/sip/grammar/uri.rb +116 -0
  52. data/lib/oversip/sip/launcher.rb +180 -0
  53. data/lib/oversip/sip/listeners/ipv4_tcp_client.rb +21 -0
  54. data/lib/oversip/sip/listeners/ipv4_tcp_server.rb +21 -0
  55. data/lib/oversip/sip/listeners/ipv4_tls_client.rb +21 -0
  56. data/lib/oversip/sip/listeners/ipv4_tls_server.rb +21 -0
  57. data/lib/oversip/sip/listeners/ipv4_tls_tunnel_server.rb +21 -0
  58. data/lib/oversip/sip/listeners/ipv4_udp_server.rb +20 -0
  59. data/lib/oversip/sip/listeners/ipv6_tcp_client.rb +21 -0
  60. data/lib/oversip/sip/listeners/ipv6_tcp_server.rb +21 -0
  61. data/lib/oversip/sip/listeners/ipv6_tls_client.rb +21 -0
  62. data/lib/oversip/sip/listeners/ipv6_tls_server.rb +21 -0
  63. data/lib/oversip/sip/listeners/ipv6_tls_tunnel_server.rb +21 -0
  64. data/lib/oversip/sip/listeners/ipv6_udp_server.rb +20 -0
  65. data/lib/oversip/sip/listeners/reactor.rb +39 -0
  66. data/lib/oversip/sip/listeners/tcp_client.rb +73 -0
  67. data/lib/oversip/sip/listeners/tcp_reactor.rb +185 -0
  68. data/lib/oversip/sip/listeners/tcp_server.rb +71 -0
  69. data/lib/oversip/sip/listeners/tls_client.rb +117 -0
  70. data/lib/oversip/sip/listeners/tls_server.rb +70 -0
  71. data/lib/oversip/sip/listeners/tls_tunnel_reactor.rb +113 -0
  72. data/lib/oversip/sip/listeners/tls_tunnel_server.rb +61 -0
  73. data/lib/oversip/sip/listeners/udp_reactor.rb +213 -0
  74. data/lib/oversip/sip/listeners.rb +28 -0
  75. data/lib/oversip/sip/logic.rb +14 -0
  76. data/lib/oversip/sip/message.rb +168 -0
  77. data/lib/oversip/sip/message_processor.rb +202 -0
  78. data/lib/oversip/sip/modules/core.rb +200 -0
  79. data/lib/oversip/sip/modules/registrar_without_path.rb +75 -0
  80. data/lib/oversip/sip/modules/user_assertion.rb +123 -0
  81. data/lib/oversip/sip/proxy.rb +460 -0
  82. data/lib/oversip/sip/request.rb +128 -0
  83. data/lib/oversip/sip/response.rb +30 -0
  84. data/lib/oversip/sip/rfc3263.rb +646 -0
  85. data/lib/oversip/sip/server_transaction.rb +295 -0
  86. data/lib/oversip/sip/sip.rb +74 -0
  87. data/lib/oversip/sip/tags.rb +39 -0
  88. data/lib/oversip/sip/timers.rb +55 -0
  89. data/lib/oversip/sip/transport_manager.rb +129 -0
  90. data/lib/oversip/syslogger_process.rb +119 -0
  91. data/lib/oversip/tls.rb +179 -0
  92. data/lib/oversip/utils.rb +25 -0
  93. data/lib/oversip/version.rb +23 -0
  94. data/lib/oversip/websocket/constants.rb +56 -0
  95. data/lib/oversip/websocket/default_policy.rb +19 -0
  96. data/lib/oversip/websocket/http_request.rb +63 -0
  97. data/lib/oversip/websocket/launcher.rb +207 -0
  98. data/lib/oversip/websocket/listeners/ipv4_tcp_server.rb +15 -0
  99. data/lib/oversip/websocket/listeners/ipv4_tls_server.rb +15 -0
  100. data/lib/oversip/websocket/listeners/ipv4_tls_tunnel_server.rb +15 -0
  101. data/lib/oversip/websocket/listeners/ipv6_tcp_server.rb +15 -0
  102. data/lib/oversip/websocket/listeners/ipv6_tls_server.rb +15 -0
  103. data/lib/oversip/websocket/listeners/ipv6_tls_tunnel_server.rb +15 -0
  104. data/lib/oversip/websocket/listeners/tcp_server.rb +265 -0
  105. data/lib/oversip/websocket/listeners/tls_server.rb +69 -0
  106. data/lib/oversip/websocket/listeners/tls_tunnel_server.rb +100 -0
  107. data/lib/oversip/websocket/listeners.rb +12 -0
  108. data/lib/oversip/websocket/ws_app.rb +75 -0
  109. data/lib/oversip/websocket/ws_apps/ipv4_ws_sip_app.rb +21 -0
  110. data/lib/oversip/websocket/ws_apps/ipv4_wss_sip_app.rb +21 -0
  111. data/lib/oversip/websocket/ws_apps/ipv6_ws_sip_app.rb +21 -0
  112. data/lib/oversip/websocket/ws_apps/ipv6_wss_sip_app.rb +22 -0
  113. data/lib/oversip/websocket/ws_apps/ws_autobahn_app.rb +23 -0
  114. data/lib/oversip/websocket/ws_apps/ws_sip_app.rb +156 -0
  115. data/lib/oversip/websocket/ws_apps.rb +9 -0
  116. data/lib/oversip/websocket/ws_framing.rb +597 -0
  117. data/lib/oversip.rb +59 -0
  118. data/test/oversip_test_helper.rb +20 -0
  119. data/test/test_http_parser.rb +73 -0
  120. data/test/test_sip_parser.rb +139 -0
  121. metadata +256 -0
@@ -0,0 +1,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