ffi-rzmq 0.9.0 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
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.