sctp-socket 0.0.4 → 0.0.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 30d42e64586703d527155f2fb7582e165ce6662fa3ddecec417b9905479454ca
4
- data.tar.gz: ad2fce717f7d4c42a83db6524e7323c92b1b1edf1b73058757e6689a638cc3ce
3
+ metadata.gz: 6a4c2e587ffc98a2c81d1d2a267fa4936539dc2456a9106a0146f31275e6db21
4
+ data.tar.gz: e5aa191fd3beb57240128ef58ef82df8f3b6beba3c25a5b357bc9b5effc7c238
5
5
  SHA512:
6
- metadata.gz: 94b319f18b44be59f7b5434ccbd9c4e2b4b1e948d9dfcf155c29c497e13059a6016a945aca04712b0b1afaa6801043450268533c758491ce118dc615d1209c4b
7
- data.tar.gz: f77fd5430cc646354117a27c3a5a2064b8af11cdc7019c7400286300065eea6b107b6b7bb7796408de0f5998661c652eb16b07460b54ef25defca5a231ffa731
6
+ metadata.gz: d023d5c17b03912812d02c8cb58279b5c874c45c481bdc1cd685dd89e8f2d62565512675d2cdc89f5e6b8107dce42634a3a1b4a063df8a6b32fed6762029adb4
7
+ data.tar.gz: 900e6fb83030d63453d99f9046942b2e6dfaee4340615d668669a922abc5628f58056aa464c9f36fe974ac0cccec4f3699fee7211778b6e49f49d856d7ea002d
checksums.yaml.gz.sig CHANGED
Binary file
@@ -0,0 +1,4 @@
1
+ # These are supported funding model platforms
2
+
3
+ github: djberg96
4
+ open_collective: daniel-berger
data/.gitignore CHANGED
@@ -3,3 +3,4 @@
3
3
  *.log
4
4
  *.lock
5
5
  Makefile
6
+ tmp/
data/CHANGES.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## 0.0.6 - 24-May-2024
2
+ * Fixup the sendv method and add some documentation.
3
+ * Added documentation to the get_status method.
4
+ * Update the example server and client code, including comments for how to
5
+ setup multiple dummy IP addresses locally for testing.
6
+ * Some warning cleanup and build improvements.
7
+ * Added SCTP_BINDX constants.
8
+ * Started adding some real specs.
9
+
10
+ ## 0.0.5 - 15-Dec-2021
11
+ * Add handling for Linux platforms that don't support the sctp_sendv function
12
+ and/or the SCTP_SEND_FAILED_EVENT notification.
13
+ * Some minor updates to Rakefile and Gemfile.
14
+
1
15
  ## 0.0.4 - 3-Dec-2020
2
16
  * Added the send method. Use this when you already have a connection.
3
17
  * Fixed a flags bug in the sendmsg method.
data/Gemfile CHANGED
@@ -1,10 +1,2 @@
1
- source 'https://rubygems.org' do
2
- group 'test' do
3
- gem 'rake'
4
- gem 'rspec', '~> 3.9'
5
- end
6
-
7
- group 'development' do
8
- gem 'rake-compiler', '~> 1.1'
9
- end
10
- end
1
+ source 'https://rubygems.org'
2
+ gemspec
data/README.md CHANGED
@@ -2,17 +2,19 @@
2
2
 
3
3
  A Ruby interface for SCTP sockets.
4
4
 
5
- WARNING: THIS IS CURRENTLY AN ALPHA PRODUCT. NOT RECOMMENDED FOR PRODUCTION USE AT THIS TIME.
6
-
7
5
  ## Prerequisites
8
6
 
9
7
  You will need the sctp development headers installed.
10
8
 
11
- On some systems, such as RHEL8, you may need to enable the sctp module.
9
+ On some systems, such as RHEL8 or later, you may need to enable the sctp module.
12
10
 
13
11
  ## Installation
14
12
 
15
- `gem install sctp-socket`
13
+ `gem install sctp-socket`
14
+
15
+ ## Installing the Trusted Cert
16
+
17
+ `gem cert --add <(curl -Ls https://raw.githubusercontent.com/djberg96/sctp-socket/main/certs/djberg96_pub.pem)`
16
18
 
17
19
  ## About SCTP
18
20
 
@@ -30,7 +32,7 @@ is applied to correct loss or corruption of data.
30
32
 
31
33
  ## Synopsis
32
34
 
33
- ```
35
+ ```ruby
34
36
  # sample_server.rb
35
37
  require 'sctp/socket'
36
38
 
@@ -62,17 +64,25 @@ end
62
64
  Currently this has only been developed and tested on Linux. Other platforms
63
65
  will probably only be supported via community contributions.
64
66
 
67
+ The sendv method is not available on some Linux variants. Use the sendmsg method instead.
68
+
65
69
  Please report any issues on the github project page.
66
70
 
67
71
  https://github.com/djberg96/sctp-socket
68
72
 
73
+ ## More Information on SCTP
74
+
75
+ * https://www.linuxjournal.com/article/9748
76
+ * https://www.linuxjournal.com/article/9749
77
+ * https://www.linuxjournal.com/article/9784
78
+
69
79
  ## License
70
80
 
71
81
  Apache-2.0
72
82
 
73
83
  ## Copyright
74
84
 
75
- (C) 2020, Daniel J. Berger
85
+ (C) 2020-2024, Daniel J. Berger
76
86
  Al Rights Reserved
