ffi-rzmq 0.9.0 → 0.9.2

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.
data/lib/ffi-rzmq/poll.rb CHANGED
@@ -85,7 +85,7 @@ module ZMQ
85
85
  item[:fd] = fd
86
86
  end
87
87
 
88
- @raw_to_socket[item[:socket].address] = sock
88
+ @raw_to_socket[item.socket.address] = sock
89
89
  @items << item
90
90
  end
91
91
 
@@ -143,7 +143,7 @@ module ZMQ
143
143
  removed_readable = deregister_readable sock
144
144
  removed_writable = deregister_writable sock
145
145
 
146
- if (size = @sockets.size) > 0
146
+ unless (removed_readable || removed_writable) || (size = @sockets.size).zero?
147
147
  @sockets.delete_if { |socket| socket.socket.address == sock.socket.address }
148
148
  socket_deleted = size != @sockets.size
149
149
 
@@ -172,7 +172,7 @@ module ZMQ
172
172
 
173
173
  def items_hash hash
174
174
  @items.each do |poll_item|
175
- hash[@raw_to_socket[poll_item[:socket].address]] = poll_item
175
+ hash[@raw_to_socket[poll_item.socket.address]] = poll_item
176
176
  end
177
177
  end
178
178
 
@@ -181,8 +181,14 @@ module ZMQ
181
181
  @writables.clear
182
182
 
183
183
  @items.each do |poll_item|
184
- @readables << @raw_to_socket[poll_item[:socket].address] if poll_item.readable?
185
- @writables << @raw_to_socket[poll_item[:socket].address] if poll_item.writable?
184
+ #FIXME: spec for sockets *and* file descriptors
185
+ if poll_item.readable?
186
+ @readables << (poll_item.socket.address.zero? ? poll_item.fd : @raw_to_socket[poll_item.socket.address])
187
+ end
188
+
189
+ if poll_item.writable?
190
+ @writables << (poll_item.socket.address.zero? ? poll_item.fd : @raw_to_socket[poll_item.socket.address])
191
+ end
186
192
  end
187
193
  end
188
194
 
@@ -194,11 +200,22 @@ module ZMQ
194
200
  # Users will pass in values measured as
195
201
  # milliseconds, so we need to convert that value to
196
202
  # microseconds for the library.
197
- def adjust timeout
198
- if :blocking == timeout || -1 == timeout
199
- -1
200
- else
201
- (timeout * 1000).to_i
203
+ if LibZMQ.version2?
204
+ def adjust timeout
205
+ if :blocking == timeout || -1 == timeout
206
+ -1
207
+ else
208
+ (timeout * 1000).to_i
209
+ end
210
+ end
211
+ else
212
+ # version3 changed units from microseconds to milliseconds
213
+ def adjust timeout
214
+ if :blocking == timeout || -1 == timeout
215
+ -1
216
+ else
217
+ timeout.to_i
218
+ end
202
219
  end
203
220
  end
204
221
  end
@@ -34,7 +34,7 @@ module ZMQ
34
34
  def self.create context_ptr, type, opts = {:receiver_class => ZMQ::Message}
35
35
  new(context_ptr, type, opts) rescue nil
36
36
  end
37
-
37
+
38
38
  # To avoid rescuing exceptions, use the factory method #create for
39
39
  # all socket creation.
40
40
  #
@@ -68,7 +68,7 @@ module ZMQ
68
68
  # users may override the classes used for receiving; class must conform to the
69
69
  # same public API as ZMQ::Message
70
70
  @receiver_klass = opts[:receiver_class]
71
-
71
+
72
72
  context_ptr = context_ptr.pointer if context_ptr.kind_of?(ZMQ::Context)
73
73
 
74
74
  unless context_ptr.null?
@@ -100,14 +100,13 @@ module ZMQ
100
100
  # ZMQ::RECONNECT_IVL
101
101
  # ZMQ::BACKLOG
102
102
  # ZMQ::RECOVER_IVL_MSEC (version 2 only)
103
- # ZMQ::RECONNECT_IVL_MAX (version 3/4 only)
104
- # ZMQ::MAXMSGSIZE (version 3/4 only)
105
- # ZMQ::SNDHWM (version 3/4 only)
106
- # ZMQ::RCVHWM (version 3/4 only)
107
- # ZMQ::MULTICAST_HOPS (version 3/4 only)
108
- # ZMQ::RCVTIMEO (version 3/4 only)
109
- # ZMQ::SNDTIMEO (version 3/4 only)
110
- # ZMQ::RCVLABEL (version 3/4 only)
103
+ # ZMQ::RECONNECT_IVL_MAX (version 3 only)
104
+ # ZMQ::MAXMSGSIZE (version 3 only)
105
+ # ZMQ::SNDHWM (version 3 only)
106
+ # ZMQ::RCVHWM (version 3 only)
107
+ # ZMQ::MULTICAST_HOPS (version 3 only)
108
+ # ZMQ::RCVTIMEO (version 3 only)
109
+ # ZMQ::SNDTIMEO (version 3 only)
111
110
  #
