sctp-socket 0.1.2 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 89d20d26ad8e90c5673d4d126da8daa8f69d907a54ba0ddc9caf529ef5929c6e
4
- data.tar.gz: 886d28171c2e7242a7875b7a998e7073a9bec469da7da5b9205859a4e2d3e257
3
+ metadata.gz: 9a53fb8e5953dbf9ca5c45e273ab45d4982ade9ec4b77e44657cd826757fb8ef
4
+ data.tar.gz: 8d3aa7a1087c0f348cf25d8dde354fcb5bfba61b7a9c6db78cf60922496bf983
5
5
  SHA512:
6
- metadata.gz: ee23fbff8da2e3efa66f87f583ba1f631d39957a6f74bff530d1b71ae1a15ab773ecb6653f34d8d5e17e034a15f6a736c90a16f3c8f3ed636734ab674dee54ca
7
- data.tar.gz: 68ff54d9088bfe723f0726c3bcc41c102aab7c3f631f1156f64651bd078ffa1a852b247505a4babf36cb37c61aa11726587db407ad34171c974b6afca96283a8
6
+ metadata.gz: 8e23832cbb9cc0b8741ef696ed97aa494c17a12cc22bbf2b6eeaaab401cd654efb9b9966913557d2d442ae694e698c081c147d6b448d88876efecc831254c0d7
7
+ data.tar.gz: 17617bb21948741bc3397c9528bf283c5a07ec6bc06b57f7db17b925236025738cbe72390d7cb9ceb791d4b992ecba438d0a5ef3752baffc1d3b676fff5c719c
checksums.yaml.gz.sig CHANGED
Binary file
@@ -35,3 +35,25 @@ jobs:
35
35
  bundler-cache: true
36
36
  - name: Run Specs
37
37
  run: bundle exec rake
38
+ freebsd:
39
+ runs-on: ubuntu-latest
40
+ steps:
41
+ - uses: actions/checkout@v4
42
+ - name: Test in FreeBSD
43
+ id: test
44
+ uses: vmactions/freebsd-vm@v1
45
+ with:
46
+ usesh: true
47
+ prepare: |
48
+ pkg install -y llvm ruby devel/ruby-gems sctplib git-tiny
49
+
50
+ run: |
51
+ git config --global --add safe.directory /home/runner/work/sctp-socket/sctp-socket
52
+ kldload sctp
53
+ ifconfig lo1 create
54
+ ifconfig lo1 1.1.1.1/24 up
55
+ ifconfig lo2 create
56
+ ifconfig lo2 1.1.1.2/24 up
57
+ gem install bundler --no-document
58
+ bundle install --quiet
59
+ bundle exec rake
data/CHANGES.md CHANGED
@@ -1,3 +1,14 @@
1
+ ## 0.1.4 - 1-Feb-2025
2
+ * Added the set_retransmission_info method.
3
+ * Added the get_rto_info and set_rto_info aliases.
4
+ * Added the set_association_info method.
5
+ * Some spec updates and refactoring.
6
+
7
+ ## 0.1.3 - 22-Jan-2025
8
+ * The close method now accepts an optional `linger` argument.
9
+ * The bindx method now accepts an optional `reuse_addr` argument.
10
+ * Fixed a bug in the bindx method for address arrays with a single element.
11
+
1
12
  ## 0.1.2 - 10-Jan-2025
2
13
  * Added support for BSD.
3
14
 
data/README.md CHANGED
@@ -67,7 +67,7 @@ Currently this has only been developed and tested on Linux and BSD. Other
67
67
  platforms will probably only be supported via community contributions.
68
68
 
69
69
  The sendv and recvv methods may not be available. Use the sendmsg and recvmsg
70
- methods instead.
70
+ methods instead if that's the case.
71
71
 
72
72
  I am currently unable to subclass the Socket class from Ruby's standard library.
73
73
  For whatever reason the call to rb_call_super works, but the fileno is always
