sctp-socket 0.0.4 → 0.0.6

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: 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