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,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
@@ -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,19 @@
1
+ module OverSIP::WebSocket
2
+
3
+ module DefaultPolicy
4
+
5
+ def check_hostport host=nil, port=nil
6
+ true
7
+ end
8
+
9
+ def check_origin origin=nil
10
+ true
11
+ end
12
+
13
+ def check_request_uri path=nil, query=nil
14
+ true
15
+ end
16
+
17
+ end
18
+
19
+ 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