112
111
  # Valid +name+ values that take a string +value+ are:
113
112
  # ZMQ::IDENTITY (version 2/3 only)
@@ -169,7 +168,7 @@ module ZMQ
169
168
  def more_parts?
170
169
  array = []
171
170
  rc = getsockopt ZMQ::RCVMORE, array
172
-
171
+
173
172
  Util.resultcode_ok?(rc) ? array.at(0) : false
174
173
  end
175
174
 
@@ -197,7 +196,7 @@ module ZMQ
197
196
  #
198
197
  # rc = socket.close
199
198
  # puts("Given socket was invalid!") unless 0 == rc
200
- #
199
+ #
201
200
  def close
202
201
  if @socket
203
202
  remove_finalizer
@@ -244,7 +243,7 @@ module ZMQ
244
243
  length.write_int 8
245
244
  @sockopt_cache[:int64] = [FFI::MemoryPointer.new(:int64), length]
246
245
  end
247
-
246
+
248
247
  @sockopt_cache[:int64]
249
248
 
250
249
  elsif int_option?(name)
@@ -254,7 +253,7 @@ module ZMQ
254
253
  length.write_int 4
255
254
  @sockopt_cache[:int32] = [FFI::MemoryPointer.new(:int32), length]
256
255
  end
257
-
256
+
258
257
  @sockopt_cache[:int32]
259
258
 
260
259
  elsif string_option?(name)
@@ -262,7 +261,7 @@ module ZMQ
262
261
  # could be a string of up to 255 bytes
263
262
  length.write_int 255
264
263
  [FFI::MemoryPointer.new(255), length]
265
-
264
+
266
265
  else
267
266
  # uh oh, someone passed in an unknown option; use a slop buffer
268
267
  unless @sockopt_cache[:unknown]
@@ -270,7 +269,7 @@ module ZMQ
270
269
  length.write_int 4
271
270
  @sockopt_cache[:unknown] = [FFI::MemoryPointer.new(:int32), length]
272
271
  end
273
-
272
+
274
273
  @sockopt_cache[:unknown]
275
274
  end
276
275
  end
@@ -386,12 +385,12 @@ module ZMQ
386
385
  #
387
386
  def getsockopt name, array
388
387
  rc = __getsockopt__ name, array
389
-
388
+
390
389
  if Util.resultcode_ok?(rc) && (RCVMORE == name || MCAST_LOOP == name)
391
390
  # convert to boolean
392
391
  array[0] = 1 == array[0]
393
392
  end
394
-
393
+
395
394
  rc
396
395
  end
397
396
 
@@ -564,14 +563,14 @@ module ZMQ
564
563
  def recv_strings list, flag = 0
565
564
  array = []
566
565
  rc = recvmsgs array, flag
567
-
566
+
568
567
  if Util.resultcode_ok?(rc)
569
568
  array.each do |message|
570
569
  list << message.copy_out_string
571
570
  message.close
572
571
  end
573
572
  end
574
-
573
+
575
574
  rc
576
575
  end
577
576
 
@@ -594,26 +593,60 @@ module ZMQ
594
593
  def recvmsgs list, flag = 0
595
594
  flag = NOBLOCK if noblock?(flag)
596
595
 
597
- parts = []
598
596
  message = @receiver_klass.new
599
597
  rc = recv message, flag
600
- parts << message
601
-
602
- # check rc *first*; necessary because the call to #more_parts? can reset
603
- # the zmq_errno to a weird value, so the zmq_errno that was set on the
604
- # call to #recv gets lost
605
- while Util.resultcode_ok?(rc) && more_parts?
606
- message = @receiver_klass.new
607
- rc = recv message, flag
608
- parts << message
598
+
599
+ if Util.resultcode_ok?(rc)
600
+ list << message
601
+
602
+ # check rc *first*; necessary because the call to #more_parts? can reset
603
+ # the zmq_errno to a weird value, so the zmq_errno that was set on the
604
+ # call to #recv gets lost
605
+ while Util.resultcode_ok?(rc) && more_parts?
606
+ message = @receiver_klass.new
607
+ rc = recv message, flag
608
+
609
+ if Util.resultcode_ok?(rc)
610
+ list << message
611
+ else
612
+ message.close
613
+ list.each { |msg| msg.close }
614
+ list.clear
615
+ end
616
+ end
617
+ else
618
+ message.close
609
619
  end
