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,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