77
87
 
78
88
  ## Author
data/Rakefile CHANGED
@@ -6,20 +6,21 @@ require 'rake/extensiontask'
6
6
  include RbConfig
7
7
 
8
8
  CLEAN.include(
9
- '**/*.gem', # Gem files
10
- '**/*.rbc', # Rubinius
11
- '**/*.o', # C object file
12
- '**/*.log', # Ruby extension build log
13
- '**/Makefile', # C Makefile
14
- '**/conftest.dSYM', # OS X build directory
15
- "**/*.#{CONFIG['DLEXT']}" # C shared object
9
+ '**/*.gem', # Gem files
10
+ '**/*.rbc', # Rubinius
11
+ '**/*.o', # C object file
12
+ '**/*.log', # Ruby extension build log
13
+ '**/Makefile', # C Makefile
14
+ '**/conftest.dSYM', # OS X build directory
15
+ "**/*.#{CONFIG['DLEXT']}", # C shared object
16
+ 'tmp' # Rake compiler
16
17
  )
17
18
 
18
19
  namespace :gem do
19
20
  desc "Create the sys-uname gem"
20
21
  task :create => [:clean] do
21
22
  require 'rubygems/package'
22
- spec = eval(IO.read('sctp-socket.gemspec'))
23
+ spec = Gem::Specification.load('sctp-socket.gemspec')
23
24
  spec.signing_key = File.join(Dir.home, '.ssh', 'gem-private_key.pem')
24
25
  Gem::Package.build(spec)
25
26
  end
@@ -39,4 +40,4 @@ end
39
40
  RSpec::Core::RakeTask.new
40
41
 
41
42
  task :spec => :compile
42
- task :default => :spec
43
+ task :default => [:clean, :spec]
@@ -1,11 +1,40 @@
1
1
  require 'socket'
2
2
  require 'sctp/socket'
3
3
 
4
+ # Adjust as needed. Server server_example.rb for creating
5
+ # fake network interfaces for testing.
6
+ addresses = ['1.1.1.1', '1.1.1.2']
7
+
4
8
  begin
5
9
  port = 62324
6
10
  socket = SCTP::Socket.new
7
- bytes_sent = socket.sendmsg(:message => "Hello World!", :addresses => ['127.0.0.1'], :port => port, :stream => 2)
8
- p bytes_sent
11
+
12
+ # Optional, but could bind to a subset of available addresses
13
+ p socket.bind(:addresses => addresses)
14
+
15
+ # Initial connection
16
+ p socket.connect(:addresses => addresses, :port => port)
17
+
18
+ # Try a sendv
19
+ p socket.sendv(:message => ["Hello ", "World!"])
20
+
21
+ # Send messages on separate streams of the same connection
22
+ arr = []
23
+
24
+ 0.upto(4) do |n|
25
+ arr << Thread.new do |t|
26
+ puts "Stream: #{n}"
27
+ bytes_sent = socket.sendmsg(
28
+ :message => "Hello World: #{n+1}",
29
+ :addresses => addresses.shuffle,
30
+ :stream => n,
31
+ :port => port
32
+ )
33
+ puts "Bytes Sent: #{bytes_sent}"
34
+ end
35
+ end
36
+
37
+ arr.map(&:join)
9
38
  ensure
10
39
  socket.close if socket
11
40
  end
@@ -1,11 +1,31 @@
1
1
  require 'sctp/socket'
2
2
 
3
+ # rake compile + ruby -Ilib to run local version
4
+ puts "VERSION: #{SCTP::Socket::VERSION}"
5
+
6
+ # To test multiple IP addresses locally:
7
+ #
8
+ # sudo apt install iproute2
9
+ # Add 'dummy' to /etc/modules
10
+ #
11
+ # sudo ip link add dummy1 type dummy
12
+ # sudo ip link add dummy2 type dummy
13
+ #
14
+ # sudo ip addr add 1.1.1.1/24 dev dummy1
15
+ # sudo ip addr add 1.1.1.2/24 dev dummy2
16
+ #
17
+ # sudo ip link set dummy1 up
18
+ # sudo ip link set dummy2 up
19
+
3
20
  # Adjust IP addresses as needed
21
+ addresses = ['1.1.1.1', '1.1.1.2']
22
+
4
23
  begin
5
24
  port = 62324
6
25
  socket = SCTP::Socket.new
7
- socket.bind(:port => port, :addresses => ['10.0.5.5', '10.0.6.5'])
26
+ socket.bind(:port => port, :addresses => addresses)
8
27
  socket.set_initmsg(:output_streams => 5, :input_streams => 5, :max_attempts => 4)
28
+ socket.subscribe(:data_io => true, :shutdown => true, :send_failure => true, :partial_delivery => true)
9
29
  socket.listen
10
30
 
11
31
  while true
data/ext/sctp/extconf.rb CHANGED
@@ -1,5 +1,30 @@
1
1
  require 'mkmf'
2
2
 
