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
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")