610
620
 
611
- # only append the received parts if there were no errors
612
- # FIXME:
613
- # need to detect EAGAIN if flag is set; EAGAIN means we have read all that we
614
- # can and should return whatever was already read; need a spec!
621
+ rc
622
+ end
623
+
624
+ # Should only be used for XREQ, XREP, DEALER and ROUTER type sockets. Takes
625
+ # a +list+ for receiving the message body parts and a +routing_envelope+
626
+ # for receiving the message parts comprising the 0mq routing information.
627
+ #
628
+ # Returns 0 when all messages were successfully dequeued.
629
+ # Returns -1 under two conditions.
630
+ # 1. A message could not be dequeued
631
+ # 2. When +flags+ is set with ZMQ::NOBLOCK and the socket returned EAGAIN.
632
+ #
633
+ # With a -1 return code, the user must check ZMQ.errno to determine the
634
+ # cause. Also, the +list+ *may* be modified when there was an error.
635
+ #
636
+ def recv_multipart list, routing_envelope, flag = 0
637
+ parts = []
638
+ rc = recvmsgs parts, flag
639
+
615
640
  if Util.resultcode_ok?(rc)
616
- parts.each { |part| list << part }
641
+ routing = true
642
+ parts.each do |part|
643
+ if routing
644
+ routing_envelope << part
645
+ routing = part.size > 0
646
+ else
647
+ list << part
648
+ end
649
+ end
617
650
  end
618
651
 
619
652
  rc
@@ -662,7 +695,7 @@ module ZMQ
662
695
  end # LibZMQ.version2?
663
696
 
664
697
 
665
- if LibZMQ.version3? || LibZMQ.version4?
698
+ if LibZMQ.version3?
666
699
  class Socket
667
700
  include CommonSocketBehavior
668
701
  include IdentitySupport
@@ -704,41 +737,13 @@ module ZMQ
704
737
  #
705
738
  def getsockopt name, array
706
739
  rc = __getsockopt__ name, array
707
-
740
+
708
741
  if Util.resultcode_ok?(rc) && (RCVMORE == name)
709
742
  # convert to boolean
710
743
  array[0] = 1 == array[0]
711
744
  end
712
-
713
- rc
714
- end
715
745
 
716
- # The last message part received is tested to see if it is a label.
717
- #
718
- # Equivalent to calling Socket#getsockopt with ZMQ::RCVLABEL.
719
- #
720
- # Warning: if the call to #getsockopt fails, this method will return
721
- # false and swallow the error.
722
- #
723
- # labels = []
724
- # message_parts = []
725
- # message = Message.new
726
- # rc = socket.recv(message)
727
- # if ZMQ::Util.resultcode_ok?(rc)
728
- # label? ? labels.push(message) : message_parts.push(message)
729
- # while more_parts?
730
- # message = Message.new
731
- # if ZMQ::Util.resulcode_ok?(socket.recv(message))
732
- # label? ? labels.push(message) : message_parts.push(message)
733
- # end
734
- # end
735
- # end
736
- #
737
- def label?
738
- array = []
739
- rc = getsockopt ZMQ::RCVLABEL, array
740
-
741
- Util.resultcode_ok?(rc) ? array.at(0) : false
746
+ rc
742
747
  end
743
748
 
744
749
  # Queues the message for transmission. Message is assumed to conform to the
@@ -796,7 +801,7 @@ module ZMQ
796
801
  def send_strings parts, flags = 0
797
802
  return -1 if !parts || parts.empty?
798
803
  flags = DONTWAIT if dontwait?(flags)
799
-
804
+
800
805
  parts[0..-2].each do |part|
801
806
  rc = send_string part, (flags | ZMQ::SNDMORE)
802
807
  return rc unless Util.resultcode_ok?(rc)
@@ -822,7 +827,7 @@ module ZMQ
822
827
  def sendmsgs parts, flags = 0
823
828
  return -1 if !parts || parts.empty?
824
829
  flags = DONTWAIT if dontwait?(flags)
825
-
830
+
826
831
  parts[0..-2].each do |part|
827
832
  rc = sendmsg part, (flags | ZMQ::SNDMORE)
828
833
  return rc unless Util.resultcode_ok?(rc)
@@ -901,14 +906,14 @@ module ZMQ
901
906
  def recv_strings list, flag = 0
902
907
  array = []
903
908
  rc = recvmsgs array, flag
904
-
909
+
905
910
  if Util.resultcode_ok?(rc)
