oversip 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. data/AUTHORS.txt +11 -0
  2. data/LICENSE.txt +22 -0
  3. data/README.md +16 -0
  4. data/Rakefile +55 -0
  5. data/bin/oversip +182 -0
  6. data/ext/common/c_util.h +74 -0
  7. data/ext/common/ruby_c_util.h +88 -0
  8. data/ext/sip_parser/common_headers.h +209 -0
  9. data/ext/sip_parser/ext_help.h +18 -0
  10. data/ext/sip_parser/extconf.rb +3 -0
  11. data/ext/sip_parser/sip_parser.c +29649 -0
  12. data/ext/sip_parser/sip_parser.h +227 -0
  13. data/ext/sip_parser/sip_parser_ruby.c +1292 -0
  14. data/ext/stud/extconf.rb +27 -0
  15. data/ext/stud/stud.tar.gz +0 -0
  16. data/ext/stun/ext_help.h +16 -0
  17. data/ext/stun/extconf.rb +3 -0
  18. data/ext/stun/stun_ruby.c +391 -0
  19. data/ext/utils/ext_help.h +14 -0
  20. data/ext/utils/extconf.rb +3 -0
  21. data/ext/utils/haproxy_protocol.c +6163 -0
  22. data/ext/utils/haproxy_protocol.h +27 -0
  23. data/ext/utils/ip_utils.c +5952 -0
  24. data/ext/utils/ip_utils.h +61 -0
  25. data/ext/utils/outbound_utils.c +3227 -0
  26. data/ext/utils/outbound_utils.h +27 -0
  27. data/ext/utils/utils_ruby.c +384 -0
  28. data/ext/utils/utils_ruby.h +75 -0
  29. data/ext/websocket_framing_utils/ext_help.h +18 -0
  30. data/ext/websocket_framing_utils/extconf.rb +3 -0
  31. data/ext/websocket_framing_utils/ws_framing_utils.h +46 -0
  32. data/ext/websocket_framing_utils/ws_framing_utils_ruby.c +135 -0
  33. data/ext/websocket_http_parser/ext_help.h +18 -0
  34. data/ext/websocket_http_parser/extconf.rb +3 -0
  35. data/ext/websocket_http_parser/ws_http_parser.c +2598 -0
  36. data/ext/websocket_http_parser/ws_http_parser.h +86 -0
  37. data/ext/websocket_http_parser/ws_http_parser_ruby.c +630 -0
  38. data/lib/oversip/config.rb +541 -0
  39. data/lib/oversip/config_validators.rb +126 -0
  40. data/lib/oversip/errors.rb +7 -0
  41. data/lib/oversip/fiber_pool.rb +56 -0
  42. data/lib/oversip/launcher.rb +507 -0
  43. data/lib/oversip/logger.rb +170 -0
  44. data/lib/oversip/master_process.rb +67 -0
  45. data/lib/oversip/posix_mq.rb +121 -0
  46. data/lib/oversip/proxies_config.rb +169 -0
  47. data/lib/oversip/ruby_ext/eventmachine.rb +38 -0
  48. data/lib/oversip/sip/client_transaction.rb +587 -0
  49. data/lib/oversip/sip/constants.rb +87 -0
  50. data/lib/oversip/sip/grammar/name_addr.rb +27 -0
  51. data/lib/oversip/sip/grammar/uri.rb +116 -0
  52. data/lib/oversip/sip/launcher.rb +180 -0
  53. data/lib/oversip/sip/listeners/ipv4_tcp_client.rb +21 -0
  54. data/lib/oversip/sip/listeners/ipv4_tcp_server.rb +21 -0
  55. data/lib/oversip/sip/listeners/ipv4_tls_client.rb +21 -0
  56. data/lib/oversip/sip/listeners/ipv4_tls_server.rb +21 -0
  57. data/lib/oversip/sip/listeners/ipv4_tls_tunnel_server.rb +21 -0
  58. data/lib/oversip/sip/listeners/ipv4_udp_server.rb +20 -0
  59. data/lib/oversip/sip/listeners/ipv6_tcp_client.rb +21 -0
  60. data/lib/oversip/sip/listeners/ipv6_tcp_server.rb +21 -0
  61. data/lib/oversip/sip/listeners/ipv6_tls_client.rb +21 -0
  62. data/lib/oversip/sip/listeners/ipv6_tls_server.rb +21 -0
  63. data/lib/oversip/sip/listeners/ipv6_tls_tunnel_server.rb +21 -0
  64. data/lib/oversip/sip/listeners/ipv6_udp_server.rb +20 -0
  65. data/lib/oversip/sip/listeners/reactor.rb +39 -0
  66. data/lib/oversip/sip/listeners/tcp_client.rb +73 -0
  67. data/lib/oversip/sip/listeners/tcp_reactor.rb +185 -0
  68. data/lib/oversip/sip/listeners/tcp_server.rb +71 -0
  69. data/lib/oversip/sip/listeners/tls_client.rb +117 -0
  70. data/lib/oversip/sip/listeners/tls_server.rb +70 -0
  71. data/lib/oversip/sip/listeners/tls_tunnel_reactor.rb +113 -0
  72. data/lib/oversip/sip/listeners/tls_tunnel_server.rb +61 -0
  73. data/lib/oversip/sip/listeners/udp_reactor.rb +213 -0
  74. data/lib/oversip/sip/listeners.rb +28 -0
  75. data/lib/oversip/sip/logic.rb +14 -0
  76. data/lib/oversip/sip/message.rb +168 -0
  77. data/lib/oversip/sip/message_processor.rb +202 -0
  78. data/lib/oversip/sip/modules/core.rb +200 -0
  79. data/lib/oversip/sip/modules/registrar_without_path.rb +75 -0
  80. data/lib/oversip/sip/modules/user_assertion.rb +123 -0
  81. data/lib/oversip/sip/proxy.rb +460 -0
  82. data/lib/oversip/sip/request.rb +128 -0
  83. data/lib/oversip/sip/response.rb +30 -0
  84. data/lib/oversip/sip/rfc3263.rb +646 -0
  85. data/lib/oversip/sip/server_transaction.rb +295 -0
  86. data/lib/oversip/sip/sip.rb +74 -0
  87. data/lib/oversip/sip/tags.rb +39 -0
  88. data/lib/oversip/sip/timers.rb +55 -0
  89. data/lib/oversip/sip/transport_manager.rb +129 -0
  90. data/lib/oversip/syslogger_process.rb +119 -0
  91. data/lib/oversip/tls.rb +179 -0
  92. data/lib/oversip/utils.rb +25 -0
  93. data/lib/oversip/version.rb +23 -0
  94. data/lib/oversip/websocket/constants.rb +56 -0
  95. data/lib/oversip/websocket/default_policy.rb +19 -0
  96. data/lib/oversip/websocket/http_request.rb +63 -0
  97. data/lib/oversip/websocket/launcher.rb +207 -0
  98. data/lib/oversip/websocket/listeners/ipv4_tcp_server.rb +15 -0
  99. data/lib/oversip/websocket/listeners/ipv4_tls_server.rb +15 -0
  100. data/lib/oversip/websocket/listeners/ipv4_tls_tunnel_server.rb +15 -0
  101. data/lib/oversip/websocket/listeners/ipv6_tcp_server.rb +15 -0
  102. data/lib/oversip/websocket/listeners/ipv6_tls_server.rb +15 -0
  103. data/lib/oversip/websocket/listeners/ipv6_tls_tunnel_server.rb +15 -0
  104. data/lib/oversip/websocket/listeners/tcp_server.rb +265 -0
  105. data/lib/oversip/websocket/listeners/tls_server.rb +69 -0
  106. data/lib/oversip/websocket/listeners/tls_tunnel_server.rb +100 -0
  107. data/lib/oversip/websocket/listeners.rb +12 -0
  108. data/lib/oversip/websocket/ws_app.rb +75 -0
  109. data/lib/oversip/websocket/ws_apps/ipv4_ws_sip_app.rb +21 -0
  110. data/lib/oversip/websocket/ws_apps/ipv4_wss_sip_app.rb +21 -0
  111. data/lib/oversip/websocket/ws_apps/ipv6_ws_sip_app.rb +21 -0
  112. data/lib/oversip/websocket/ws_apps/ipv6_wss_sip_app.rb +22 -0
  113. data/lib/oversip/websocket/ws_apps/ws_autobahn_app.rb +23 -0
  114. data/lib/oversip/websocket/ws_apps/ws_sip_app.rb +156 -0
  115. data/lib/oversip/websocket/ws_apps.rb +9 -0
  116. data/lib/oversip/websocket/ws_framing.rb +597 -0
  117. data/lib/oversip.rb +59 -0
  118. data/test/oversip_test_helper.rb +20 -0
  119. data/test/test_http_parser.rb +73 -0
  120. data/test/test_sip_parser.rb +139 -0
  121. metadata +256 -0