3
- have_header('netinet/sctp.h')
3
+ dir_config('sctp')
4
+
5
+ unless have_header('netinet/sctp.h')
6
+ os = IO.readlines('/etc/os-release').first.split('=').last
7
+ msg = "\nSCTP HEADERS NOT FOUND. PLEASE INSTALL THEM FIRST LIKE SO:\n\n"
8
+
9
+ if os =~ /red|fedora|centos/i
10
+ msg << "#####################################################################################\n"
11
+ msg << "# dnf install lksctp-tools #\n"
12
+ msg << "# dnf install kernel-modules-extra #\n"
13
+ msg << "# #\n"
14
+ msg << "# sed -e '/blacklist sctp/s/^b/#b/g' -i /etc/modprobe.d/sctp-blacklist.conf #\n"
15
+ msg << "# sed -e '/blacklist sctp/s/^b/#b/g' -i /etc/modprobe.d/sctp_diag-blacklist.conf #\n"
16
+ msg << "# #\n"
17
+ msg << "# sudo systemctl restart systemd-modules-load.service #\n"
18
+ msg << "#####################################################################################\n"
19
+ else
20
+ msg << "sudo apt-get install libsctp-dev lksctp-tools\n\n"
21
+ end
22
+
23
+ warn msg
24
+ exit
25
+ end
26
+
4
27
  have_library('sctp')
28
+ have_func('sctp_sendv', 'netinet/sctp.h')
29
+ have_struct_member('struct sctp_event_subscribe', 'sctp_send_failure_event', 'netinet/sctp.h')
5
30
  create_makefile('sctp/socket')
data/ext/sctp/socket.c CHANGED
@@ -17,11 +17,27 @@ VALUE v_adaptation_event_struct;
17
17
  VALUE v_partial_delivery_event_struct;
18
18
  VALUE v_auth_event_struct;
19
19
  VALUE v_sockaddr_in_struct;