data/Rakefile CHANGED
@@ -39,13 +39,21 @@ end
39
39
 
40
40
  desc "Create dummy IP addresses to use for testing"
41
41
  task :create_dummy_links do
42
- system('sudo ip link add dummy1 type dummy')
43
- system('sudo ip link add dummy2 type dummy')
44
- system('sudo ip addr add 1.1.1.1/24 dev dummy1')
45
- system('sudo ip addr add 1.1.1.2/24 dev dummy2')
46
- system('sudo ip link set dummy1 up')
47
- system('sudo ip link set dummy2 up')
48
- system('ip link show')
42
+ if RbConfig::CONFIG['host_os'] =~ /linux/i
43
+ system('sudo ip link add dummy1 type dummy')
44
+ system('sudo ip link add dummy2 type dummy')
45
+ system('sudo ip addr add 1.1.1.1/24 dev dummy1')
46
+ system('sudo ip addr add 1.1.1.2/24 dev dummy2')
47
+ system('sudo ip link set dummy1 up')
48
+ system('sudo ip link set dummy2 up')
49
+ system('ip link show')
50
+ else
51
+ system("sudo ifconfig lo1 create")
52
+ system("sudo ifconfig lo1 1.1.1.1/24 up")
53
+ system("sudo ifconfig lo2 create")
54
+ system("sudo ifconfig lo2 1.1.1.2/24 up")
55
+ system("sudo ifconfig -a")
56
+ end
49
57
  end
50
58
 
51
59
  RSpec::Core::RakeTask.new
@@ -10,7 +10,7 @@ begin
10
10
  socket = SCTP::Socket.new
11
11
 
12
12
  # Optional, but could bind to a subset of available addresses
13
- p socket.bindx(:addresses => addresses)
13
+ # p socket.bindx(:addresses => addresses)
14
14
 
15
15
  # Initial connection
16
16
  p socket.connectx(:addresses => addresses, :port => port)
@@ -30,6 +30,7 @@ begin
30
30
 
31
31
  while true
32
32
  info = socket.recvmsg
33
+ # info = socket.recvv # Or this
33
34
  p info
34
35
  end
35
36
  ensure