@@ -0,0 +1,27 @@
1
+ require "mkmf"
2
+ require "fileutils"
3
+
4
+
5
+ def sys(cmd)
6
+ puts "system command: #{cmd}"
7
+ unless ret = xsystem(cmd)
8
+ raise "system command `#{cmd}' failed"
9
+ end
10
+ ret
11
+ end
12
+
13
+
14
+ here = File.expand_path(File.dirname(__FILE__))
15
+ stud_tarball = "#{here}/stud.tar.gz"
16
+
17
+ Dir.chdir(here) do
18
+ sys("tar -zxf #{stud_tarball}")
19
+ Dir.chdir("stud") do
20
+ sys("make")
21
+ FileUtils.mv "stud", "../../../bin/oversip_stud"
22
+ end
23
+
24
+ FileUtils.remove_dir("stud", force = true)
25
+ end
26
+
27
+ create_makefile("stud")
Binary file
@@ -0,0 +1,16 @@
1
+ #ifndef ext_help_h
2
+ #define ext_help_h
3
+
4
+ /* Uncomment for enabling TRACE() function. */
5
+ /*#define DEBUG*/
6
+
7
+ #ifdef DEBUG
8
+ #define TRACE() fprintf(stderr, "TRACE: %s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__)
9
+ #define LOG(string) fprintf(stderr, "LOG: %s:%d:%s: %s\n", __FILE__, __LINE__, __FUNCTION__, string)
10
+ #else
11
+ #define TRACE()
12
+ #define LOG(string)
13
+ #endif
14
+
15
+ #endif
16
+
@@ -0,0 +1,3 @@
1
+ require "mkmf"
2
+
3
+ create_makefile("oversip/stun")
@@ -0,0 +1,391 @@
1
+ #include <ruby.h>
2
+ #include <netinet/in.h>
3
+ #include <arpa/inet.h>
4
+ #include "ext_help.h"
5
+
6
+
7
+ #define STUN_MESSAGE_MIN_SIZE 20
8
+ #define STUN_MAGIC_COOKIE_LEN 4
9
+ #define STUN_TRANSACTION_ID_LEN 12
10
+ #define STUN_BINDING_SUCCESS_RESPONSE_IPV4_SIZE 32
11
+ #define STUN_BINDING_SUCCESS_RESPONSE_IPV6_SIZE 44
12
+
13
+
14
+ static VALUE mOverSIP;
15
+ static VALUE mStun;
16
+
17
+
18
+ /*
19
+ * Ruby functions.
20
+ */
21
+
22
+
23
+ /*
24
+ * RFC 5389.
25
+ *
26
+ * 6. STUN Message Structure
27
+ *
28
+ * 0 1 2 3
29
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
30
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
31
+ * |0 0| STUN Message Type | Message Length |
32
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
33
+ * | Magic Cookie |
34
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35
+ * | |
36
+ * | Transaction ID (96 bits) |
37
+ * | |
38
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39
+ *
40
+ */
41
+
42
+
43
+ /*
44
+ * Expects 3 arguments:
45
+ * - String containing a STUN Binding Request (MUST not be empty!!).
46
+ * - String containing the source IP of the request.
47
+ * - Fxinum containing the source port of the request.
48
+ * Return value:
49
+ * - If it's a valid STUN Binding Request, returns a Ruby String representing the
50
+ * STUN Binding Response.
51
+ * - If it seems a valid STUN message but not a valid STUN Binding Request, returns _false_.
52
+ * - Otherwise returns _nil_ (so it could be a SIP message).
53
+ */
54
+ VALUE Stun_parse_request(VALUE self, VALUE rb_stun_request, VALUE rb_source_ip, VALUE rb_source_port)
55
+ {
56
+ TRACE();
57
+
58
+ char *request = NULL;
59
+ size_t request_len = 0;
60
+ char *source_ip = NULL;
61
+ short source_ip_is_ipv6 = 0;
62
+ uint16_t source_port;
63
+
64
+ char *transaction_id;
65
+ uint16_t message_length;
66
+ char *magic_cookie;
67
+ short is_rfc3489_client = 0;
68
+
69
+ struct in_addr in_addr_ipv4;
70
+ struct in6_addr in_addr_ipv6;
71
+ uint16_t xor_port;
72
+ uint32_t xor_ipv4;
73
+ unsigned char xor_ipv6[16];
74
+
75
+ /* The size of our STUN Binding Response is the sum of:
76
+ * - STUN message header: 20 bytes.
77
+ * - One attribute (XOR-MAPPED-ADDRESS or MAPPED-ADDRESS).
78
+ * - Type + Length: 4 bytes.
79
+ * - XOR-MAPPED-ADDRESS or MAPPED-ADDRESS for IPv4: 4 + 4 = 8 bytes.
80
+ * - XOR-MAPPED-ADDRESS or MAPPED-ADDRESS for IPv6: 4 + 16 = 20 bytes.
81
+ * - Size for a response with IPv4: 20 + 4 + 8 = 32 bytes.
82
+ * - Size for a response with IPv6: 20 + 4 + 20 = 44 bytes.
83
+ */
84
+ char response[STUN_BINDING_SUCCESS_RESPONSE_IPV6_SIZE];
85
+
86
+ if (TYPE(rb_stun_request) != T_STRING)
87
+ rb_raise(rb_eTypeError, "First argument must be a String containing the STUN Binding Request");
88
+
89
+ request = RSTRING_PTR(rb_stun_request);
90
+
91
+ /* First octet of any STUN *request* must be 0. Return false otherwise. */
92
+ if (request[0]) {
93
+ LOG("first octet is not 0, so it's not a STUN request\n");
94
+ return Qnil;
95
+ }
96
+
97
+ /* Any STUN message must contain, at least, 20 bytes. Return false otherwise. */
98
+ if ((request_len = RSTRING_LEN(rb_stun_request)) < STUN_MESSAGE_MIN_SIZE) {
99
+ LOG("ERROR: request length less than 20 bytes, invalid STUN message\n");
100
+ return Qfalse;
101
+ }
102
+
103
+ if (TYPE(rb_source_ip) != T_STRING)
104
+ rb_raise(rb_eTypeError, "Third argument must be a String containing the source IP");
105
+
106
+ if (TYPE(rb_source_port) != T_FIXNUM)
107
+ rb_raise(rb_eTypeError, "Fourth argument must be a Fixnum containing the source port");
108
+
109
+ /*
110
+ * RFC 5389 section 6.
111
+ *
112
+ * a Binding request has class=0b00 (request) and method=0b000000000001 (Binding)
113
+ * and is encoded into the first 16 bits as 0x0001.
114
+ *
115
+ * So let's check the second byte which must be 0x1.
116
+ */
117
+ if ( request[1] != 0b00000001 ) {
118
+ LOG("ERROR: not a valid STUN Binding Request, maybe an STUN Indication (so ignore it)\n");
119
+ return Qfalse;
120
+ }
121
+
122
+ /*
123
+ * RFC 5389 section 6.
124
+ *
125
+ * The magic cookie field MUST contain the fixed value 0x2112A442 in network byte order.
126
+ *
127
+ * 0x21 = 33, 0x12 = 18, 0xA4 = -92, 0x42=66.
128
+ */
129
+ if (! (request[4] == 33 && request[5] == 18 && request[6] == -92 && request[7] == 66) ) {
130
+ LOG("WARN: STUN magic cookie does not match, using backward compatibility with RFC 3489\n");
131
+
132
+ /*
133
+ * RFC 5389 section 12.2.
134
+ *
135
+ * A STUN server can detect when a given Binding request message was
136
+ * sent from an RFC 3489 [RFC3489] client by the absence of the correct
137
+ * value in the magic cookie field. When the server detects an RFC 3489
138
+ * client, it SHOULD copy the value seen in the magic cookie field in
139
+ * the Binding request to the magic cookie field in the Binding response
140
+ * message, and insert a MAPPED-ADDRESS attribute instead of an
141
+ * XOR-MAPPED-ADDRESS attribute.
142
+ *
143
+ */
144
+ is_rfc3489_client = 1;
145
+ }
146
+
147
+ /* Get the Magic Cookie. */
148
+ magic_cookie = ((char *)request)+4;
149
+
150
+ /* Get the Transaction ID. */
151
+ transaction_id = ((char *)request)+8;
152
+
153
+ /*
154
+ * RFC 5389 section 6.
155
+ * "The message length MUST contain the size, in bytes, of the message
156
+ * not including the 20-byte STUN header. Since all STUN attributes are
157
+ * padded to a multiple of 4 bytes, the last 2 bits of this field are
158
+ * always zero. This provides another way to distinguish STUN packets
159
+ * from packets of other protocols."
160
+ *
161
+ */
162
+ message_length = ntohs(*(uint16_t *)(request+2));
163
+
164
+
165
+
166
+ /*
167
+ * Create the STUN Binding Response.
168
+ */
169
+
170
+ /* A Binding response has class=0b10 (success response) and method=*0b000000000001,
171
+ * and is encoded into the first 16 bits as 0x0101. */
172
+ response[0] = 1;
173
+ response[1] = 1;
174
+
175
+ /* Add the received Magic Cookie (for RFC 3489 backward compatibility). */
176
+ memcpy(response+4, magic_cookie, STUN_MAGIC_COOKIE_LEN);
177
+
178
+ /* Add the received Transaction Id. */
179
+ memcpy(response+8, transaction_id, STUN_TRANSACTION_ID_LEN);
180
+
181
+ /*
182
+ * Add an attribute XOR-MAPPED-ADDRESS (or MAPPED-ADDRESS if it's a RFC 3489 client).
183
+ */
184
+
185
+ /*
186
+ * STUN Attribute.
187
+ *
188
+ * 0 1 2 3
189
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
190
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
191
+ * | Type | Length |
192
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
193
+ * | Value (variable) ....
194
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
195
+ *
196
+ *
197
+ * XOR-MAPPED-ADDRESS.
198
+ *
199
+ * 0 1 2 3
200
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
201
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
202
+ * |x x x x x x x x| Family | X-Port |
203
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
204
+ * | X-Address (Variable)
205
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
206
+ *
207
+ *
208
+ * MAPPED-ADDRESS.
209
+ *
210
+ * 0 1 2 3
211
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
212
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
213
+ * |0 0 0 0 0 0 0 0| Family | Port |
214
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
215
+ * | |
216
+ * | Address (32 bits or 128 bits) |
217
+ * | |
218
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
219
+ *
220
+ */
221
+
222
+ source_ip = StringValueCStr(rb_source_ip);
223
+
224
+ /* Check the IP and its type (IPv4 or IPv6). */
225
+ switch(inet_pton(AF_INET, source_ip, &in_addr_ipv4)) {
226
+ /* It's valid IPv4. */
227
+ case 1:
228
+ break;
229
+ /* Not valid INET family, hummmm. */
230
+ case -1:
231
+ rb_raise(rb_eTypeError, "Family AF_INET (IPv4) not supported");
232
+ break;
233
+ /* Let's check with IPv6. */
234
+ case 0:
235
+ switch(inet_pton(AF_INET6, source_ip, &in_addr_ipv6)) {
236
+ /* It's valid IPv6. */
237
+ case 1:
238
+ source_ip_is_ipv6 = 1;
239
+ break;
240
+ /* Not valid INET family, hummmm. */
241
+ case -1:
242
+ rb_raise(rb_eTypeError, "Family AF_INET6 (IPv6) not supported");
243
+ break;
244
+ /* The string is neither an IPv4 or IPv6. */
245
+ case 0:
246
+ rb_raise(rb_eTypeError, "Given IP string is neither IPv4 or IPv6");
247
+ break;
248
+ }
249
+ }
250
+
251
+ /* Get the port in an integer (two bytes) */
252
+ source_port = (uint16_t)(FIX2INT(rb_source_port));
253
+
254
+ /* It's a RFC 5389 compliant client, so add XOR-MAPPED-ADDRESS. */
255
+ if (! is_rfc3489_client) {
256
+ /* STUN attribute type: 0x0020: XOR-MAPPED-ADDRESS */
257
+ response[20] = 0x00;
258
+ response[21] = 0x20;
259
+
260
+ /*
261
+ * XOR-MAPPED-ADDRESS fields.
262
+ */
263
+
264
+ /* First byte must be 0x00. */
265
+ response[24] = 0x00;
266
+
267
+ /* Second byte is the IP Family (0x01:IPv4, 0x02:IPv6). */
268
+ if (source_ip_is_ipv6)
269
+ response[25] = 0x02;
270
+ else
271
+ response[25] = 0x01;
272
+
273
+ /* Bytes 3 and 4 are the X-Port. X-Port is computed by taking the mapped port in
274
+ * host byte order, XOR'ing it with the most significant 16 bits of the magic cookie,
275
+ * and then the converting the result to network byte order. */
276
+ xor_port = htons(source_port ^ *(uint16_t *)(magic_cookie));
277
+
278
+ memcpy(response+26, &xor_port, 2);
279
+
280
+ /* Next bytes are the IP in network byte order with XOR stuff. */
281
+
282
+ /* IPv4. */
283
+ if (! source_ip_is_ipv6) {
284
+ /* If the IP address family is IPv4, X-Address is computed by taking the mapped IP
285
+ * address in host byte order, XOR'ing it with the magic cookie, and converting the
286
+ * result to network byte order. */
287
+ xor_ipv4 = htons((uint32_t)(in_addr_ipv4.s_addr) ^ *(uint32_t *)(magic_cookie));
288
+
289
+ memcpy(response+28, &xor_ipv4, 4);
290
+ /* So set the attribute Length to 8. */
291
+ response[22] = 0;
292
+ response[23] = 8;
293
+ /* So set the STUN Response Message Length to 12 bytes. */
294
+ response[2] = 0;
295
+ response[3] = 12;
296
+
297
+ /* Return the Ruby string containing the response. */
298
+ return rb_str_new(response, STUN_BINDING_SUCCESS_RESPONSE_IPV4_SIZE);
299
+ }
300
+ /* IPv6. */
301
+ else {
302
+ /* If the IP address family is IPv6, X-Address is computed by taking the
303
+ * mapped IP address in host byte order, XOR'ing it with the concatenation
304
+ * of the magic cookie and the 96-bit transaction ID, and converting the result
305
+ * to network byte order. */
306
+ /* NOTE: struct in_addr.s6_addr is an array of 16 char in network byte order (big-endian). */
307
+ /* TODO: So do I need to convert in_addr_ipv6.s6_addr to host byte order and later the
308
+ * whole result to network byte order? */
309
+ int i;
310
+ for(i=0; i<16; i++)
311
+ xor_ipv6[i] = in_addr_ipv6.s6_addr[i] ^ magic_cookie[i];
312
+
313
+ memcpy(response+28, xor_ipv6, 16);
314
+
315
+ /* So set the attribute Length to 20. */
316
+ response[22] = 0;
317
+ response[23] = 20;
318
+ /* So set the STUN Response Message Length to 24 bytes. */
319
+ response[2] = 0;
320
+ response[3] = 24;
321
+
322
+ /* Return the Ruby string containing the response. */
323
+ return rb_str_new(response, STUN_BINDING_SUCCESS_RESPONSE_IPV6_SIZE);
324
+ }
325
+ }
326
+
327
+ /* It's a RFC 3489 compliant client, so add MAPPED-ADDRESS. */
328
+ else {
329
+ /* STUN attribute type: 0x0001: MAPPED-ADDRESS */
330
+ response[20] = 0x00;
331
+ response[21] = 0x01;
332
+
333
+ /*
334
+ * MAPPED-ADDRESS fields.
335
+ */
336
+
337
+ /* First byte must be 0x00. */
338
+ response[24] = 0x00;
339
+
340
+ /* Second byte is the IP Family (0x01:IPv4, 0x02:IPv6). */
341
+ if (source_ip_is_ipv6)
342
+ response[25] = 0x02;
343
+ else
344
+ response[25] = 0x01;
345
+
346
+ /* Bytes 3 and 4 are the Port in network byte order. */
347
+ source_port = htons(source_port);
348
+ memcpy(response+26, &source_port, 2);
349
+
350
+ /* Next bytes are the IP in network byte order. */
351
+
352
+ /* IPv4. */
353
+ if (! source_ip_is_ipv6) {
354
+ memcpy(response+28, &in_addr_ipv4.s_addr, 4);
355
+ /* So set the attribute Length to 8. */
356
+ response[22] = 0;
357
+ response[23] = 8;
358
+ /* So set the STUN Response Message Length to 12 bytes. */
359
+ response[2] = 0;
360
+ response[3] = 12;
361
+
362
+ /* Return the Ruby string containing the response. */
363
+ return rb_str_new(response, STUN_BINDING_SUCCESS_RESPONSE_IPV4_SIZE);
364
+ }
365
+ /* IPv6. */
366
+ else {
367
+ memcpy(response+28, &in_addr_ipv6.s6_addr, 16);
368
+ /* So set the attribute Length to 20. */
369
+ response[22] = 0;
370
+ response[23] = 20;
371
+ /* So set the STUN Response Message Length to 24 bytes. */
372
+ response[2] = 0;
373
+ response[3] = 24;
374
+
375
+ /* Return the Ruby string containing the response. */
376
+ return rb_str_new(response, STUN_BINDING_SUCCESS_RESPONSE_IPV6_SIZE);
377
+ }
378
+ }
379
+
380
+ }
381
+
382
+
383
+ void Init_stun()
384
+ {
385
+ TRACE();
386
+
387
+ mOverSIP = rb_define_module("OverSIP");
388
+ mStun = rb_define_module_under(mOverSIP, "Stun");
389
+
390
+ rb_define_module_function(mStun, "parse_request", Stun_parse_request, 3);
391
+ }
@@ -0,0 +1,14 @@
1
+ #ifndef ext_help_h
2
+ #define ext_help_h
3
+
4
+ /* Uncomment for enabling TRACE() function. */
5
+ /*#define DEBUG*/
6
+
7
+ #ifdef DEBUG
8
+ #define TRACE() fprintf(stderr, "TRACE: %s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__)
9
+ #else
10
+ #define TRACE()
11
+ #endif
12
+
13
+ #endif
14
+
@@ -0,0 +1,3 @@
1
+ require "mkmf"
2
+
3
+ create_makefile("oversip/utils")