oversip 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS.txt +11 -0
- data/LICENSE.txt +22 -0
- data/README.md +16 -0
- data/Rakefile +55 -0
- data/bin/oversip +182 -0
- data/ext/common/c_util.h +74 -0
- data/ext/common/ruby_c_util.h +88 -0
- data/ext/sip_parser/common_headers.h +209 -0
- data/ext/sip_parser/ext_help.h +18 -0
- data/ext/sip_parser/extconf.rb +3 -0
- data/ext/sip_parser/sip_parser.c +29649 -0
- data/ext/sip_parser/sip_parser.h +227 -0
- data/ext/sip_parser/sip_parser_ruby.c +1292 -0
- data/ext/stud/extconf.rb +27 -0
- data/ext/stud/stud.tar.gz +0 -0
- data/ext/stun/ext_help.h +16 -0
- data/ext/stun/extconf.rb +3 -0
- data/ext/stun/stun_ruby.c +391 -0
- data/ext/utils/ext_help.h +14 -0
- data/ext/utils/extconf.rb +3 -0
- data/ext/utils/haproxy_protocol.c +6163 -0
- data/ext/utils/haproxy_protocol.h +27 -0
- data/ext/utils/ip_utils.c +5952 -0
- data/ext/utils/ip_utils.h +61 -0
- data/ext/utils/outbound_utils.c +3227 -0
- data/ext/utils/outbound_utils.h +27 -0
- data/ext/utils/utils_ruby.c +384 -0
- data/ext/utils/utils_ruby.h +75 -0
- data/ext/websocket_framing_utils/ext_help.h +18 -0
- data/ext/websocket_framing_utils/extconf.rb +3 -0
- data/ext/websocket_framing_utils/ws_framing_utils.h +46 -0
- data/ext/websocket_framing_utils/ws_framing_utils_ruby.c +135 -0
- data/ext/websocket_http_parser/ext_help.h +18 -0
- data/ext/websocket_http_parser/extconf.rb +3 -0
- data/ext/websocket_http_parser/ws_http_parser.c +2598 -0
- data/ext/websocket_http_parser/ws_http_parser.h +86 -0
- data/ext/websocket_http_parser/ws_http_parser_ruby.c +630 -0
- data/lib/oversip/config.rb +541 -0
- data/lib/oversip/config_validators.rb +126 -0
- data/lib/oversip/errors.rb +7 -0
- data/lib/oversip/fiber_pool.rb +56 -0
- data/lib/oversip/launcher.rb +507 -0
- data/lib/oversip/logger.rb +170 -0
- data/lib/oversip/master_process.rb +67 -0
- data/lib/oversip/posix_mq.rb +121 -0
- data/lib/oversip/proxies_config.rb +169 -0
- data/lib/oversip/ruby_ext/eventmachine.rb +38 -0
- data/lib/oversip/sip/client_transaction.rb +587 -0
- data/lib/oversip/sip/constants.rb +87 -0
- data/lib/oversip/sip/grammar/name_addr.rb +27 -0
- data/lib/oversip/sip/grammar/uri.rb +116 -0
- data/lib/oversip/sip/launcher.rb +180 -0
- data/lib/oversip/sip/listeners/ipv4_tcp_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tcp_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tls_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tls_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tls_tunnel_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_udp_server.rb +20 -0
- data/lib/oversip/sip/listeners/ipv6_tcp_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tcp_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tls_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tls_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tls_tunnel_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_udp_server.rb +20 -0
- data/lib/oversip/sip/listeners/reactor.rb +39 -0
- data/lib/oversip/sip/listeners/tcp_client.rb +73 -0
- data/lib/oversip/sip/listeners/tcp_reactor.rb +185 -0
- data/lib/oversip/sip/listeners/tcp_server.rb +71 -0
- data/lib/oversip/sip/listeners/tls_client.rb +117 -0
- data/lib/oversip/sip/listeners/tls_server.rb +70 -0
- data/lib/oversip/sip/listeners/tls_tunnel_reactor.rb +113 -0
- data/lib/oversip/sip/listeners/tls_tunnel_server.rb +61 -0
- data/lib/oversip/sip/listeners/udp_reactor.rb +213 -0
- data/lib/oversip/sip/listeners.rb +28 -0
- data/lib/oversip/sip/logic.rb +14 -0
- data/lib/oversip/sip/message.rb +168 -0
- data/lib/oversip/sip/message_processor.rb +202 -0
- data/lib/oversip/sip/modules/core.rb +200 -0
- data/lib/oversip/sip/modules/registrar_without_path.rb +75 -0
- data/lib/oversip/sip/modules/user_assertion.rb +123 -0
- data/lib/oversip/sip/proxy.rb +460 -0
- data/lib/oversip/sip/request.rb +128 -0
- data/lib/oversip/sip/response.rb +30 -0
- data/lib/oversip/sip/rfc3263.rb +646 -0
- data/lib/oversip/sip/server_transaction.rb +295 -0
- data/lib/oversip/sip/sip.rb +74 -0
- data/lib/oversip/sip/tags.rb +39 -0
- data/lib/oversip/sip/timers.rb +55 -0
- data/lib/oversip/sip/transport_manager.rb +129 -0
- data/lib/oversip/syslogger_process.rb +119 -0
- data/lib/oversip/tls.rb +179 -0
- data/lib/oversip/utils.rb +25 -0
- data/lib/oversip/version.rb +23 -0
- data/lib/oversip/websocket/constants.rb +56 -0
- data/lib/oversip/websocket/default_policy.rb +19 -0
- data/lib/oversip/websocket/http_request.rb +63 -0
- data/lib/oversip/websocket/launcher.rb +207 -0
- data/lib/oversip/websocket/listeners/ipv4_tcp_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv4_tls_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv4_tls_tunnel_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv6_tcp_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv6_tls_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv6_tls_tunnel_server.rb +15 -0
- data/lib/oversip/websocket/listeners/tcp_server.rb +265 -0
- data/lib/oversip/websocket/listeners/tls_server.rb +69 -0
- data/lib/oversip/websocket/listeners/tls_tunnel_server.rb +100 -0
- data/lib/oversip/websocket/listeners.rb +12 -0
- data/lib/oversip/websocket/ws_app.rb +75 -0
- data/lib/oversip/websocket/ws_apps/ipv4_ws_sip_app.rb +21 -0
- data/lib/oversip/websocket/ws_apps/ipv4_wss_sip_app.rb +21 -0
- data/lib/oversip/websocket/ws_apps/ipv6_ws_sip_app.rb +21 -0
- data/lib/oversip/websocket/ws_apps/ipv6_wss_sip_app.rb +22 -0
- data/lib/oversip/websocket/ws_apps/ws_autobahn_app.rb +23 -0
- data/lib/oversip/websocket/ws_apps/ws_sip_app.rb +156 -0
- data/lib/oversip/websocket/ws_apps.rb +9 -0
- data/lib/oversip/websocket/ws_framing.rb +597 -0
- data/lib/oversip.rb +59 -0
- data/test/oversip_test_helper.rb +20 -0
- data/test/test_http_parser.rb +73 -0
- data/test/test_sip_parser.rb +139 -0
- metadata +256 -0
@@ -0,0 +1,119 @@
|
|
1
|
+
# Ruby built-in libraries.
|
2
|
+
|
3
|
+
require "syslog"
|
4
|
+
|
5
|
+
|
6
|
+
# Ruby external gems.
|
7
|
+
|
8
|
+
gem "eventmachine-le", ">= 1.1.0"
|
9
|
+
require "eventmachine-le"
|
10
|
+
|
11
|
+
gem "em-posixmq", ">= 0.2.3"
|
12
|
+
require "em-posixmq"
|
13
|
+
|
14
|
+
# OverSIP libraries.
|
15
|
+
# (not required to be loaded as needed ones have been already
|
16
|
+
# loaded before forking).
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
module OverSIP
|
21
|
+
|
22
|
+
module SysLoggerProcess
|
23
|
+
|
24
|
+
SYSLOG_FACILITY_MAPPING = {
|
25
|
+
"kern" => Syslog::LOG_KERN,
|
26
|
+
"user" => Syslog::LOG_USER,
|
27
|
+
"daemon" => Syslog::LOG_DAEMON,
|
28
|
+
"local0" => Syslog::LOG_LOCAL0,
|
29
|
+
"local1" => Syslog::LOG_LOCAL1,
|
30
|
+
"local2" => Syslog::LOG_LOCAL2,
|
31
|
+
"local3" => Syslog::LOG_LOCAL3,
|
32
|
+
"local4" => Syslog::LOG_LOCAL4,
|
33
|
+
"local5" => Syslog::LOG_LOCAL5,
|
34
|
+
"local6" => Syslog::LOG_LOCAL6,
|
35
|
+
"local7" => Syslog::LOG_LOCAL7
|
36
|
+
}
|
37
|
+
|
38
|
+
class SysLoggerWatcher < ::EM::PosixMQ::Watcher
|
39
|
+
|
40
|
+
def receive_message string, priority
|
41
|
+
level = string.getbyte 0
|
42
|
+
msg = string[1..-1].gsub(/%/,"%%").gsub(/\x00/,"")
|
43
|
+
|
44
|
+
case level
|
45
|
+
when 48 # "0" =>DEBUG
|
46
|
+
::Syslog.debug sprintf("%7s %s", "DEBUG:", msg)
|
47
|
+
when 49 # "1" => INFO
|
48
|
+
::Syslog.info sprintf("%7s %s", "INFO:", msg)
|
49
|
+
when 50 # "2" => NOTICE
|
50
|
+
::Syslog.notice sprintf("%7s %s", "NOTICE:", msg)
|
51
|
+
when 51 # "3" => WARN
|
52
|
+
::Syslog.warning sprintf("%7s %s", "WARN:", msg)
|
53
|
+
when 52 # "4" => ERR
|
54
|
+
::Syslog.err sprintf("%7s %s", "ERROR:", msg)
|
55
|
+
when 53 # "5" => CRIT
|
56
|
+
::Syslog.crit sprintf("%7s %s", "CRIT:", msg)
|
57
|
+
when 54 # "6" => ALERT
|
58
|
+
::Syslog.alert sprintf("%7s %s", "ALERT:", msg)
|
59
|
+
when 55 # "7" => EMERG
|
60
|
+
::Syslog.emerg sprintf("%7s %s", "EMERG:", msg)
|
61
|
+
else # Shouldn't occur.
|
62
|
+
::Syslog.err sprintf("%7s %s", "UNKNOWN:", msg)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end # class SysLoggerWatcher
|
67
|
+
|
68
|
+
def self.run options={}
|
69
|
+
$0 = ::OverSIP.master_name + "_syslogger"
|
70
|
+
|
71
|
+
syslog_options = ::Syslog::LOG_PID | ::Syslog::LOG_NDELAY
|
72
|
+
syslog_facility = SYSLOG_FACILITY_MAPPING[::OverSIP.configuration[:core][:syslog_facility]]
|
73
|
+
::Syslog.open(::OverSIP.master_name, syslog_options, syslog_facility)
|
74
|
+
|
75
|
+
ppid = ::Process.ppid
|
76
|
+
|
77
|
+
at_exit do
|
78
|
+
::Syslog.notice sprintf("%7s %s", "INFO:", "<syslogger> syslogger process terminated")
|
79
|
+
exit!
|
80
|
+
end
|
81
|
+
|
82
|
+
EM.run do
|
83
|
+
begin
|
84
|
+
syslogger_mq = ::POSIX_MQ.new ::OverSIP.syslogger_mq_name, ::IO::RDONLY | ::IO::NONBLOCK
|
85
|
+
::EM::PosixMQ.run syslogger_mq, SysLoggerWatcher
|
86
|
+
|
87
|
+
# Change process permissions if requested.
|
88
|
+
::OverSIP::Launcher.set_user_group(options[:user], options[:group])
|
89
|
+
|
90
|
+
rescue => e
|
91
|
+
::Syslog.crit sprintf("%7s %s", "CRIT:", "<syslogger> #{e.class}: #{e}")
|
92
|
+
::Syslog.crit sprintf("%7s %s", "CRIT:", "<syslogger> syslogger process terminated")
|
93
|
+
exit! 1
|
94
|
+
end
|
95
|
+
|
96
|
+
# Periodically check that master process remains alive and
|
97
|
+
# die otherwise.
|
98
|
+
::EM.add_periodic_timer(1) do
|
99
|
+
if ::Process.ppid != ppid
|
100
|
+
# Wait 0.5 seconds. Maybe the master process has been killed properly and just now
|
101
|
+
# it's sending us the QUIT signal.
|
102
|
+
::EM.add_timer(0.5) do
|
103
|
+
::Syslog.crit sprintf("%7s %s", "CRIT:", "<syslogger> master process died, syslogger process terminated")
|
104
|
+
exit! 1
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
::EM.error_handler do |e|
|
110
|
+
::Syslog.crit sprintf("%7s %s", "CRIT:", "<syslogger> error raised during event loop and rescued by EM.error_handler: #{e.message} (#{e.class})\n#{(e.backtrace || [])[0..3].join("\n")}")
|
111
|
+
end
|
112
|
+
|
113
|
+
::Syslog.info sprintf("%7s %s", "INFO:", "<syslogger> syslogger process (PID #{$$}) ready")
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
end # module SysLoggerProcess
|
118
|
+
|
119
|
+
end
|
data/lib/oversip/tls.rb
ADDED
@@ -0,0 +1,179 @@
|
|
1
|
+
module OverSIP
|
2
|
+
|
3
|
+
module TLS
|
4
|
+
|
5
|
+
extend ::OverSIP::Logger
|
6
|
+
|
7
|
+
TLS_PEM_CHAIN_REGEXP = /-{5}BEGIN CERTIFICATE-{5}\n.*?-{5}END CERTIFICATE-{5}\n/m
|
8
|
+
|
9
|
+
|
10
|
+
def self.log_id
|
11
|
+
@log_id ||= "TLS"
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def self.module_init
|
16
|
+
configuration = ::OverSIP.configuration
|
17
|
+
if configuration[:tls][:public_cert] and configuration[:tls][:private_cert]
|
18
|
+
log_system_info "TLS enabled"
|
19
|
+
|
20
|
+
::OverSIP.tls = true
|
21
|
+
::OverSIP.tls_public_cert = configuration[:tls][:public_cert]
|
22
|
+
::OverSIP.tls_private_cert = configuration[:tls][:private_cert]
|
23
|
+
|
24
|
+
if (::OverSIP.tls_proxy_ipv4 = configuration[:tls][:tls_proxy_ipv4])
|
25
|
+
log_system_info "TLS proxy enabled from IPv4 #{::OverSIP.tls_proxy_ipv4}"
|
26
|
+
end
|
27
|
+
if (::OverSIP.tls_proxy_ipv6 = configuration[:tls][:tls_proxy_ipv6])
|
28
|
+
log_system_info "TLS proxy enabled from IPv6 #{::OverSIP.tls_proxy_ipv6}"
|
29
|
+
end
|
30
|
+
|
31
|
+
else
|
32
|
+
log_system_info "TLS dissabled"
|
33
|
+
return
|
34
|
+
end
|
35
|
+
|
36
|
+
if (ca_dir = configuration[:tls][:ca_dir])
|
37
|
+
@store = ::OpenSSL::X509::Store.new
|
38
|
+
num_certs_added = 0
|
39
|
+
|
40
|
+
::Dir.chdir ca_dir
|
41
|
+
ca_files = ::Dir["*"]
|
42
|
+
ca_files.select! { |ca_file| ::File.file?(ca_file) and ::File.readable?(ca_file) }
|
43
|
+
ca_files.each do |ca_file|
|
44
|
+
log_system_info "inspecting CA file '#{ca_file}'..."
|
45
|
+
|
46
|
+
ca_file_content = ::File.read(ca_file)
|
47
|
+
unless ca_file_content.valid_encoding?
|
48
|
+
log_system_error "ignoring '#{ca_file}', invalid symbols found"
|
49
|
+
next
|
50
|
+
end
|
51
|
+
|
52
|
+
pems = ca_file_content.scan(TLS_PEM_CHAIN_REGEXP).flatten
|
53
|
+
num_pems = pems.size
|
54
|
+
|
55
|
+
if num_pems == 0
|
56
|
+
log_system_warn "'#{ca_file}': no public certificates found"
|
57
|
+
next
|
58
|
+
end
|
59
|
+
log_system_info "'#{ca_file}': #{num_pems} public certificates found"
|
60
|
+
|
61
|
+
now = ::Time.now
|
62
|
+
certs = []
|
63
|
+
pems.each do |pem|
|
64
|
+
begin
|
65
|
+
certs << ::OpenSSL::X509::Certificate.new(pem)
|
66
|
+
rescue => e
|
67
|
+
log_system_error "ignoring invalid X509 certificate: #{e.message} (#{e.class})"
|
68
|
+
num_pems -= 1
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
certs.reject! { |cert| cert.not_after < now }
|
73
|
+
if certs.size != num_pems
|
74
|
+
log_system_info "'#{ca_file}': ignoring #{num_pems - certs.size} expired certificates"
|
75
|
+
end
|
76
|
+
|
77
|
+
certs.each do |cert|
|
78
|
+
begin
|
79
|
+
@store.add_cert cert
|
80
|
+
num_certs_added += 1
|
81
|
+
# This occurs when a certificate is repeated.
|
82
|
+
rescue ::OpenSSL::X509::StoreError => e
|
83
|
+
log_system_warn "'#{ca_file}': ignoring certificate: #{e.message} (#{e.class})"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
if num_certs_added == 0
|
89
|
+
log_system_notice "zero public certificates found in '#{ca_dir}' directory, dissabling TLS validation"
|
90
|
+
@store = nil
|
91
|
+
end
|
92
|
+
log_system_info "#{num_certs_added} public certificates available for TLS validation"
|
93
|
+
end
|
94
|
+
|
95
|
+
end # def self.module_init
|
96
|
+
|
97
|
+
|
98
|
+
# Return an array with the result of the TLS certificate validation as follows:
|
99
|
+
# validated, cert, tls_error, tls_error_string
|
100
|
+
# where:
|
101
|
+
# - validated: true if the given certificate(s) have been validated, false otherwise
|
102
|
+
# and nil if no certificate is provided by peer or no CA's were configured
|
103
|
+
# for TLS validation.
|
104
|
+
# - cert: the ::OpenSSL::X509::Certificate instance of the first PEM provided by
|
105
|
+
# the peer, nil otherwise.
|
106
|
+
# - tls_error: OpenSSL validation error code (Fixnum) in case of validation error.
|
107
|
+
# - tls_error_string: OpenSSL validation error string in case of validation error.
|
108
|
+
def self.validate pem, intermediate_pems=nil
|
109
|
+
return nil, nil, nil, "no CAs provided, validation dissabled" unless @store
|
110
|
+
return nil, nil, nil, "no certificate provided by peer" unless pem
|
111
|
+
|
112
|
+
begin
|
113
|
+
cert = ::OpenSSL::X509::Certificate.new pem
|
114
|
+
|
115
|
+
if intermediate_pems and intermediate_pems.any?
|
116
|
+
intermediate_certs = []
|
117
|
+
intermediate_pems.each do |pem|
|
118
|
+
intermediate_certs << ::OpenSSL::X509::Certificate.new(pem)
|
119
|
+
end
|
120
|
+
else
|
121
|
+
intermediate_certs = nil
|
122
|
+
end
|
123
|
+
|
124
|
+
if @store.verify cert, intermediate_certs
|
125
|
+
return true, cert
|
126
|
+
else
|
127
|
+
return false, cert, @store.error, @store.error_string
|
128
|
+
end
|
129
|
+
|
130
|
+
rescue => e
|
131
|
+
log_system_error "exception validating a certificate: #{e.class}: #{e.message}"
|
132
|
+
return false, nil, e.class, e.message
|
133
|
+
end
|
134
|
+
end # def self.validate
|
135
|
+
|
136
|
+
|
137
|
+
def self.get_sip_identities cert
|
138
|
+
verify_subjectAltName_DNS = true
|
139
|
+
verify_CN = true
|
140
|
+
subjectAltName_URI_sip_entries = []
|
141
|
+
subjectAltName_DNS_entries = []
|
142
|
+
sip_identities = {}
|
143
|
+
|
144
|
+
cert.extensions.each do |ext|
|
145
|
+
next if ext.oid != "subjectAltName"
|
146
|
+
verify_CN = false
|
147
|
+
|
148
|
+
ext.value.split(/,\s+/).each do |name|
|
149
|
+
if /^URI:sip:([^@]*)/i =~ name
|
150
|
+
verify_subjectAltName_DNS = false
|
151
|
+
subjectAltName_URI_sip_entries << $1.downcase
|
152
|
+
elsif verify_subjectAltName_DNS && /^DNS:(.*)/i =~ name
|
153
|
+
subjectAltName_DNS_entries << $1.downcase
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
unless verify_CN
|
159
|
+
unless verify_subjectAltName_DNS
|
160
|
+
subjectAltName_URI_sip_entries.each {|domain| sip_identities[domain] = true}
|
161
|
+
else
|
162
|
+
subjectAltName_DNS_entries.each {|domain| sip_identities[domain] = true}
|
163
|
+
end
|
164
|
+
|
165
|
+
else
|
166
|
+
cert.subject.to_a.each do |oid, value|
|
167
|
+
if oid == "CN"
|
168
|
+
sip_identities[value.downcase] = true
|
169
|
+
break
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
return sip_identities
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module OverSIP
|
2
|
+
|
3
|
+
module Utils
|
4
|
+
|
5
|
+
# It ensures that two identical byte secuences are matched regardless
|
6
|
+
# they have different encoding.
|
7
|
+
# For example in Ruby the following returns false:
|
8
|
+
# "iñaki".force_encoding(::Encoding::BINARY) == "iñaki"
|
9
|
+
def self.string_compare string1, string2
|
10
|
+
string1.force_encoding(::Encoding::BINARY) == string2.force_encoding(::Encoding::BINARY)
|
11
|
+
end
|
12
|
+
|
13
|
+
# This avoid "invalid byte sequence in UTF-8" when the directly doing:
|
14
|
+
# string =~ /EXPRESSION/
|
15
|
+
# and string has invalid UTF-8 bytes secuence.
|
16
|
+
# NOTE: expression argument must be a Regexp expression (with / symbols at the
|
17
|
+
# begining and at the end).
|
18
|
+
def self.regexp_compare string, expression
|
19
|
+
return false unless string && string.valid_encoding?
|
20
|
+
string.force_encoding(::Encoding::BINARY) =~ expression
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module OverSIP
|
4
|
+
|
5
|
+
module Version
|
6
|
+
MAJOR = 0
|
7
|
+
MINOR = 9
|
8
|
+
TINY = 0
|
9
|
+
end
|
10
|
+
|
11
|
+
PROGRAM_NAME = "OverSIP"
|
12
|
+
PROGRAM_NAME_LOW = PROGRAM_NAME.downcase
|
13
|
+
PROGRAM_DESC = "OverSIP Server"
|
14
|
+
VERSION = [Version::MAJOR, Version::MINOR, Version::TINY].join('.')
|
15
|
+
AUTHOR = "Iñaki Baz Castillo"
|
16
|
+
AUTHOR_EMAIL = "ibc@aliax.net"
|
17
|
+
DESCRIPTION = "#{PROGRAM_NAME} #{VERSION}\n2012, #{AUTHOR} <#{AUTHOR_EMAIL}>"
|
18
|
+
|
19
|
+
module GemVersion
|
20
|
+
VERSION = ::OverSIP::VERSION
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module OverSIP::WebSocket
|
2
|
+
|
3
|
+
CRLF = "\r\n"
|
4
|
+
|
5
|
+
REASON_PHARSE = {
|
6
|
+
100 => "Continue",
|
7
|
+
101 => "Switching Protocols",
|
8
|
+
200 => "OK",
|
9
|
+
201 => "Created",
|
10
|
+
202 => "Accepted",
|
11
|
+
203 => "Non-Authoritative Information",
|
12
|
+
204 => "No Content",
|
13
|
+
205 => "Reset Content",
|
14
|
+
206 => "Partial Content",
|
15
|
+
300 => "Multiple Choices",
|
16
|
+
301 => "Moved Permanently",
|
17
|
+
302 => "Found",
|
18
|
+
303 => "See Other",
|
19
|
+
304 => "Not Modified",
|
20
|
+
305 => "Use Proxy",
|
21
|
+
307 => "Temporary Redirect",
|
22
|
+
400 => "Bad Request",
|
23
|
+
401 => "Unauthorized",
|
24
|
+
402 => "Payment Required",
|
25
|
+
403 => "Forbidden",
|
26
|
+
404 => "Not Found",
|
27
|
+
405 => "Method Not Allowed",
|
28
|
+
406 => "Not Acceptable",
|
29
|
+
407 => "Proxy Authentication Required",
|
30
|
+
408 => "Request Timeout",
|
31
|
+
409 => "Conflict",
|
32
|
+
410 => "Gone",
|
33
|
+
411 => "Length Required",
|
34
|
+
412 => "Precondition Failed",
|
35
|
+
413 => "Request Entity Too Large",
|
36
|
+
414 => "Request-URI Too Long",
|
37
|
+
415 => "Unsupported Media Type",
|
38
|
+
416 => "Requested Range Not Satisfiable",
|
39
|
+
417 => "Expectation Failed",
|
40
|
+
426 => "Upgrade Required", # RFC 2817
|
41
|
+
500 => "Server Internal Error",
|
42
|
+
501 => "Not Implemented",
|
43
|
+
502 => "Bad Gateway",
|
44
|
+
503 => "Service Unavailable",
|
45
|
+
504 => "Gateway Time-out",
|
46
|
+
505 => "HTTP Version Not Supported"
|
47
|
+
}
|
48
|
+
|
49
|
+
REASON_PHARSE_NOT_SET = "Reason Phrase Not Set"
|
50
|
+
|
51
|
+
HDR_SERVER = "Server: #{::OverSIP::PROGRAM_DESC}/#{::OverSIP::VERSION}"
|
52
|
+
|
53
|
+
WS_SIP_PROTOCOL = "sip"
|
54
|
+
WS_AUTOBAHN_PROTOCOL = "autobahn"
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module OverSIP::WebSocket
|
2
|
+
|
3
|
+
class HttpRequest < ::Hash
|
4
|
+
|
5
|
+
include ::OverSIP::Logger
|
6
|
+
|
7
|
+
# HTTP related attributes.
|
8
|
+
attr_accessor :transport
|
9
|
+
attr_accessor :source_ip
|
10
|
+
attr_accessor :source_ip_type
|
11
|
+
attr_accessor :source_port
|
12
|
+
attr_accessor :connection
|
13
|
+
|
14
|
+
# HTTP request attributes.
|
15
|
+
attr_reader :http_method
|
16
|
+
attr_reader :http_version
|
17
|
+
attr_reader :uri_scheme
|
18
|
+
attr_reader :uri
|
19
|
+
attr_reader :uri_path
|
20
|
+
attr_reader :uri_query
|
21
|
+
attr_reader :uri_fragment
|
22
|
+
attr_reader :host
|
23
|
+
attr_reader :port
|
24
|
+
attr_reader :content_length
|
25
|
+
attr_reader :hdr_connection
|
26
|
+
attr_reader :hdr_upgrade
|
27
|
+
attr_reader :hdr_origin
|
28
|
+
attr_reader :hdr_sec_websocket_version
|
29
|
+
attr_reader :hdr_sec_websocket_key
|
30
|
+
attr_reader :hdr_sec_websocket_protocol
|
31
|
+
|
32
|
+
|
33
|
+
def log_id
|
34
|
+
@log_id ||= "HTTP Request #{@connection.connection_log_id}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def unknown_method? ; @is_unknown_method end
|
38
|
+
|
39
|
+
|
40
|
+
def reply status_code, reason_phrase=nil, extra_headers={}
|
41
|
+
reason_phrase ||= REASON_PHARSE[status_code] || REASON_PHARSE_NOT_SET
|
42
|
+
extra_headers ||= {}
|
43
|
+
|
44
|
+
response = "#{@http_version} #{status_code} #{reason_phrase}\r\n"
|
45
|
+
|
46
|
+
extra_headers.each {|header| response << header << "\r\n"}
|
47
|
+
|
48
|
+
response << HDR_SERVER << "\r\n\r\n"
|
49
|
+
|
50
|
+
log_system_debug "replying #{status_code} \"#{reason_phrase}\"" if $oversip_debug
|
51
|
+
|
52
|
+
if @connection.error?
|
53
|
+
log_system_warn "cannot send response, TCP connection is closed"
|
54
|
+
return false
|
55
|
+
end
|
56
|
+
|
57
|
+
@connection.send_data response
|
58
|
+
return true
|
59
|
+
end
|
60
|
+
|
61
|
+
end # class HttpRequest
|
62
|
+
|
63
|
+
end
|
@@ -0,0 +1,207 @@
|
|
1
|
+
module OverSIP::WebSocket
|
2
|
+
|
3
|
+
module Launcher
|
4
|
+
|
5
|
+
extend OverSIP::Logger
|
6
|
+
|
7
|
+
IP_TYPE = {
|
8
|
+
:ipv4 => "IPv4",
|
9
|
+
:ipv6 => "IPv6"
|
10
|
+
}
|
11
|
+
|
12
|
+
|
13
|
+
def self.log_id
|
14
|
+
@log_id ||= "WebSocket launcher"
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
def self.run enabled, ip_type, ip, port, transport, ws_protocol, virtual_ip=nil, virtual_port=nil
|
19
|
+
uri_ip = case ip_type
|
20
|
+
when :ipv4 ; ip
|
21
|
+
when :ipv6 ; "[#{ip}]"
|
22
|
+
end
|
23
|
+
|
24
|
+
if virtual_ip
|
25
|
+
uri_virtual_ip = case ip_type
|
26
|
+
when :ipv4 ; virtual_ip
|
27
|
+
when :ipv6 ; "[#{virtual_ip}]"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
klass = case transport
|
32
|
+
when :tcp
|
33
|
+
case ip_type
|
34
|
+
when :ipv4 ; OverSIP::WebSocket::IPv4TcpServer
|
35
|
+
when :ipv6 ; OverSIP::WebSocket::IPv6TcpServer
|
36
|
+
end
|
37
|
+
when :tls
|
38
|
+
case ip_type
|
39
|
+
when :ipv4 ; OverSIP::WebSocket::IPv4TlsServer
|
40
|
+
when :ipv6 ; OverSIP::WebSocket::IPv6TlsServer
|
41
|
+
end
|
42
|
+
when :tls_tunnel
|
43
|
+
case ip_type
|
44
|
+
when :ipv4 ; OverSIP::WebSocket::IPv4TlsTunnelServer
|
45
|
+
when :ipv6 ; OverSIP::WebSocket::IPv6TlsTunnelServer
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
case ws_protocol
|
50
|
+
|
51
|
+
when OverSIP::WebSocket::WS_SIP_PROTOCOL
|
52
|
+
|
53
|
+
ws_app_klass = case transport
|
54
|
+
when :tcp
|
55
|
+
case ip_type
|
56
|
+
when :ipv4 ; OverSIP::WebSocket::IPv4WsSipApp
|
57
|
+
when :ipv6 ; OverSIP::WebSocket::IPv6WsSipApp
|
58
|
+
end
|
59
|
+
when :tls, :tls_tunnel
|
60
|
+
case ip_type
|
61
|
+
when :ipv4 ; OverSIP::WebSocket::IPv4WssSipApp
|
62
|
+
when :ipv6 ; OverSIP::WebSocket::IPv6WssSipApp
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
ws_app_klass.ip = virtual_ip || ip
|
67
|
+
ws_app_klass.port = virtual_port || port
|
68
|
+
|
69
|
+
case
|
70
|
+
|
71
|
+
when klass == OverSIP::WebSocket::IPv4TcpServer
|
72
|
+
ws_app_klass.via_core = "SIP/2.0/WS #{uri_ip}:#{port}"
|
73
|
+
ws_app_klass.record_route = "<sip:#{uri_ip}:#{port};transport=ws;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid}>"
|
74
|
+
ws_app_klass.outbound_record_route_fragment = "@#{uri_ip}:#{port};transport=ws;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid}>"
|
75
|
+
ws_app_klass.outbound_path_fragment = "@#{uri_ip}:#{port};transport=ws;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid};ob>"
|
76
|
+
|
77
|
+
if enabled
|
78
|
+
EM.start_server(ip, port, klass) do |conn|
|
79
|
+
conn.ws_protocol = ws_protocol
|
80
|
+
conn.ws_app_klass = ws_app_klass
|
81
|
+
conn.post_connection
|
82
|
+
conn.set_comm_inactivity_timeout 3600 # TODO
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
when klass == OverSIP::WebSocket::IPv6TcpServer
|
87
|
+
ws_app_klass.via_core = "SIP/2.0/WS #{uri_ip}:#{port}"
|
88
|
+
ws_app_klass.record_route = "<sip:#{uri_ip}:#{port};transport=ws;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid}>"
|
89
|
+
ws_app_klass.outbound_record_route_fragment = "@#{uri_ip}:#{port};transport=ws;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid}>"
|
90
|
+
ws_app_klass.outbound_path_fragment = "@#{uri_ip}:#{port};transport=ws;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid};ob>"
|
91
|
+
|
92
|
+
if enabled
|
93
|
+
EM.start_server(ip, port, klass) do |conn|
|
94
|
+
conn.ws_protocol = ws_protocol
|
95
|
+
conn.ws_app_klass = ws_app_klass
|
96
|
+
conn.post_connection
|
97
|
+
conn.set_comm_inactivity_timeout 3600 # TODO
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
when klass == OverSIP::WebSocket::IPv4TlsServer
|
102
|
+
ws_app_klass.via_core = "SIP/2.0/WSS #{uri_ip}:#{port}"
|
103
|
+
rr_host = ::OverSIP.configuration[:sip][:record_route_hostname_tls_ipv4] || uri_ip
|
104
|
+
ws_app_klass.record_route = "<sip:#{rr_host}:#{port};transport=wss;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid}>"
|
105
|
+
ws_app_klass.outbound_record_route_fragment = "@#{rr_host}:#{port};transport=wss;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid}>"
|
106
|
+
ws_app_klass.outbound_path_fragment = "@#{rr_host}:#{port};transport=wss;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid};ob>"
|
107
|
+
|
108
|
+
if enabled
|
109
|
+
EM.start_server(ip, port, klass) do |conn|
|
110
|
+
conn.ws_protocol = ws_protocol
|
111
|
+
conn.ws_app_klass = ws_app_klass
|
112
|
+
conn.post_connection
|
113
|
+
conn.set_comm_inactivity_timeout 3600 # TODO
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
when klass == OverSIP::WebSocket::IPv6TlsServer
|
118
|
+
ws_app_klass.via_core = "SIP/2.0/WSS #{uri_ip}:#{port}"
|
119
|
+
rr_host = ::OverSIP.configuration[:sip][:record_route_hostname_tls_ipv6] || uri_ip
|
120
|
+
ws_app_klass.record_route = "<sips:#{rr_host}:#{port};transport=ws;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid}>"
|
121
|
+
ws_app_klass.outbound_record_route_fragment = "@#{rr_host}:#{port};transport=wss;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid}>"
|
122
|
+
ws_app_klass.outbound_path_fragment = "@#{rr_host}:#{port};transport=wss;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid};ob>"
|
123
|
+
|
124
|
+
if enabled
|
125
|
+
EM.start_server(ip, port, klass) do |conn|
|
126
|
+
conn.ws_protocol = ws_protocol
|
127
|
+
conn.ws_app_klass = ws_app_klass
|
128
|
+
conn.post_connection
|
129
|
+
conn.set_comm_inactivity_timeout 3600 # TODO
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
when klass == OverSIP::WebSocket::IPv4TlsTunnelServer
|
134
|
+
ws_app_klass.via_core = "SIP/2.0/WSS #{uri_virtual_ip}:#{virtual_port}"
|
135
|
+
rr_host = ::OverSIP.configuration[:sip][:record_route_hostname_tls_ipv4] || uri_virtual_ip
|
136
|
+
ws_app_klass.record_route = "<sip:#{rr_host}:#{virtual_port};transport=wss;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid}>"
|
137
|
+
ws_app_klass.outbound_record_route_fragment = "@#{rr_host}:#{virtual_port};transport=wss;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid}>"
|
138
|
+
ws_app_klass.outbound_path_fragment = "@#{rr_host}:#{virtual_port};transport=wss;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid};ob>"
|
139
|
+
|
140
|
+
if enabled
|
141
|
+
EM.start_server(ip, port, klass) do |conn|
|
142
|
+
conn.ws_protocol = ws_protocol
|
143
|
+
conn.ws_app_klass = ws_app_klass
|
144
|
+
conn.post_connection
|
145
|
+
conn.set_comm_inactivity_timeout 3600 # TODO
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
when klass == OverSIP::WebSocket::IPv6TlsTunnelServer
|
150
|
+
ws_app_klass.via_core = "SIP/2.0/WSS #{uri_virtual_ip}:#{virtual_port}"
|
151
|
+
rr_host = ::OverSIP.configuration[:sip][:record_route_hostname_tls_ipv6] || uri_virtual_ip
|
152
|
+
ws_app_klass.record_route = "<sip:#{rr_host}:#{virtual_port};transport=wss;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid}>"
|
153
|
+
ws_app_klass.outbound_record_route_fragment = "@#{rr_host}:#{virtual_port};transport=wss;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid}>"
|
154
|
+
ws_app_klass.outbound_path_fragment = "@#{rr_host}:#{virtual_port};transport=wss;lr;ovid=#{OverSIP::SIP::Tags.value_for_route_ovid};ob>"
|
155
|
+
|
156
|
+
if enabled
|
157
|
+
EM.start_server(ip, port, klass) do |conn|
|
158
|
+
conn.ws_protocol = ws_protocol
|
159
|
+
conn.ws_app_klass = ws_app_klass
|
160
|
+
conn.post_connection
|
161
|
+
conn.set_comm_inactivity_timeout 3600 # TODO
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
end # case
|
166
|
+
|
167
|
+
|
168
|
+
when OverSIP::WebSocket::WS_AUTOBAHN_PROTOCOL
|
169
|
+
|
170
|
+
ws_app_klass = case transport
|
171
|
+
when :tcp
|
172
|
+
case ip_type
|
173
|
+
when :ipv4 ; OverSIP::WebSocket::WsAutobahnApp
|
174
|
+
end
|
175
|
+
when :tls
|
176
|
+
case ip_type
|
177
|
+
when :ipv4 ; OverSIP::WebSocket::WsAutobahnApp
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
EM.start_server(ip, port, klass) do |conn|
|
182
|
+
conn.ws_protocol = ws_protocol
|
183
|
+
conn.ws_app_klass = ws_app_klass
|
184
|
+
conn.post_connection
|
185
|
+
conn.set_comm_inactivity_timeout 60
|
186
|
+
end
|
187
|
+
|
188
|
+
|
189
|
+
else
|
190
|
+
fatal "unknown WebSocket protocol: #{ws_protocol}"
|
191
|
+
|
192
|
+
end # case
|
193
|
+
|
194
|
+
transport_str = case transport
|
195
|
+
when :tls_tunnel ; "TLS-Tunnel"
|
196
|
+
else ; transport.to_s.upcase
|
197
|
+
end
|
198
|
+
|
199
|
+
if enabled
|
200
|
+
log_system_info "WebSocket #{transport_str} server listening on #{IP_TYPE[ip_type]} #{uri_ip}:#{port} provides '#{ws_protocol}' WS subprotocol"
|
201
|
+
end
|
202
|
+
|
203
|
+
end # def self.run
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|