sctp-socket 0.0.6 → 0.0.7
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +3 -4
- data/CHANGES.md +15 -0
- data/README.md +1 -1
- data/examples/client_example.rb +3 -2
- data/examples/server_example.rb +1 -1
- data/ext/sctp/extconf.rb +1 -0
- data/ext/sctp/socket.c +267 -86
- data/sctp-socket.gemspec +1 -1
- data.tar.gz.sig +0 -0
- metadata +2 -2
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0475ccb484ff3e6e758c037edf11b16fdb833e49aee961a98532dfb67c84f799
|
4
|
+
data.tar.gz: 70f7add0defeeb84a1ab6bb38ed3aeabb5f643bb05dea06a00a11c1934f588ed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e5e40484afdf170570c38ab9331c99ae4a6f42ba217d97e91ecd5bfbf9296c2ef95f219498fba13b524ad08a1f00271de8be6f358f2982a4c5e45fdc190f0951
|
7
|
+
data.tar.gz: f9b9dac418aeae1c79916e732d7310049812c2456c0f4f1c578641f145c2c72b73fbceb655954ad99b03c3c69a890cab9a7455930199902a40aed9de239754a8
|
checksums.yaml.gz.sig
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
|
-
D
|
3
|
-
|
4
|
-
f�WT)��p|,��7�'���G��!;�h{b�a��]ч�Dw�� �x��`�'�O��18�Fh�ɎP���-}�V4��Ey��,I:�"���0ڸ����P��DŽ��T
|
1
|
+
|
2
|
+
���#��:���Ww���m�x����TM��}��G����9����SЮ���/�e$����ǎce��1˪5��*�eNN^�=b�igE���s���x��D%p�i�`ʹ��l��3Ja�Ⱦ�x��4[�9F@�VIi����t���>v���&�\�`y�1)[�|}za˾�������%�^v�9o�v�tA6��
|
3
|
+
�9�t�Ljꔰ�Ҁ�[1&�*��[L�fV��J�z�9|G�Ek�~�j'��O�J�:I�B2��m+�D�6/�}f�M�J��i=�m����7$���!*I'�}*�bb��`p����+�g�2����ؘP[K�J�1X�uup��e��q?��Y6��Z����0���5�|v�s��\�X���_
|
data/CHANGES.md
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
## 0.0.7 - 28-May-2024
|
2
|
+
* Added the recvv method.
|
3
|
+
* The getlocalnames and getpeernames methods now accept optional fileno and
|
4
|
+
association ID arguments.
|
5
|
+
* The peeloff method now returns the peeled off fileno and no longer modifies
|
6
|
+
the receiver, so I dropped the exclamation point from the method name.
|
7
|
+
* Added the get_subscriptions method.
|
8
|
+
* Changed bind method to bindx and connect method to connectx. I may try to
|
9
|
+
subclass Socket someday so I didn't want a conflict, and this more closely
|
10
|
+
matches the underlying function name anyway.
|
11
|
+
* Changed the sock_fd method to fileno.
|
12
|
+
* Changed the default backlog from 1024 to 128 for the listen method.
|
13
|
+
* Updated comments and documentation.
|
14
|
+
* Added more specs.
|
15
|
+
|
1
16
|
## 0.0.6 - 24-May-2024
|
2
17
|
* Fixup the sendv method and add some documentation.
|
3
18
|
* Added documentation to the get_status method.
|
data/README.md
CHANGED
@@ -39,7 +39,7 @@ require 'sctp/socket'
|
|
39
39
|
begin
|
40
40
|
port = 62324
|
41
41
|
socket = SCTP::Socket.new
|
42
|
-
socket.
|
42
|
+
socket.bindx(:port => port, :addresses => ['10.0.5.4', '10.0.6.4'])
|
43
43
|
socket.set_initmsg(:output_streams => 5, :input_streams => 5, :max_attempts => 4)
|
44
44
|
socket.subscribe(:data_io => true)
|
45
45
|
socket.listen
|
data/examples/client_example.rb
CHANGED
@@ -10,10 +10,11 @@ begin
|
|
10
10
|
socket = SCTP::Socket.new
|
11
11
|
|
12
12
|
# Optional, but could bind to a subset of available addresses
|
13
|
-
p socket.
|
13
|
+
p socket.bindx(:addresses => addresses)
|
14
14
|
|
15
15
|
# Initial connection
|
16
|
-
p socket.
|
16
|
+
p socket.connectx(:addresses => addresses, :port => port)
|
17
|
+
p socket.get_status
|
17
18
|
|
18
19
|
# Try a sendv
|
19
20
|
p socket.sendv(:message => ["Hello ", "World!"])
|
data/examples/server_example.rb
CHANGED
@@ -23,7 +23,7 @@ addresses = ['1.1.1.1', '1.1.1.2']
|
|
23
23
|
begin
|
24
24
|
port = 62324
|
25
25
|
socket = SCTP::Socket.new
|
26
|
-
socket.
|
26
|
+
socket.bindx(:port => port, :addresses => addresses)
|
27
27
|
socket.set_initmsg(:output_streams => 5, :input_streams => 5, :max_attempts => 4)
|
28
28
|
socket.subscribe(:data_io => true, :shutdown => true, :send_failure => true, :partial_delivery => true)
|
29
29
|
socket.listen
|
data/ext/sctp/extconf.rb
CHANGED
data/ext/sctp/socket.c
CHANGED
@@ -21,6 +21,8 @@ VALUE v_sctp_status_struct;
|
|
21
21
|
VALUE v_sctp_rtoinfo_struct;
|
22
22
|
VALUE v_sctp_associnfo_struct;
|
23
23
|
VALUE v_sctp_default_send_params_struct;
|
24
|
+
VALUE v_sctp_event_subscribe_struct;
|
25
|
+
VALUE v_sctp_receive_info_struct;
|
24
26
|
|
25
27
|
#if !defined(IOV_MAX)
|
26
28
|
#if defined(_SC_IOV_MAX)
|
@@ -77,7 +79,7 @@ VALUE rb_hash_aref2(VALUE v_hash, const char* key){
|
|
77
79
|
* socket2 = SCTP::Socket.new(Socket::AF_INET, Socket::SOCK_STREAM)
|
78
80
|
*/
|
79
81
|
static VALUE rsctp_init(int argc, VALUE* argv, VALUE self){
|
80
|
-
int
|
82
|
+
int fileno;
|
81
83
|
VALUE v_domain, v_type;
|
82
84
|
|
83
85
|
rb_scan_args(argc, argv, "02", &v_domain, &v_type);
|
@@ -88,14 +90,14 @@ static VALUE rsctp_init(int argc, VALUE* argv, VALUE self){
|
|
88
90
|
if(NIL_P(v_type))
|
89
91
|
v_type = INT2NUM(SOCK_SEQPACKET);
|
90
92
|
|
91
|
-
|
93
|
+
fileno = socket(NUM2INT(v_domain), NUM2INT(v_type), IPPROTO_SCTP);
|
92
94
|
|
93
|
-
if(
|
95
|
+
if(fileno < 0)
|
94
96
|
rb_raise(rb_eSystemCallError, "socket: %s", strerror(errno));
|
95
97
|
|
96
98
|
rb_iv_set(self, "@domain", v_domain);
|
97
99
|
rb_iv_set(self, "@type", v_type);
|
98
|
-
rb_iv_set(self, "@
|
100
|
+
rb_iv_set(self, "@fileno", INT2NUM(fileno));
|
99
101
|
rb_iv_set(self, "@association_id", INT2NUM(0));
|
100
102
|
|
101
103
|
return self;
|
@@ -114,19 +116,19 @@ static VALUE rsctp_init(int argc, VALUE* argv, VALUE self){
|
|
114
116
|
* socket = SCTP::Socket.new
|
115
117
|
*
|
116
118
|
* # Bind 2 addresses
|
117
|
-
* socket.
|
119
|
+
* socket.bindx(:port => 64325, :addresses => ['10.0.4.5', '10.0.5.5'])
|
118
120
|
*
|
119
121
|
* # Remove 1 later
|
120
|
-
* socket.
|
122
|
+
* socket.bindx(:addresses => ['10.0.4.5'], :flags => SCTP::Socket::BINDX_REM_ADDR)
|
121
123
|
*
|
122
124
|
* If no addresses are specified, then it will bind to all available interfaces. If
|
123
125
|
* no port is specified, then one will be assigned by the host.
|
124
126
|
*
|
125
127
|
* Returns the port that it was bound to.
|
126
128
|
*/
|
127
|
-
static VALUE
|
129
|
+
static VALUE rsctp_bindx(int argc, VALUE* argv, VALUE self){
|
128
130
|
struct sockaddr_in addrs[8];
|
129
|
-
int i,
|
131
|
+
int i, fileno, num_ip, flags, domain, port;
|
130
132
|
VALUE v_addresses, v_port, v_flags, v_address, v_options;
|
131
133
|
|
132
134
|
rb_scan_args(argc, argv, "01", &v_options);
|
@@ -156,7 +158,7 @@ static VALUE rsctp_bind(int argc, VALUE* argv, VALUE self){
|
|
156
158
|
num_ip = RARRAY_LEN(v_addresses);
|
157
159
|
|
158
160
|
domain = NUM2INT(rb_iv_get(self, "@domain"));
|
159
|
-
|
161
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
160
162
|
|
161
163
|
if(num_ip > 1){
|
162
164
|
for(i = 0; i < num_ip; i++){
|
@@ -172,14 +174,14 @@ static VALUE rsctp_bind(int argc, VALUE* argv, VALUE self){
|
|
172
174
|
addrs[0].sin_addr.s_addr = htonl(INADDR_ANY);
|
173
175
|
}
|
174
176
|
|
175
|
-
if(sctp_bindx(
|
177
|
+
if(sctp_bindx(fileno, (struct sockaddr *) addrs, num_ip, flags) != 0)
|
176
178
|
rb_raise(rb_eSystemCallError, "sctp_bindx: %s", strerror(errno));
|
177
179
|
|
178
180
|
if(port == 0){
|
179
181
|
struct sockaddr_in sin;
|
180
182
|
socklen_t len = sizeof(sin);
|
181
183
|
|
182
|
-
if(getsockname(
|
184
|
+
if(getsockname(fileno, (struct sockaddr *)&sin, &len) == -1)
|
183
185
|
rb_raise(rb_eSystemCallError, "getsockname: %s", strerror(errno));
|
184
186
|
|
185
187
|
port = sin.sin_port;
|
@@ -197,13 +199,13 @@ static VALUE rsctp_bind(int argc, VALUE* argv, VALUE self){
|
|
197
199
|
* Example:
|
198
200
|
*
|
199
201
|
* socket = SCTP::Socket.new
|
200
|
-
* socket.
|
202
|
+
* socket.connectx(:port => 62354, :addresses => ['10.0.4.5', '10.0.5.5'])
|
201
203
|
*
|
202
204
|
* Note that this will also set/update the object's association_id.
|
203
205
|
*/
|
204
|
-
static VALUE
|
206
|
+
static VALUE rsctp_connectx(int argc, VALUE* argv, VALUE self){
|
205
207
|
struct sockaddr_in addrs[8];
|
206
|
-
int i, num_ip,
|
208
|
+
int i, num_ip, fileno;
|
207
209
|
sctp_assoc_t assoc;
|
208
210
|
VALUE v_address, v_domain, v_options, v_addresses, v_port;
|
209
211
|
|
@@ -235,9 +237,9 @@ static VALUE rsctp_connect(int argc, VALUE* argv, VALUE self){
|
|
235
237
|
addrs[i].sin_addr.s_addr = inet_addr(StringValueCStr(v_address));
|
236
238
|
}
|
237
239
|
|
238
|
-
|
240
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
239
241
|
|
240
|
-
if(sctp_connectx(
|
242
|
+
if(sctp_connectx(fileno, (struct sockaddr *) addrs, num_ip, &assoc) < 0)
|
241
243
|
rb_raise(rb_eSystemCallError, "sctp_connectx: %s", strerror(errno));
|
242
244
|
|
243
245
|
rb_iv_set(self, "@association_id", INT2NUM(assoc));
|
@@ -254,30 +256,55 @@ static VALUE rsctp_connect(int argc, VALUE* argv, VALUE self){
|
|
254
256
|
* socket.close
|
255
257
|
*/
|
256
258
|
static VALUE rsctp_close(VALUE self){
|
257
|
-
VALUE
|
259
|
+
VALUE v_fileno = rb_iv_get(self, "@fileno");
|
258
260
|
|
259
|
-
if(close(NUM2INT(
|
261
|
+
if(close(NUM2INT(v_fileno)))
|
260
262
|
rb_raise(rb_eSystemCallError, "close: %s", strerror(errno));
|
261
263
|
|
262
264
|
return self;
|
263
265
|
}
|
264
266
|
|
265
267
|
/*
|
266
|
-
* Return an array of all addresses of a peer
|
268
|
+
* Return an array of all addresses of a peer of the current socket
|
269
|
+
* and association number.
|
270
|
+
*
|
271
|
+
* You may optionally pass a assocation fileno and association ID. Typically
|
272
|
+
* this information would come from the peeloff method.
|
273
|
+
*
|
274
|
+
* Example:
|
275
|
+
*
|
276
|
+
* socket = SCTP::Socket.new
|
277
|
+
* # ...
|
278
|
+
* p socket.getpeernames
|
279
|
+
*
|
280
|
+
* info = socket.recvmsg
|
281
|
+
* association_fileno = socket.peeloff(info.association_id)
|
282
|
+
*
|
283
|
+
* p socket.getpeernames(association_fileno, info.association_id)
|
267
284
|
*/
|
268
|
-
static VALUE rsctp_getpeernames(VALUE self){
|
285
|
+
static VALUE rsctp_getpeernames(int argc, VALUE* argv, VALUE self){
|
269
286
|
sctp_assoc_t assoc_id;
|
270
287
|
struct sockaddr* addrs;
|
271
|
-
int i,
|
288
|
+
int i, fileno, num_addrs;
|
272
289
|
char str[16];
|
290
|
+
VALUE v_fileno, v_association_id;
|
273
291
|
VALUE v_array = rb_ary_new();
|
274
292
|
|
275
293
|
bzero(&addrs, sizeof(addrs));
|
276
294
|
|
277
|
-
|
278
|
-
|
295
|
+
rb_scan_args(argc, argv, "02", &v_fileno, &v_association_id);
|
296
|
+
|
297
|
+
if(NIL_P(v_fileno))
|
298
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
299
|
+
else
|
300
|
+
fileno = NUM2INT(v_fileno);
|
301
|
+
|
302
|
+
if(NIL_P(v_association_id))
|
303
|
+
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
304
|
+
else
|
305
|
+
assoc_id = NUM2INT(v_association_id);
|
279
306
|
|
280
|
-
num_addrs = sctp_getpaddrs(
|
307
|
+
num_addrs = sctp_getpaddrs(fileno, assoc_id, &addrs);
|
281
308
|
|
282
309
|
if(num_addrs < 0){
|
283
310
|
sctp_freepaddrs(addrs);
|
@@ -303,20 +330,35 @@ static VALUE rsctp_getpeernames(VALUE self){
|
|
303
330
|
* socket = SCTP::Socket.new
|
304
331
|
* socket.bind(:addresses => ['10.0.4.5', '10.0.5.5'])
|
305
332
|
* socket.getlocalnames # => ['10.0.4.5', '10.0.5.5'])
|
333
|
+
*
|
334
|
+
* # or get info from a peeled off association...
|
335
|
+
*
|
336
|
+
* assoc_fileno = socket.peeloff(some_association_id)
|
337
|
+
* socket.getlocalnames(assoc_fileno, some_association_id)
|
306
338
|
*/
|
307
|
-
static VALUE rsctp_getlocalnames(VALUE self){
|
339
|
+
static VALUE rsctp_getlocalnames(int argc, VALUE* argv, VALUE self){
|
308
340
|
sctp_assoc_t assoc_id;
|
309
341
|
struct sockaddr* addrs;
|
310
|
-
int i,
|
342
|
+
int i, fileno, num_addrs;
|
311
343
|
char str[16];
|
344
|
+
VALUE v_assoc_fileno, v_assoc_id;
|
312
345
|
VALUE v_array = rb_ary_new();
|
313
346
|
|
314
347
|
bzero(&addrs, sizeof(addrs));
|
315
348
|
|
316
|
-
|
317
|
-
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
349
|
+
rb_scan_args(argc, argv, "02", &v_assoc_fileno, &v_assoc_id);
|
318
350
|
|
319
|
-
|
351
|
+
if(NIL_P(v_assoc_fileno))
|
352
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
353
|
+
else
|
354
|
+
fileno = NUM2INT(v_assoc_fileno);
|
355
|
+
|
356
|
+
if(NIL_P(v_assoc_id))
|
357
|
+
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
358
|
+
else
|
359
|
+
assoc_id = NUM2INT(v_assoc_id);
|
360
|
+
|
361
|
+
num_addrs = sctp_getladdrs(fileno, assoc_id, &addrs);
|
320
362
|
|
321
363
|
if(num_addrs < 0){
|
322
364
|
sctp_freeladdrs(addrs);
|
@@ -362,7 +404,7 @@ static VALUE rsctp_sendv(VALUE self, VALUE v_options){
|
|
362
404
|
struct iovec iov[IOV_MAX];
|
363
405
|
struct sockaddr_in* addrs;
|
364
406
|
struct sctp_sndinfo info;
|
365
|
-
int i,
|
407
|
+
int i, fileno, num_bytes, size, num_ip;
|
366
408
|
|
367
409
|
Check_Type(v_options, T_HASH);
|
368
410
|
|
@@ -385,7 +427,7 @@ static VALUE rsctp_sendv(VALUE self, VALUE v_options){
|
|
385
427
|
num_ip = 0;
|
386
428
|
}
|
387
429
|
|
388
|
-
|
430
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
389
431
|
size = RARRAY_LEN(v_message);
|
390
432
|
|
391
433
|
if(!size)
|
@@ -424,7 +466,7 @@ static VALUE rsctp_sendv(VALUE self, VALUE v_options){
|
|
424
466
|
}
|
425
467
|
|
426
468
|
num_bytes = sctp_sendv(
|
427
|
-
|
469
|
+
fileno,
|
428
470
|
iov,
|
429
471
|
size,
|
430
472
|
(struct sockaddr*)addrs,
|
@@ -442,6 +484,74 @@ static VALUE rsctp_sendv(VALUE self, VALUE v_options){
|
|
442
484
|
}
|
443
485
|
#endif
|
444
486
|
|
487
|
+
#ifdef HAVE_SCTP_RECVV
|
488
|
+
static VALUE rsctp_recvv(int argc, VALUE* argv, VALUE self){
|
489
|
+
VALUE v_flags;
|
490
|
+
int fileno, flags, bytes, on;
|
491
|
+
uint infotype;
|
492
|
+
socklen_t infolen;
|
493
|
+
struct iovec iov[1];
|
494
|
+
struct sctp_rcvinfo info;
|
495
|
+
char buffer[1024];
|
496
|
+
|
497
|
+
bzero(&iov, sizeof(iov));
|
498
|
+
bzero(&info, sizeof(info));
|
499
|
+
bzero(&buffer, sizeof(buffer));
|
500
|
+
|
501
|
+
iov->iov_base = buffer;
|
502
|
+
iov->iov_len = sizeof(buffer);
|
503
|
+
|
504
|
+
rb_scan_args(argc, argv, "01", &v_flags);
|
505
|
+
|
506
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
507
|
+
|
508
|
+
if(NIL_P(v_flags))
|
509
|
+
flags = 0;
|
510
|
+
else
|
511
|
+
flags = NUM2INT(v_flags);
|
512
|
+
|
513
|
+
on = 1;
|
514
|
+
if(setsockopt(fileno, IPPROTO_SCTP, SCTP_RECVRCVINFO, &on, sizeof(on)) < 0)
|
515
|
+
rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
|
516
|
+
|
517
|
+
infolen = sizeof(struct sctp_rcvinfo);
|
518
|
+
infotype = 0;
|
519
|
+
|
520
|
+
bytes = sctp_recvv(
|
521
|
+
fileno,
|
522
|
+
iov,
|
523
|
+
1,
|
524
|
+
NULL,
|
525
|
+
NULL,
|
526
|
+
&info,
|
527
|
+
&infolen,
|
528
|
+
&infotype,
|
529
|
+
&flags
|
530
|
+
);
|
531
|
+
|
532
|
+
if(bytes < 0)
|
533
|
+
rb_raise(rb_eSystemCallError, "sctp_recvv: %s", strerror(errno));
|
534
|
+
|
535
|
+
if(infotype != SCTP_RECVV_RCVINFO){
|
536
|
+
return Qnil;
|
537
|
+
}
|
538
|
+
else{
|
539
|
+
return rb_struct_new(
|
540
|
+
v_sctp_receive_info_struct,
|
541
|
+
rb_str_new2(iov->iov_base),
|
542
|
+
UINT2NUM(info.rcv_sid),
|
543
|
+
UINT2NUM(info.rcv_ssn),
|
544
|
+
UINT2NUM(info.rcv_flags),
|
545
|
+
UINT2NUM(info.rcv_ppid),
|
546
|
+
UINT2NUM(info.rcv_tsn),
|
547
|
+
UINT2NUM(info.rcv_cumtsn),
|
548
|
+
UINT2NUM(info.rcv_context),
|
549
|
+
UINT2NUM(info.rcv_assoc_id)
|
550
|
+
);
|
551
|
+
}
|
552
|
+
}
|
553
|
+
#endif
|
554
|
+
|
445
555
|
/*
|
446
556
|
* Send a message on an already-connected socket to a specific association.
|
447
557
|
*
|
@@ -458,7 +568,7 @@ static VALUE rsctp_send(VALUE self, VALUE v_options){
|
|
458
568
|
uint16_t stream;
|
459
569
|
uint32_t ppid, send_flags, ctrl_flags, ttl, context;
|
460
570
|
ssize_t num_bytes;
|
461
|
-
int
|
571
|
+
int fileno;
|
462
572
|
sctp_assoc_t assoc_id;
|
463
573
|
struct sctp_sndrcvinfo info;
|
464
574
|
VALUE v_msg, v_stream, v_ppid, v_context, v_send_flags, v_ctrl_flags, v_ttl, v_assoc_id;
|
@@ -519,10 +629,10 @@ static VALUE rsctp_send(VALUE self, VALUE v_options){
|
|
519
629
|
info.sinfo_timetolive = ttl;
|
520
630
|
info.sinfo_assoc_id = assoc_id;
|
521
631
|
|
522
|
-
|
632
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
523
633
|
|
524
634
|
num_bytes = sctp_send(
|
525
|
-
|
635
|
+
fileno,
|
526
636
|
StringValueCStr(v_msg),
|
527
637
|
RSTRING_LEN(v_msg),
|
528
638
|
&info,
|
@@ -570,7 +680,7 @@ static VALUE rsctp_sendmsg(VALUE self, VALUE v_options){
|
|
570
680
|
uint32_t ppid, flags, ttl, context;
|
571
681
|
ssize_t num_bytes;
|
572
682
|
struct sockaddr_in addrs[8];
|
573
|
-
int
|
683
|
+
int fileno, size;
|
574
684
|
|
575
685
|
Check_Type(v_options, T_HASH);
|
576
686
|
|
@@ -637,10 +747,10 @@ static VALUE rsctp_sendmsg(VALUE self, VALUE v_options){
|
|
637
747
|
size = 0;
|
638
748
|
}
|
639
749
|
|
640
|
-
|
750
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
641
751
|
|
642
752
|
num_bytes = sctp_sendmsg(
|
643
|
-
|
753
|
+
fileno,
|
644
754
|
StringValueCStr(v_msg),
|
645
755
|
RSTRING_LEN(v_msg),
|
646
756
|
(struct sockaddr*)addrs,
|
@@ -681,7 +791,7 @@ static VALUE rsctp_recvmsg(int argc, VALUE* argv, VALUE self){
|
|
681
791
|
VALUE v_flags, v_notification, v_message;
|
682
792
|
struct sctp_sndrcvinfo sndrcvinfo;
|
683
793
|
struct sockaddr_in clientaddr;
|
684
|
-
int flags, bytes,
|
794
|
+
int flags, bytes, fileno;
|
685
795
|
char buffer[1024]; // TODO: Let this be configurable?
|
686
796
|
socklen_t length;
|
687
797
|
|
@@ -692,7 +802,7 @@ static VALUE rsctp_recvmsg(int argc, VALUE* argv, VALUE self){
|
|
692
802
|
else
|
693
803
|
flags = NUM2INT(v_flags);
|
694
804
|
|
695
|
-
|
805
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
696
806
|
length = sizeof(struct sockaddr_in);
|
697
807
|
|
698
808
|
bzero(buffer, sizeof(buffer));
|
@@ -700,7 +810,7 @@ static VALUE rsctp_recvmsg(int argc, VALUE* argv, VALUE self){
|
|
700
810
|
bzero(&sndrcvinfo, sizeof(sndrcvinfo));
|
701
811
|
|
702
812
|
bytes = sctp_recvmsg(
|
703
|
-
|
813
|
+
fileno,
|
704
814
|
buffer,
|
705
815
|
sizeof(buffer),
|
706
816
|
(struct sockaddr*)&clientaddr,
|
@@ -923,7 +1033,7 @@ static VALUE rsctp_recvmsg(int argc, VALUE* argv, VALUE self){
|
|
923
1033
|
* By default these values are set to zero (i.e. ignored).
|
924
1034
|
*/
|
925
1035
|
static VALUE rsctp_set_initmsg(VALUE self, VALUE v_options){
|
926
|
-
int
|
1036
|
+
int fileno;
|
927
1037
|
struct sctp_initmsg initmsg;
|
928
1038
|
VALUE v_output, v_input, v_attempts, v_timeout;
|
929
1039
|
|
@@ -934,7 +1044,7 @@ static VALUE rsctp_set_initmsg(VALUE self, VALUE v_options){
|
|
934
1044
|
v_attempts = rb_hash_aref2(v_options, "max_attempts");
|
935
1045
|
v_timeout = rb_hash_aref2(v_options, "timeout");
|
936
1046
|
|
937
|
-
|
1047
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
938
1048
|
|
939
1049
|
if(!NIL_P(v_output))
|
940
1050
|
initmsg.sinit_num_ostreams = NUM2INT(v_output);
|
@@ -948,15 +1058,15 @@ static VALUE rsctp_set_initmsg(VALUE self, VALUE v_options){
|
|
948
1058
|
if(!NIL_P(v_timeout))
|
949
1059
|
initmsg.sinit_max_init_timeo = NUM2INT(v_timeout);
|
950
1060
|
|
951
|
-
if(setsockopt(
|
1061
|
+
if(setsockopt(fileno, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg)) < 0)
|
952
1062
|
rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
|
953
1063
|
|
954
1064
|
return self;
|
955
1065
|
}
|
956
1066
|
|
957
1067
|
/*
|
958
|
-
* Subscribe to various notification
|
959
|
-
* data that the socket may receive. The possible notification
|
1068
|
+
* Subscribe to various notification type events, which will generate additional
|
1069
|
+
* data that the socket may receive. The possible notification type events are
|
960
1070
|
* as follows:
|
961
1071
|
*
|
962
1072
|
* :association
|
@@ -993,11 +1103,13 @@ static VALUE rsctp_set_initmsg(VALUE self, VALUE v_options){
|
|
993
1103
|
* socket.subscribe(:data_io => true, :shutdown => true, :send_failure => true)
|
994
1104
|
*/
|
995
1105
|
static VALUE rsctp_subscribe(VALUE self, VALUE v_options){
|
996
|
-
int
|
1106
|
+
int fileno;
|
997
1107
|
struct sctp_event_subscribe events;
|
998
1108
|
|
999
1109
|
bzero(&events, sizeof(events));
|
1000
|
-
|
1110
|
+
Check_Type(v_options, T_HASH);
|
1111
|
+
|
1112
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
1001
1113
|
|
1002
1114
|
if(RTEST(rb_hash_aref2(v_options, "data_io")))
|
1003
1115
|
events.sctp_data_io_event = 1;
|
@@ -1033,7 +1145,7 @@ static VALUE rsctp_subscribe(VALUE self, VALUE v_options){
|
|
1033
1145
|
if(RTEST(rb_hash_aref2(v_options, "sender_dry")))
|
1034
1146
|
events.sctp_sender_dry_event = 1;
|
1035
1147
|
|
1036
|
-
if(setsockopt(
|
1148
|
+
if(setsockopt(fileno, IPPROTO_SCTP, SCTP_EVENTS, &events, sizeof(events)) < 0)
|
1037
1149
|
rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
|
1038
1150
|
|
1039
1151
|
return self;
|
@@ -1044,29 +1156,39 @@ static VALUE rsctp_subscribe(VALUE self, VALUE v_options){
|
|
1044
1156
|
* will be used to accept incoming connection requests.
|
1045
1157
|
*
|
1046
1158
|
* The backlog argument defines the maximum length to which the queue of
|
1047
|
-
* pending connections for sockfd may grow. The default is
|
1159
|
+
* pending connections for sockfd may grow. The default value is 128. The
|
1160
|
+
* maximum value is Socket::SOMAXCONN.
|
1161
|
+
*
|
1162
|
+
* Why a default of 128? The answer is a "best guess" compromise between
|
1163
|
+
* handling server load versus avoiding SYN flood attacks. I leave it as an
|
1164
|
+
* exercise to the programmer to adjust as desired.
|
1165
|
+
*
|
1166
|
+
* See https://tangentsoft.com/wskfaq/advanced.html#backlog if you want
|
1167
|
+
* more details on the advantages and drawbacks of various values.
|
1048
1168
|
*
|
1049
1169
|
* Example:
|
1050
1170
|
*
|
1051
1171
|
* socket = SCTP::Socket.new
|
1052
1172
|
* socket.bind(:port => 62534, :addresses => ['127.0.0.1'])
|
1053
1173
|
* socket.listen
|
1054
|
-
*
|
1055
1174
|
*/
|
1056
1175
|
static VALUE rsctp_listen(int argc, VALUE* argv, VALUE self){
|
1057
1176
|
VALUE v_backlog;
|
1058
|
-
int backlog,
|
1177
|
+
int backlog, fileno;
|
1059
1178
|
|
1060
1179
|
rb_scan_args(argc, argv, "01", &v_backlog);
|
1061
1180
|
|
1062
1181
|
if(NIL_P(v_backlog))
|
1063
|
-
backlog =
|
1182
|
+
backlog = 128;
|
1064
1183
|
else
|
1065
1184
|
backlog = NUM2INT(v_backlog);
|
1066
1185
|
|
1067
|
-
|
1186
|
+
if(backlog > SOMAXCONN)
|
1187
|
+
rb_raise(rb_eArgError, "backlog value exceeds maximum value of: %i", SOMAXCONN);
|
1068
1188
|
|
1069
|
-
|
1189
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
1190
|
+
|
1191
|
+
if(listen(fileno, backlog) < 0)
|
1070
1192
|
rb_raise(rb_eSystemCallError, "listen: %s", strerror(errno));
|
1071
1193
|
|
1072
1194
|
return self;
|
@@ -1074,38 +1196,47 @@ static VALUE rsctp_listen(int argc, VALUE* argv, VALUE self){
|
|
1074
1196
|
|
1075
1197
|
/*
|
1076
1198
|
* Extracts an association contained by a one-to-many socket connection into
|
1077
|
-
* a one-to-one style socket.
|
1199
|
+
* a one-to-one style socket. Returns the socket descriptor (fileno).
|
1200
|
+
*
|
1201
|
+
* Example:
|
1202
|
+
*
|
1203
|
+
* socket = SCTP::Socket.new
|
1204
|
+
* # etc...
|
1205
|
+
*
|
1206
|
+
* while true
|
1207
|
+
* info = socket.recvmsg
|
1208
|
+
* assoc_fileno = socket.peeloff(info.association_id)
|
1209
|
+
* # ... Do something with this new
|
1210
|
+
* end
|
1078
1211
|
*/
|
1079
1212
|
static VALUE rsctp_peeloff(VALUE self, VALUE v_assoc_id){
|
1080
|
-
int
|
1213
|
+
int fileno, assoc_fileno;
|
1081
1214
|
sctp_assoc_t assoc_id;
|
1082
1215
|
|
1083
|
-
|
1216
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
1084
1217
|
assoc_id = NUM2INT(v_assoc_id);
|
1085
1218
|
|
1086
|
-
|
1219
|
+
assoc_fileno = sctp_peeloff(fileno, assoc_id);
|
1087
1220
|
|
1088
|
-
if(
|
1221
|
+
if(assoc_fileno < 0)
|
1089
1222
|
rb_raise(rb_eSystemCallError, "sctp_peeloff: %s", strerror(errno));
|
1090
1223
|
|
1091
|
-
|
1092
|
-
|
1093
|
-
return self;
|
1224
|
+
return INT2NUM(assoc_fileno);
|
1094
1225
|
}
|
1095
1226
|
|
1096
1227
|
static VALUE rsctp_get_default_send_params(VALUE self){
|
1097
|
-
int
|
1228
|
+
int fileno;
|
1098
1229
|
socklen_t size;
|
1099
1230
|
sctp_assoc_t assoc_id;
|
1100
1231
|
struct sctp_sndrcvinfo sndrcv;
|
1101
1232
|
|
1102
1233
|
bzero(&sndrcv, sizeof(sndrcv));
|
1103
1234
|
|
1104
|
-
|
1235
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
1105
1236
|
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
1106
1237
|
size = sizeof(struct sctp_sndrcvinfo);
|
1107
1238
|
|
1108
|
-
if(sctp_opt_info(
|
1239
|
+
if(sctp_opt_info(fileno, assoc_id, SCTP_DEFAULT_SEND_PARAM, (void*)&sndrcv, &size) < 0)
|
1109
1240
|
rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
|
1110
1241
|
|
1111
1242
|
return rb_struct_new(
|
@@ -1123,18 +1254,18 @@ static VALUE rsctp_get_default_send_params(VALUE self){
|
|
1123
1254
|
}
|
1124
1255
|
|
1125
1256
|
static VALUE rsctp_get_association_info(VALUE self){
|
1126
|
-
int
|
1257
|
+
int fileno;
|
1127
1258
|
socklen_t size;
|
1128
1259
|
sctp_assoc_t assoc_id;
|
1129
1260
|
struct sctp_assocparams assoc;
|
1130
1261
|
|
1131
1262
|
bzero(&assoc, sizeof(assoc));
|
1132
1263
|
|
1133
|
-
|
1264
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
1134
1265
|
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
1135
1266
|
size = sizeof(struct sctp_assocparams);
|
1136
1267
|
|
1137
|
-
if(sctp_opt_info(
|
1268
|
+
if(sctp_opt_info(fileno, assoc_id, SCTP_ASSOCINFO, (void*)&assoc, &size) < 0)
|
1138
1269
|
rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
|
1139
1270
|
|
1140
1271
|
return rb_struct_new(
|
@@ -1149,10 +1280,10 @@ static VALUE rsctp_get_association_info(VALUE self){
|
|
1149
1280
|
}
|
1150
1281
|
|
1151
1282
|
static VALUE rsctp_shutdown(int argc, VALUE* argv, VALUE self){
|
1152
|
-
int how,
|
1283
|
+
int how, fileno;
|
1153
1284
|
VALUE v_how;
|
1154
1285
|
|
1155
|
-
|
1286
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
1156
1287
|
|
1157
1288
|
rb_scan_args(argc, argv, "01", &v_how);
|
1158
1289
|
|
@@ -1164,25 +1295,25 @@ static VALUE rsctp_shutdown(int argc, VALUE* argv, VALUE self){
|
|
1164
1295
|
how = NUM2INT(v_how);
|
1165
1296
|
}
|
1166
1297
|
|
1167
|
-
if(shutdown(
|
1298
|
+
if(shutdown(fileno, how) < 0)
|
1168
1299
|
rb_raise(rb_eSystemCallError, "shutdown: %s", strerror(errno));
|
1169
1300
|
|
1170
1301
|
return self;
|
1171
1302
|
}
|
1172
1303
|
|
1173
1304
|
static VALUE rsctp_get_retransmission_info(VALUE self){
|
1174
|
-
int
|
1305
|
+
int fileno;
|
1175
1306
|
socklen_t size;
|
1176
1307
|
sctp_assoc_t assoc_id;
|
1177
1308
|
struct sctp_rtoinfo rto;
|
1178
1309
|
|
1179
1310
|
bzero(&rto, sizeof(rto));
|
1180
1311
|
|
1181
|
-
|
1312
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
1182
1313
|
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
1183
1314
|
size = sizeof(struct sctp_rtoinfo);
|
1184
1315
|
|
1185
|
-
if(sctp_opt_info(
|
1316
|
+
if(sctp_opt_info(fileno, assoc_id, SCTP_RTOINFO, (void*)&rto, &size) < 0)
|
1186
1317
|
rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
|
1187
1318
|
|
1188
1319
|
return rb_struct_new(
|
@@ -1216,7 +1347,7 @@ static VALUE rsctp_get_retransmission_info(VALUE self){
|
|
1216
1347
|
* * primary (IP)
|
1217
1348
|
*/
|
1218
1349
|
static VALUE rsctp_get_status(VALUE self){
|
1219
|
-
int
|
1350
|
+
int fileno;
|
1220
1351
|
socklen_t size;
|
1221
1352
|
sctp_assoc_t assoc_id;
|
1222
1353
|
struct sctp_status status;
|
@@ -1225,11 +1356,11 @@ static VALUE rsctp_get_status(VALUE self){
|
|
1225
1356
|
|
1226
1357
|
bzero(&status, sizeof(status));
|
1227
1358
|
|
1228
|
-
|
1359
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
1229
1360
|
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
1230
1361
|
size = sizeof(struct sctp_status);
|
1231
1362
|
|
1232
|
-
if(sctp_opt_info(
|
1363
|
+
if(sctp_opt_info(fileno, assoc_id, SCTP_STATUS, (void*)&status, &size) < 0)
|
1233
1364
|
rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
|
1234
1365
|
|
1235
1366
|
spinfo = &status.sstat_primary;
|
@@ -1258,6 +1389,39 @@ static VALUE rsctp_get_status(VALUE self){
|
|
1258
1389
|
);
|
1259
1390
|
}
|
1260
1391
|
|
1392
|
+
static VALUE rsctp_get_subscriptions(VALUE self){
|
1393
|
+
int fileno;
|
1394
|
+
socklen_t size;
|
1395
|
+
sctp_assoc_t assoc_id;
|
1396
|
+
struct sctp_event_subscribe events;
|
1397
|
+
|
1398
|
+
bzero(&events, sizeof(events));
|
1399
|
+
|
1400
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
1401
|
+
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
1402
|
+
size = sizeof(struct sctp_event_subscribe);
|
1403
|
+
|
1404
|
+
if(sctp_opt_info(fileno, assoc_id, SCTP_EVENTS, (void*)&events, &size) < 0)
|
1405
|
+
rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
|
1406
|
+
|
1407
|
+
return rb_struct_new(v_sctp_event_subscribe_struct,
|
1408
|
+
(events.sctp_data_io_event ? Qtrue : Qfalse),
|
1409
|
+
(events.sctp_association_event ? Qtrue : Qfalse),
|
1410
|
+
(events.sctp_address_event ? Qtrue : Qfalse),
|
1411
|
+
(events.sctp_send_failure_event ? Qtrue : Qfalse),
|
1412
|
+
(events.sctp_peer_error_event ? Qtrue : Qfalse),
|
1413
|
+
(events.sctp_shutdown_event ? Qtrue : Qfalse),
|
1414
|
+
(events.sctp_partial_delivery_event ? Qtrue : Qfalse),
|
1415
|
+
(events.sctp_adaptation_layer_event ? Qtrue : Qfalse),
|
1416
|
+
(events.sctp_authentication_event ? Qtrue : Qfalse),
|
1417
|
+
(events.sctp_sender_dry_event ? Qtrue : Qfalse),
|
1418
|
+
(events.sctp_stream_reset_event ? Qtrue : Qfalse),
|
1419
|
+
(events.sctp_assoc_reset_event ? Qtrue : Qfalse),
|
1420
|
+
(events.sctp_stream_change_event ? Qtrue : Qfalse),
|
1421
|
+
(events.sctp_send_failure_event_event ? Qtrue : Qfalse)
|
1422
|
+
);
|
1423
|
+
}
|
1424
|
+
|
1261
1425
|
void Init_socket(void){
|
1262
1426
|
mSCTP = rb_define_module("SCTP");
|
1263
1427
|
cSocket = rb_define_class_under(mSCTP, "Socket", rb_cObject);
|
@@ -1330,19 +1494,32 @@ void Init_socket(void){
|
|
1330
1494
|
"ttl", "tsn", "cumtsn", "association_id", NULL
|
1331
1495
|
);
|
1332
1496
|
|
1497
|
+
v_sctp_event_subscribe_struct = rb_struct_define(
|
1498
|
+
"EventSubscriptions", "data_io", "association", "address", "send_failure",
|
1499
|
+
"peer_error", "shutdown", "partial_delivery", "adaptation_layer",
|
1500
|
+
"authentication", "sender_dry", "stream_reset", "assoc_reset",
|
1501
|
+
"stream_change", "send_failure_event", NULL
|
1502
|
+
);
|
1503
|
+
|
1504
|
+
v_sctp_receive_info_struct = rb_struct_define(
|
1505
|
+
"ReceiveInfo", "message", "sid", "ssn", "flags", "ppid", "tsn",
|
1506
|
+
"cumtsn", "context", "assocation_id", NULL
|
1507
|
+
);
|
1508
|
+
|
1333
1509
|
rb_define_method(cSocket, "initialize", rsctp_init, -1);
|
1334
1510
|
|
1335
|
-
rb_define_method(cSocket, "
|
1511
|
+
rb_define_method(cSocket, "bindx", rsctp_bindx, -1);
|
1336
1512
|
rb_define_method(cSocket, "close", rsctp_close, 0);
|
1337
|
-
rb_define_method(cSocket, "
|
1338
|
-
rb_define_method(cSocket, "getpeernames", rsctp_getpeernames,
|
1339
|
-
rb_define_method(cSocket, "getlocalnames", rsctp_getlocalnames,
|
1513
|
+
rb_define_method(cSocket, "connectx", rsctp_connectx, -1);
|
1514
|
+
rb_define_method(cSocket, "getpeernames", rsctp_getpeernames, -1);
|
1515
|
+
rb_define_method(cSocket, "getlocalnames", rsctp_getlocalnames, -1);
|
1340
1516
|
rb_define_method(cSocket, "get_status", rsctp_get_status, 0);
|
1341
1517
|
rb_define_method(cSocket, "get_default_send_params", rsctp_get_default_send_params, 0);
|
1342
1518
|
rb_define_method(cSocket, "get_retransmission_info", rsctp_get_retransmission_info, 0);
|
1343
1519
|
rb_define_method(cSocket, "get_association_info", rsctp_get_association_info, 0);
|
1520
|
+
rb_define_method(cSocket, "get_subscriptions", rsctp_get_subscriptions, 0);
|
1344
1521
|
rb_define_method(cSocket, "listen", rsctp_listen, -1);
|
1345
|
-
rb_define_method(cSocket, "peeloff
|
1522
|
+
rb_define_method(cSocket, "peeloff", rsctp_peeloff, 1);
|
1346
1523
|
rb_define_method(cSocket, "recvmsg", rsctp_recvmsg, -1);
|
1347
1524
|
rb_define_method(cSocket, "send", rsctp_send, 1);
|
1348
1525
|
|
@@ -1350,6 +1527,10 @@ void Init_socket(void){
|
|
1350
1527
|
rb_define_method(cSocket, "sendv", rsctp_sendv, 1);
|
1351
1528
|
#endif
|
1352
1529
|
|
1530
|
+
#ifdef HAVE_SCTP_RECVV
|
1531
|
+
rb_define_method(cSocket, "recvv", rsctp_recvv, -1);
|
1532
|
+
#endif
|
1533
|
+
|
1353
1534
|
rb_define_method(cSocket, "sendmsg", rsctp_sendmsg, 1);
|
1354
1535
|
rb_define_method(cSocket, "set_initmsg", rsctp_set_initmsg, 1);
|
1355
1536
|
rb_define_method(cSocket, "shutdown", rsctp_shutdown, -1);
|
@@ -1357,12 +1538,12 @@ void Init_socket(void){
|
|
1357
1538
|
|
1358
1539
|
rb_define_attr(cSocket, "domain", 1, 1);
|
1359
1540
|
rb_define_attr(cSocket, "type", 1, 1);
|
1360
|
-
rb_define_attr(cSocket, "
|
1541
|
+
rb_define_attr(cSocket, "fileno", 1, 1);
|
1361
1542
|
rb_define_attr(cSocket, "association_id", 1, 1);
|
1362
1543
|
rb_define_attr(cSocket, "port", 1, 1);
|
1363
1544
|
|
1364
|
-
/* 0.0.
|
1365
|
-
rb_define_const(cSocket, "VERSION", rb_str_new2("0.0.
|
1545
|
+
/* 0.0.7: The version of this library */
|
1546
|
+
rb_define_const(cSocket, "VERSION", rb_str_new2("0.0.7"));
|
1366
1547
|
|
1367
1548
|
/* send flags */
|
1368
1549
|
|
data/sctp-socket.gemspec
CHANGED
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sctp-socket
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Berger
|
@@ -35,7 +35,7 @@ cert_chain:
|
|
35
35
|
ORVCZpRuCPpmC8qmqxUnARDArzucjaclkxjLWvCVHeFa9UP7K3Nl9oTjJNv+7/jM
|
36
36
|
WZs4eecIcUc4tKdHxcAJ0MO/Dkqq7hGaiHpwKY76wQ1+8xAh
|
37
37
|
-----END CERTIFICATE-----
|
38
|
-
date: 2024-05-
|
38
|
+
date: 2024-05-28 00:00:00.000000000 Z
|
39
39
|
dependencies:
|
40
40
|
- !ruby/object:Gem::Dependency
|
41
41
|
name: bundler
|
metadata.gz.sig
CHANGED
Binary file
|