data/ext/sctp/socket.c CHANGED
@@ -335,11 +335,28 @@ static VALUE rsctp_init(int argc, VALUE* argv, VALUE self){
335
335
  *
336
336
  * Bind a subset of IP addresses associated with the host system on the
337
337
  * given port, or a port assigned by the operating system if none is provided.
338
+ * You may bind a maximum of eight IP addresses.
338
339
  *
339
340
  * Note that you can both add or remove an address to or from the socket
340
341
  * using the SCTP_BINDX_ADD_ADDR (default) or SCTP_BINDX_REM_ADDR constants,
341
342
  * respectively.
342
343
  *
344
+ * Possible options:
345
+ *
346
+ * * addresses - Array of IP addresses to bind to. If none are specified then
347
+ * INADDR_ANY is used.
348
+ *
349
+ * * port - The port to bind to. If none is specified then 0 is used, i.e. the
350
+ * OS will select one for you.
351
+ *
352
+ * * flags - Flags to pass to the underlying sctp_bindx function. In practice
353
+ * there are only two options: BINDX_ADD_ADDR and BINDX_REM_ADDR. By
354
+ * default a flag of BINDX_ADD_ADDR is assumed.
355
+ *
356
+ * * reuse_addr - If set to true, then the SO_REUSEADDR flag will be applied to
357
+ * the socket before the bind call. This will allow other sockets to reuse
358
+ * the addresses that are currently bound to the socket.
359
+ *
343
360
  * Example:
344
361
  *
345
362
  * socket = SCTP::Socket.new
@@ -357,8 +374,8 @@ static VALUE rsctp_init(int argc, VALUE* argv, VALUE self){
357
374
  */
358
375
  static VALUE rsctp_bindx(int argc, VALUE* argv, VALUE self){
359
376
  struct sockaddr_in addrs[8];
360
- int i, fileno, num_ip, flags, domain, port;
361
- VALUE v_addresses, v_port, v_flags, v_address, v_options;
377
+ int i, fileno, num_ip, flags, domain, port, on;
378
+ VALUE v_addresses, v_port, v_flags, v_address, v_reuse_addr, v_options;
362
379
 
363
380
  rb_scan_args(argc, argv, "01", &v_options);
364
381
 
@@ -370,6 +387,7 @@ static VALUE rsctp_bindx(int argc, VALUE* argv, VALUE self){
370
387
  v_addresses = rb_hash_aref2(v_options, "addresses");
371
388
  v_flags = rb_hash_aref2(v_options, "flags");
372
389
  v_port = rb_hash_aref2(v_options, "port");
390
+ v_reuse_addr = rb_hash_aref2(v_options, "reuse_addr");
373
391
 
374
392
  if(NIL_P(v_port))
375
393
  port = 0;
@@ -386,10 +404,13 @@ static VALUE rsctp_bindx(int argc, VALUE* argv, VALUE self){
386
404
  else
387
405
  num_ip = (int)RARRAY_LEN(v_addresses);
388
406
 
407
+ if(num_ip > 8)
408
+ rb_raise(rb_eArgError, "too many IP addresses to bind, maximum is eight");
409
+
389
410
  domain = NUM2INT(rb_iv_get(self, "@domain"));
390
411
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
391
412
 
392
- if(num_ip > 1){
413
+ if(!NIL_P(v_addresses)){
393
414
  for(i = 0; i < num_ip; i++){
394
415
  v_address = RARRAY_PTR(v_addresses)[i];
395
416
  addrs[i].sin_family = domain;
@@ -409,6 +430,12 @@ static VALUE rsctp_bindx(int argc, VALUE* argv, VALUE self){
409
430
  #endif
410
431
  }
411
432
 
433
+ if(v_reuse_addr == Qtrue){
434
+ on = 1;
435
+ if(setsockopt(fileno, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
436
+ rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
437
+ }
438
+
412
439
  if(sctp_bindx(fileno, (struct sockaddr *) addrs, num_ip, flags) != 0)
413
440
  rb_raise(rb_eSystemCallError, "sctp_bindx: %s", strerror(errno));
414
441
 
@@ -497,15 +524,46 @@ static VALUE rsctp_connectx(int argc, VALUE* argv, VALUE self){
497
524
  *
498
525
  * Close the socket. You should always do this.
499
526
  *
527
+ * By default the underlying close operation is non-blocking. This means that the
528
+ * bound IP addresses may not be available right away after closing. You may
529
+ * optionally control this behavior with the +linger+ option.
530
+ *
531
+ *
532
+ * * linger - If present, this should be set to a numeric value, in seconds.
533
+ * The value will cause the close operation to block for that number of
534
+ * seconds, after which it will return (i.e. return to non-blocking).
535
+ *
500
536
  * Example:
501
537
  *
502
538
  * socket = SCTP::Socket.new
503
- * socket.close
539
+ * socket.close # or
540
+ * socket.close(linger: 5)
504
541
  */
505
- static VALUE rsctp_close(VALUE self){
506
- VALUE v_fileno = rb_iv_get(self, "@fileno");
542
+ static VALUE rsctp_close(int argc, VALUE* argv, VALUE self){
543
+ VALUE v_options, v_linger;
544
+ int fileno;
507
545
 
508
- if(close(NUM2INT(v_fileno)))
546
+ rb_scan_args(argc, argv, "01", &v_options);
547
+
548
+ if(NIL_P(v_options))
549
+ v_options = rb_hash_new();
550
+
551
+ Check_Type(v_options, T_HASH);
552
+
553
+ v_linger = rb_hash_aref2(v_options, "linger");
554
+
555
+ fileno = NUM2INT(rb_iv_get(self, "@fileno"));
556
+
557
+ if(!NIL_P(v_linger)){
558
+ struct linger lin;
559
+ lin.l_onoff = 1;
560
+ lin.l_linger = NUM2INT(v_linger);
561
+
562
+ if(setsockopt(fileno, SOL_SOCKET, SO_LINGER, &lin, sizeof(struct linger)) < 0)
563
+ rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
564
+ }
565
+
566
+ if(close(fileno))
509
567
  rb_raise(rb_eSystemCallError, "close: %s", strerror(errno));
510
568
 
511
569
  return self;
@@ -695,6 +753,7 @@ static VALUE rsctp_sendv(VALUE self, VALUE v_options){
695
753
  rb_raise(rb_eArgError, "Array size is greater than IOV_MAX");
696
754
 
697
755
  // TODO: Make this configurable
756
+ spa.sendv_flags = SCTP_SEND_SNDINFO_VALID;
698
757
  spa.sendv_sndinfo.snd_flags = SCTP_UNORDERED;
699
758
  spa.sendv_sndinfo.snd_assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
700
759
 
@@ -1469,6 +1528,75 @@ static VALUE rsctp_get_association_info(VALUE self){
1469
1528
  );
1470
1529
  }
1471
1530
 
1531
+ /*
1532
+ * call-seq:
1533
+ * SCTP::Socket#set_association_info(options)
1534
+ *
1535
+ * Sets the association specific parameters. The +options+ parameter
1536
+ * is a hash that accepts the following keywords:
1537
+ *
1538
+ * * association_id
1539
+ * * max_retransmission_count
1540
+ * * number_peer_destinations
1541
+ * * peer_receive_window
1542
+ * * local_receive_window
1543
+ * * cookie_life
1544
+ *
1545
+ * All values that refer to time values are measured in milliseconds.
1546
+ */
1547
+ static VALUE rsctp_set_association_info(VALUE self, VALUE v_options){
1548
+ VALUE v_assoc_id, v_max_rxt, v_nbr_peer, v_peer_rw, v_local_rw, v_cookie;
1549
+ int fileno;
1550
+ sctp_assoc_t assoc_id;
1551
+ struct sctp_assocparams assoc;
1552
+
1553
+ bzero(&assoc, sizeof(assoc));
1554
+
1555
+ fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1556
+
1557
+ v_assoc_id = rb_hash_aref2(v_options, "association_id");
1558
+ v_max_rxt = rb_hash_aref2(v_options, "max_retransmission_count");
1559
+ v_nbr_peer = rb_hash_aref2(v_options, "number_peer_destinations");
1560
+ v_peer_rw = rb_hash_aref2(v_options, "peer_receive_window");
1561
+ v_local_rw = rb_hash_aref2(v_options, "local_receive_window");
1562
+ v_cookie = rb_hash_aref2(v_options, "cookie_life");
1563
+
1564
+ if(NIL_P(v_assoc_id))
1565
+ assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
1566
+ else
1567
+ assoc_id = NUM2INT(v_assoc_id);
1568
+
1569
+ assoc.sasoc_assoc_id = assoc_id;
1570
+
1571
+ if(!NIL_P(v_max_rxt))
1572
+ assoc.sasoc_asocmaxrxt = NUM2INT(v_max_rxt);
1573
+
1574
+ if(!NIL_P(v_nbr_peer))
1575
+ assoc.sasoc_number_peer_destinations = NUM2INT(v_nbr_peer);
1576
+
1577
+ if(!NIL_P(v_peer_rw))
1578
+ assoc.sasoc_peer_rwnd = NUM2INT(v_peer_rw);
1579
+
1580
+ if(!NIL_P(v_local_rw))
1581
+ assoc.sasoc_local_rwnd = NUM2INT(v_local_rw);
1582
+
1583
+ if(!NIL_P(v_cookie))
1584
+ assoc.sasoc_cookie_life = NUM2INT(v_cookie);
1585
+
1586
+ if(setsockopt(fileno, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, sizeof(assoc)) < 0)
1587
+ rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
1588
+
1589
+ return rb_struct_new(
1590
+ v_sctp_associnfo_struct,
1591
+ INT2NUM(assoc.sasoc_assoc_id),
1592
+ INT2NUM(assoc.sasoc_asocmaxrxt),
1593
+ INT2NUM(assoc.sasoc_number_peer_destinations),
1594
+ INT2NUM(assoc.sasoc_peer_rwnd),
1595
+ INT2NUM(assoc.sasoc_local_rwnd),
1596
+ INT2NUM(assoc.sasoc_cookie_life)
1597
+ );
1598
+ }
1599
+
1472
1600
  /*
1473
1601
  * call-seq:
1474
1602
  * SCTP::Socket#shutdown
@@ -1543,6 +1671,64 @@ static VALUE rsctp_get_retransmission_info(VALUE self){
1543
1671
  );
1544
1672
  }
1545
1673
 
1674
+ /*
1675
+ * call-seq:
1676
+ * SCTP::Socket#set_retransmission_info(options)
1677
+ *
1678
+ * Sets the protocol parameters that are used to initialize and bind the
1679
+ * retransmission timeout (RTO) tunable. The method accepts a hash with
1680
+ * the following possible keys:
1681
+ *
1682
+ * * association_id
1683
+ * * initial
1684
+ * * max
1685
+ * * min
1686
+ *
1687
+ * The +initial+, +max+ and +min+ options default to zero (unchanged).
1688
+ */
1689
+ static VALUE rsctp_set_retransmission_info(VALUE self, VALUE v_options){
1690
+ VALUE v_assoc_id, v_initial, v_max, v_min;
1691
+ int fileno;
1692
+ sctp_assoc_t assoc_id;
1693
+ struct sctp_rtoinfo rto;
1694
+
1695
+ bzero(&rto, sizeof(rto));
1696
+
1697
+ fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1698
+
1699
+ v_assoc_id = rb_hash_aref2(v_options, "association_id");
1700
+ v_initial = rb_hash_aref2(v_options, "initial");
1701
+ v_max = rb_hash_aref2(v_options, "max");
1702
+ v_min = rb_hash_aref2(v_options, "min");
1703
+
1704
+ if(NIL_P(v_assoc_id))
1705
+ v_assoc_id = rb_iv_get(self, "@association_id");
1706
+
1707
+ assoc_id = NUM2INT(v_assoc_id);
1708
+
1709
+ rto.srto_assoc_id = assoc_id;
1710
+
1711
+ if(!NIL_P(v_initial))
1712
+ rto.srto_initial = NUM2INT(v_initial);
1713
+
1714
+ if(!NIL_P(v_max))
1715
+ rto.srto_max = NUM2INT(v_max);
1716
+
1717
+ if(!NIL_P(v_min))
1718
+ rto.srto_min = NUM2INT(v_min);
1719
+
1720
+ if(setsockopt(fileno, IPPROTO_SCTP, SCTP_RTOINFO, &rto, sizeof(rto)) < 0)
1721
+ rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
1722
+
1723
+ return rb_struct_new(
1724
+ v_sctp_rtoinfo_struct,
1725
+ v_assoc_id,
1726
+ v_initial,
1727
+ v_max,
1728
+ v_min
1729
+ );
1730
+ }
1731
+
1546
1732
  /*
1547
1733
  * call-seq:
1548
1734
  * SCTP::Socket#get_status
@@ -2298,7 +2484,7 @@ void Init_socket(void){
2298
2484
 
2299
2485
  rb_define_method(cSocket, "autoclose=", rsctp_set_autoclose, 1);
2300
2486
  rb_define_method(cSocket, "bindx", rsctp_bindx, -1);
2301
- rb_define_method(cSocket, "close", rsctp_close, 0);
2487
+ rb_define_method(cSocket, "close", rsctp_close, -1);
2302
2488
  rb_define_method(cSocket, "connectx", rsctp_connectx, -1);
2303
2489
  rb_define_method(cSocket, "delete_shared_key", rsctp_delete_shared_key, -1);
2304
2490
  rb_define_method(cSocket, "disable_fragments=", rsctp_disable_fragments, 1);
@@ -2332,20 +2518,24 @@ void Init_socket(void){
2332
2518
 
2333
2519
  rb_define_method(cSocket, "sendmsg", rsctp_sendmsg, 1);
2334
2520
  rb_define_method(cSocket, "set_active_shared_key", rsctp_set_active_shared_key, -1);
2521
+ rb_define_method(cSocket, "set_association_info", rsctp_set_association_info, 1);
2335
2522
  rb_define_method(cSocket, "set_initmsg", rsctp_set_initmsg, 1);
2336
- //rb_define_method(cSocket, "set_retransmission_info", rsctp_set_retransmission_info, -1);
2523
+ rb_define_method(cSocket, "set_retransmission_info", rsctp_set_retransmission_info, 1);
2337
2524
  rb_define_method(cSocket, "set_shared_key", rsctp_set_shared_key, -1);
2338
2525
  rb_define_method(cSocket, "shutdown", rsctp_shutdown, -1);
2339
2526
  rb_define_method(cSocket, "subscribe", rsctp_subscribe, 1);
2340
2527
 
2528
+ rb_define_alias(cSocket, "get_rto_info", "get_retransmission_info");
2529
+ rb_define_alias(cSocket, "set_rto_info", "set_retransmission_info");
2530
+
2341
2531
  rb_define_attr(cSocket, "domain", 1, 1);
2342
2532
  rb_define_attr(cSocket, "type", 1, 1);
2343
2533
  rb_define_attr(cSocket, "fileno", 1, 1);
2344
2534
  rb_define_attr(cSocket, "association_id", 1, 1);
2345
2535
  rb_define_attr(cSocket, "port", 1, 1);
2346
2536
 
2347
- /* 0.1.2: The version of this library */
2348
- rb_define_const(cSocket, "VERSION", rb_str_new2("0.1.2"));
2537
+ /* 0.1.4: The version of this library */
2538
+ rb_define_const(cSocket, "VERSION", rb_str_new2("0.1.4"));
2349
2539
 
2350
2540
  /* send flags */
2351
2541
 
data/sctp-socket.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = 'sctp-socket'
3
- spec.version = '0.1.2'
3
+ spec.version = '0.1.4'
4
4
  spec.author = 'Daniel Berger'
5
5
  spec.email = 'djberg96@gmail.com'
6
6
  spec.summary = 'Ruby bindings for SCTP sockets'
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,11 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sctp-socket
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Berger
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain:
11
11
  - |
@@ -35,7 +35,7 @@ cert_chain:
35
35
  ORVCZpRuCPpmC8qmqxUnARDArzucjaclkxjLWvCVHeFa9UP7K3Nl9oTjJNv+7/jM
36
36
  WZs4eecIcUc4tKdHxcAJ0MO/Dkqq7hGaiHpwKY76wQ1+8xAh
37
37
  -----END CERTIFICATE-----
38
- date: 2025-01-10 00:00:00.000000000 Z
38
+ date: 2025-02-01 00:00:00.000000000 Z
39
39
  dependencies:
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: bundler
@@ -133,7 +133,7 @@ metadata:
133
133
  wiki_uri: https://github.com/djberg96/sctp-socket/wiki
134
134
  rubygems_mfa_required: 'true'
135
135
  funding_uri: https://github.com/sponsors/djberg96
136
- post_install_message:
136
+ post_install_message:
137
137
  rdoc_options: []
138
138
  require_paths:
139
139
  - lib
@@ -149,7 +149,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
149
149
  version: '0'
150
150
  requirements: []
151
151
  rubygems_version: 3.5.22
152
- signing_key:
152
+ signing_key:
153
153
  specification_version: 4
154
154
  summary: Ruby bindings for SCTP sockets
155
155
  test_files: []
metadata.gz.sig CHANGED
Binary file