906
911
  array.each do |message|
907
912
  list << message.copy_out_string
908
913
  message.close
909
914
  end
910
915
  end
911
-
916
+
912
917
  rc
913
918
  end
914
919
 
@@ -918,28 +923,55 @@ module ZMQ
918
923
  # +flag+ may be ZMQ::DONTWAIT. Any other flag will be
919
924
  # removed.
920
925
  #
921
- # Raises the same exceptions as Socket#recv.
922
- #
923
926
  def recvmsgs list, flag = 0
924
927
  flag = DONTWAIT if dontwait?(flag)
925
928
 
926
- parts = []
927
929
  message = @receiver_klass.new
928
930
  rc = recvmsg message, flag
929
- parts << message
930
-
931
- # check rc *first*; necessary because the call to #more_parts? can reset
932
- # the zmq_errno to a weird value, so the zmq_errno that was set on the
933
- # call to #recv gets lost
934
- while Util.resultcode_ok?(rc) && more_parts?
935
- message = @receiver_klass.new
936
- rc = recvmsg message, flag
937
- parts << message
931
+
932
+ if Util.resultcode_ok?(rc)
933
+ list << message
934
+
935
+ # check rc *first*; necessary because the call to #more_parts? can reset
936
+ # the zmq_errno to a weird value, so the zmq_errno that was set on the
937
+ # call to #recv gets lost
938
+ while Util.resultcode_ok?(rc) && more_parts?
939
+ message = @receiver_klass.new
940
+ rc = recvmsg message, flag
941
+
942
+ if Util.resultcode_ok?(rc)
943
+ list << message
944
+ else
945
+ message.close
946
+ list.each { |msg| msg.close }
947
+ list.clear
948
+ end
949
+ end
950
+ else
951
+ message.close
938
952
  end
939
953
 
940
- # only append the received parts if there were no errors
954
+ rc
955
+ end
956
+
957
+ # Should only be used for XREQ, XREP, DEALER and ROUTER type sockets. Takes
958
+ # a +list+ for receiving the message body parts and a +routing_envelope+
959
+ # for receiving the message parts comprising the 0mq routing information.
960
+ #
961
+ def recv_multipart list, routing_envelope, flag = 0
962
+ parts = []
963
+ rc = recvmsgs parts, flag
964
+
941
965
  if Util.resultcode_ok?(rc)
942
- parts.each { |part| list << part }
966
+ routing = true
967
+ parts.each do |part|
968
+ if routing
969
+ routing_envelope << part
970
+ routing = part.size > 0
971
+ else
972
+ list << part
973
+ end
974
+ end
943
975
  end
944
976
 
945
977
  rc
@@ -955,7 +987,6 @@ module ZMQ
955
987
 
956
988
  def int_option? name
957
989
  super ||
958
- RCVLABEL == name ||
959
990
  RECONNECT_IVL_MAX == name ||
960
991
  RCVHWM == name ||
961
992
  SNDHWM == name ||
data/lib/ffi-rzmq/util.rb CHANGED
@@ -42,6 +42,22 @@ module ZMQ
42
42
  [major.read_int, minor.read_int, patch.read_int]
43
43
  end
44
44
 
45
+ # Attempts to bind to a random tcp port on +host+ up to +max_tries+
46
+ # times. Returns the port number upon success or nil upon failure.
47
+ #
48
+ def self.bind_to_random_tcp_port host = '127.0.0.1', max_tries = 500
49
+ tries = 0
50
+ rc = -1
51
+
52
+ while !resultcode_ok?(rc) && tries < max_tries
53
+ tries += 1
54
+ random = random_port
55
+ rc = socket.bind "tcp://#{host}:#{random}"
56
+ end
57
+
58
+ resultcode_ok?(rc) ? random : nil
59
+ end
60
+
45
61
  # Returns the proper flag value for non-blocking regardless of 0mq
46
62
  # version.
47
63
  #
@@ -51,7 +67,7 @@ module ZMQ
51
67
  NOBLOCK
52
68
  end
53
69
 
54
- elsif LibZMQ.version3? || LibZMQ.version4?
70
+ elsif LibZMQ.version3?
55
71
 
56
72
  def self.nonblocking_flag
57
73
  DONTWAIT
@@ -62,6 +78,11 @@ module ZMQ
62
78
 
63
79
  private
64
80
 
81
+ # generate a random port between 10_000 and 65534
82
+ def self.random_port
83
+ rand(55534) + 10_000
84
+ end
85
+
65
86
  # :doc:
66
87
  # Called by most library methods to verify there were no errors during
67
88
  # operation. If any are found, raise the appropriate #ZeroMQError.