sctp-socket 0.0.7 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/ext/sctp/socket.c CHANGED
@@ -23,6 +23,9 @@ VALUE v_sctp_associnfo_struct;
23
23
  VALUE v_sctp_default_send_params_struct;
24
24
  VALUE v_sctp_event_subscribe_struct;
25
25
  VALUE v_sctp_receive_info_struct;
26
+ VALUE v_sctp_peer_addr_params_struct;
27
+ VALUE v_sender_dry_event_struct;
28
+ VALUE v_sctp_initmsg_struct;
26
29
 
27
30
  #if !defined(IOV_MAX)
28
31
  #if defined(_SC_IOV_MAX)
@@ -61,7 +64,195 @@ VALUE rb_hash_aref2(VALUE v_hash, const char* key){
61
64
  return v_val;
62
65
  }
63
66
 
67
+ VALUE get_notification_info(char* buffer){
68
+ uint32_t i;
69
+ char str[16];
70
+ union sctp_notification* snp;
71
+ VALUE v_notification = Qnil;
72
+ VALUE v_str = Qnil;
73
+ VALUE* v_temp;
74
+
75
+ snp = (union sctp_notification*)buffer;
76
+
77
+ switch(snp->sn_header.sn_type){
78
+ case SCTP_ASSOC_CHANGE:
79
+ switch(snp->sn_assoc_change.sac_state){
80
+ case SCTP_COMM_LOST:
81
+ v_str = rb_str_new2("comm lost");
82
+ break;
83
+ case SCTP_COMM_UP:
84
+ v_str = rb_str_new2("comm up");
85
+ break;
86
+ case SCTP_RESTART:
87
+ v_str = rb_str_new2("restart");
88
+ break;
89
+ case SCTP_SHUTDOWN_COMP:
90
+ v_str = rb_str_new2("shutdown complete");
91
+ break;
92
+ case SCTP_CANT_STR_ASSOC:
93
+ v_str = rb_str_new2("association setup failed");
94
+ break;
95
+ default:
96
+ v_str = rb_str_new2("unknown");
97
+ }
98
+
99
+ v_notification = rb_struct_new(v_assoc_change_struct,
100
+ UINT2NUM(snp->sn_assoc_change.sac_type),
101
+ UINT2NUM(snp->sn_assoc_change.sac_length),
102
+ UINT2NUM(snp->sn_assoc_change.sac_state),
103
+ UINT2NUM(snp->sn_assoc_change.sac_error),
104
+ UINT2NUM(snp->sn_assoc_change.sac_outbound_streams),
105
+ UINT2NUM(snp->sn_assoc_change.sac_inbound_streams),
106
+ UINT2NUM(snp->sn_assoc_change.sac_assoc_id),
107
+ v_str
108
+ );
109
+ break;
110
+ case SCTP_PEER_ADDR_CHANGE:
111
+ switch(snp->sn_paddr_change.spc_state){
112
+ case SCTP_ADDR_AVAILABLE:
113
+ v_str = rb_str_new2("available");
114
+ break;
115
+ case SCTP_ADDR_UNREACHABLE:
116
+ v_str = rb_str_new2("unreachable");
117
+ break;
118
+ case SCTP_ADDR_REMOVED:
119
+ v_str = rb_str_new2("removed from association");
120
+ break;
121
+ case SCTP_ADDR_ADDED:
122
+ v_str = rb_str_new2("added to association");
123
+ break;
124
+ case SCTP_ADDR_MADE_PRIM:
125
+ v_str = rb_str_new2("primary destination");
126
+ break;
127
+ default:
128
+ v_str = rb_str_new2("unknown");
129
+ }
130
+
131
+ inet_ntop(
132
+ ((struct sockaddr_in *)&snp->sn_paddr_change.spc_aaddr)->sin_family,
133
+ &(((struct sockaddr_in *)&snp->sn_paddr_change.spc_aaddr)->sin_addr),
134
+ str,
135
+ sizeof(str)
136
+ );
137
+
138
+ v_notification = rb_struct_new(v_peeraddr_change_struct,
139
+ UINT2NUM(snp->sn_paddr_change.spc_type),
140
+ UINT2NUM(snp->sn_paddr_change.spc_length),
141
+ rb_str_new2(str),
142
+ UINT2NUM(snp->sn_paddr_change.spc_state),
143
+ UINT2NUM(snp->sn_paddr_change.spc_error),
144
+ UINT2NUM(snp->sn_paddr_change.spc_assoc_id),
145
+ v_str
146
+ );
147
+ break;
148
+ case SCTP_REMOTE_ERROR:
149
+ v_temp = ALLOCA_N(VALUE, snp->sn_remote_error.sre_length);
150
+
151
+ for(i = 0; i < snp->sn_remote_error.sre_length; i++){
152
+ v_temp[i] = UINT2NUM(snp->sn_remote_error.sre_data[i]);
153
+ }
154
+
155
+ v_notification = rb_struct_new(v_remote_error_struct,
156
+ UINT2NUM(snp->sn_remote_error.sre_type),
157
+ UINT2NUM(snp->sn_remote_error.sre_flags),
158
+ UINT2NUM(snp->sn_remote_error.sre_length),
159
+ UINT2NUM(snp->sn_remote_error.sre_error),
160
+ UINT2NUM(snp->sn_remote_error.sre_assoc_id),
161
+ rb_ary_new4(snp->sn_remote_error.sre_length, v_temp)
162
+ );
163
+ break;
164
+ #ifdef SCTP_SEND_FAILED_EVENT
165
+ case SCTP_SEND_FAILED_EVENT:
166
+ v_temp = ALLOCA_N(VALUE, snp->sn_send_failed_event.ssf_length);
167
+
168
+ for(i = 0; i < snp->sn_send_failed_event.ssf_length; i++){
169
+ v_temp[i] = UINT2NUM(snp->sn_send_failed_event.ssf_data[i]);
170
+ }
171
+
172
+ v_notification = rb_struct_new(v_send_failed_event_struct,
173
+ UINT2NUM(snp->sn_send_failed_event.ssf_type),
174
+ UINT2NUM(snp->sn_send_failed_event.ssf_length),
175
+ UINT2NUM(snp->sn_send_failed_event.ssf_error),
176
+ rb_struct_new(v_sndinfo_struct,
177
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_sid),
178
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_flags),
179
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_ppid),
180
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_context),
181
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_assoc_id)
182
+ ),
183
+ UINT2NUM(snp->sn_send_failed_event.ssf_assoc_id),
184
+ rb_ary_new4(snp->sn_send_failed_event.ssf_length, v_temp)
185
+ );
186
+ break;
187
+ #else
188
+ case SCTP_SEND_FAILED:
189
+ v_temp = ALLOCA_N(VALUE, snp->sn_send_failed.ssf_length);
190
+
191
+ for(i = 0; i < snp->sn_send_failed.ssf_length; i++){
192
+ v_temp[i] = UINT2NUM(snp->sn_send_failed.ssf_data[i]);
193
+ }
194
+
195
+ v_notification = rb_struct_new(v_send_failed_event_struct,
196
+ UINT2NUM(snp->sn_send_failed.ssf_type),
197
+ UINT2NUM(snp->sn_send_failed.ssf_length),
198
+ UINT2NUM(snp->sn_send_failed.ssf_error),
199
+ Qnil,
200
+ UINT2NUM(snp->sn_send_failed.ssf_assoc_id),
201
+ rb_ary_new4(snp->sn_send_failed.ssf_length, v_temp)
202
+ );
203
+ break;
204
+ #endif
205
+ case SCTP_SHUTDOWN_EVENT:
206
+ v_notification = rb_struct_new(v_shutdown_event_struct,
207
+ UINT2NUM(snp->sn_shutdown_event.sse_type),
208
+ UINT2NUM(snp->sn_shutdown_event.sse_length),
209
+ UINT2NUM(snp->sn_shutdown_event.sse_assoc_id)
210
+ );
211
+ break;
212
+ case SCTP_ADAPTATION_INDICATION:
213
+ v_notification = rb_struct_new(v_adaptation_event_struct,
214
+ UINT2NUM(snp->sn_adaptation_event.sai_type),
215
+ UINT2NUM(snp->sn_adaptation_event.sai_length),
216
+ UINT2NUM(snp->sn_adaptation_event.sai_adaptation_ind),
217
+ UINT2NUM(snp->sn_adaptation_event.sai_assoc_id)
218
+ );
219
+ break;
220
+ case SCTP_PARTIAL_DELIVERY_EVENT:
221
+ v_notification = rb_struct_new(v_partial_delivery_event_struct,
222
+ UINT2NUM(snp->sn_pdapi_event.pdapi_type),
223
+ UINT2NUM(snp->sn_pdapi_event.pdapi_length),
224
+ UINT2NUM(snp->sn_pdapi_event.pdapi_indication),
225
+ UINT2NUM(snp->sn_pdapi_event.pdapi_stream),
226
+ UINT2NUM(snp->sn_pdapi_event.pdapi_seq),
227
+ UINT2NUM(snp->sn_pdapi_event.pdapi_assoc_id)
228
+ );
229
+ break;
230
+ case SCTP_AUTHENTICATION_EVENT:
231
+ v_notification = rb_struct_new(v_auth_event_struct,
232
+ UINT2NUM(snp->sn_authkey_event.auth_type),
233
+ UINT2NUM(snp->sn_authkey_event.auth_length),
234
+ UINT2NUM(snp->sn_authkey_event.auth_keynumber),
235
+ UINT2NUM(snp->sn_authkey_event.auth_indication),
236
+ UINT2NUM(snp->sn_authkey_event.auth_assoc_id)
237
+ );
238
+ break;
239
+ case SCTP_SENDER_DRY_EVENT:
240
+ v_notification = rb_struct_new(v_sender_dry_event_struct,
241
+ UINT2NUM(snp->sn_sender_dry_event.sender_dry_type),
242
+ UINT2NUM(snp->sn_sender_dry_event.sender_dry_flags),
243
+ UINT2NUM(snp->sn_sender_dry_event.sender_dry_length),
244
+ UINT2NUM(snp->sn_sender_dry_event.sender_dry_assoc_id)
245
+ );
246
+ break;
247
+ }
248
+
249
+ return v_notification;
250
+ }
251
+
64
252
  /*
253
+ * call-seq:
254
+ * SCTP::Socket.new(domain = Socket::AF_INET, type = Socket::SOCK_STREAM)
255
+ *
65
256
  * Create and return a new SCTP::Socket instance. You may optionally pass in
66
257
  * a domain (aka family) value and socket type. By default these are AF_INET
67
258
  * and SOCK_SEQPACKET, respectively.
@@ -104,27 +295,30 @@ static VALUE rsctp_init(int argc, VALUE* argv, VALUE self){
104
295
  }
105
296
 
106
297
  /*
107
- * Bind a subset of IP addresses associated with the host system on the
108
- * given port, or a port assigned by the operating system if none is provided.
298
+ * call-seq:
299
+ * SCTP::Socket#bindx(options)
109
300
  *
110
- * Note that you can both add or remove an address to or from the socket
111
- * using the SCTP_BINDX_ADD_ADDR (default) or SCTP_BINDX_REM_ADDR constants,
112
- * respectively.
301
+ * Bind a subset of IP addresses associated with the host system on the
302
+ * given port, or a port assigned by the operating system if none is provided.
113
303
  *
114
- * Example:
304
+ * Note that you can both add or remove an address to or from the socket
305
+ * using the SCTP_BINDX_ADD_ADDR (default) or SCTP_BINDX_REM_ADDR constants,
306
+ * respectively.
115
307
  *
116
- * socket = SCTP::Socket.new
308
+ * Example:
117
309
  *
118
- * # Bind 2 addresses
119
- * socket.bindx(:port => 64325, :addresses => ['10.0.4.5', '10.0.5.5'])
310
+ * socket = SCTP::Socket.new
120
311
  *
121
- * # Remove 1 later
122
- * socket.bindx(:addresses => ['10.0.4.5'], :flags => SCTP::Socket::BINDX_REM_ADDR)
312
+ * # Bind 2 addresses
313
+ * socket.bindx(:port => 64325, :addresses => ['10.0.4.5', '10.0.5.5'])
123
314
  *
124
- * If no addresses are specified, then it will bind to all available interfaces. If
125
- * no port is specified, then one will be assigned by the host.
315
+ * # Remove 1 later
316
+ * socket.bindx(:addresses => ['10.0.4.5'], :flags => SCTP::Socket::BINDX_REM_ADDR)
126
317
  *
127
- * Returns the port that it was bound to.
318
+ * If no addresses are specified, then it will bind to all available interfaces. If
319
+ * no port is specified, then one will be assigned by the host.
320
+ *
321
+ * Returns the port that it was bound to.
128
322
  */
