oversip 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS.txt +11 -0
- data/LICENSE.txt +22 -0
- data/README.md +16 -0
- data/Rakefile +55 -0
- data/bin/oversip +182 -0
- data/ext/common/c_util.h +74 -0
- data/ext/common/ruby_c_util.h +88 -0
- data/ext/sip_parser/common_headers.h +209 -0
- data/ext/sip_parser/ext_help.h +18 -0
- data/ext/sip_parser/extconf.rb +3 -0
- data/ext/sip_parser/sip_parser.c +29649 -0
- data/ext/sip_parser/sip_parser.h +227 -0
- data/ext/sip_parser/sip_parser_ruby.c +1292 -0
- data/ext/stud/extconf.rb +27 -0
- data/ext/stud/stud.tar.gz +0 -0
- data/ext/stun/ext_help.h +16 -0
- data/ext/stun/extconf.rb +3 -0
- data/ext/stun/stun_ruby.c +391 -0
- data/ext/utils/ext_help.h +14 -0
- data/ext/utils/extconf.rb +3 -0
- data/ext/utils/haproxy_protocol.c +6163 -0
- data/ext/utils/haproxy_protocol.h +27 -0
- data/ext/utils/ip_utils.c +5952 -0
- data/ext/utils/ip_utils.h +61 -0
- data/ext/utils/outbound_utils.c +3227 -0
- data/ext/utils/outbound_utils.h +27 -0
- data/ext/utils/utils_ruby.c +384 -0
- data/ext/utils/utils_ruby.h +75 -0
- data/ext/websocket_framing_utils/ext_help.h +18 -0
- data/ext/websocket_framing_utils/extconf.rb +3 -0
- data/ext/websocket_framing_utils/ws_framing_utils.h +46 -0
- data/ext/websocket_framing_utils/ws_framing_utils_ruby.c +135 -0
- data/ext/websocket_http_parser/ext_help.h +18 -0
- data/ext/websocket_http_parser/extconf.rb +3 -0
- data/ext/websocket_http_parser/ws_http_parser.c +2598 -0
- data/ext/websocket_http_parser/ws_http_parser.h +86 -0
- data/ext/websocket_http_parser/ws_http_parser_ruby.c +630 -0
- data/lib/oversip/config.rb +541 -0
- data/lib/oversip/config_validators.rb +126 -0
- data/lib/oversip/errors.rb +7 -0
- data/lib/oversip/fiber_pool.rb +56 -0
- data/lib/oversip/launcher.rb +507 -0
- data/lib/oversip/logger.rb +170 -0
- data/lib/oversip/master_process.rb +67 -0
- data/lib/oversip/posix_mq.rb +121 -0
- data/lib/oversip/proxies_config.rb +169 -0
- data/lib/oversip/ruby_ext/eventmachine.rb +38 -0
- data/lib/oversip/sip/client_transaction.rb +587 -0
- data/lib/oversip/sip/constants.rb +87 -0
- data/lib/oversip/sip/grammar/name_addr.rb +27 -0
- data/lib/oversip/sip/grammar/uri.rb +116 -0
- data/lib/oversip/sip/launcher.rb +180 -0
- data/lib/oversip/sip/listeners/ipv4_tcp_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tcp_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tls_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tls_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tls_tunnel_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_udp_server.rb +20 -0
- data/lib/oversip/sip/listeners/ipv6_tcp_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tcp_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tls_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tls_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tls_tunnel_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_udp_server.rb +20 -0
- data/lib/oversip/sip/listeners/reactor.rb +39 -0
- data/lib/oversip/sip/listeners/tcp_client.rb +73 -0
- data/lib/oversip/sip/listeners/tcp_reactor.rb +185 -0
- data/lib/oversip/sip/listeners/tcp_server.rb +71 -0
- data/lib/oversip/sip/listeners/tls_client.rb +117 -0
- data/lib/oversip/sip/listeners/tls_server.rb +70 -0
- data/lib/oversip/sip/listeners/tls_tunnel_reactor.rb +113 -0
- data/lib/oversip/sip/listeners/tls_tunnel_server.rb +61 -0
- data/lib/oversip/sip/listeners/udp_reactor.rb +213 -0
- data/lib/oversip/sip/listeners.rb +28 -0
- data/lib/oversip/sip/logic.rb +14 -0
- data/lib/oversip/sip/message.rb +168 -0
- data/lib/oversip/sip/message_processor.rb +202 -0
- data/lib/oversip/sip/modules/core.rb +200 -0
- data/lib/oversip/sip/modules/registrar_without_path.rb +75 -0
- data/lib/oversip/sip/modules/user_assertion.rb +123 -0
- data/lib/oversip/sip/proxy.rb +460 -0
- data/lib/oversip/sip/request.rb +128 -0
- data/lib/oversip/sip/response.rb +30 -0
- data/lib/oversip/sip/rfc3263.rb +646 -0
- data/lib/oversip/sip/server_transaction.rb +295 -0
- data/lib/oversip/sip/sip.rb +74 -0
- data/lib/oversip/sip/tags.rb +39 -0
- data/lib/oversip/sip/timers.rb +55 -0
- data/lib/oversip/sip/transport_manager.rb +129 -0
- data/lib/oversip/syslogger_process.rb +119 -0
- data/lib/oversip/tls.rb +179 -0
- data/lib/oversip/utils.rb +25 -0
- data/lib/oversip/version.rb +23 -0
- data/lib/oversip/websocket/constants.rb +56 -0
- data/lib/oversip/websocket/default_policy.rb +19 -0
- data/lib/oversip/websocket/http_request.rb +63 -0
- data/lib/oversip/websocket/launcher.rb +207 -0
- data/lib/oversip/websocket/listeners/ipv4_tcp_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv4_tls_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv4_tls_tunnel_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv6_tcp_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv6_tls_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv6_tls_tunnel_server.rb +15 -0
- data/lib/oversip/websocket/listeners/tcp_server.rb +265 -0
- data/lib/oversip/websocket/listeners/tls_server.rb +69 -0
- data/lib/oversip/websocket/listeners/tls_tunnel_server.rb +100 -0
- data/lib/oversip/websocket/listeners.rb +12 -0
- data/lib/oversip/websocket/ws_app.rb +75 -0
- data/lib/oversip/websocket/ws_apps/ipv4_ws_sip_app.rb +21 -0
- data/lib/oversip/websocket/ws_apps/ipv4_wss_sip_app.rb +21 -0
- data/lib/oversip/websocket/ws_apps/ipv6_ws_sip_app.rb +21 -0
- data/lib/oversip/websocket/ws_apps/ipv6_wss_sip_app.rb +22 -0
- data/lib/oversip/websocket/ws_apps/ws_autobahn_app.rb +23 -0
- data/lib/oversip/websocket/ws_apps/ws_sip_app.rb +156 -0
- data/lib/oversip/websocket/ws_apps.rb +9 -0
- data/lib/oversip/websocket/ws_framing.rb +597 -0
- data/lib/oversip.rb +59 -0
- data/test/oversip_test_helper.rb +20 -0
- data/test/test_http_parser.rb +73 -0
- data/test/test_sip_parser.rb +139 -0
- metadata +256 -0
@@ -0,0 +1,27 @@
|
|
1
|
+
#ifndef outbound_utils_h
|
2
|
+
#define outbound_utils_h
|
3
|
+
|
4
|
+
|
5
|
+
#include <sys/types.h>
|
6
|
+
|
7
|
+
|
8
|
+
enum enum_outbound_udp_flow_token_ip_type {
|
9
|
+
outbound_udp_flow_token_ip_type_ipv4 = 1,
|
10
|
+
outbound_udp_flow_token_ip_type_ipv6
|
11
|
+
};
|
12
|
+
|
13
|
+
|
14
|
+
typedef struct struct_outbound_udp_flow_token {
|
15
|
+
unsigned short int valid;
|
16
|
+
enum enum_outbound_udp_flow_token_ip_type ip_type;
|
17
|
+
size_t ip_s;
|
18
|
+
size_t ip_len;
|
19
|
+
size_t port_s;
|
20
|
+
size_t port_len;
|
21
|
+
} struct_outbound_udp_flow_token;
|
22
|
+
|
23
|
+
|
24
|
+
struct_outbound_udp_flow_token outbound_udp_flow_token_parser_execute(const char *str, size_t len);
|
25
|
+
|
26
|
+
|
27
|
+
#endif
|
@@ -0,0 +1,384 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include "ext_help.h"
|
3
|
+
#include "ip_utils.h"
|
4
|
+
#include "utils_ruby.h"
|
5
|
+
#include "../common/c_util.h"
|
6
|
+
|
7
|
+
|
8
|
+
static VALUE mOverSIP;
|
9
|
+
static VALUE mUtils;
|
10
|
+
|
11
|
+
static VALUE symbol_ipv4;
|
12
|
+
static VALUE symbol_ipv6;
|
13
|
+
static VALUE symbol_ipv6_reference;
|
14
|
+
|
15
|
+
|
16
|
+
|
17
|
+
/*
|
18
|
+
* Ruby functions.
|
19
|
+
*/
|
20
|
+
|
21
|
+
VALUE Utils_is_ip(VALUE self, VALUE string)
|
22
|
+
{
|
23
|
+
TRACE();
|
24
|
+
char *str;
|
25
|
+
long len;
|
26
|
+
|
27
|
+
if (TYPE(string) != T_STRING)
|
28
|
+
rb_raise(rb_eTypeError, "Argument must be a String");
|
29
|
+
|
30
|
+
str = RSTRING_PTR(string);
|
31
|
+
len = RSTRING_LEN(string);
|
32
|
+
|
33
|
+
if (utils_ip_parser_execute(str, len) != ip_type_error)
|
34
|
+
return Qtrue;
|
35
|
+
else
|
36
|
+
return Qfalse;
|
37
|
+
}
|
38
|
+
|
39
|
+
|
40
|
+
VALUE Utils_is_pure_ip(VALUE self, VALUE string)
|
41
|
+
{
|
42
|
+
TRACE();
|
43
|
+
char *str;
|
44
|
+
long len;
|
45
|
+
|
46
|
+
if (TYPE(string) != T_STRING)
|
47
|
+
rb_raise(rb_eTypeError, "Argument must be a String");
|
48
|
+
|
49
|
+
str = RSTRING_PTR(string);
|
50
|
+
len = RSTRING_LEN(string);
|
51
|
+
|
52
|
+
switch(utils_ip_parser_execute(str, len)) {
|
53
|
+
case(ip_type_ipv4):
|
54
|
+
return Qtrue;
|
55
|
+
break;
|
56
|
+
case(ip_type_ipv6):
|
57
|
+
return Qtrue;
|
58
|
+
break;
|
59
|
+
default:
|
60
|
+
return Qfalse;
|
61
|
+
break;
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
|
66
|
+
VALUE Utils_ip_type(VALUE self, VALUE string)
|
67
|
+
{
|
68
|
+
TRACE();
|
69
|
+
char *str;
|
70
|
+
long len;
|
71
|
+
|
72
|
+
if (TYPE(string) != T_STRING)
|
73
|
+
rb_raise(rb_eTypeError, "Argument must be a String");
|
74
|
+
|
75
|
+
str = RSTRING_PTR(string);
|
76
|
+
len = RSTRING_LEN(string);
|
77
|
+
|
78
|
+
switch(utils_ip_parser_execute(str, len)) {
|
79
|
+
case(ip_type_ipv4):
|
80
|
+
return symbol_ipv4;
|
81
|
+
break;
|
82
|
+
case(ip_type_ipv6):
|
83
|
+
return symbol_ipv6;
|
84
|
+
break;
|
85
|
+
case(ip_type_ipv6_reference):
|
86
|
+
return symbol_ipv6_reference;
|
87
|
+
break;
|
88
|
+
default:
|
89
|
+
return Qfalse;
|
90
|
+
break;
|
91
|
+
}
|
92
|
+
}
|
93
|
+
|
94
|
+
|
95
|
+
/*
|
96
|
+
* Returns true if both IP's are equal (binary comparison).
|
97
|
+
* Returns false if both IP's are not equal.
|
98
|
+
* Returns nil if at least one of the IP's is not valid IPv4, IPv6 or IPv6 reference.
|
99
|
+
* This function also allows comparing an IPv6 with an IPv6 reference.
|
100
|
+
*/
|
101
|
+
VALUE Utils_compare_ips(VALUE self, VALUE string1, VALUE string2)
|
102
|
+
{
|
103
|
+
TRACE();
|
104
|
+
char *str1, *str2;
|
105
|
+
long len1, len2;
|
106
|
+
enum enum_ip_type ip1_type, ip2_type;
|
107
|
+
|
108
|
+
if (TYPE(string1) != T_STRING || TYPE(string2) != T_STRING)
|
109
|
+
rb_raise(rb_eTypeError, "Arguments must be two String");
|
110
|
+
|
111
|
+
str1 = RSTRING_PTR(string1);
|
112
|
+
len1 = RSTRING_LEN(string1);
|
113
|
+
str2 = RSTRING_PTR(string2);
|
114
|
+
len2 = RSTRING_LEN(string2);
|
115
|
+
|
116
|
+
switch(ip1_type = utils_ip_parser_execute(str1, len1)) {
|
117
|
+
case(ip_type_error):
|
118
|
+
return Qnil;
|
119
|
+
break;
|
120
|
+
case(ip_type_ipv6_reference):
|
121
|
+
str1 += 1;
|
122
|
+
len1 -= 2;
|
123
|
+
ip1_type = ip_type_ipv6;
|
124
|
+
break;
|
125
|
+
default:
|
126
|
+
break;
|
127
|
+
}
|
128
|
+
switch(ip2_type = utils_ip_parser_execute(str2, len2)) {
|
129
|
+
case(ip_type_error):
|
130
|
+
return Qnil;
|
131
|
+
break;
|
132
|
+
case(ip_type_ipv6_reference):
|
133
|
+
str2 += 1;
|
134
|
+
len2 -= 2;
|
135
|
+
ip2_type = ip_type_ipv6;
|
136
|
+
break;
|
137
|
+
default:
|
138
|
+
break;
|
139
|
+
}
|
140
|
+
|
141
|
+
if (utils_compare_pure_ips(str1, len1, ip1_type, str2, len2, ip2_type))
|
142
|
+
return Qtrue;
|
143
|
+
else
|
144
|
+
return Qfalse;
|
145
|
+
}
|
146
|
+
|
147
|
+
|
148
|
+
/*
|
149
|
+
* Returns true if both IP's are equal (binary comparison).
|
150
|
+
* Returns false if both IP's are not equal.
|
151
|
+
* Returns nil if at least one of the IP's is not valid IPv4 or IPv6.
|
152
|
+
* This function does not allow comparing an IPv6 with an IPv6 reference.
|
153
|
+
*/
|
154
|
+
VALUE Utils_compare_pure_ips(VALUE self, VALUE string1, VALUE string2)
|
155
|
+
{
|
156
|
+
TRACE();
|
157
|
+
char *str1, *str2;
|
158
|
+
long len1, len2;
|
159
|
+
enum enum_ip_type ip1_type, ip2_type;
|
160
|
+
|
161
|
+
if (TYPE(string1) != T_STRING || TYPE(string2) != T_STRING)
|
162
|
+
rb_raise(rb_eTypeError, "Arguments must be two String");
|
163
|
+
|
164
|
+
str1 = RSTRING_PTR(string1);
|
165
|
+
len1 = RSTRING_LEN(string1);
|
166
|
+
str2 = RSTRING_PTR(string2);
|
167
|
+
len2 = RSTRING_LEN(string2);
|
168
|
+
|
169
|
+
switch(ip1_type = utils_ip_parser_execute(str1, len1)) {
|
170
|
+
case(ip_type_error):
|
171
|
+
return Qnil;
|
172
|
+
break;
|
173
|
+
case(ip_type_ipv6_reference):
|
174
|
+
return Qnil;
|
175
|
+
break;
|
176
|
+
default:
|
177
|
+
break;
|
178
|
+
}
|
179
|
+
switch(ip2_type = utils_ip_parser_execute(str2, len2)) {
|
180
|
+
case(ip_type_error):
|
181
|
+
return Qnil;
|
182
|
+
break;
|
183
|
+
case(ip_type_ipv6_reference):
|
184
|
+
return Qnil;
|
185
|
+
break;
|
186
|
+
default:
|
187
|
+
break;
|
188
|
+
}
|
189
|
+
|
190
|
+
if (utils_compare_pure_ips(str1, len1, ip1_type, str2, len2, ip2_type))
|
191
|
+
return Qtrue;
|
192
|
+
else
|
193
|
+
return Qfalse;
|
194
|
+
}
|
195
|
+
|
196
|
+
|
197
|
+
/*
|
198
|
+
* Returns the normalized printable string of the given IPv6.
|
199
|
+
* - First argument is a string to normalize. It must be a valid IPv6 or
|
200
|
+
* IPv6 reference. If not, the method returns false.
|
201
|
+
* - Second argument is optional. If true, returned value is a pure IPv6 even
|
202
|
+
* if the first argument is a IPv6 reference.
|
203
|
+
*/
|
204
|
+
VALUE Utils_normalize_ipv6(int argc, VALUE *argv, VALUE self)
|
205
|
+
{
|
206
|
+
TRACE();
|
207
|
+
VALUE string;
|
208
|
+
int force_pure_ipv6 = 0;
|
209
|
+
|
210
|
+
if (argc == 0 || argc > 2)
|
211
|
+
rb_raise(rb_eTypeError, "Wrong number of arguments (pass one or two)");
|
212
|
+
|
213
|
+
string = argv[0];
|
214
|
+
if (TYPE(string) != T_STRING)
|
215
|
+
rb_raise(rb_eTypeError, "First argument must be a String");
|
216
|
+
|
217
|
+
if (argc == 2 && TYPE(argv[1]) != T_NIL && TYPE(argv[1]) != T_FALSE)
|
218
|
+
force_pure_ipv6 = 1;
|
219
|
+
|
220
|
+
return utils_normalize_ipv6(string, force_pure_ipv6);
|
221
|
+
}
|
222
|
+
|
223
|
+
|
224
|
+
/*
|
225
|
+
* Returns the normalized printable string of the given IPv4 or IPv6.
|
226
|
+
* - First argument is a string to normalize. It must be a valid IPv4, IPv6 or
|
227
|
+
* IPv6 reference. If not, the method returns the string itself.
|
228
|
+
* - Second argument is the type of host (:ipv4, :ipv6, :ipv6_reference or :domain).
|
229
|
+
* - Third argument is optional. If true, returned value is a pure IPv6 even
|
230
|
+
* if the first argument is a IPv6 reference.
|
231
|
+
*/
|
232
|
+
VALUE Utils_normalize_host(int argc, VALUE *argv, VALUE self)
|
233
|
+
{
|
234
|
+
TRACE();
|
235
|
+
VALUE host, ip_type;
|
236
|
+
int force_pure_ipv6 = 0;
|
237
|
+
|
238
|
+
if (argc == 0 || argc > 3)
|
239
|
+
rb_raise(rb_eTypeError, "Wrong number of arguments (pass one, two or three)");
|
240
|
+
|
241
|
+
host = argv[0];
|
242
|
+
if (TYPE(host) != T_STRING)
|
243
|
+
rb_raise(rb_eTypeError, "First argument must be a String");
|
244
|
+
|
245
|
+
ip_type = argv[1];
|
246
|
+
if (TYPE(ip_type) != T_SYMBOL)
|
247
|
+
rb_raise(rb_eTypeError, "Second argument must be a Symbol (:ipv4, :ipv6 or :domain)");
|
248
|
+
|
249
|
+
if (argc == 3 && TYPE(argv[2]) != T_NIL && TYPE(argv[2]) != T_FALSE)
|
250
|
+
force_pure_ipv6 = 1;
|
251
|
+
|
252
|
+
if (ip_type == symbol_ipv6 || ip_type == symbol_ipv6_reference)
|
253
|
+
return utils_normalize_ipv6(host, force_pure_ipv6);
|
254
|
+
else
|
255
|
+
return host;
|
256
|
+
}
|
257
|
+
|
258
|
+
|
259
|
+
/*
|
260
|
+
* If the given argument is a IPV6 reference it returns a new string with the pure IPv6.
|
261
|
+
* In any other case, return the given argument.
|
262
|
+
*/
|
263
|
+
VALUE Utils_to_pure_ip(VALUE self, VALUE string)
|
264
|
+
{
|
265
|
+
TRACE();
|
266
|
+
char *str;
|
267
|
+
|
268
|
+
str = StringValueCStr(string);
|
269
|
+
if (str[0] == '[')
|
270
|
+
return rb_str_new(RSTRING_PTR(string)+1, RSTRING_LEN(string)-2);
|
271
|
+
else
|
272
|
+
return string;
|
273
|
+
}
|
274
|
+
|
275
|
+
|
276
|
+
/*
|
277
|
+
* Expects a string like "1.2.3.4_5060" or "1af:43::ab_9090" and returns
|
278
|
+
* an Array as follows:
|
279
|
+
* [ ip_type, ip, port ]
|
280
|
+
* where:
|
281
|
+
* - ip_type is :ipv4 or :ipv6,
|
282
|
+
* - ip is a String,
|
283
|
+
* - port is a Fixnum
|
284
|
+
* If the string is invalid it returns false.
|
285
|
+
*/
|
286
|
+
VALUE Utils_parser_outbound_udp_flow_token(VALUE self, VALUE string)
|
287
|
+
{
|
288
|
+
TRACE();
|
289
|
+
char *str = NULL;
|
290
|
+
long len = 0;
|
291
|
+
struct_outbound_udp_flow_token outbound_udp_flow_token;
|
292
|
+
VALUE ip_type, ip, port;
|
293
|
+
|
294
|
+
if (TYPE(string) != T_STRING)
|
295
|
+
rb_raise(rb_eTypeError, "Argument must be a String");
|
296
|
+
|
297
|
+
str = RSTRING_PTR(string);
|
298
|
+
len = RSTRING_LEN(string);
|
299
|
+
|
300
|
+
/* Remove the leading "_" from the string. */
|
301
|
+
outbound_udp_flow_token = outbound_udp_flow_token_parser_execute(str, len);
|
302
|
+
|
303
|
+
if (outbound_udp_flow_token.valid == 0)
|
304
|
+
return Qfalse;
|
305
|
+
else {
|
306
|
+
if (outbound_udp_flow_token.ip_type == outbound_udp_flow_token_ip_type_ipv4)
|
307
|
+
ip_type = symbol_ipv4;
|
308
|
+
else
|
309
|
+
ip_type = symbol_ipv6;
|
310
|
+
|
311
|
+
ip = rb_str_new((char *)outbound_udp_flow_token.ip_s, outbound_udp_flow_token.ip_len);
|
312
|
+
port = INT2FIX(str_to_int((char *)outbound_udp_flow_token.port_s, outbound_udp_flow_token.port_len));
|
313
|
+
|
314
|
+
return rb_ary_new3(3, ip_type, ip, port);
|
315
|
+
}
|
316
|
+
}
|
317
|
+
|
318
|
+
|
319
|
+
/*
|
320
|
+
* Expects a string like "PROXY TCP4 192.168.0.1 192.168.0.11 56324 443\r\n" and returns
|
321
|
+
* an Array as follows:
|
322
|
+
* [ num_bytes, ip_type, ip, port ]
|
323
|
+
* where:
|
324
|
+
* - num_bytes is the length of the HAProxy Protocol line (to be removed), a Fixnum.
|
325
|
+
* - ip_type is :ipv4 or :ipv6,
|
326
|
+
* - ip is a String,
|
327
|
+
* - port is a Fixnum
|
328
|
+
* If the string is invalid it returns false.
|
329
|
+
*/
|
330
|
+
VALUE Utils_parser_haproxy_protocol(VALUE self, VALUE string)
|
331
|
+
{
|
332
|
+
TRACE();
|
333
|
+
char *str = NULL;
|
334
|
+
long len = 0;
|
335
|
+
struct_haproxy_protocol haproxy_protocol;
|
336
|
+
VALUE num_bytes, ip_type, ip, port;
|
337
|
+
|
338
|
+
if (TYPE(string) != T_STRING)
|
339
|
+
rb_raise(rb_eTypeError, "Argument must be a String");
|
340
|
+
|
341
|
+
str = RSTRING_PTR(string);
|
342
|
+
len = RSTRING_LEN(string);
|
343
|
+
|
344
|
+
haproxy_protocol = struct_haproxy_protocol_parser_execute(str, len);
|
345
|
+
|
346
|
+
if (haproxy_protocol.valid == 0)
|
347
|
+
return Qfalse;
|
348
|
+
else {
|
349
|
+
if (haproxy_protocol.ip_type == haproxy_protocol_ip_type_ipv4)
|
350
|
+
ip_type = symbol_ipv4;
|
351
|
+
else
|
352
|
+
ip_type = symbol_ipv6;
|
353
|
+
|
354
|
+
ip = rb_str_new((char *)haproxy_protocol.ip_s, haproxy_protocol.ip_len);
|
355
|
+
port = INT2FIX(str_to_int((char *)haproxy_protocol.port_s, haproxy_protocol.port_len));
|
356
|
+
num_bytes = INT2FIX(haproxy_protocol.total_len);
|
357
|
+
|
358
|
+
return rb_ary_new3(4, num_bytes, ip_type, ip, port);
|
359
|
+
}
|
360
|
+
}
|
361
|
+
|
362
|
+
|
363
|
+
void Init_utils()
|
364
|
+
{
|
365
|
+
TRACE();
|
366
|
+
|
367
|
+
mOverSIP = rb_define_module("OverSIP");
|
368
|
+
mUtils = rb_define_module_under(mOverSIP, "Utils");
|
369
|
+
|
370
|
+
rb_define_module_function(mUtils, "ip?", Utils_is_ip, 1);
|
371
|
+
rb_define_module_function(mUtils, "pure_ip?", Utils_is_pure_ip, 1);
|
372
|
+
rb_define_module_function(mUtils, "ip_type", Utils_ip_type, 1);
|
373
|
+
rb_define_module_function(mUtils, "compare_ips", Utils_compare_ips, 2);
|
374
|
+
rb_define_module_function(mUtils, "compare_pure_ips", Utils_compare_pure_ips, 2);
|
375
|
+
rb_define_module_function(mUtils, "normalize_ipv6", Utils_normalize_ipv6, -1);
|
376
|
+
rb_define_module_function(mUtils, "normalize_host", Utils_normalize_host, -1);
|
377
|
+
rb_define_module_function(mUtils, "to_pure_ip", Utils_to_pure_ip, 1);
|
378
|
+
rb_define_module_function(mUtils, "parse_outbound_udp_flow_token", Utils_parser_outbound_udp_flow_token, 1);
|
379
|
+
rb_define_module_function(mUtils, "parse_haproxy_protocol", Utils_parser_haproxy_protocol, 1);
|
380
|
+
|
381
|
+
symbol_ipv4 = ID2SYM(rb_intern("ipv4"));
|
382
|
+
symbol_ipv6 = ID2SYM(rb_intern("ipv6"));
|
383
|
+
symbol_ipv6_reference = ID2SYM(rb_intern("ipv6_reference"));
|
384
|
+
}
|
@@ -0,0 +1,75 @@
|
|
1
|
+
/*
|
2
|
+
* This file is not used by Ruby OverSIP::Utils module itself, its aim is to
|
3
|
+
* be included by other OverSIP Ruby C extensions.
|
4
|
+
*/
|
5
|
+
|
6
|
+
#ifndef utils_ruby_h
|
7
|
+
#define utils_ruby_h
|
8
|
+
|
9
|
+
|
10
|
+
#include "ip_utils.h"
|
11
|
+
#include "outbound_utils.h"
|
12
|
+
#include "haproxy_protocol.h"
|
13
|
+
|
14
|
+
|
15
|
+
/* Export the Ruby C functions so other C libraries within OverSIP can use them. */
|
16
|
+
VALUE Utils_is_ip(VALUE self, VALUE string);
|
17
|
+
VALUE Utils_is_pure_ip(VALUE self, VALUE string);
|
18
|
+
VALUE Utils_ip_type(VALUE self, VALUE string);
|
19
|
+
VALUE Utils_compare_ips(VALUE self, VALUE string1, VALUE string2);
|
20
|
+
VALUE Utils_compare_pure_ips(VALUE self, VALUE string1, VALUE string2);
|
21
|
+
VALUE Utils_normalize_ipv6(int argc, VALUE *argv, VALUE self);
|
22
|
+
VALUE Utils_normalize_host(int argc, VALUE *argv, VALUE self);
|
23
|
+
VALUE Utils_to_pure_ip(VALUE self, VALUE string);
|
24
|
+
VALUE Utils_parser_outbound_udp_flow_token(VALUE self, VALUE string);
|
25
|
+
VALUE Utils_parser_haproxy_protocol(VALUE self, VALUE string);
|
26
|
+
|
27
|
+
|
28
|
+
VALUE utils_normalize_ipv6(VALUE string, int force_pure_ipv6)
|
29
|
+
{
|
30
|
+
struct in6_addr addr;
|
31
|
+
char normalized_ipv6[INET6_ADDRSTRLEN + 1];
|
32
|
+
char normalized_ipv6_reference[INET6_ADDRSTRLEN + 3];
|
33
|
+
char *str, str2[INET6_ADDRSTRLEN + 3], *str_pointer;
|
34
|
+
int is_ipv6_reference = 0;
|
35
|
+
|
36
|
+
str = StringValueCStr(string);
|
37
|
+
if (str[0] != '[') {
|
38
|
+
str_pointer = str;
|
39
|
+
}
|
40
|
+
else {
|
41
|
+
is_ipv6_reference = 1;
|
42
|
+
memcpy(str2, str + 1, strlen(str) - 2);
|
43
|
+
str2[strlen(str) - 2] = '\0';
|
44
|
+
str_pointer = str2;
|
45
|
+
}
|
46
|
+
|
47
|
+
switch(inet_pton(AF_INET6, str_pointer, &addr)) {
|
48
|
+
/* Not a valid IPv6. */
|
49
|
+
case 0:
|
50
|
+
return Qfalse;
|
51
|
+
break;
|
52
|
+
/* Some error ocurred. */
|
53
|
+
case -1:
|
54
|
+
return Qnil;
|
55
|
+
break;
|
56
|
+
default:
|
57
|
+
break;
|
58
|
+
}
|
59
|
+
|
60
|
+
if (inet_ntop(AF_INET6, &addr, normalized_ipv6, INET6_ADDRSTRLEN))
|
61
|
+
if (is_ipv6_reference && !force_pure_ipv6) {
|
62
|
+
memcpy(normalized_ipv6_reference, "[", 1);
|
63
|
+
memcpy(normalized_ipv6_reference + 1, normalized_ipv6, strlen(normalized_ipv6));
|
64
|
+
memcpy(normalized_ipv6_reference + strlen(normalized_ipv6) + 1, "]\0", 2);
|
65
|
+
return rb_str_new_cstr(normalized_ipv6_reference);
|
66
|
+
}
|
67
|
+
else
|
68
|
+
return rb_str_new_cstr(normalized_ipv6);
|
69
|
+
/* Some error ocurred. */
|
70
|
+
else
|
71
|
+
return Qnil;
|
72
|
+
}
|
73
|
+
|
74
|
+
|
75
|
+
#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,46 @@
|
|
1
|
+
#ifndef ws_framing_utils_h
|
2
|
+
#define ws_framing_utils_h
|
3
|
+
|
4
|
+
|
5
|
+
#include <stdint.h>
|
6
|
+
|
7
|
+
|
8
|
+
/* Extracted from http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ */
|
9
|
+
|
10
|
+
#define UTF8_ACCEPT 0
|
11
|
+
#define UTF8_REJECT 1
|
12
|
+
#define UTF8D_SIZE 400
|
13
|
+
|
14
|
+
static const uint8_t utf8d[] = {
|
15
|
+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 00..1f */
|
16
|
+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 20..3f */
|
17
|
+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 40..5f */
|
18
|
+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 60..7f */
|
19
|
+
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, /* 80..9f */
|
20
|
+
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* a0..bf */
|
21
|
+
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* c0..df */
|
22
|
+
0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, /* e0..ef */
|
23
|
+
0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, /* f0..ff */
|
24
|
+
0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, /* s0..s0 */
|
25
|
+
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, /* s1..s2 */
|
26
|
+
1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, /* s3..s4 */
|
27
|
+
1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, /* s5..s6 */
|
28
|
+
1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1 /* s7..s8 */
|
29
|
+
};
|
30
|
+
|
31
|
+
uint32_t inline utf8_decode(uint32_t* state, uint32_t* codep, uint32_t byte) {
|
32
|
+
uint32_t type = utf8d[byte];
|
33
|
+
|
34
|
+
*codep = (*state != UTF8_ACCEPT) ? (byte & 0x3fu) | (*codep << 6) : (0xff >> type) & (byte);
|
35
|
+
*state = utf8d[256 + *state*16 + type];
|
36
|
+
return *state;
|
37
|
+
}
|
38
|
+
|
39
|
+
|
40
|
+
typedef struct utf8_validator {
|
41
|
+
uint32_t codepoint;
|
42
|
+
uint32_t state;
|
43
|
+
} utf8_validator;
|
44
|
+
|
45
|
+
|
46
|
+
#endif
|
@@ -0,0 +1,135 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include "ws_framing_utils.h"
|
3
|
+
#include "ext_help.h"
|
4
|
+
|
5
|
+
|
6
|
+
static VALUE mOverSIP;
|
7
|
+
static VALUE mWebSocket;
|
8
|
+
static VALUE mFramingUtils;
|
9
|
+
static VALUE cUtf8Validator;
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
/*
|
14
|
+
* Ruby functions.
|
15
|
+
*/
|
16
|
+
|
17
|
+
VALUE WsFrammingUtils_unmask(VALUE self, VALUE payload, VALUE mask)
|
18
|
+
{
|
19
|
+
char *payload_str, *mask_str;
|
20
|
+
long payload_len; /* mask length is always 4 bytes. */
|
21
|
+
char *unmasked_payload_str;
|
22
|
+
VALUE rb_unmasked_payload;
|
23
|
+
int i;
|
24
|
+
|
25
|
+
if (TYPE(payload) != T_STRING)
|
26
|
+
rb_raise(rb_eTypeError, "Argument must be a String");
|
27
|
+
|
28
|
+
if (TYPE(mask) != T_STRING)
|
29
|
+
rb_raise(rb_eTypeError, "Argument must be a String");
|
30
|
+
|
31
|
+
if (RSTRING_LEN(mask) != 4)
|
32
|
+
rb_raise(rb_eTypeError, "mask size must be 4 bytes");
|
33
|
+
|
34
|
+
payload_str = RSTRING_PTR(payload);
|
35
|
+
payload_len = RSTRING_LEN(payload);
|
36
|
+
mask_str = RSTRING_PTR(mask);
|
37
|
+
|
38
|
+
/* NOTE: In Ruby C extensions always use:
|
39
|
+
* pointer = ALLOC_N(type, n)
|
40
|
+
* which means: pointer = (type*)xmalloc(sizeof(type)*(n))
|
41
|
+
* and:
|
42
|
+
* xfree()
|
43
|
+
*/
|
44
|
+
|
45
|
+
unmasked_payload_str = ALLOC_N(char, payload_len);
|
46
|
+
|
47
|
+
for(i=0; i < payload_len; i++)
|
48
|
+
unmasked_payload_str[i] = payload_str[i] ^ mask_str[i % 4];
|
49
|
+
|
50
|
+
rb_unmasked_payload = rb_str_new(unmasked_payload_str, payload_len);
|
51
|
+
xfree(unmasked_payload_str);
|
52
|
+
return(rb_unmasked_payload);
|
53
|
+
}
|
54
|
+
|
55
|
+
|
56
|
+
static void Utf8Validator_free(void *validator)
|
57
|
+
{
|
58
|
+
TRACE();
|
59
|
+
if(validator) {
|
60
|
+
xfree(validator);
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
|
65
|
+
VALUE Utf8Validator_alloc(VALUE klass)
|
66
|
+
{
|
67
|
+
TRACE();
|
68
|
+
VALUE obj;
|
69
|
+
utf8_validator *validator = ALLOC(utf8_validator);
|
70
|
+
|
71
|
+
validator->state = UTF8_ACCEPT;
|
72
|
+
|
73
|
+
obj = Data_Wrap_Struct(klass, NULL, Utf8Validator_free, validator);
|
74
|
+
return obj;
|
75
|
+
}
|
76
|
+
|
77
|
+
|
78
|
+
VALUE Utf8Validator_reset(VALUE self)
|
79
|
+
{
|
80
|
+
TRACE();
|
81
|
+
utf8_validator *validator = NULL;
|
82
|
+
DATA_GET(self, utf8_validator, validator);
|
83
|
+
|
84
|
+
validator->state = UTF8_ACCEPT;
|
85
|
+
|
86
|
+
return Qnil;
|
87
|
+
}
|
88
|
+
|
89
|
+
|
90
|
+
/*
|
91
|
+
* Returns:
|
92
|
+
* - true: Valid UTF-8 string.
|
93
|
+
* - nil: Valid but not terminated UTF-8 string.
|
94
|
+
* - false: Invalid UTF-8 string.
|
95
|
+
*/
|
96
|
+
VALUE Utf8Validator_validate(VALUE self, VALUE string)
|
97
|
+
{
|
98
|
+
TRACE();
|
99
|
+
utf8_validator *validator = NULL;
|
100
|
+
uint8_t *str = NULL;
|
101
|
+
int i;
|
102
|
+
|
103
|
+
REQUIRE_TYPE(string, T_STRING);
|
104
|
+
str = RSTRING_PTR(string);
|
105
|
+
|
106
|
+
DATA_GET(self, utf8_validator, validator);
|
107
|
+
|
108
|
+
for(i=0; i < RSTRING_LEN(string); i++)
|
109
|
+
if (utf8_decode(&validator->state, &validator->codepoint, str[i]) == UTF8_REJECT)
|
110
|
+
return Qfalse;
|
111
|
+
|
112
|
+
switch(validator->state) {
|
113
|
+
case UTF8_ACCEPT:
|
114
|
+
return Qtrue;
|
115
|
+
break;
|
116
|
+
default:
|
117
|
+
return Qnil;
|
118
|
+
break;
|
119
|
+
}
|
120
|
+
}
|
121
|
+
|
122
|
+
|
123
|
+
void Init_ws_framing_utils()
|
124
|
+
{
|
125
|
+
mOverSIP = rb_define_module("OverSIP");
|
126
|
+
mWebSocket = rb_define_module_under(mOverSIP, "WebSocket");
|
127
|
+
mFramingUtils = rb_define_module_under(mWebSocket, "FramingUtils");
|
128
|
+
cUtf8Validator = rb_define_class_under(mFramingUtils, "Utf8Validator", rb_cObject);
|
129
|
+
|
130
|
+
rb_define_module_function(mFramingUtils, "unmask", WsFrammingUtils_unmask,2);
|
131
|
+
|
132
|
+
rb_define_alloc_func(cUtf8Validator, Utf8Validator_alloc);
|
133
|
+
rb_define_method(cUtf8Validator, "reset", Utf8Validator_reset,0);
|
134
|
+
rb_define_method(cUtf8Validator, "validate", Utf8Validator_validate,1);
|
135
|
+
}
|
@@ -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
|