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
data/AUTHORS.txt ADDED
@@ -0,0 +1,11 @@
1
+ MAIN AUTHOR
2
+ ===========
3
+
4
+ - Iñaki Baz Castillo <ibc@aliax.net> (Github @ibc)
5
+
6
+
7
+
8
+ CONTRIBUTORS
9
+ ============
10
+
11
+ - Jon Bonilla <manwe@aholab.ehu.es> (Github @manwe)
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ The MIT LICENSE
2
+
3
+ Copyright (c) 2012 Iñaki Baz Castillo <ibc@aliax.net>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,16 @@
1
+ OverSIP
2
+ =======
3
+
4
+ **UNDER CONSTRUCTION:** please wait a bit...
5
+
6
+ OverSIP is an async SIP proxy/server programmable in Ruby language.
7
+
8
+ Some features of OverSIP are:
9
+ * SIP transports: UDP, TCP, TLS and WebSocket.
10
+ * Full IPv4 and IPv6 support.
11
+ * RFC 3263: SIP DNS mechanism (NAPTR, SRV, A, AAAA) for failover and load balancing based on DNS.
12
+ * RFC 5626: OverSIP is a perfect Outbound EDGE proxy, including an integrated STUN server.
13
+ * Fully programmable in Ruby language (make SIP easy).
14
+ * Fast and efficient: OverSIP core is coded in C language.
15
+
16
+ OverSIP is build on top of EventMachine async library which follows the Reactor Pattern design, allowing thousands of concurrent connections and requests in a never-blocking fashion.
data/Rakefile ADDED
@@ -0,0 +1,55 @@
1
+ require "rake/testtask"
2
+ require "rake/clean"
3
+
4
+
5
+ OVERSIP_EXTENSIONS = [
6
+ { :dir => "ext/sip_parser", :so => "sip_parser.so", :dest => "lib/oversip/sip" },
7
+ { :dir => "ext/stun", :so => "stun.so", :dest => "lib/oversip" },
8
+ { :dir => "ext/utils", :so => "utils.so", :dest => "lib/oversip" },
9
+ { :dir => "ext/websocket_framing_utils", :so => "ws_framing_utils.so", :dest => "lib/oversip/websocket" },
10
+ { :dir => "ext/websocket_http_parser", :so => "ws_http_parser.so", :dest => "lib/oversip/websocket" },
11
+ ]
12
+
13
+ OVERSIP_EXTENSIONS.each do |ext|
14
+ file ext[:so] => Dir.glob(["#{ext[:dir]}/*{.c,.h}"]) do
15
+ Dir.chdir(ext[:dir]) do
16
+ ruby "extconf.rb"
17
+ sh "make"
18
+ end
19
+ cp "#{ext[:dir]}/#{ext[:so]}", "#{ext[:dest]}/"
20
+ end
21
+
22
+ CLEAN.include("#{ext[:dir]}/*{.o,.log,.so,.a}")
23
+ CLEAN.include("#{ext[:dir]}/Makefile")
24
+ CLEAN.include("#{ext[:dest]}/#{ext[:so]}")
25
+ end
26
+
27
+ # Stud stuff.
28
+ directory "tmp"
29
+ file "bin/oversip_stud" => "tmp" do
30
+ Dir.chdir("ext/stud") do
31
+ ruby "extconf.rb"
32
+ end
33
+ FileUtils.remove_dir "tmp"
34
+ end
35
+ CLEAN.include("ext/stud/Makefile")
36
+ CLEAN.include("ext/stud/mkmf.log")
37
+ CLEAN.include("bin/oversip_stud")
38
+
39
+
40
+ OVERSIP_COMPILE_ITEMS = OVERSIP_EXTENSIONS.map {|e| e[:so]} << "bin/oversip_stud"
41
+
42
+
43
+ task :default => :compile
44
+
45
+ desc "Compile"
46
+ task :compile => OVERSIP_COMPILE_ITEMS
47
+
48
+ Rake::TestTask.new do |t|
49
+ t.libs << "test"
50
+ end
51
+
52
+ # Make the :test task depend on the shared object, so it will be built automatically
53
+ # before running the tests.
54
+ desc "Run tests"
55
+ task :test => OVERSIP_COMPILE_ITEMS
data/bin/oversip ADDED
@@ -0,0 +1,182 @@
1
+ #!/usr/bin/ruby1.9
2
+ # -*- encoding: binary -*-
3
+
4
+ unless RUBY_VERSION >= "1.9.2"
5
+ raise LoadError, "OverSIP requires Ruby version >= 1.9.2 (current version is #{RUBY_VERSION})"
6
+ end
7
+
8
+
9
+ # First of all, trap some signals in order to ignore them if they arrive while
10
+ # loading server libraries.
11
+ [:HUP, :INT, :USR1, :USR2].each {|signal| trap(signal) {} }
12
+
13
+
14
+ require "optparse"
15
+ require "etc"
16
+ require "oversip"
17
+
18
+
19
+ module OverSIP
20
+
21
+ class Executable
22
+
23
+ @log_id = "executable"
24
+
25
+ def self.run
26
+ ::OverSIP::Logger.load_methods
27
+ extend ::OverSIP::Logger
28
+
29
+ # Options by default.
30
+ options = {
31
+ :colorize => true
32
+ }
33
+
34
+ OptionParser.new("", 24, " ") do |opts|
35
+ opts.banner = "#{::OverSIP::DESCRIPTION}" \
36
+ "\n\nUsage: #{File.basename(__FILE__)} " \
37
+ "[#{::OverSIP::PROGRAM_NAME} options] [Ruby options]"
38
+
39
+ opts.separator "\n#{::OverSIP::PROGRAM_NAME} options:"
40
+
41
+ opts.on("-P", "--pid FILE", "Create a PID file (required)") do |value|
42
+ options[:pid_file] = value
43
+ end
44
+
45
+ opts.on("-p", "--process_name NAME", "Change the running process name, also affects to syslogger process and Posix Message Queue name (default 'oversip')") do |value|
46
+ options[:process_name] = value
47
+ end
48
+
49
+ opts.on("-c", "--dir_config DIR", "Absolute path to the directory with user configuration files (default '/etc/oversip/')") do |value|
50
+ options[:dir_config] = value
51
+ end
52
+
53
+ opts.on("-u", "--user USER", "System user to run with") do |value|
54
+ options[:user] = value
55
+ end
56
+
57
+ opts.on("-g", "--group GROUP", "System group to run with") do |value|
58
+ options[:group] = value
59
+ end
60
+
61
+ opts.on("--no-color", "Don't colorize text printed in stdout") do |value|
62
+ options[:colorize] = false
63
+ end
64
+
65
+ opts.on("--remove-mqueue MQUEUE", "Destroy the Posix Message Queue with the given name and exit") do |value|
66
+ require "posix_mq"
67
+
68
+ begin
69
+ POSIX_MQ.unlink value
70
+ rescue ::Errno::ENOENT
71
+ rescue ::Errno::EACCES => e
72
+ fatal "cannot remove '#{value}' posix message queue due file permissions"
73
+ exit 1
74
+ rescue ::Errno::EINVAL => e
75
+ fatal "cannot remove '#{value}' posix message queue, invalid name"
76
+ exit 1
77
+ ensure
78
+ exit
79
+ end
80
+ end
81
+
82
+ opts.separator "\nRuby options:"
83
+
84
+ opts.on("-d", "--debug", "Set debugging flags ($DEBUG = true)") do
85
+ $DEBUG = true
86
+ end
87
+
88
+ opts.on("-w", "--warn", "Turn warnings on ($-w = true)") do
89
+ $-w = true
90
+ end
91
+
92
+ opts.on("-I", "--include PATH", "Add PATH to $LOAD_PATH (may be used more than once)") do |path|
93
+ $LOAD_PATH.unshift(*path.split(/:/))
94
+ end
95
+
96
+ opts.on("-r", "--require LIBRARY", "Load LIBRARY before running the programm (may be used more than once)") do |library|
97
+ require library
98
+ end
99
+
100
+ opts.separator "\nCommon options:"
101
+
102
+ opts.on_tail("-h", "--help", "Show this message") do
103
+ puts opts.to_s
104
+ exit
105
+ end
106
+
107
+ opts.on_tail("-v", "--version", "Show version") do
108
+ puts ::OverSIP::DESCRIPTION
109
+ exit
110
+ end
111
+
112
+ begin
113
+ opts.parse! ARGV
114
+ rescue ::OptionParser::InvalidOption => e
115
+ log_system_error e.message
116
+ puts
117
+ puts opts.to_s
118
+ exit! 1
119
+ rescue ::OptionParser::MissingArgument => e
120
+ log_system_error e.message
121
+ puts
122
+ puts opts.to_s
123
+ exit! 1
124
+ end
125
+ end
126
+
127
+ log_system_info "#{::OverSIP::PROGRAM_NAME} #{::OverSIP::VERSION} starting..."
128
+
129
+ # Options checks.
130
+
131
+ # PID file is required.
132
+ unless options[:pid_file]
133
+ fatal "PID file is required (use -P or --pid option)"
134
+ end
135
+
136
+ # Ignore user/group if the launcher is not being running as root.
137
+ unless Process.euid == 0
138
+ log_system_warn "ignoring user/group parameters when not running as root"
139
+ options.delete :user
140
+ options.delete :group
141
+ else
142
+ # Get the uid and gid to run with.
143
+ if options[:user]
144
+ begin
145
+ Etc.getpwnam options[:user]
146
+ rescue ArgumentError
147
+ fatal "user '#{options[:user]}' does not exist in the system"
148
+ end
149
+ end
150
+ if options[:group]
151
+ begin
152
+ Etc.getgrnam options[:group]
153
+ rescue ArgumentError
154
+ fatal "group '#{options[:group]}' does not exist in the system"
155
+ end
156
+ end
157
+ end
158
+
159
+ # Set the command name (as it appears in "ps" output) to given --process_name option (-p)
160
+ # or to the script filename otherwise.
161
+ $0 = options[:process_name] || File.basename(__FILE__)
162
+
163
+ OverSIP.master_name = $0
164
+ log_system_info "master process name: #{OverSIP.master_name}"
165
+
166
+ OverSIP::Config.load options[:dir_config]
167
+ log_system_info "applied configuration:"
168
+ OverSIP::Config.print options[:colorize]
169
+
170
+ log_system_info "creating Posix Message Queue for communicating master and syslogger processes"
171
+ OverSIP::Logger.init_logger_mq options[:group]
172
+ OverSIP::Logger.load_methods
173
+
174
+ OverSIP::Launcher.daemonize!(options)
175
+ OverSIP::Launcher.run(options)
176
+
177
+ end # def run
178
+ end # class Executable
179
+ end # module OverSIP
180
+
181
+
182
+ ::OverSIP::Executable.run
@@ -0,0 +1,74 @@
1
+ /*
2
+ * Generic C functions and macros go here, there are no dependencies
3
+ * on OverSIP internal structures or the Ruby C API in here.
4
+ */
5
+
6
+ #ifndef c_util_h
7
+ #define c_util_h
8
+
9
+
10
+ #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
11
+
12
+
13
+ /*
14
+ * str_to_int: Given a pointer to char and length returns an int (but just possitive).
15
+ */
16
+ static int str_to_int(const char* str, size_t len)
17
+ {
18
+ TRACE();
19
+ int number = 0;
20
+ const char *s = str;
21
+
22
+ while (len--) {
23
+ /* Ignore zeroes at the beginning. */
24
+ if (number || *s != '0')
25
+ number = number*10 + (*s)-'0';
26
+ s++;
27
+ }
28
+ return number;
29
+ }
30
+
31
+
32
+ /*
33
+ * strnchr: Find the first character in a length limited string.
34
+ * @s: The string to be searched
35
+ * @len: The number of characters to be searched
36
+ * @c: The character to search for
37
+ */
38
+ static char *strnchr(const char *s, size_t len, size_t c)
39
+ {
40
+ TRACE();
41
+ for (; len--; ++s)
42
+ if (*s == (char)c)
43
+ return (char *)s;
44
+ return NULL;
45
+ }
46
+
47
+
48
+ /*
49
+ * str_find_upcase: Returns non zero if the string (*str, len) contains at least
50
+ * an upcase letter.
51
+ */
52
+ static char *str_find_upcase(const char *s, size_t len)
53
+ {
54
+ TRACE();
55
+ for (; len--; ++s)
56
+ if (*s >= 'A' && *s <= 'Z')
57
+ return (char *)s;
58
+ return NULL;
59
+ }
60
+
61
+
62
+ /*
63
+ * capitalizes all lower-case ASCII characters.
64
+ */
65
+ static void downcase_char(char *c)
66
+ {
67
+ TRACE();
68
+ if (*c >= 'A' && *c <= 'Z')
69
+ *c += 32;
70
+ }
71
+
72
+
73
+ #endif
74
+
@@ -0,0 +1,88 @@
1
+ /*
2
+ * Generic Ruby C functions and macros go here.
3
+ */
4
+
5
+ #ifndef ruby_c_util_h
6
+ #define ruby_c_util_h
7
+
8
+
9
+ #include <ruby.h>
10
+ #include <ruby/encoding.h> /* Required: http://redmine.ruby-lang.org/issues/show/4272 */
11
+ #include "c_util.h"
12
+
13
+
14
+ #define RB_STR_UTF8_NEW(s, len) (rb_enc_str_new(s, len, rb_utf8_encoding()))
15
+
16
+
17
+ /*
18
+ * my_rb_str_hex_unescape: Unexcapes hexadecimal encoded symbols (%NN).
19
+ */
20
+ static VALUE my_rb_str_hex_unescape(const char *str, size_t len)
21
+ {
22
+ TRACE();
23
+ /* Check if hexadecimal unescaping is required. */
24
+ if (strnchr(str, len, '%')) {
25
+ char *new_str;
26
+ VALUE str_unescaped;
27
+
28
+ new_str = ALLOC_N(char, len);
29
+ memcpy(new_str, str, len);
30
+
31
+ char *s, *t;
32
+ char hex[3] = {0, 0, 0};
33
+ int i;
34
+
35
+ for (s = t = new_str, i = 0 ; i < len ; s++, i++) {
36
+ if (*s != '%' || !(*(s+1)) || !(*(s+2)))
37
+ *t++ = *s;
38
+ else {
39
+ hex[0] = *(s+1);
40
+ hex[1] = *(s+2);
41
+ *t++ = (strtol(hex, NULL, 16) & 0xFF);
42
+ s += 2;
43
+ len -= 2;
44
+ }
45
+ }
46
+
47
+ str_unescaped = RB_STR_UTF8_NEW(new_str, len);
48
+ xfree(new_str);
49
+ return(str_unescaped);
50
+ }
51
+ /* If unescaping is not required, then create a Ruby string with original pointer and length. */
52
+ else
53
+ return(RB_STR_UTF8_NEW(str, len));
54
+ }
55
+
56
+ /*
57
+ * my_rb_str_downcase: Downcases a string formed by simple symbols (ASCII).
58
+ */
59
+ static VALUE my_rb_str_downcase(const char *str, size_t len)
60
+ {
61
+ TRACE();
62
+ /* Check if there is at least an upcase char. */
63
+ if (str_find_upcase(str, len)) {
64
+ char *new_str;
65
+ VALUE str_downcased;
66
+
67
+ new_str = ALLOC_N(char, len);
68
+ memcpy(new_str, str, len);
69
+
70
+ char *s;
71
+ int i;
72
+
73
+ for (s = new_str, i = 0 ; i < len ; s++, i++)
74
+ if (*s >= 'A' && *s <= 'Z')
75
+ *s += 32;
76
+
77
+ str_downcased = RB_STR_UTF8_NEW(new_str, len);
78
+ xfree(new_str);
79
+ return(str_downcased);
80
+ }
81
+ /* If not, then create a Ruby string with original pointer and length. */
82
+ else
83
+ return(RB_STR_UTF8_NEW(str, len));
84
+ }
85
+
86
+
87
+ #endif
88
+
@@ -0,0 +1,209 @@
1
+ #ifndef common_headers_h
2
+ #define common_headers_h
3
+
4
+ #include "../common/c_util.h"
5
+ #include "ruby.h"
6
+
7
+
8
+ /* There are 20 headers with sort representation. */
9
+ #define NUM_SHORT_HEADERS 20
10
+
11
+
12
+ struct common_header_name {
13
+ const signed long len;
14
+ const char *name;
15
+ VALUE value;
16
+ const char short_name;
17
+ };
18
+
19
+
20
+ struct short_header {
21
+ char abbr;
22
+ VALUE value;
23
+ };
24
+
25
+
26
+ /*
27
+ * A list of common SIP headers we expect to receive.
28
+ * This allows us to avoid repeatedly creating identical string
29
+ * objects to be used with rb_hash_aset().
30
+ */
31
+ static struct common_header_name common_headers[] = {
32
+ #define f(N, S) { (sizeof(N) - 1), N, Qnil, S }
33
+ f("Accept", ' '),
34
+ f("Accept-Contact", 'A'),
35
+ f("Accept-Encoding", ' '),
36
+ f("Accept-Language", ' '),
37
+ f("Alert-Info", ' '),
38
+ f("Allow", ' '),
39
+ f("Allow-Events", 'U'),
40
+ f("Authentication-Info", ' '),
41
+ f("Authorization", ' '),
42
+ f("Call-ID", 'I'),
43
+ f("Call-Info", ' '),
44
+ f("Contact", 'M'),
45
+ f("Content-Disposition", ' '),
46
+ f("Content-Encoding", 'E'),
47
+ f("Content-Language", ' '),
48
+ f("Content-Length", 'L'),
49
+ f("Content-Type", 'C'),
50
+ f("CSeq", ' '),
51
+ f("Date", ' '),
52
+ f("Event", 'O'),
53
+ f("Error-Info", ' '),
54
+ f("Expires", ' '),
55
+ f("From", 'F'),
56
+ f("Identity", 'Y'),
57
+ f("Identity-Info", 'N'),
58
+ f("In-Reply-To", ' '),
59
+ f("Max-Forwards", ' '),
60
+ f("Min-Expires", ' '),
61
+ f("MIME-Version", ' '),
62
+ f("Organization", ' '),
63
+ f("Priority", ' '),
64
+ f("Proxy-Authenticate", ' '),
65
+ f("Proxy-Authorization", ' '),
66
+ f("Proxy-Require", ' '),
67
+ f("Record-Route", ' '),
68
+ f("Refer-To", 'R'),
69
+ f("Referred-By", 'B'),
70
+ f("Reject-Contact", 'J'),
71
+ f("Reply-To", ' '),
72
+ f("Request-Disposition", 'D'),
73
+ f("Require", ' '),
74
+ f("Retry-After", ' '),
75
+ f("Route", ' '),
76
+ f("Server", ' '),
77
+ f("Session-Expires", 'X'),
78
+ f("Subject", 'S'),
79
+ f("Supported", 'K'),
80
+ f("Timestamp", ' '),
81
+ f("To", 'T'),
82
+ f("Unsupported", ' '),
83
+ f("User-Agent", ' '),
84
+ f("Via", 'V'),
85
+ f("Warning", ' '),
86
+ f("WWW-Authenticate", ' ')
87
+ # undef f
88
+ };
89
+
90
+
91
+ /*
92
+ * The list of short headers. This list is filled by the funcion
93
+ * init_short_header_names.
94
+ */
95
+ static struct short_header short_headers[NUM_SHORT_HEADERS];
96
+
97
+
98
+ /* this function is not performance-critical, called only at load time */
99
+ static void init_common_headers(void)
100
+ {
101
+ TRACE();
102
+ int i;
103
+ struct common_header_name *cf = common_headers;
104
+
105
+ for(i = ARRAY_SIZE(common_headers); --i >= 0; cf++) {
106
+ cf->value = rb_str_new(cf->name, cf->len);
107
+ cf->value = rb_obj_freeze(cf->value);
108
+ /* This tell Ruby not to GC global variables which refer to Ruby's objects,
109
+ but are not exported to the Ruby world. */
110
+ rb_global_variable(&cf->value);
111
+ }
112
+ }
113
+
114
+ /* this funcion fills the list of short headers taken the data from
115
+ * common_headers array.
116
+ */
117
+ static void init_short_headers(void)
118
+ {
119
+ TRACE();
120
+ int i, j;
121
+ struct common_header_name *cf = common_headers;
122
+
123
+ for(i = ARRAY_SIZE(common_headers), j=0; --i >= 0; cf++) {
124
+ if (cf->short_name != ' ') {
125
+ short_headers[j].abbr = cf->short_name;
126
+ short_headers[j].value = cf->value;
127
+ j++;
128
+ }
129
+ }
130
+ }
131
+
132
+ /* this function is called for every header set */
133
+ static VALUE find_common_header_name(const char *name, size_t len)
134
+ {
135
+ TRACE();
136
+ int i;
137
+ struct common_header_name *cf = common_headers;
138
+
139
+ for(i = ARRAY_SIZE(common_headers); --i >= 0; cf++) {
140
+ if (cf->len == (long)len && !strncasecmp(cf->name, name, len))
141
+ return cf->value;
142
+ }
143
+ return Qnil;
144
+ }
145
+
146
+ /* This function is called for every short header found */
147
+ static VALUE find_short_header_name(char abbr)
148
+ {
149
+ TRACE();
150
+ int i;
151
+ struct short_header *sh = short_headers;
152
+
153
+ for(i = ARRAY_SIZE(short_headers); --i >= 0; sh++) {
154
+ if (sh->abbr == toupper(abbr))
155
+ return sh->value;
156
+ }
157
+ return Qnil;
158
+ }
159
+
160
+
161
+ /* Tries to lookup the header name in a list of well-known headers. If so,
162
+ * returns the retrieved VALUE. It also works for short headers.
163
+ * In case the header is unknown, it normalizes it (by capitalizing the
164
+ * first letter and each letter under a "-" or "_" symbol).
165
+ */
166
+ static VALUE headerize(const char* hname, size_t hname_len)
167
+ {
168
+ TRACE();
169
+ VALUE headerized;
170
+ char* str;
171
+ int i;
172
+
173
+ /* Header short name. */
174
+ if (hname_len == 1) {
175
+ headerized = find_short_header_name(hname[0]);
176
+ if (NIL_P(headerized)) {
177
+ headerized = rb_str_new(hname, hname_len);
178
+ /* Downcase the header name. */
179
+ downcase_char(RSTRING_PTR(headerized));
180
+ }
181
+ }
182
+
183
+ /* Header long name. */
184
+ else {
185
+ headerized = find_common_header_name(hname, hname_len);
186
+ if (NIL_P(headerized)) {
187
+ headerized = rb_str_new(hname, hname_len);
188
+ str = RSTRING_PTR(headerized);
189
+ if (*str >= 'a' && *str <= 'z')
190
+ *str &= ~0x20;
191
+
192
+ for(i = 1; i < hname_len; i++) {
193
+ if (str[i-1] == '-' || str[i-1] == '_') {
194
+ if (str[i] >= 'a' && str[i] <= 'z')
195
+ str[i] &= ~0x20;
196
+ }
197
+ else {
198
+ if (str[i] >= 'A' && str[i] <= 'Z')
199
+ str[i] += 32;
200
+ }
201
+ }
202
+ }
203
+ }
204
+
205
+ return(headerized);
206
+ }
207
+
208
+
209
+ #endif
@@ -0,0 +1,18 @@
1
+ #ifndef ext_help_h
2
+ #define ext_help_h
3
+
4
+ #define RAISE_NOT_NULL(T) if(T == NULL) rb_raise(rb_eArgError, "NULL found for " # T " when shouldn't be.");
5
+ #define DATA_GET(from,type,name) Data_Get_Struct(from,type,name); RAISE_NOT_NULL(name);
6
+ #define REQUIRE_TYPE(V, T) if(TYPE(V) != T) rb_raise(rb_eTypeError, "Wrong argument type for " # V " required " # T);
7
+
8
+
9
+ /* Uncomment for enabling TRACE() function. */
10
+ /*#define DEBUG */
11
+
12
+ #ifdef DEBUG
13
+ #define TRACE() fprintf(stderr, "TRACE: %s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__)
14
+ #else
15
+ #define TRACE()
16
+ #endif
17
+
18
+ #endif
@@ -0,0 +1,3 @@
1
+ require "mkmf"
2
+
3
+ create_makefile("oversip/sip/sip_parser")