129
323
  static VALUE rsctp_bindx(int argc, VALUE* argv, VALUE self){
130
324
  struct sockaddr_in addrs[8];
@@ -180,6 +374,7 @@ static VALUE rsctp_bindx(int argc, VALUE* argv, VALUE self){
180
374
  if(port == 0){
181
375
  struct sockaddr_in sin;
182
376
  socklen_t len = sizeof(sin);
377
+ bzero(&sin, len);
183
378
 
184
379
  if(getsockname(fileno, (struct sockaddr *)&sin, &len) == -1)
185
380
  rb_raise(rb_eSystemCallError, "getsockname: %s", strerror(errno));
@@ -193,6 +388,9 @@ static VALUE rsctp_bindx(int argc, VALUE* argv, VALUE self){
193
388
  }
194
389
 
195
390
  /*
391
+ * call-seq:
392
+ * SCTP::Socket#connectx(options)
393
+ *
196
394
  * Connect the socket to a multihomed peer via the provided array of addresses
197
395
  * using the domain specified in the constructor. You must also specify the port.
198
396
  *
@@ -201,7 +399,9 @@ static VALUE rsctp_bindx(int argc, VALUE* argv, VALUE self){
201
399
  * socket = SCTP::Socket.new
202
400
  * socket.connectx(:port => 62354, :addresses => ['10.0.4.5', '10.0.5.5'])
203
401
  *
204
- * Note that this will also set/update the object's association_id.
402
+ * Note that this will also set/update the object's association_id. Also note that
403
+ * this method is not strictly necessary on the client side, since the various send
404
+ * methods will automatically establish associations.
205
405
  */
206
406
  static VALUE rsctp_connectx(int argc, VALUE* argv, VALUE self){
207
407
  struct sockaddr_in addrs[8];
@@ -248,6 +448,9 @@ static VALUE rsctp_connectx(int argc, VALUE* argv, VALUE self){
248
448
  }
249
449
 
250
450
  /*
451
+ * call-seq:
452
+ * SCTP::Socket#close
453
+ *
251
454
  * Close the socket. You should always do this.
252
455
  *
253
456
  * Example:
@@ -265,22 +468,25 @@ static VALUE rsctp_close(VALUE self){
265
468
  }
266
469
 
267
470
  /*
268
- * Return an array of all addresses of a peer of the current socket
269
- * and association number.
471
+ * call-seq:
472
+ * SCTP::Socket#getpeernames
270
473
  *
271
- * You may optionally pass a assocation fileno and association ID. Typically
272
- * this information would come from the peeloff method.
474
+ * Return an array of all addresses of a peer of the current socket
475
+ * and association number.
273
476
  *
274
- * Example:
477
+ * You may optionally pass a assocation fileno and association ID. Typically
478
+ * this information would come from the peeloff method.
275
479
  *
276
- * socket = SCTP::Socket.new
277
- * # ...
278
- * p socket.getpeernames
480
+ * Example:
279
481
  *
280
- * info = socket.recvmsg
281
- * association_fileno = socket.peeloff(info.association_id)
482
+ * socket = SCTP::Socket.new
483
+ * # ...
484
+ * p socket.getpeernames
485
+ *
486
+ * info = socket.recvmsg
487
+ * association_fileno = socket.peeloff(info.association_id)
282
488
  *
283
- * p socket.getpeernames(association_fileno, info.association_id)
489
+ * p socket.getpeernames(association_fileno, info.association_id)
284
490
  */
285
491
  static VALUE rsctp_getpeernames(int argc, VALUE* argv, VALUE self){
286
492
  sctp_assoc_t assoc_id;
@@ -323,6 +529,9 @@ static VALUE rsctp_getpeernames(int argc, VALUE* argv, VALUE self){
323
529
  }
324
530
 
325
531
  /*
532
+ * call-seq:
533
+ * SCTP::Socket#getlocalnames
534
+ *
326
535
  * Return an array of local addresses that are part of the association.
327
536
  *
328
537
  * Example:
@@ -378,6 +587,9 @@ static VALUE rsctp_getlocalnames(int argc, VALUE* argv, VALUE self){
378
587
 
379
588
  #ifdef HAVE_SCTP_SENDV
380
589
  /*
590
+ * call-seq:
591
+ * SCTP::Socket#sendv(options)
592
+ *
381
593
  * Transmit a message to an SCTP endpoint using a gather-write. The following
382
594
  * hash of options is permitted:
383
595
  *
@@ -389,13 +601,14 @@ static VALUE rsctp_getlocalnames(int argc, VALUE* argv, VALUE self){
389
601
  *
390
602
  * socket = SCTP::Socket.new
391
603
  *
604
+ * # You can specify addresses here or in an earlier connectx call.
392
605
  * socket.sendv
393
606
  * :message => ['Hello ', 'World.'],
394
607
  * :addresses => ['10.0.5.4', '10.0.6.4'],
395
608
  * :info_type => SCTP::Socket:::SCTP_SENDV_SNDINFO
396
609
  * )
397
610
  *
398
- * CAVEAT: Currently addresses does not work, and info_type is not yet supported.
611
+ * CAVEAT: Currently info_type is not yet supported.
399
612
  *
400
613
  * Returns the number of bytes sent.
401
614
  */
@@ -403,13 +616,13 @@ static VALUE rsctp_sendv(VALUE self, VALUE v_options){
403
616
  VALUE v_msg, v_message, v_addresses;
404
617
  struct iovec iov[IOV_MAX];
405
618
  struct sockaddr_in* addrs;
406
- struct sctp_sndinfo info;
619
+ struct sctp_sendv_spa spa;
407
620
  int i, fileno, num_bytes, size, num_ip;
408
621
 
409
622
  Check_Type(v_options, T_HASH);
410
623
 
411
624
  bzero(&iov, sizeof(iov));
412
- bzero(&info, sizeof(info));
625
+ bzero(&spa, sizeof(spa));
413
626
 
414
627
  v_message = rb_hash_aref2(v_options, "message");
415
628
  v_addresses = rb_hash_aref2(v_options, "addresses");
@@ -420,7 +633,7 @@ static VALUE rsctp_sendv(VALUE self, VALUE v_options){
420
633
  if(!NIL_P(v_addresses)){
421
634
  Check_Type(v_addresses, T_ARRAY);
422
635
  num_ip = RARRAY_LEN(v_addresses);
423
- addrs = (struct sockaddr_in*)alloca(sizeof(struct sockaddr_in) * num_ip);
636
+ addrs = (struct sockaddr_in*)alloca(num_ip * sizeof(*addrs));
424
637
  }
425
638
  else{
426
639
  addrs = NULL;
@@ -436,26 +649,28 @@ static VALUE rsctp_sendv(VALUE self, VALUE v_options){
436
649
  if(size > IOV_MAX)
437
650
  rb_raise(rb_eArgError, "Array size is greater than IOV_MAX");
438
651
 
439
- info.snd_flags = SCTP_UNORDERED;
440
- info.snd_assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
652
+ // TODO: Make this configurable
653
+ spa.sendv_sndinfo.snd_flags = SCTP_UNORDERED;
654
+ spa.sendv_sndinfo.snd_assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
441
655
 
442
656
  if(!NIL_P(v_addresses)){
443
- int i, port;
657
+ int i, port, domain;
444
658
  VALUE v_address, v_port;
445
659
 
446
- v_port = NUM2INT(rb_iv_get(self, "@port"));
660
+ v_port = rb_iv_get(self, "@port");
447
661
 
448
662
  if(NIL_P(v_port))
449
663
  port = 0;
450
664
  else
451
665
  port = NUM2INT(v_port);
452
666
 
667
+ domain = NUM2INT(rb_iv_get(self, "@domain"));
668
+
453
669
  for(i = 0; i < num_ip; i++){
454
670
  v_address = RARRAY_PTR(v_addresses)[i];
455
- addrs->sin_family = NUM2INT(rb_iv_get(self, "@domain"));
456
- addrs->sin_port = htons(port);
457
- addrs->sin_addr.s_addr = inet_addr(StringValueCStr(v_address));
458
- addrs += sizeof(struct sockaddr_in);
671
+ addrs[i].sin_family = domain;
672
+ addrs[i].sin_port = htons(port);
673
+ addrs[i].sin_addr.s_addr = inet_addr(StringValueCStr(v_address));
459
674
  }
460
675
  }
461
676
 
@@ -471,9 +686,9 @@ static VALUE rsctp_sendv(VALUE self, VALUE v_options){
471
686
  size,
472
687
  (struct sockaddr*)addrs,
473
688
  num_ip,
474
- &info,
475
- sizeof(info),
476
- SCTP_SENDV_SNDINFO,
689
+ &spa,
690
+ sizeof(spa),
691
+ SCTP_SENDV_SPA,
477
692
  0
478
693
  );
479
694
 
@@ -553,6 +768,9 @@ static VALUE rsctp_recvv(int argc, VALUE* argv, VALUE self){
553
768
  #endif
554
769
 
555
770
  /*
771
+ * call-seq:
772
+ * SCTP::Socket.send(options)
773
+ *
556
774
  * Send a message on an already-connected socket to a specific association.
557
775
  *
558
776
  * Example:
@@ -646,6 +864,9 @@ static VALUE rsctp_send(VALUE self, VALUE v_options){
646
864
  }
647
865
 
648
866
  /*
867
+ * call-seq:
868
+ * SCTP::Socket#sendmsg(options)
869
+ *
649
870
  * Transmit a message to an SCTP endpoint. The following hash of options
650
871
  * is permitted:
651
872
  *
@@ -769,6 +990,9 @@ static VALUE rsctp_sendmsg(VALUE self, VALUE v_options){
769
990
  }
770
991
 
771
992
  /*
993
+ * call-seq:
994
+ * SCTP::Socket#recvmsg(flags=0)
995
+ *
772
996
  * Receive a message from another SCTP endpoint.
773
997
  *
774
998
  * Example:
@@ -824,178 +1048,8 @@ static VALUE rsctp_recvmsg(int argc, VALUE* argv, VALUE self){
824
1048
 
825
1049
  v_notification = Qnil;
826
1050
 
827
- if(flags & MSG_NOTIFICATION){
828
- uint32_t i;
829
- char str[16];
830
- union sctp_notification* snp;
831
- VALUE v_str;
832
- VALUE* v_temp;
833
-
834
- snp = (union sctp_notification*)buffer;
835
-
836
- switch(snp->sn_header.sn_type){
837
- case SCTP_ASSOC_CHANGE:
838
- switch(snp->sn_assoc_change.sac_state){
839
- case SCTP_COMM_LOST:
840
- v_str = rb_str_new2("comm lost");
841
- break;
842
- case SCTP_COMM_UP:
843
- v_str = rb_str_new2("comm up");
844
- break;
845
- case SCTP_RESTART:
846
- v_str = rb_str_new2("restart");
847
- break;
848
- case SCTP_SHUTDOWN_COMP:
849
- v_str = rb_str_new2("shutdown complete");
850
- break;
851
- case SCTP_CANT_STR_ASSOC:
852
- v_str = rb_str_new2("association setup failed");
853
- break;
854
- default:
855
- v_str = rb_str_new2("unknown");
856
- }
857
-
858
- v_notification = rb_struct_new(v_assoc_change_struct,
859
- UINT2NUM(snp->sn_assoc_change.sac_type),
860
- UINT2NUM(snp->sn_assoc_change.sac_length),
861
- UINT2NUM(snp->sn_assoc_change.sac_state),
862
- UINT2NUM(snp->sn_assoc_change.sac_error),
863
- UINT2NUM(snp->sn_assoc_change.sac_outbound_streams),
864
- UINT2NUM(snp->sn_assoc_change.sac_inbound_streams),
865
- UINT2NUM(snp->sn_assoc_change.sac_assoc_id),
866
- v_str
867
- );
868
- break;
869
- case SCTP_PEER_ADDR_CHANGE:
870
- switch(snp->sn_paddr_change.spc_state){
871
- case SCTP_ADDR_AVAILABLE:
872
- v_str = rb_str_new2("available");
873
- break;
874
- case SCTP_ADDR_UNREACHABLE:
875
- v_str = rb_str_new2("unreachable");
876
- break;
877
- case SCTP_ADDR_REMOVED:
878
- v_str = rb_str_new2("removed from association");
879
- break;
880
- case SCTP_ADDR_ADDED:
881
- v_str = rb_str_new2("added to association");
882
- break;
883
- case SCTP_ADDR_MADE_PRIM:
884
- v_str = rb_str_new2("primary destination");
885
- break;
886
- default:
887
- v_str = rb_str_new2("unknown");
888
- }
889
-
890
- inet_ntop(
891
- ((struct sockaddr_in *)&snp->sn_paddr_change.spc_aaddr)->sin_family,
892
- &(((struct sockaddr_in *)&snp->sn_paddr_change.spc_aaddr)->sin_addr),
893
- str,
894
- sizeof(str)
895
- );
896
-
897
- v_notification = rb_struct_new(v_peeraddr_change_struct,
898
- UINT2NUM(snp->sn_paddr_change.spc_type),
899
- UINT2NUM(snp->sn_paddr_change.spc_length),
900
- rb_str_new2(str),
901
- UINT2NUM(snp->sn_paddr_change.spc_state),
902
- UINT2NUM(snp->sn_paddr_change.spc_error),
903
- UINT2NUM(snp->sn_paddr_change.spc_assoc_id),
904
- v_str
905
- );
906
- break;
907
- case SCTP_REMOTE_ERROR:
908
- v_temp = ALLOCA_N(VALUE, snp->sn_remote_error.sre_length);
909
-
910
- for(i = 0; i < snp->sn_remote_error.sre_length; i++){
911
- v_temp[i] = UINT2NUM(snp->sn_remote_error.sre_data[i]);
912
- }
913
-
914
- v_notification = rb_struct_new(v_remote_error_struct,
915
- UINT2NUM(snp->sn_remote_error.sre_type),
916
- UINT2NUM(snp->sn_remote_error.sre_length),
917
- UINT2NUM(snp->sn_remote_error.sre_error),
918
- UINT2NUM(snp->sn_remote_error.sre_assoc_id),
919
- rb_ary_new4(snp->sn_remote_error.sre_length, v_temp)
920
- );
921
- break;
922
- #ifdef SCTP_SEND_FAILED_EVENT
923
- case SCTP_SEND_FAILED_EVENT:
924
- v_temp = ALLOCA_N(VALUE, snp->sn_send_failed_event.ssf_length);
925
-
926
- for(i = 0; i < snp->sn_send_failed_event.ssf_length; i++){
927
- v_temp[i] = UINT2NUM(snp->sn_send_failed_event.ssf_data[i]);
928
- }
929
-
930
- v_notification = rb_struct_new(v_send_failed_event_struct,
931
- UINT2NUM(snp->sn_send_failed_event.ssf_type),
932
- UINT2NUM(snp->sn_send_failed_event.ssf_length),
933
- UINT2NUM(snp->sn_send_failed_event.ssf_error),
934
- rb_struct_new(v_sndinfo_struct,
935
- UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_sid),
936
- UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_flags),
937
- UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_ppid),
938
- UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_context),
939
- UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_assoc_id)
940
- ),
941
- UINT2NUM(snp->sn_send_failed_event.ssf_assoc_id),
942
- rb_ary_new4(snp->sn_send_failed_event.ssf_length, v_temp)
943
- );
944
- break;
945
- #else
946
- case SCTP_SEND_FAILED:
947
- v_temp = ALLOCA_N(VALUE, snp->sn_send_failed.ssf_length);
948
-
949
- for(i = 0; i < snp->sn_send_failed.ssf_length; i++){
950
- v_temp[i] = UINT2NUM(snp->sn_send_failed.ssf_data[i]);
951
- }
952
-
953
- v_notification = rb_struct_new(v_send_failed_event_struct,
954
- UINT2NUM(snp->sn_send_failed.ssf_type),
955
- UINT2NUM(snp->sn_send_failed.ssf_length),
956
- UINT2NUM(snp->sn_send_failed.ssf_error),
957
- Qnil,
958
- UINT2NUM(snp->sn_send_failed.ssf_assoc_id),
959
- rb_ary_new4(snp->sn_send_failed.ssf_length, v_temp)
960
- );
961
- break;
962
- #endif
963
- case SCTP_SHUTDOWN_EVENT:
964
- v_notification = rb_struct_new(v_shutdown_event_struct,
965
- UINT2NUM(snp->sn_shutdown_event.sse_type),
966
- UINT2NUM(snp->sn_shutdown_event.sse_length),
967
- UINT2NUM(snp->sn_shutdown_event.sse_assoc_id)
968
- );
969
- break;
970
- case SCTP_ADAPTATION_INDICATION:
971
- v_notification = rb_struct_new(v_adaptation_event_struct,
972
- UINT2NUM(snp->sn_adaptation_event.sai_type),
973
- UINT2NUM(snp->sn_adaptation_event.sai_length),
974
- UINT2NUM(snp->sn_adaptation_event.sai_adaptation_ind),
975
- UINT2NUM(snp->sn_adaptation_event.sai_assoc_id)
976
- );
977
- break;
978
- case SCTP_PARTIAL_DELIVERY_EVENT:
979
- v_notification = rb_struct_new(v_partial_delivery_event_struct,
980
- UINT2NUM(snp->sn_pdapi_event.pdapi_type),
981
- UINT2NUM(snp->sn_pdapi_event.pdapi_length),
982
- UINT2NUM(snp->sn_pdapi_event.pdapi_indication),
983
- UINT2NUM(snp->sn_pdapi_event.pdapi_stream),
984
- UINT2NUM(snp->sn_pdapi_event.pdapi_seq),
985
- UINT2NUM(snp->sn_pdapi_event.pdapi_assoc_id)
986
- );
987
- break;
988
- case SCTP_AUTHENTICATION_EVENT:
989
- v_notification = rb_struct_new(v_auth_event_struct,
990
- UINT2NUM(snp->sn_authkey_event.auth_type),
991
- UINT2NUM(snp->sn_authkey_event.auth_length),
992
- UINT2NUM(snp->sn_authkey_event.auth_keynumber),
993
- UINT2NUM(snp->sn_authkey_event.auth_indication),
994
- UINT2NUM(snp->sn_authkey_event.auth_assoc_id)
995
- );
996
- break;
997
- }
998
- }
1051
+ if(flags & MSG_NOTIFICATION)
1052
+ v_notification = get_notification_info(buffer);
999
1053
 
1000
1054
  if(NIL_P(v_notification))
1001
1055
  v_message = rb_str_new(buffer, bytes);
@@ -1016,6 +1070,9 @@ static VALUE rsctp_recvmsg(int argc, VALUE* argv, VALUE self){
1016
1070
  }
1017
1071
 
1018
1072
  /*
1073
+ * call-seq:
1074
+ * SCTP::Socket#set_initmsg(options)
1075
+ *
1019
1076
  * Set the initial parameters used by the socket when sending out the INIT message.
1020
1077
  *
1021
1078
  * Example:
@@ -1025,10 +1082,10 @@ static VALUE rsctp_recvmsg(int argc, VALUE* argv, VALUE self){
1025
1082
  *
1026
1083
  * The following parameters can be configured:
1027
1084
  *
1028
- * :output_streams - The number of outbound SCTP streams an application would like to request.
1029
- * :input_streams - The maximum number of inbound streams an application is prepared to allow.
1030
- * :max_attempts - How many times the the SCTP stack should send the initial INIT message before it's considered unreachable.
1031
- * :timeout - The maximum RTO value for the INIT timer.
1085
+ * :output_streams - The number of outbound SCTP streams an application would like to request.
1086
+ * :input_streams - The maximum number of inbound streams an application is prepared to allow.
1087
+ * :max_attempts - How many times the the SCTP stack should send the initial INIT message before it's considered unreachable.
1088
+ * :timeout - The maximum RTO value for the INIT timer.
1032
1089
  *
1033
1090
  * By default these values are set to zero (i.e. ignored).
1034
1091
  */
@@ -1065,6 +1122,9 @@ static VALUE rsctp_set_initmsg(VALUE self, VALUE v_options){
1065
1122
  }
1066
1123
 
1067
1124
  /*
1125
+ * call-seq:
1126
+ * SCTP::Socket#subscribe(options)
1127
+ *
1068
1128
  * Subscribe to various notification type events, which will generate additional
1069
1129
  * data that the socket may receive. The possible notification type events are
1070
1130
  * as follows:
@@ -1089,11 +1149,8 @@ static VALUE rsctp_set_initmsg(VALUE self, VALUE v_options){
1089
1149
  * :adaptation
1090
1150
  * :authentication
1091
1151
  * :partial_delivery
1092
- *
1093
- * Not yet supported:
1094
- *
1095
1152
  * :sender_dry
1096
- * :peer_error
1153
+ * :peer_error (aka remote error)
1097
1154
  *
1098
1155
  * Example:
1099
1156
  *
@@ -1152,6 +1209,9 @@ static VALUE rsctp_subscribe(VALUE self, VALUE v_options){
1152
1209
  }
1153
1210
 
1154
1211
  /*
1212
+ * call-seq:
1213
+ * SCTP::Socket#listen(backlog=128)
1214
+ *
1155
1215
  * Marks the socket referred to by sockfd as a passive socket, i.e. a socket that
1156
1216
  * will be used to accept incoming connection requests.
1157
1217
  *
@@ -1195,6 +1255,9 @@ static VALUE rsctp_listen(int argc, VALUE* argv, VALUE self){
1195
1255
  }
1196
1256
 
1197
1257
  /*
1258
+ * call-seq:
1259
+ * SCTP::Socket#peeloff(association_id)
1260
+ *
1198
1261
  * Extracts an association contained by a one-to-many socket connection into
1199
1262
  * a one-to-one style socket. Returns the socket descriptor (fileno).
1200
1263
  *
@@ -1206,7 +1269,7 @@ static VALUE rsctp_listen(int argc, VALUE* argv, VALUE self){
1206
1269
  * while true
1207
1270
  * info = socket.recvmsg
1208
1271
  * assoc_fileno = socket.peeloff(info.association_id)
1209
- * # ... Do something with this new
1272
+ * # ... Do something with this new fileno
1210
1273
  * end
1211
1274
  */
1212
1275
  static VALUE rsctp_peeloff(VALUE self, VALUE v_assoc_id){
@@ -1224,6 +1287,24 @@ static VALUE rsctp_peeloff(VALUE self, VALUE v_assoc_id){
1224
1287
  return INT2NUM(assoc_fileno);
1225
1288
  }
1226
1289
 
1290
+ /*
1291
+ * call-seq:
1292
+ * SCTP::Socket#get_default_send_params
1293
+ *
1294
+ * Returns the default set of parameters that a call to the sendto function
1295
+ * uses on this association. This is a struct that contains the following
1296
+ * members:
1297
+ *
1298
+ * * stream
1299
+ * * ssn
1300
+ * * flags
1301
+ * * ppid
1302
+ * * context
1303
+ * * ttl
1304
+ * * tsn
1305
+ * * cumtsn
1306
+ * * association_id
1307
+ */
1227
1308
  static VALUE rsctp_get_default_send_params(VALUE self){
1228
1309
  int fileno;
1229
1310
  socklen_t size;
@@ -1253,6 +1334,22 @@ static VALUE rsctp_get_default_send_params(VALUE self){
1253
1334
  );
1254
1335
  }
1255
1336
 
1337
+ /*
1338
+ * call-seq:
1339
+ * SCTP::Socket#get_association_info
1340
+ *
1341
+ * Returns the association specific parameters. This is a struct
1342
+ * that contains the following members:
1343
+ *
1344
+ * * association_id
1345
+ * * max_retransmission_count
1346
+ * * number_peer_destinations
1347
+ * * peer_receive_window
1348
+ * * local_receive_window
1349
+ * * cookie_life
1350
+ *
1351
+ * All values that refer to time values are measured in milliseconds.
1352
+ */
1256
1353
  static VALUE rsctp_get_association_info(VALUE self){
1257
1354
  int fileno;
1258
1355
  socklen_t size;
@@ -1279,6 +1376,21 @@ static VALUE rsctp_get_association_info(VALUE self){
1279
1376
  );
1280
1377
  }
1281
1378
 
1379
+ /*
1380
+ * call-seq:
1381
+ * SCTP::Socket#shutdown
1382
+ *
1383
+ * Shuts down socket send and receive operations.
1384
+ *
1385
+ * Optionally accepts an argument that specifieds the type of shutdown.
1386
+ * This can be one of the following values:
1387
+ *
1388
+ * * SHUT_RD - Disables further receive operations.
1389
+ * * SHUT_WR - Disables further send operations.
1390
+ * * SHUT_RDWR - Disables further send and receive operations.
1391
+ *
1392
+ * The default is SHUT_RDWR.
1393
+ */
1282
1394
  static VALUE rsctp_shutdown(int argc, VALUE* argv, VALUE self){
1283
1395
  int how, fileno;
1284
1396
  VALUE v_how;
@@ -1301,6 +1413,19 @@ static VALUE rsctp_shutdown(int argc, VALUE* argv, VALUE self){
1301
1413
  return self;
1302
1414
  }
1303
1415
 
1416
+ /*
1417
+ * call-seq:
1418
+ * SCTP::Socket#get_retransmission_info
1419
+ *
1420
+ * Returns the protocol parameters that are used to initialize and bind the
1421
+ * retransmission timeout (RTO) tunable. This is a struct with the following
1422
+ * members:
1423
+ *
1424
+ * * association_id
1425
+ * * initial
1426
+ * * max
1427
+ * * min
1428
+ */
1304
1429
  static VALUE rsctp_get_retransmission_info(VALUE self){
1305
1430
  int fileno;
1306
1431
  socklen_t size;
@@ -1326,6 +1451,9 @@ static VALUE rsctp_get_retransmission_info(VALUE self){
1326
1451
  }
1327
1452
 
1328
1453
  /*
1454
+ * call-seq:
1455
+ * SCTP::Socket#get_status
1456
+ *
1329
1457
  * Get the status of a connected socket.
1330
1458
  *
1331
1459
  * Example:
@@ -1389,6 +1517,29 @@ static VALUE rsctp_get_status(VALUE self){
1389
1517
  );
1390
1518
  }
1391
1519
 
1520
+ /*
1521
+ * call-seq:
1522
+ * SCTP::Socket#get_subscriptions
1523
+ *
1524
+ * Returns a struct of events detailing which events have been
1525
+ * subscribed to by the socket. The struct contains the following
1526
+ * members:
1527
+ *
1528
+ * * data_io
1529
+ * * association
1530
+ * * address
1531
+ * * send_failure
1532
+ * * peer_error
1533
+ * * shutdown
1534
+ * * partial_delivery
1535
+ * * adaptation_layer
1536
+ * * authentication
1537
+ * * sender_dry
1538
+ * * stream_reset
1539
+ * * assoc_reset
1540
+ * * stream_change
1541
+ * * send_failure_event
1542
+ */
1392
1543
  static VALUE rsctp_get_subscriptions(VALUE self){
1393
1544
  int fileno;
1394
1545
  socklen_t size;
@@ -1422,6 +1573,492 @@ static VALUE rsctp_get_subscriptions(VALUE self){
1422
1573
  );
1423
1574
  }
1424
1575
 
1576
+ /*
1577
+ * call-seq:
1578
+ * SCTP::Socket#get_peer_address_params
1579
+ *
1580
+ * Applications can enable or disable heartbeats for any peer address of
1581
+ * an association, modify an address's heartbeat interval, force a
1582
+ * heartbeat to be sent immediately, and adjust the address's maximum
1583
+ * number of retransmissions sent before an address is considered
1584
+ * unreachable.
1585
+ *
1586
+ * This method returns a struct that contains this information. It contains
1587
+ * the following struct members.
1588
+ *
1589
+ * * association_id
1590
+ * * address
1591
+ * * heartbeat_interval
1592
+ * * max_retransmission_count
1593
+ * * path_mtu
1594
+ * * flags
1595
+ * * ipv6_flowlabel
1596
+ */
1597
+ static VALUE rsctp_get_peer_address_params(VALUE self){
1598
+ int fileno;
1599
+ char str[16];
1600
+ socklen_t size;
1601
+ sctp_assoc_t assoc_id;
1602
+ struct sctp_paddrparams paddr;
1603
+
1604
+ bzero(&paddr, sizeof(paddr));
1605
+ bzero(&str, sizeof(str));
1606
+
1607
+ fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1608
+ assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
1609
+ size = sizeof(struct sctp_paddrparams);
1610
+
1611
+ if(sctp_opt_info(fileno, assoc_id, SCTP_PEER_ADDR_PARAMS, (void*)&paddr, &size) < 0)
1612
+ rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
1613
+
1614
+ inet_ntop(AF_INET, ((struct sockaddr_in*)&paddr.spp_address), str, sizeof(str));
1615
+
1616
+ return rb_struct_new(
1617
+ v_sctp_peer_addr_params_struct,
1618
+ INT2NUM(paddr.spp_assoc_id),
1619
+ rb_str_new2(str),
1620
+ INT2NUM(paddr.spp_hbinterval),
1621
+ INT2NUM(paddr.spp_pathmaxrxt),
1622
+ INT2NUM(paddr.spp_pathmtu),
1623
+ INT2NUM(paddr.spp_flags),
1624
+ INT2NUM(paddr.spp_ipv6_flowlabel)
1625
+ );
1626
+ }
1627
+
1628
+ /*
1629
+ * call-seq:
1630
+ * SCTP::Socket#get_init_msg
1631
+ *
1632
+ * Returns a structure that contains various initialization parameters.
1633
+ *
1634
+ * * num_ostreams: A number representing the number of streams that the
1635
+ * application wishes to be able to send to.
1636
+ *
1637
+ * * max_instreams: The maximum number of inbound streams the application
1638
+ * is prepared to support.
1639
+ *
1640
+ * * max_attempts: The number of attempts the SCTP endpoint should make at
1641
+ * resending the INIT.
1642
+ *
1643
+ * * max_init_timeout: This value represents the largest Timeout or RTO value
1644
+ * (in milliseconds) to use in attempting an INIT.
1645
+ */
1646
+ static VALUE rsctp_get_init_msg(VALUE self){
1647
+ int fileno;
1648
+ socklen_t size;
1649
+ sctp_assoc_t assoc_id;
1650
+ struct sctp_initmsg initmsg;
1651
+
1652
+ bzero(&initmsg, sizeof(initmsg));
1653
+
1654
+ fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1655
+ assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
1656
+ size = sizeof(struct sctp_initmsg);
1657
+
1658
+ if(sctp_opt_info(fileno, assoc_id, SCTP_INITMSG, (void*)&initmsg, &size) < 0)
1659
+ rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
1660
+
1661
+ return rb_struct_new(
1662
+ v_sctp_initmsg_struct,
1663
+ INT2NUM(initmsg.sinit_num_ostreams),
1664
+ INT2NUM(initmsg.sinit_max_instreams),
1665
+ INT2NUM(initmsg.sinit_max_attempts),
1666
+ INT2NUM(initmsg.sinit_max_init_timeo)
1667
+ );
1668
+ }
1669
+
1670
+ /*
1671
+ * call-seq:
1672
+ * SCTP::Socket#nodelay?
1673
+ *
1674
+ * Returns whether or not the nodelay option has been set.
1675
+ */
1676
+ static VALUE rsctp_get_nodelay(VALUE self){
1677
+ int fileno;
1678
+ socklen_t size;
1679
+ sctp_assoc_t assoc_id;
1680
+ int value;
1681
+
1682
+ fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1683
+ assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
1684
+ size = sizeof(int);
1685
+
1686
+ if(sctp_opt_info(fileno, assoc_id, SCTP_NODELAY, (void*)&value, &size) < 0)
1687
+ rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
1688
+
1689
+ if(value)
1690
+ return Qtrue;
1691
+ else
1692
+ return Qfalse;
1693
+ }
1694
+
1695
+ /*
1696
+ * call-seq:
1697
+ * SCTP::Socket#nodelay=(bool)
1698
+ *
1699
+ * Turn on/off any Nagle-like algorithm. This means that packets are generally
1700
+ * sent as soon as possible and no unnecessary delays are introduced, at the
1701
+ * cost of more packets in the network.
1702
+ */
1703
+ static VALUE rsctp_set_nodelay(VALUE self, VALUE v_bool){
1704
+ int fileno;
1705
+ socklen_t size;
1706
+ sctp_assoc_t assoc_id;
1707
+ int value;
1708
+
1709
+ fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1710
+ assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
1711
+ size = sizeof(int);
1712
+
1713
+ if(NIL_P(v_bool) || v_bool == Qfalse)
1714
+ value = 0;
1715
+ else
1716
+ value = 1;
1717
+
1718
+ if(sctp_opt_info(fileno, assoc_id, SCTP_NODELAY, (void*)&value, &size) < 0)
1719
+ rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
1720
+
1721
+ if(value)
1722
+ return Qtrue;
1723
+ else
1724
+ return Qfalse;
1725
+ }
1726
+
1727
+ /*
1728
+ * call-seq:
1729
+ * SCTP::Socket#autoclose
1730
+ *
1731
+ * Returns the number of seconds before socket associations automatically
1732
+ * shut down.
1733
+ */
1734
+ static VALUE rsctp_get_autoclose(VALUE self){
1735
+ int fileno;
1736
+ socklen_t size;
1737
+ sctp_assoc_t assoc_id;
1738
+ int value;
1739
+
1740
+ fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1741
+ assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
1742
+ size = sizeof(int);
1743
+
1744
+ if(sctp_opt_info(fileno, assoc_id, SCTP_AUTOCLOSE, (void*)&value, &size) < 0)
1745
+ rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
1746
+
1747
+ return INT2NUM(value);
1748
+ }
1749
+
1750
+ /*
1751
+ * call-seq:
1752
+ * SCTP::Socket#autoclose=(seconds=0)
1753
+ *
1754
+ * When set it will cause associations that are idle for more than the specified
1755
+ * number of seconds to automatically close using the graceful shutdown
1756
+ * procedure. An association being idle is defined as an association that has
1757
+ * NOT sent or received user data.
1758
+ *
1759
+ * The special value of 0 indicates that no automatic close of any associations
1760
+ * should be performed, this is the default value. The option expects an integer
1761
+ * defining the number of seconds of idle time before an association is closed.
1762
+ *
1763
+ * An application using this option should enable receiving the association
1764
+ * change notification. This is the only mechanism an application is informed
1765
+ * about the closing of an association. After an association is closed, the
1766
+ * association ID assigned to it can be reused. An application should be aware
1767
+ * of this to avoid the possible problem of sending data to an incorrect peer
1768
+ * end point.
1769
+ *
1770
+ * This socket option is applicable to the one-to-many style socket only.
1771
+ */
1772
+ static VALUE rsctp_set_autoclose(VALUE self, VALUE v_seconds){
1773
+ int fileno;
1774
+ socklen_t size;
1775
+ sctp_assoc_t assoc_id;
1776
+ int value;
1777
+
1778
+ value = NUM2INT(v_seconds);
1779
+ fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1780
+ assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
1781
+ size = sizeof(int);
1782
+
1783
+ if(sctp_opt_info(fileno, assoc_id, SCTP_AUTOCLOSE, (void*)&value, &size) < 0)
1784
+ rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
1785
+
1786
+ return v_seconds;
1787
+ }
1788
+
1789
+ /*
1790
+ * call-seq:
1791
+ * SCTP::Socket#enable_auth_support(association_id=nil)
1792
+ *
1793
+ * Enables auth for future associations.
1794
+ */
1795
+ static VALUE rsctp_enable_auth_support(int argc, VALUE* argv, VALUE self){
1796
+ int fileno;
1797
+ socklen_t size;
1798
+ sctp_assoc_t assoc_id;
1799
+ struct sctp_assoc_value assoc_value;
1800
+ VALUE v_assoc_id;
1801
+
1802
+ rb_scan_args(argc, argv, "01", &v_assoc_id);
1803
+
1804
+ fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1805
+ size = sizeof(struct sctp_assoc_value);
1806
+
1807
+ if(NIL_P(v_assoc_id))
1808
+ assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
1809
+ else
1810
+ assoc_id = NUM2INT(v_assoc_id);
1811
+
1812
+ assoc_value.assoc_id = assoc_id;
1813
+ assoc_value.assoc_value = 1;
1814
+
1815
+ if(sctp_opt_info(fileno, assoc_id, SCTP_AUTH_SUPPORTED, (void*)&assoc_value, &size) < 0)
1816
+ rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
1817
+
1818
+ return self;
1819
+ }
1820
+
1821
+ /*
1822
+ * call-seq:
1823
+ * SCTP::Socket#set_shared_key(key, keynum, association_id=nil)
1824
+ *
1825
+ * This option will set a shared secret key which is used to build an
1826
+ * association shared key.
1827
+ *
1828
+ * The +key+ parameter should be a string (converted to an array of bytes
1829
+ * internally) that is to be used by the endpoint (or association) as the
1830
+ * shared secret key. If an empty string is used, then a null key is set.
1831
+ *
1832
+ * The +keynum+ parameter is the shared key identifier by which the
1833
+ * application will refer to this key. If a key of the specified index already
1834
+ * exists, then this new key will replace the old existing key. Note that
1835
+ * shared key identifier '0' defaults to a null key.
1836
+ *
1837
+ * The +association_id+, if non-zero, indicates what association that the shared
1838
+ * key is being set upon. If this argument is zero, then the shared key is set
1839
+ * upon the endpoint and all future associations will use this key (if not
1840
+ * changed by subsequent calls). By default this is the result of the
1841
+ * SCTP::Socket#association_id method.
1842
+ *
1843
+ * For one-to-one sockets, this parameter is ignored. Note, however, that this
1844
+ * option will set a key on the association if the socket is connected,
1845
+ * otherwise this will set a key on the endpoint.
1846
+ */
1847
+ static VALUE rsctp_set_shared_key(int argc, VALUE* argv, VALUE self){
1848
+ int fileno, len;
1849
+ char* key;
1850
+ uint keynum;
1851
+ socklen_t size;
1852
+ sctp_assoc_t assoc_id;
1853
+ struct sctp_authkey* auth_key;
1854
+ VALUE v_key, v_keynumber, v_assoc_id;
1855
+
1856
+ rb_scan_args(argc, argv, "12", &v_key, &v_keynumber, &v_assoc_id);
1857
+
1858
+ fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1859
+ key = StringValuePtr(v_key);
1860
+ len = strlen(key);
1861
+ unsigned char byte_array[len+1];
1862
+
1863
+ for(int i = 0; i < len; i++)
1864
+ byte_array[i] = key[i];
1865
+
1866
+ byte_array[len] = '\0';
1867
+
1868
+ auth_key = malloc(sizeof(auth_key) + sizeof(char[strlen(key)+1]));
1869
+ size = sizeof(auth_key);
1870
+
1871
+ if(NIL_P(v_assoc_id))
1872
+ assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
1873
+ else
1874
+ assoc_id = NUM2INT(v_assoc_id);
1875
+
1876
+ if(NIL_P(v_keynumber))
1877
+ keynum = 1;
1878
+ else
1879
+ keynum = NUM2INT(v_keynumber);
1880
+
1881
+ auth_key->sca_assoc_id = assoc_id;
1882
+ auth_key->sca_keynumber = keynum;
1883
+ auth_key->sca_keylength = strlen(key);
1884
+ memcpy(auth_key->sca_key, byte_array, sizeof(byte_array));
1885
+
1886
+ if(sctp_opt_info(fileno, assoc_id, SCTP_AUTH_KEY, (void*)auth_key, &size) < 0)
1887
+ rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
1888
+
1889
+ return self;
1890
+ }
1891
+
1892
+ /*
1893
+ * call-seq:
1894
+ * SCTP::Socket#get_active_shared_key(keynum, association_id=nil)
1895
+ *
1896
+ * Gets the active shared key to be used to build the association shared key.
1897
+ */
1898
+ static VALUE rsctp_get_active_shared_key(int argc, VALUE* argv, VALUE self){
1899
+ int fileno;
1900
+ socklen_t size;
1901
+ struct sctp_authkeyid authkey;
1902
+ sctp_assoc_t assoc_id;
1903
+ VALUE v_assoc_id, v_keynum;
1904
+ uint keynum;
1905
+
1906
+ rb_scan_args(argc, argv, "11", &v_keynum, &v_assoc_id);
1907
+
1908
+ bzero(&authkey, sizeof(authkey));
1909
+
1910
+ fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1911
+ keynum = NUM2UINT(v_keynum);
1912
+
1913
+ if(NIL_P(v_assoc_id))
1914
+ assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
1915
+ else
1916
+ assoc_id = NUM2INT(v_assoc_id);
1917
+
1918
+ authkey.scact_assoc_id = assoc_id;
1919
+ authkey.scact_keynumber = keynum;
1920
+
1921
+ size = sizeof(struct sctp_authkeyid);
1922
+
1923
+ if(sctp_opt_info(fileno, assoc_id, SCTP_AUTH_ACTIVE_KEY, (void*)&authkey, &size) < 0)
1924
+ rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
1925
+
1926
+ return INT2NUM(authkey.scact_keynumber);
1927
+ }
1928
+
1929
+ /*
1930
+ * call-seq:
1931
+ * SCTP::Socket#set_active_shared_key(keynum, association_id=nil)
1932
+ *
1933
+ * Sets the active shared key to be used to build the association shared key.
1934
+ *
1935
+ * Th +keynum+ parameter is the shared key identifier which the application is
1936
+ * requesting to become the active shared key to be used for sending
1937
+ * authenticated chunks. The key identifier MUST correspond to an existing
1938
+ * shared key. Note that shared key identifier '0' defaults to a null key.
1939
+ *
1940
+ * The association_idparameter, if non-zero, indicates what association that
1941
+ * the shared key identifier is being set active upon. If this element contains
1942
+ * zero, then the activation applies to the endpoint and all future
1943
+ * associations will use the specified shared key identifier.
1944
+ *
1945
+ * For one-to-one sockets, this parameter is ignored. Note, however, that this
1946
+ * option will set the active key on the association if the socket is connected,
1947
+ * otherwise this will set the default active key for the endpoint.
1948
+ *
1949
+ * By default, the association_id is the result of SCTP::Socket#association_id.
1950
+ */
1951
+ static VALUE rsctp_set_active_shared_key(int argc, VALUE* argv, VALUE self){
1952
+ int fileno;
1953
+ socklen_t size;
1954
+ struct sctp_authkeyid authkey;
1955
+ sctp_assoc_t assoc_id;
1956
+ VALUE v_assoc_id, v_keynum;
1957
+ uint keynum;
1958
+
1959
+ rb_scan_args(argc, argv, "11", &v_keynum, &v_assoc_id);
1960
+
1961
+ keynum = NUM2UINT(v_keynum);
1962
+ fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1963
+
1964
+ if(NIL_P(v_assoc_id))
1965
+ assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
1966
+ else
1967
+ assoc_id = NUM2INT(v_assoc_id);
1968
+
1969
+ authkey.scact_assoc_id = assoc_id;
1970
+ authkey.scact_keynumber = keynum;
1971
+ size = sizeof(struct sctp_authkeyid);
1972
+
1973
+ if(sctp_opt_info(fileno, assoc_id, SCTP_AUTH_ACTIVE_KEY, (void*)&authkey, &size) < 0)
1974
+ rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
1975
+
1976
+ return self;
1977
+ }
1978
+
1979
+ /*
1980
+ * call-seq:
1981
+ * SCTP::Socket#delete_shared_key(keynum, association_id=nil)
1982
+ *
1983
+ * Delete a shared secret key from use.
1984
+ *
1985
+ * The +keynum+ parameter is the shared key identifier which the application
1986
+ * is requesting to be deleted. The key identifier MUST correspond to an
1987
+ * existing shared key and MUST NOT be the current active key.
1988
+ *
1989
+ * If this parameter is zero, use of the null key identifier '0' is disabled
1990
+ * on the endpoint and/or association.
1991
+ *
1992
+ * The +association_id+ parameter, if non-zero, indicates what association that
1993
+ * the shared key identifier is being deleted from. By default this is the
1994
+ * association that's returned via SCTP::Socket#association_id.
1995
+ *
1996
+ * If set to zero, then the shared key is deleted from the endpoint and
1997
+ * and ALL associations will no longer use the specified shared key identifier
1998
+ * (unless otherwise set on the association using SCTP_AUTH_KEY).
1999
+ *
2000
+ * For one-to-one sockets, this parameter is ignored. Note, however, that this
2001
+ * option will delete the key from the association if the socket is connected,
2002
+ * otherwise this will delete the key from the endpoint.
2003
+ */
2004
+ static VALUE rsctp_delete_shared_key(int argc, VALUE* argv, VALUE self){
2005
+ int fileno;
2006
+ socklen_t size;
2007
+ struct sctp_authkeyid authkey;
2008
+ sctp_assoc_t assoc_id;
2009
+ VALUE v_assoc_id, v_keynum;
2010
+ uint keynum;
2011
+
2012
+ rb_scan_args(argc, argv, "11", &v_keynum, &v_assoc_id);
2013
+
2014
+ bzero(&authkey, sizeof(authkey));
2015
+
2016
+ fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2017
+ keynum = NUM2UINT(v_keynum);
2018
+
2019
+ if(NIL_P(v_assoc_id))
2020
+ assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
2021
+ else
2022
+ assoc_id = NUM2INT(v_assoc_id);
2023
+
2024
+ authkey.scact_assoc_id = assoc_id;
2025
+ authkey.scact_keynumber = keynum;
2026
+
2027
+ size = sizeof(struct sctp_authkeyid);
2028
+
2029
+ if(sctp_opt_info(fileno, assoc_id, SCTP_AUTH_DELETE_KEY, (void*)&authkey, &size) < 0)
2030
+ rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
2031
+
2032
+ return INT2NUM(authkey.scact_keynumber);
2033
+ }
2034
+
2035
+ /*
2036
+ * call-seq:
2037
+ * SCTP::Socket#map_ipv4=(bool)
2038
+ *
2039
+ * If set to true and the socket is type PF_INET6, then IPv4 addresses will be
2040
+ * mapped to V6 representation. If set to false (the default), then no mapping
2041
+ * will be done of V4 addresses and a user will receive both PF_INET6 and
2042
+ * PF_INET type addresses on the socket.
2043
+ */
2044
+ static VALUE rsctp_map_ipv4(VALUE self, VALUE v_bool){
2045
+ int fileno, boolean;
2046
+ sctp_assoc_t assoc_id;
2047
+ socklen_t size;
2048
+
2049
+ boolean = 0;
2050
+ fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2051
+ assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
2052
+
2053
+ if(v_bool == Qtrue)
2054
+ boolean = 1;
2055
+
2056
+ if(sctp_opt_info(fileno, assoc_id, SCTP_I_WANT_MAPPED_V4_ADDR, (void*)&boolean, &size) < 0)
2057
+ rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
2058
+
2059
+ return v_bool;
2060
+ }
2061
+
1425
2062
  void Init_socket(void){
1426
2063
  mSCTP = rb_define_module("SCTP");
1427
2064
  cSocket = rb_define_class_under(mSCTP, "Socket", rb_cObject);
@@ -1442,7 +2079,7 @@ void Init_socket(void){
1442
2079
  );
1443
2080
 
1444
2081
  v_remote_error_struct = rb_struct_define(
1445
- "RemoteError", "type", "length", "error", "association_id", "data", NULL
2082
+ "RemoteError", "type", "flags", "length", "error", "association_id", "data", NULL
1446
2083
  );
1447
2084
 
1448
2085
  v_send_failed_event_struct = rb_struct_define(
@@ -1470,6 +2107,10 @@ void Init_socket(void){
1470
2107
  "AuthEvent", "type", "length", "key_number", "indication", "association_id", NULL
1471
2108
  );
1472
2109
 
2110
+ v_sender_dry_event_struct = rb_struct_define(
2111
+ "SenderDryEvent", "type", "flags", "length", "association_id", NULL
2112
+ );
2113
+
1473
2114
  v_sockaddr_in_struct = rb_struct_define(
1474
2115
  "SockAddrIn", "family", "port", "address", NULL
1475
2116
  );
@@ -1506,19 +2147,39 @@ void Init_socket(void){
1506
2147
  "cumtsn", "context", "assocation_id", NULL
1507
2148
  );
1508
2149
 
2150
+ v_sctp_peer_addr_params_struct = rb_struct_define(
2151
+ "PeerAddressParams", "association_id", "address", "heartbeat_interval",
2152
+ "max_retransmission_count", "path_mtu", "flags",
2153
+ "ipv6_flowlabel", NULL
2154
+ );
2155
+
2156
+ v_sctp_initmsg_struct = rb_struct_define(
2157
+ "InitMsg", "num_ostreams", "max_instreams", "max_attempts", "max_init_timeout", NULL
2158
+ );
2159
+
1509
2160
  rb_define_method(cSocket, "initialize", rsctp_init, -1);
1510
2161
 
2162
+ rb_define_method(cSocket, "autoclose=", rsctp_set_autoclose, 1);
1511
2163
  rb_define_method(cSocket, "bindx", rsctp_bindx, -1);
1512
2164
  rb_define_method(cSocket, "close", rsctp_close, 0);
1513
2165
  rb_define_method(cSocket, "connectx", rsctp_connectx, -1);
2166
+ rb_define_method(cSocket, "delete_shared_key", rsctp_delete_shared_key, -1);
2167
+ rb_define_method(cSocket, "enable_auth_support", rsctp_enable_auth_support, -1);
1514
2168
  rb_define_method(cSocket, "getpeernames", rsctp_getpeernames, -1);
1515
2169
  rb_define_method(cSocket, "getlocalnames", rsctp_getlocalnames, -1);
1516
- rb_define_method(cSocket, "get_status", rsctp_get_status, 0);
2170
+ rb_define_method(cSocket, "get_active_shared_key", rsctp_get_active_shared_key, -1);
2171
+ rb_define_method(cSocket, "get_association_info", rsctp_get_association_info, 0);
2172
+ rb_define_method(cSocket, "get_autoclose", rsctp_get_autoclose, 0);
1517
2173
  rb_define_method(cSocket, "get_default_send_params", rsctp_get_default_send_params, 0);
2174
+ rb_define_method(cSocket, "get_initmsg", rsctp_get_init_msg, 0);
2175
+ rb_define_method(cSocket, "get_peer_address_params", rsctp_get_peer_address_params, 0);
1518
2176
  rb_define_method(cSocket, "get_retransmission_info", rsctp_get_retransmission_info, 0);
1519
- rb_define_method(cSocket, "get_association_info", rsctp_get_association_info, 0);
2177
+ rb_define_method(cSocket, "get_status", rsctp_get_status, 0);
1520
2178
  rb_define_method(cSocket, "get_subscriptions", rsctp_get_subscriptions, 0);
1521
2179
  rb_define_method(cSocket, "listen", rsctp_listen, -1);
2180
+ rb_define_method(cSocket, "map_ipv4=", rsctp_map_ipv4, 1);
2181
+ rb_define_method(cSocket, "nodelay?", rsctp_get_nodelay, 0);
2182
+ rb_define_method(cSocket, "nodelay=", rsctp_set_nodelay, 1);
1522
2183
  rb_define_method(cSocket, "peeloff", rsctp_peeloff, 1);
1523
2184
  rb_define_method(cSocket, "recvmsg", rsctp_recvmsg, -1);
1524
2185
  rb_define_method(cSocket, "send", rsctp_send, 1);
@@ -1532,7 +2193,10 @@ void Init_socket(void){
1532
2193
  #endif
1533
2194
 
1534
2195
  rb_define_method(cSocket, "sendmsg", rsctp_sendmsg, 1);
2196
+ rb_define_method(cSocket, "set_active_shared_key", rsctp_set_active_shared_key, -1);
1535
2197
  rb_define_method(cSocket, "set_initmsg", rsctp_set_initmsg, 1);
2198
+ //rb_define_method(cSocket, "set_retransmission_info", rsctp_set_retransmission_info, -1);
2199
+ rb_define_method(cSocket, "set_shared_key", rsctp_set_shared_key, -1);
1536
2200
  rb_define_method(cSocket, "shutdown", rsctp_shutdown, -1);
1537
2201
  rb_define_method(cSocket, "subscribe", rsctp_subscribe, 1);
1538
2202
 
@@ -1542,8 +2206,8 @@ void Init_socket(void){
1542
2206
  rb_define_attr(cSocket, "association_id", 1, 1);
1543
2207
  rb_define_attr(cSocket, "port", 1, 1);
1544
2208
 
1545
- /* 0.0.7: The version of this library */
1546
- rb_define_const(cSocket, "VERSION", rb_str_new2("0.0.7"));
2209
+ /* 0.1.1: The version of this library */
2210
+ rb_define_const(cSocket, "VERSION", rb_str_new2("0.1.1"));
1547
2211
 
1548
2212
  /* send flags */
1549
2213