20
-
20
+ VALUE v_sctp_status_struct;
21
+ VALUE v_sctp_rtoinfo_struct;
22
+ VALUE v_sctp_associnfo_struct;
23
+ VALUE v_sctp_default_send_params_struct;
24
+
25
+ #if !defined(IOV_MAX)
26
+ #if defined(_SC_IOV_MAX)
27
+ #define IOV_MAX (sysconf(_SC_IOV_MAX))
28
+ #else
29
+ #define IOV_MAX INT_MAX
30
+ #endif
31
+ #endif
32
+
33
+ // TODO: Yes, I know I need to update the signature.
21
34
  VALUE convert_sockaddr_in_to_struct(struct sockaddr_in* addr){
22
- char ipbuf[16];
35
+ char ipbuf[INET6_ADDRSTRLEN];
23
36
 
24
- inet_ntop(addr->sin_family, &(((struct sockaddr_in *)addr)->sin_addr), ipbuf, sizeof(ipbuf));
37
+ if(addr->sin_family == AF_INET6)
38
+ inet_ntop(addr->sin_family, &(((struct sockaddr_in6 *)addr)->sin6_addr), ipbuf, sizeof(ipbuf));
39
+ else
40
+ inet_ntop(addr->sin_family, &(((struct sockaddr_in *)addr)->sin_addr), ipbuf, sizeof(ipbuf));
25
41
 
26
42
  return rb_struct_new(v_sockaddr_in_struct,
27
43
  INT2NUM(addr->sin_family),
@@ -169,6 +185,8 @@ static VALUE rsctp_bind(int argc, VALUE* argv, VALUE self){
169
185
  port = sin.sin_port;
170
186
  }
171
187
 
188
+ rb_iv_set(self, "@port", INT2NUM(port));
189
+
172
190
  return INT2NUM(port);
173
191
  }
174
192
 
@@ -316,6 +334,114 @@ static VALUE rsctp_getlocalnames(VALUE self){
316
334
  return v_array;
317
335
  }
318
336
 
337
+ #ifdef HAVE_SCTP_SENDV
338
+ /*
339
+ * Transmit a message to an SCTP endpoint using a gather-write. The following
340
+ * hash of options is permitted:
341
+ *
342
+ * * message - An array of strings that will be joined into a single message.
343
+ * * addresses - An array of IP addresses to setup an association to send the message.
344
+ * * info_type - The type of information provided. The default is SCTP_SENDV_SNDINFO.
345
+ *
346
+ * Example:
347
+ *
348
+ * socket = SCTP::Socket.new
349
+ *
350
+ * socket.sendv
351
+ * :message => ['Hello ', 'World.'],
352
+ * :addresses => ['10.0.5.4', '10.0.6.4'],
353
+ * :info_type => SCTP::Socket:::SCTP_SENDV_SNDINFO
354
+ * )
355
+ *
356
+ * CAVEAT: Currently addresses does not work, and info_type is not yet supported.
357
+ *
358
+ * Returns the number of bytes sent.
359
+ */
360
+ static VALUE rsctp_sendv(VALUE self, VALUE v_options){
361
+ VALUE v_msg, v_message, v_addresses;
362
+ struct iovec iov[IOV_MAX];
363
+ struct sockaddr_in* addrs;
364
+ struct sctp_sndinfo info;
365
+ int i, sock_fd, num_bytes, size, num_ip;
366
+
367
+ Check_Type(v_options, T_HASH);
368
+
369
+ bzero(&iov, sizeof(iov));
370
+ bzero(&info, sizeof(info));
371
+
372
+ v_message = rb_hash_aref2(v_options, "message");
373
+ v_addresses = rb_hash_aref2(v_options, "addresses");
374
+
375
+ if(!NIL_P(v_message))
376
+ Check_Type(v_message, T_ARRAY);
377
+
378
+ if(!NIL_P(v_addresses)){
379
+ Check_Type(v_addresses, T_ARRAY);
380
+ num_ip = RARRAY_LEN(v_addresses);
381
+ addrs = (struct sockaddr_in*)alloca(sizeof(struct sockaddr_in) * num_ip);
382
+ }
383
+ else{
384
+ addrs = NULL;
385
+ num_ip = 0;
386
+ }
387
+
388
+ sock_fd = NUM2INT(rb_iv_get(self, "@sock_fd"));
389
+ size = RARRAY_LEN(v_message);
390
+
391
+ if(!size)
392
+ rb_raise(rb_eArgError, "Must contain at least one message");
393
+
394
+ if(size > IOV_MAX)
395
+ rb_raise(rb_eArgError, "Array size is greater than IOV_MAX");
396
+
397
+ info.snd_flags = SCTP_UNORDERED;
398
+ info.snd_assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
399
+
400
+ if(!NIL_P(v_addresses)){
401
+ int i, port;
402
+ VALUE v_address, v_port;
403
+
404
+ v_port = NUM2INT(rb_iv_get(self, "@port"));
405
+
406
+ if(NIL_P(v_port))
407
+ port = 0;
408
+ else
409
+ port = NUM2INT(v_port);
410
+
411
+ for(i = 0; i < num_ip; i++){
412
+ v_address = RARRAY_PTR(v_addresses)[i];
413
+ addrs->sin_family = NUM2INT(rb_iv_get(self, "@domain"));
414
+ addrs->sin_port = htons(port);
415
+ addrs->sin_addr.s_addr = inet_addr(StringValueCStr(v_address));
416
+ addrs += sizeof(struct sockaddr_in);
417
+ }
418
+ }
419
+
420
+ for(i = 0; i < size; i++){
421
+ v_msg = RARRAY_PTR(v_message)[i];
422
+ iov[i].iov_base = StringValueCStr(v_msg);
423
+ iov[i].iov_len = RSTRING_LEN(v_msg);
424
+ }
425
+
426
+ num_bytes = sctp_sendv(
427
+ sock_fd,
428
+ iov,
429
+ size,
430
+ (struct sockaddr*)addrs,
431
+ num_ip,
432
+ &info,
433
+ sizeof(info),
434
+ SCTP_SENDV_SNDINFO,
435
+ 0
436
+ );
437
+
438
+ if(num_bytes < 0)
439
+ rb_raise(rb_eSystemCallError, "sctp_sendv: %s", strerror(errno));
440
+
441
+ return INT2NUM(num_bytes);
442
+ }
443
+ #endif
444
+
319
445
  /*
320
446
  * Send a message on an already-connected socket to a specific association.
321
447
  *
@@ -413,14 +539,14 @@ static VALUE rsctp_send(VALUE self, VALUE v_options){
413
539
  * Transmit a message to an SCTP endpoint. The following hash of options
414
540
  * is permitted:
415
541
  *
416
- * :message -> The message to send to the endpoint. Mandatory.
417
- * :stream -> The SCTP stream number you wish to send the message on.
418
- * :to -> An array of addresses to send the message to.
419
- * :context -> The default context used for the sendmsg call if the send fails.
420
- * :ppid -> The payload protocol identifier that is passed to the peer endpoint.
421
- * :flags -> A bitwise integer that contain one or more values that control behavior.
542
+ * :message -> The message to send to the endpoint. Mandatory.
543
+ * :stream -> The SCTP stream number you wish to send the message on.
544
+ * :addresses -> An array of addresses to send the message to.
545
+ * :context -> The default context used for the sendmsg call if the send fails.
546
+ * :ppid -> The payload protocol identifier that is passed to the peer endpoint.
547
+ * :flags -> A bitwise integer that contain one or more values that control behavior.
422
548
  *
423
- * Note that the :to option is not mandatory in a one-to-one (SOCK_STREAM)
549
+ * Note that the :addresses option is not mandatory in a one-to-one (SOCK_STREAM)
424
550
  * socket connection. However, it must have been set previously via the
425
551
  * connect method.
426
552
  *
@@ -429,12 +555,14 @@ static VALUE rsctp_send(VALUE self, VALUE v_options){
429
555
  * socket = SCTP::Socket.new
430
556
  *
431
557
  * socket.sendmsg(
432
- * :message => "Hello World!",
433
- * :stream => 3,
434
- * :flags => SCTP::Socket::SCTP_UNORDERED | SCTP::Socket::SCTP_SENDALL,
435
- * :ttl => 100,
436
- * :to => ['10.0.5.4', '10.0.6.4']
558
+ * :message => "Hello World!",
559
+ * :stream => 3,
560
+ * :flags => SCTP::Socket::SCTP_UNORDERED | SCTP::Socket::SCTP_SENDALL,
561
+ * :ttl => 100,
562
+ * :addresses => ['10.0.5.4', '10.0.6.4']
437
563
  * )
564
+ *
565
+ * Returns the number of bytes sent.
438
566
  */
439
567
  static VALUE rsctp_sendmsg(VALUE self, VALUE v_options){
440
568
  VALUE v_msg, v_ppid, v_flags, v_stream, v_ttl, v_context, v_addresses;
@@ -566,7 +694,10 @@ static VALUE rsctp_recvmsg(int argc, VALUE* argv, VALUE self){
566
694
 
567
695
  sock_fd = NUM2INT(rb_iv_get(self, "@sock_fd"));
568
696
  length = sizeof(struct sockaddr_in);
697
+
569
698
  bzero(buffer, sizeof(buffer));
699
+ bzero(&clientaddr, sizeof(clientaddr));
700
+ bzero(&sndrcvinfo, sizeof(sndrcvinfo));
570
701
 
571
702
  bytes = sctp_recvmsg(
572
703
  sock_fd,
@@ -678,6 +809,7 @@ static VALUE rsctp_recvmsg(int argc, VALUE* argv, VALUE self){
678
809
  rb_ary_new4(snp->sn_remote_error.sre_length, v_temp)
679
810
  );
680
811
  break;
812
+ #ifdef SCTP_SEND_FAILED_EVENT
681
813
  case SCTP_SEND_FAILED_EVENT:
682
814
  v_temp = ALLOCA_N(VALUE, snp->sn_send_failed_event.ssf_length);
683
815
 
@@ -700,6 +832,24 @@ static VALUE rsctp_recvmsg(int argc, VALUE* argv, VALUE self){
700
832
  rb_ary_new4(snp->sn_send_failed_event.ssf_length, v_temp)
701
833
  );
702
834
  break;
835
+ #else
836
+ case SCTP_SEND_FAILED:
837
+ v_temp = ALLOCA_N(VALUE, snp->sn_send_failed.ssf_length);
838
+
839
+ for(i = 0; i < snp->sn_send_failed.ssf_length; i++){
840
+ v_temp[i] = UINT2NUM(snp->sn_send_failed.ssf_data[i]);
841
+ }
842
+
843
+ v_notification = rb_struct_new(v_send_failed_event_struct,
844
+ UINT2NUM(snp->sn_send_failed.ssf_type),
845
+ UINT2NUM(snp->sn_send_failed.ssf_length),
846
+ UINT2NUM(snp->sn_send_failed.ssf_error),
847
+ Qnil,
848
+ UINT2NUM(snp->sn_send_failed.ssf_assoc_id),
849
+ rb_ary_new4(snp->sn_send_failed.ssf_length, v_temp)
850
+ );
851
+ break;
852
+ #endif
703
853
  case SCTP_SHUTDOWN_EVENT:
704
854
  v_notification = rb_struct_new(v_shutdown_event_struct,
705
855
  UINT2NUM(snp->sn_shutdown_event.sse_type),
@@ -822,7 +972,7 @@ static VALUE rsctp_set_initmsg(VALUE self, VALUE v_options){
822
972
  * - The peer has sent a shutdown to the local endpoint.
823
973
  *
824
974
  * :data_io
825
- * - Message data was received. On by default.
975
+ * - Message data was received. You will want to subscribe to this in most cases.
826
976
  *
827
977
  * Others:
828
978
  *
@@ -835,14 +985,12 @@ static VALUE rsctp_set_initmsg(VALUE self, VALUE v_options){
835
985
  * :sender_dry
836
986
  * :peer_error
837
987
  *
838
- * By default only data_io is subscribed to.
839
- *
840
988
  * Example:
841
989
  *
842
990
  * socket = SCTP::Socket.new
843
991
  *
844
992
  * socket.bind(:port => port, :addresses => ['127.0.0.1'])
845
- * socket.subscribe(:shutdown => true, :send_failure => true)
993
+ * socket.subscribe(:data_io => true, :shutdown => true, :send_failure => true)
846
994
  */
847
995
  static VALUE rsctp_subscribe(VALUE self, VALUE v_options){
848
996
  int sock_fd;
@@ -860,9 +1008,12 @@ static VALUE rsctp_subscribe(VALUE self, VALUE v_options){
860
1008
  if(RTEST(rb_hash_aref2(v_options, "address")))
861
1009
  events.sctp_address_event = 1;
862
1010
 
863
- // Use the new version
864
1011
  if(RTEST(rb_hash_aref2(v_options, "send_failure")))
1012
+ #ifdef HAVE_STRUCT_SCTP_EVENT_SUBSCRIBE_SCTP_SEND_FAILURE_EVENT
1013
+ events.sctp_send_failure_event = 1;
1014
+ #else
865
1015
  events.sctp_send_failure_event_event = 1;
1016
+ #endif
866
1017
 
867
1018
  if(RTEST(rb_hash_aref2(v_options, "peer_error")))
868
1019
  events.sctp_peer_error_event = 1;
@@ -916,7 +1067,7 @@ static VALUE rsctp_listen(int argc, VALUE* argv, VALUE self){
916
1067
  sock_fd = NUM2INT(rb_iv_get(self, "@sock_fd"));
917
1068
 
918
1069
  if(listen(sock_fd, backlog) < 0)
919
- rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
1070
+ rb_raise(rb_eSystemCallError, "listen: %s", strerror(errno));
920
1071
 
921
1072
  return self;
922
1073
  }
@@ -942,6 +1093,61 @@ static VALUE rsctp_peeloff(VALUE self, VALUE v_assoc_id){
942
1093
  return self;
943
1094
  }
944
1095
 
1096
+ static VALUE rsctp_get_default_send_params(VALUE self){
1097
+ int sock_fd;
1098
+ socklen_t size;
1099
+ sctp_assoc_t assoc_id;
1100
+ struct sctp_sndrcvinfo sndrcv;
1101
+
1102
+ bzero(&sndrcv, sizeof(sndrcv));
1103
+
1104
+ sock_fd = NUM2INT(rb_iv_get(self, "@sock_fd"));
1105
+ assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
1106
+ size = sizeof(struct sctp_sndrcvinfo);
1107
+
1108
+ if(sctp_opt_info(sock_fd, assoc_id, SCTP_DEFAULT_SEND_PARAM, (void*)&sndrcv, &size) < 0)
1109
+ rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
1110
+
1111
+ return rb_struct_new(
1112
+ v_sctp_default_send_params_struct,
1113
+ INT2NUM(sndrcv.sinfo_stream),
1114
+ INT2NUM(sndrcv.sinfo_ssn),
1115
+ INT2NUM(sndrcv.sinfo_flags),
1116
+ INT2NUM(sndrcv.sinfo_ppid),
1117
+ INT2NUM(sndrcv.sinfo_context),
1118
+ INT2NUM(sndrcv.sinfo_timetolive),
1119
+ INT2NUM(sndrcv.sinfo_tsn),
1120
+ INT2NUM(sndrcv.sinfo_cumtsn),
1121
+ INT2NUM(sndrcv.sinfo_assoc_id)
1122
+ );
1123
+ }
1124
+
1125
+ static VALUE rsctp_get_association_info(VALUE self){
1126
+ int sock_fd;
1127
+ socklen_t size;
1128
+ sctp_assoc_t assoc_id;
1129
+ struct sctp_assocparams assoc;
1130
+
1131
+ bzero(&assoc, sizeof(assoc));
1132
+
1133
+ sock_fd = NUM2INT(rb_iv_get(self, "@sock_fd"));
1134
+ assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
1135
+ size = sizeof(struct sctp_assocparams);
1136
+
1137
+ if(sctp_opt_info(sock_fd, assoc_id, SCTP_ASSOCINFO, (void*)&assoc, &size) < 0)
1138
+ rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
1139
+
1140
+ return rb_struct_new(
1141
+ v_sctp_associnfo_struct,
1142
+ INT2NUM(assoc.sasoc_assoc_id),
1143
+ INT2NUM(assoc.sasoc_asocmaxrxt),
1144
+ INT2NUM(assoc.sasoc_number_peer_destinations),
1145
+ INT2NUM(assoc.sasoc_peer_rwnd),
1146
+ INT2NUM(assoc.sasoc_local_rwnd),
1147
+ INT2NUM(assoc.sasoc_cookie_life)
1148
+ );
1149
+ }
1150
+
945
1151
  static VALUE rsctp_shutdown(int argc, VALUE* argv, VALUE self){
946
1152
  int how, sock_fd;
947
1153
  VALUE v_how;
@@ -964,7 +1170,95 @@ static VALUE rsctp_shutdown(int argc, VALUE* argv, VALUE self){
964
1170
  return self;
965
1171
  }
966
1172
 
967
- void Init_socket(){
1173
+ static VALUE rsctp_get_retransmission_info(VALUE self){
1174
+ int sock_fd;
1175
+ socklen_t size;
1176
+ sctp_assoc_t assoc_id;
1177
+ struct sctp_rtoinfo rto;
1178
+
1179
+ bzero(&rto, sizeof(rto));
1180
+
1181
+ sock_fd = NUM2INT(rb_iv_get(self, "@sock_fd"));
1182
+ assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
1183
+ size = sizeof(struct sctp_rtoinfo);
1184
+
1185
+ if(sctp_opt_info(sock_fd, assoc_id, SCTP_RTOINFO, (void*)&rto, &size) < 0)
1186
+ rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
1187
+
1188
+ return rb_struct_new(
1189
+ v_sctp_rtoinfo_struct,
1190
+ INT2NUM(rto.srto_assoc_id),
1191
+ INT2NUM(rto.srto_initial),
1192
+ INT2NUM(rto.srto_max),
1193
+ INT2NUM(rto.srto_min)
1194
+ );
1195
+ }
1196
+
1197
+ /*
1198
+ * Get the status of a connected socket.
1199
+ *
1200
+ * Example:
1201
+ *
1202
+ * socket = SCTP::Socket.new
1203
+ * socket.connect(...)
1204
+ * socket.get_status
1205
+ *
1206
+ * Returns a Struct::Status object, which contains the following fields:
1207
+ *
1208
+ * * association_id
1209
+ * * state
1210
+ * * receive_window
1211
+ * * unacknowledged_data
1212
+ * * pending_data
1213
+ * * inbound_streams
1214
+ * * outbound_streams
1215
+ * * fragmentation_point
1216
+ * * primary (IP)
1217
+ */
1218
+ static VALUE rsctp_get_status(VALUE self){
1219
+ int sock_fd;
1220
+ socklen_t size;
1221
+ sctp_assoc_t assoc_id;
1222
+ struct sctp_status status;
1223
+ struct sctp_paddrinfo* spinfo;
1224
+ char tmpname[INET_ADDRSTRLEN];
1225
+
1226
+ bzero(&status, sizeof(status));
1227
+
1228
+ sock_fd = NUM2INT(rb_iv_get(self, "@sock_fd"));
1229
+ assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
1230
+ size = sizeof(struct sctp_status);
1231
+
1232
+ if(sctp_opt_info(sock_fd, assoc_id, SCTP_STATUS, (void*)&status, &size) < 0)
1233
+ rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
1234
+
1235
+ spinfo = &status.sstat_primary;
1236
+
1237
+ if (spinfo->spinfo_address.ss_family == AF_INET6) {
1238
+ struct sockaddr_in6 *sin6;
1239
+ sin6 = (struct sockaddr_in6 *)&spinfo->spinfo_address;
1240
+ inet_ntop(AF_INET6, &sin6->sin6_addr, tmpname, sizeof (tmpname));
1241
+ }
1242
+ else {
1243
+ struct sockaddr_in *sin;
1244
+ sin = (struct sockaddr_in *)&spinfo->spinfo_address;
1245
+ inet_ntop(AF_INET, &sin->sin_addr, tmpname, sizeof (tmpname));
1246
+ }
1247
+
1248
+ return rb_struct_new(v_sctp_status_struct,
1249
+ INT2NUM(status.sstat_assoc_id),
1250
+ INT2NUM(status.sstat_state),
1251
+ INT2NUM(status.sstat_rwnd),
1252
+ INT2NUM(status.sstat_unackdata),
1253
+ INT2NUM(status.sstat_penddata),
1254
+ INT2NUM(status.sstat_instrms),
1255
+ INT2NUM(status.sstat_outstrms),
1256
+ INT2NUM(status.sstat_fragmentation_point),
1257
+ rb_str_new2(tmpname)
1258
+ );
1259
+ }
1260
+
1261
+ void Init_socket(void){
968
1262
  mSCTP = rb_define_module("SCTP");
969
1263
  cSocket = rb_define_class_under(mSCTP, "Socket", rb_cObject);
970
1264
 
@@ -1016,6 +1310,26 @@ void Init_socket(){
1016
1310
  "SockAddrIn", "family", "port", "address", NULL
1017
1311
  );
1018
1312
 
1313
+ v_sctp_status_struct = rb_struct_define(
1314
+ "Status", "association_id", "state", "receive_window", "unacknowledged_data",
1315
+ "pending_data", "inbound_streams", "outbound_streams", "fragmentation_point", "primary", NULL
1316
+ );
1317
+
1318
+ v_sctp_rtoinfo_struct = rb_struct_define(
1319
+ "RetransmissionInfo", "association_id", "initial", "max", "min", NULL
1320
+ );
1321
+
1322
+ v_sctp_associnfo_struct = rb_struct_define(
1323
+ "AssociationInfo", "association_id", "max_retransmission_count",
1324
+ "number_peer_destinations", "peer_receive_window", "local_receive_window",
1325
+ "cookie_life", NULL
1326
+ );
1327
+
1328
+ v_sctp_default_send_params_struct = rb_struct_define(
1329
+ "DefaultSendParams", "stream", "ssn", "flags", "ppid", "context",
1330
+ "ttl", "tsn", "cumtsn", "association_id", NULL
1331
+ );
1332
+
1019
1333
  rb_define_method(cSocket, "initialize", rsctp_init, -1);
1020
1334
 
1021
1335
  rb_define_method(cSocket, "bind", rsctp_bind, -1);
@@ -1023,10 +1337,19 @@ void Init_socket(){
1023
1337
  rb_define_method(cSocket, "connect", rsctp_connect, -1);
1024
1338
  rb_define_method(cSocket, "getpeernames", rsctp_getpeernames, 0);
1025
1339
  rb_define_method(cSocket, "getlocalnames", rsctp_getlocalnames, 0);
1340
+ rb_define_method(cSocket, "get_status", rsctp_get_status, 0);
1341
+ rb_define_method(cSocket, "get_default_send_params", rsctp_get_default_send_params, 0);
1342
+ rb_define_method(cSocket, "get_retransmission_info", rsctp_get_retransmission_info, 0);
1343
+ rb_define_method(cSocket, "get_association_info", rsctp_get_association_info, 0);
1026
1344
  rb_define_method(cSocket, "listen", rsctp_listen, -1);
1027
1345
  rb_define_method(cSocket, "peeloff!", rsctp_peeloff, 1);
1028
1346
  rb_define_method(cSocket, "recvmsg", rsctp_recvmsg, -1);
1029
1347
  rb_define_method(cSocket, "send", rsctp_send, 1);
1348
+
1349
+ #ifdef HAVE_SCTP_SENDV
1350
+ rb_define_method(cSocket, "sendv", rsctp_sendv, 1);
1351
+ #endif
1352
+
1030
1353
  rb_define_method(cSocket, "sendmsg", rsctp_sendmsg, 1);
1031
1354
  rb_define_method(cSocket, "set_initmsg", rsctp_set_initmsg, 1);
1032
1355
  rb_define_method(cSocket, "shutdown", rsctp_shutdown, -1);
@@ -1038,8 +1361,8 @@ void Init_socket(){
1038
1361
  rb_define_attr(cSocket, "association_id", 1, 1);
1039
1362
  rb_define_attr(cSocket, "port", 1, 1);
1040
1363
 
1041
- /* 0.0.4: The version of this library */
1042
- rb_define_const(cSocket, "VERSION", rb_str_new2("0.0.4"));
1364
+ /* 0.0.6: The version of this library */
1365
+ rb_define_const(cSocket, "VERSION", rb_str_new2("0.0.6"));
1043
1366
 
1044
1367
  /* send flags */
1045
1368
 
@@ -1059,4 +1382,21 @@ void Init_socket(){
1059
1382
  rb_define_const(cSocket, "SCTP_SENDALL", INT2NUM(SCTP_SENDALL));
1060
1383
 
1061
1384
  rb_define_const(cSocket, "MSG_NOTIFICATION", INT2NUM(MSG_NOTIFICATION));
1385
+
1386
+ // ASSOCIATION STATES //
1387
+
1388
+ rb_define_const(cSocket, "SCTP_EMPTY", INT2NUM(SCTP_EMPTY));
1389
+ rb_define_const(cSocket, "SCTP_CLOSED", INT2NUM(SCTP_CLOSED));
1390
+ rb_define_const(cSocket, "SCTP_COOKIE_WAIT", INT2NUM(SCTP_COOKIE_WAIT));
1391
+ rb_define_const(cSocket, "SCTP_COOKIE_ECHOED", INT2NUM(SCTP_COOKIE_ECHOED));
1392
+ rb_define_const(cSocket, "SCTP_ESTABLISHED", INT2NUM(SCTP_ESTABLISHED));
1393
+ rb_define_const(cSocket, "SCTP_SHUTDOWN_PENDING", INT2NUM(SCTP_SHUTDOWN_PENDING));
1394
+ rb_define_const(cSocket, "SCTP_SHUTDOWN_SENT", INT2NUM(SCTP_SHUTDOWN_SENT));
1395
+ rb_define_const(cSocket, "SCTP_SHUTDOWN_RECEIVED", INT2NUM(SCTP_SHUTDOWN_RECEIVED));
1396
+ rb_define_const(cSocket, "SCTP_SHUTDOWN_ACK_SENT", INT2NUM(SCTP_SHUTDOWN_ACK_SENT));
1397
+
1398
+ // BINDING //
1399
+
1400
+ rb_define_const(cSocket, "SCTP_BINDX_ADD_ADDR", INT2NUM(SCTP_BINDX_ADD_ADDR));
1401
+ rb_define_const(cSocket, "SCTP_BINDX_REM_ADDR", INT2NUM(SCTP_BINDX_REM_ADDR));
1062
1402
  }
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.0.4'
3
+ spec.version = '0.0.6'
4
4
  spec.author = 'Daniel Berger'
5
5
  spec.email = 'djberg96@gmail.com'
6
6
  spec.summary = 'Ruby bindings for SCTP sockets'
@@ -19,6 +19,16 @@ Gem::Specification.new do |spec|
19
19
  spec.add_development_dependency 'rake-compiler', '~> 1.1'
20
20
  spec.add_development_dependency 'rspec', '~> 3.9'
21
21
 
22
+ spec.metadata = {
23
+ 'homepage_uri' => 'https://github.com/djberg96/sctp-socket',
24
+ 'bug_tracker_uri' => 'https://github.com/djberg96/sctp-socket/issues',
25
+ 'changelog_uri' => 'https://github.com/djberg96/sctp-socket/blob/main/CHANGES.md',
26
+ 'documentation_uri' => 'https://github.com/djberg96/sctp-socket/wiki',
27
+ 'source_code_uri' => 'https://github.com/djberg96/sctp-socket',
28
+ 'wiki_uri' => 'https://github.com/djberg96/sctp-socket/wiki',
29
+ 'rubygems_mfa_required' => 'true'
30
+ }
31
+
22
32
  spec.description = <<-EOF
23
33
  The sctp-socket library provides Ruby bindings for SCTP sockets. is a
24
34
  message oriented, reliable transport protocol with direct support for
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
4
+ version: 0.0.6
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: 2020-12-03 00:00:00.000000000 Z
38
+ date: 2024-05-25 00:00:00.000000000 Z
39
39
  dependencies:
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: bundler
@@ -103,6 +103,7 @@ extensions:
103
103
  - ext/sctp/extconf.rb
104
104
  extra_rdoc_files: []
105
105
  files:
106
+ - ".github/FUNDING.yml"
106
107
  - ".gitignore"
107
108
  - CHANGES.md
108
109
  - Gemfile
@@ -122,7 +123,14 @@ files:
122
123
  homepage: https://github.com/djberg96/sctp-socket
123
124
  licenses:
124
125
  - Apache-2.0
125
- metadata: {}
126
+ metadata:
127
+ homepage_uri: https://github.com/djberg96/sctp-socket
128
+ bug_tracker_uri: https://github.com/djberg96/sctp-socket/issues
129
+ changelog_uri: https://github.com/djberg96/sctp-socket/blob/main/CHANGES.md
130
+ documentation_uri: https://github.com/djberg96/sctp-socket/wiki
131
+ source_code_uri: https://github.com/djberg96/sctp-socket
132
+ wiki_uri: https://github.com/djberg96/sctp-socket/wiki
133
+ rubygems_mfa_required: 'true'
126
134
  post_install_message:
127
135
  rdoc_options: []
128
136
  require_paths:
@@ -138,7 +146,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
138
146
  - !ruby/object:Gem::Version
139
147
  version: '0'
140
148
  requirements: []
141
- rubygems_version: 3.0.6
149
+ rubygems_version: 3.4.19
142
150
  signing_key:
143
151
  specification_version: 4
144
152
  summary: Ruby bindings for SCTP sockets
metadata.gz.sig CHANGED
Binary file