firescan 0.07

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.
Files changed (77) hide show
  1. data/LICENSE.txt +202 -0
  2. data/README.txt +37 -0
  3. data/USAGE.txt +43 -0
  4. data/VERSION.txt +4 -0
  5. data/bin/firescan +4 -0
  6. data/build +7 -0
  7. data/doc/Example.html +224 -0
  8. data/doc/Firebind.html +213 -0
  9. data/doc/Firebind/Client.html +750 -0
  10. data/doc/Firebind/Portspec.html +390 -0
  11. data/doc/Firebind/Scan.html +413 -0
  12. data/doc/Firebind/ScanError.html +277 -0
  13. data/doc/Firebind/ScanState.html +1015 -0
  14. data/doc/Firebind/SimpleProtocol.html +292 -0
  15. data/doc/Firebind/TcpTransport.html +481 -0
  16. data/doc/Firebind/Transport.html +275 -0
  17. data/doc/Firebind/UdpTransport.html +472 -0
  18. data/doc/LICENSE_txt.html +323 -0
  19. data/doc/README_txt.html +171 -0
  20. data/doc/Runner.html +166 -0
  21. data/doc/TestPortspec.html +289 -0
  22. data/doc/Tools.html +321 -0
  23. data/doc/USAGE_txt.html +184 -0
  24. data/doc/VERSION_txt.html +126 -0
  25. data/doc/build.html +125 -0
  26. data/doc/created.rid +22 -0
  27. data/doc/doc/created_rid.html +121 -0
  28. data/doc/firescan_gemspec.html +140 -0
  29. data/doc/images/add.png +0 -0
  30. data/doc/images/arrow_up.png +0 -0
  31. data/doc/images/brick.png +0 -0
  32. data/doc/images/brick_link.png +0 -0
  33. data/doc/images/bug.png +0 -0
  34. data/doc/images/bullet_black.png +0 -0
  35. data/doc/images/bullet_toggle_minus.png +0 -0
  36. data/doc/images/bullet_toggle_plus.png +0 -0
  37. data/doc/images/date.png +0 -0
  38. data/doc/images/delete.png +0 -0
  39. data/doc/images/find.png +0 -0
  40. data/doc/images/loadingAnimation.gif +0 -0
  41. data/doc/images/macFFBgHack.png +0 -0
  42. data/doc/images/package.png +0 -0
  43. data/doc/images/page_green.png +0 -0
  44. data/doc/images/page_white_text.png +0 -0
  45. data/doc/images/page_white_width.png +0 -0
  46. data/doc/images/plugin.png +0 -0
  47. data/doc/images/ruby.png +0 -0
  48. data/doc/images/tag_blue.png +0 -0
  49. data/doc/images/tag_green.png +0 -0
  50. data/doc/images/transparent.png +0 -0
  51. data/doc/images/wrench.png +0 -0
  52. data/doc/images/wrench_orange.png +0 -0
  53. data/doc/images/zoom.png +0 -0
  54. data/doc/index.html +118 -0
  55. data/doc/js/darkfish.js +155 -0
  56. data/doc/js/jquery.js +18 -0
  57. data/doc/js/navigation.js +142 -0
  58. data/doc/js/search.js +94 -0
  59. data/doc/js/search_index.js +1 -0
  60. data/doc/js/searcher.js +228 -0
  61. data/doc/rdoc.css +595 -0
  62. data/doc/table_of_contents.html +230 -0
  63. data/firescan.gemspec +18 -0
  64. data/lib/example.rb +20 -0
  65. data/lib/firebind/client.rb +308 -0
  66. data/lib/firebind/portspec.rb +107 -0
  67. data/lib/firebind/scan.rb +288 -0
  68. data/lib/firebind/scan_error.rb +32 -0
  69. data/lib/firebind/scan_state.rb +140 -0
  70. data/lib/firebind/simple_protocol.rb +59 -0
  71. data/lib/firebind/tcp_transport.rb +184 -0
  72. data/lib/firebind/tools.rb +107 -0
  73. data/lib/firebind/transport.rb +44 -0
  74. data/lib/firebind/udp_transport.rb +174 -0
  75. data/test/portspec_test.rb +53 -0
  76. data/test/runner.rb +7 -0
  77. metadata +136 -0
@@ -0,0 +1,59 @@
1
+ # Firebind -- Path Scan Client Software
2
+ # Copyright (C) 2013 Firebind Inc. All rights reserved.
3
+ # Authors - Jay Houghton
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may not
6
+ # use this file except in compliance with the License. You may obtain a copy of
7
+ # the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
+ # License for the specific language governing permissions and limitations under
15
+ # the License.
16
+
17
+ require_relative 'tcp_transport'
18
+ require_relative 'udp_transport'
19
+ require_relative 'tools'
20
+
21
+ module Firebind
22
+
23
+ # Simplest of all echo protocols. This simply sends and receives an 8-byte payload representing the
24
+ # ID number of the scan that was assigned during the Scan API call.
25
+ class SimpleProtocol
26
+
27
+ include Tools
28
+
29
+ # @param [Object] transport
30
+ def initialize(guid,echo_host,transport,timeout,state=NIL)
31
+ @guid = guid
32
+ @echo_host = echo_host
33
+ @state = state
34
+ case transport
35
+ when :TCP
36
+ @transport = Firebind::TcpTransport.new @echo_host,timeout
37
+ when :UDP
38
+ @transport = Firebind::UdpTransport.new @echo_host,timeout
39
+ else
40
+ @transport = Firebind::TcpTransport.new @echo_host,timeout
41
+ end
42
+ end
43
+
44
+ def echo(port)
45
+ payload = big_endian @guid
46
+ begin
47
+ @transport.connect port # connect
48
+ end
49
+
50
+ begin
51
+ @transport.send payload # send
52
+ @transport.receive # receive
53
+ ensure
54
+ @transport.close # close
55
+ end
56
+ end
57
+
58
+ end
59
+ end
@@ -0,0 +1,184 @@
1
+ # Firebind -- Path Scan Client Software
2
+ # Copyright (C) 2013 Firebind Inc. All rights reserved.
3
+ # Authors - Jay Houghton
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may not
6
+ # use this file except in compliance with the License. You may obtain a copy of
7
+ # the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
+ # License for the specific language governing permissions and limitations under
15
+ # the License.
16
+
17
+ require_relative 'transport'
18
+ require_relative 'tools'
19
+ require_relative 'scan_error'
20
+
21
+ module Firebind
22
+
23
+ # Send and receive echo using TCP transport.
24
+ class TcpTransport < Transport
25
+ include Tools
26
+ def initialize (echo_server,timeout)
27
+ super(echo_server,timeout)
28
+ end
29
+
30
+ # establish connection to echo server on port
31
+ def connect(port)
32
+ @port = port
33
+ connect_start = Time.now
34
+ #host_addr = Socket.getaddrinfo(@echo_server,nil) # probably should get 0,3 from this guy for IPv6
35
+
36
+ begin
37
+ #noinspection RubyArgCount
38
+ @socket = Socket.new(:INET, :STREAM)
39
+ @remote_addr = Socket.pack_sockaddr_in(@port, @echo_server)
40
+ rescue
41
+ raise Firebind::ScanError.new :HANDSHAKE_CONNECTION_INITIATION_FAILURE
42
+ end
43
+
44
+ begin
45
+ @socket.connect_nonblock @remote_addr
46
+ rescue Errno::EINPROGRESS
47
+ # still doing handshake, wait @timeout until its ready to connect_nonblock again
48
+ debug("connection still inprogress select for #{@timeout}ms")
49
+
50
+ # interest ops: reading,writing,error,timeout
51
+ readables,writables,errors = IO.select([@socket], [@socket], [@socket], @timeout_seconds)
52
+ debug "readables=#{readables} writables=#{writables} errors=#{errors}"
53
+
54
+ readable = readables != NIL && readables.length > 0
55
+ writable = writables != NIL && writables.length > 0
56
+ error = errors != NIL && errors.length > 0
57
+
58
+ if error
59
+ raise Firebind::ScanError.new(:HANDSHAKE_CONNECTION_REFUSED)
60
+ end
61
+
62
+ if readable || writable
63
+ retry
64
+ else
65
+ debug "connection timeout after #{@timeout}ms"
66
+ raise Firebind::ScanError.new :HANDSHAKE_CONNECTION_TIME_OUT
67
+ end
68
+
69
+ # A time check may be required in the future (if we select for less than timeout)
70
+ # if Time.now - connect_start > @timeout_seconds
71
+ # raise Firebind::ScanError.new :HANDSHAKE_CONNECTION_TIME_OUT
72
+
73
+ rescue Errno::EISCONN # this is a linux code... todo: figure the platform codes for continuation
74
+ debug 'connection success'
75
+ rescue Errno::ECONNREFUSED => e
76
+ raise Firebind::ScanError.new(:HANDSHAKE_CONNECTION_REFUSED, e)
77
+ rescue
78
+ #collect all the ways a connection can fail... some of the conditions are:
79
+ # 1) No route to host - connect(2)
80
+ raise Firebind::ScanError.new(:HANDSHAKE_CONNECTION_REFUSED, $!)
81
+ end
82
+ end
83
+
84
+ # Send data to the echo server
85
+ #
86
+ # @param [Array[]] payload - array of bytes
87
+ def send(payload)
88
+ @payload = payload
89
+ size = payload.length
90
+ count = 0
91
+ send_start = Time.now
92
+
93
+ payload.each do |byte|
94
+ begin
95
+ count += @socket.write_nonblock [byte].pack('C')
96
+ debug "wrote #{count} bytes to #{@echo_server}:#{@port}"
97
+ rescue IO::WaitWritable, Errno::EINTR
98
+ if count == size
99
+ # we've written our payload, we're done
100
+ debug "completed #{count} byte payload to #{@echo_server}:#{@port}"
101
+ elsif Time.now - send_start > @timeout_seconds
102
+ # we've timed out of sending
103
+ raise Firebind::ScanError.new :FAILURE_ON_PAYLOAD_SEND
104
+ else
105
+ # try to write some more ? http://ruby-doc.org/core-1.9.3/IO.html#method-i-write_nonblock
106
+ retry
107
+ end
108
+
109
+ rescue
110
+ #collect all the ways a send can fail...
111
+ raise Firebind::ScanError.new(:FAILURE_ON_PAYLOAD_SEND, $!)
112
+ end
113
+
114
+ end
115
+ end
116
+
117
+ # Receive echo response from server.
118
+ #
119
+ #
120
+ # PAYLOAD_REFUSED_ON_RECV
121
+ # PAYLOAD_ERROR_ON_RECV
122
+ # PAYLOAD_TIMED_OUT_ON_RECV
123
+ #
124
+ # @return [Object]
125
+ def receive
126
+ size = @payload.length
127
+ count = 0
128
+ receive_start = Time.now
129
+ receive_buffer = ''
130
+
131
+ while Time.now - receive_start <= @timeout_seconds && count < size
132
+ begin
133
+ read_result = @socket.read_nonblock(1024)
134
+ count += read_result.length # because appending to receive_buffer won't count recv bytes via .length
135
+ # add read_result to our buffer
136
+ receive_buffer << read_result
137
+ debug "read buffer is #{count}"
138
+ rescue IO::WaitReadable
139
+ if count == size
140
+ # we're done - read all we had expected to receive
141
+ debug "completed full read of #{count} bytes"
142
+ break
143
+ elsif Time.now - receive_start > @timeout_seconds
144
+ # timeout on receive
145
+ raise Firebind::ScanError.new(:PAYLOAD_TIMED_OUT_ON_RECV)
146
+ else
147
+ # keep going
148
+ IO.select([@socket],nil,nil,@timeout_seconds)
149
+ retry
150
+ end
151
+ rescue EOFError => e
152
+ # connection was forcefully dropped or sent a final FIN ACK closing sequence
153
+ if count != size
154
+ raise Firebind::ScanError.new(:PAYLOAD_ERROR_ON_RECV,e)
155
+ end
156
+
157
+ rescue
158
+ #collect all the ways a receive can fail... todo:
159
+ if $debug
160
+ puts 'Caught unhandled socket error:'
161
+ p $1
162
+ puts $@
163
+ end
164
+ raise Firebind::ScanError.new(:PAYLOAD_REFUSED_ON_RECV,$!)
165
+ end
166
+ end
167
+
168
+ # we still could have timed out here, check rx buffer size first
169
+ if count < size
170
+ raise Firebind::ScanError.new(:PAYLOAD_TIMED_OUT_ON_RECV)
171
+ end
172
+
173
+ # now compare what we received with what we sent
174
+ received_array = receive_buffer.unpack('C*')
175
+ if received_array != @payload
176
+ debug "rx buffer #{received_array.to_s} is NOT equal to expected #{@payload.to_s}"
177
+ raise Firebind::ScanError.new(:PAYLOAD_MISMATCH_ON_RECV)
178
+ else
179
+ debug "rx buffer #{received_array.to_s} is equal to payload #{@payload.to_s}"
180
+ end
181
+
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,107 @@
1
+ # Firebind -- Path Scan Client Software
2
+ # Copyright (C) 2013 Firebind Inc. All rights reserved.
3
+ # Authors - Jay Houghton
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may not
6
+ # use this file except in compliance with the License. You may obtain a copy of
7
+ # the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
+ # License for the specific language governing permissions and limitations under
15
+ # the License.
16
+
17
+ # Utility module for translating socket and result codes.
18
+ module Tools
19
+
20
+ $debug = false
21
+ $verbose = false
22
+
23
+ def big_endian(a_number)
24
+ bytes = []
25
+ 7.downto(0) do |i|
26
+ bytes[i] = 0xFF & a_number
27
+ a_number = a_number >> 8
28
+ end
29
+ bytes
30
+ end
31
+
32
+ # @@SOCKET_CODES = { :CONNECTION_REFUSED => }
33
+
34
+ #
35
+ # Result Codes as defined in reference documents
36
+ # http://www.firebind.com/support/reference/socket_mapping.html
37
+ #
38
+ $handshake_connection_refused = 12152
39
+ $handshake_connection_timeout = 12151
40
+ #noinspection RubyGlobalVariableNamingConvention
41
+ $handshake_connection_initiation_failure = 12150
42
+ $payload_refused_on_recv = 12156
43
+ $payload_timed_out_on_recv = 12155
44
+ $payload_error_on_recv = 12158
45
+ $payload_mismatch_on_recv = 12157
46
+ $failure_on_payload_send = 12154
47
+ #noinspection RubyGlobalVariableNamingConvention
48
+ $handshake_connection_completion_failure = 12153
49
+ $success = 12110
50
+ $skipped = 12020
51
+ $scan_failure = 12111
52
+ $client_network_failure = 12112
53
+ $command_server_unavailable = 7
54
+
55
+ $result_codes = {HANDSHAKE_CONNECTION_REFUSED: $handshake_connection_refused,
56
+ HANDSHAKE_CONNECTION_TIME_OUT: $handshake_connection_timeout,
57
+ HANDSHAKE_CONNECTION_INITIATION_FAILURE: $handshake_connection_initiation_failure,
58
+ PAYLOAD_REFUSED_ON_RECV: $payload_refused_on_recv,
59
+ PAYLOAD_TIMED_OUT_ON_RECV: $payload_timed_out_on_recv,
60
+ PAYLOAD_ERROR_ON_RECV: $payload_error_on_recv,
61
+ PAYLOAD_MISMATCH_ON_RECV: $payload_mismatch_on_recv,
62
+ FAILURE_ON_PAYLOAD_SEND: $failure_on_payload_send,
63
+ HANDSHAKE_CONNECTION_COMPLETION_FAILURE: $handshake_connection_completion_failure,
64
+ SUCCESS: $success,
65
+ SKIPPED: $skipped,
66
+ TEST_FAILURE: $scan_failure,
67
+ CLIENT_NETWORK_FAILURE: $client_network_failure
68
+ }
69
+
70
+ # todo: finish reverse result code / symbol mapping
71
+
72
+ #result_code_rev = { $handshake_connection_refused => :HANDSHAKE_CONNECTION_REFUSED }
73
+
74
+ $result_code_messages = { $handshake_connection_refused => 'Handshake Connection Refused',
75
+ $handshake_connection_timeout => 'Handshake Connection Timeout',
76
+ $handshake_connection_initiation_failure => 'Handshake Connection Initiation Failure',
77
+ $payload_refused_on_recv => 'Payload Refused On Receive',
78
+ $payload_timed_out_on_recv => 'Payload Timed Out On Receive',
79
+ $payload_error_on_recv => 'Payload Error On Receive',
80
+ $payload_mismatch_on_recv => 'Payload Mismatch On Receive',
81
+ $failure_on_payload_send => 'Failure On Payload Send',
82
+ $handshake_connection_completion_failure => 'Handshake Connection Completion Failure',
83
+ $success => 'Open',
84
+ $skipped => 'Skipped',
85
+ $scan_failure => 'Scan Failure',
86
+ $client_network_failure => 'Client Network Failure'
87
+ }
88
+
89
+ # server status codes
90
+ $authentication_failure = 20401
91
+ $request_invalid = 20400
92
+ $server_bind_error = 2017
93
+ $client_scan_completed = 12021
94
+
95
+ def verbose(msg)
96
+ puts "Firescan - #{msg}" if $verbose
97
+ end
98
+
99
+ def debug(msg)
100
+ puts "DEBUG #{self.class.to_s} - #{msg}" if $debug
101
+ end
102
+
103
+ def out(msg)
104
+ puts msg
105
+ end
106
+
107
+ end
@@ -0,0 +1,44 @@
1
+ # Firebind -- Path Scan Client Software
2
+ # Copyright (C) 2013 Firebind Inc. All rights reserved.
3
+ # Authors - Jay Houghton
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may not
6
+ # use this file except in compliance with the License. You may obtain a copy of
7
+ # the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
+ # License for the specific language governing permissions and limitations under
15
+ # the License.
16
+
17
+ require_relative 'tools'
18
+ require 'socket'
19
+
20
+ module Firebind
21
+
22
+
23
+ class Transport
24
+
25
+ include Tools
26
+
27
+ def initialize (echo_server, timeout)
28
+ @echo_server = echo_server
29
+ @timeout = timeout
30
+ @timeout_seconds = timeout.to_f/1000
31
+ end
32
+
33
+
34
+ def close
35
+ begin
36
+ #noinspection RubyResolve
37
+ @socket.close
38
+ rescue
39
+ debug "error closing socket #{$!}"
40
+ end
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,174 @@
1
+ # Firebind -- Path Scan Client Software
2
+ # Copyright (C) 2013 Firebind Inc. All rights reserved.
3
+ # Authors - Jay Houghton
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may not
6
+ # use this file except in compliance with the License. You may obtain a copy of
7
+ # the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
+ # License for the specific language governing permissions and limitations under
15
+ # the License.
16
+
17
+ require_relative 'transport'
18
+ require_relative 'tools'
19
+ require_relative 'scan_error'
20
+
21
+ module Firebind
22
+
23
+ # Send and receive echo using UDP transport.
24
+ class UdpTransport < Transport
25
+ include Tools
26
+ def initialize (echo_server,timeout)
27
+ super(echo_server,timeout)
28
+ end
29
+
30
+ def connect(port)
31
+ @port = port
32
+ begin
33
+ @socket = Socket.new(:INET,:DGRAM)
34
+ @remote_addr = Socket.pack_sockaddr_in(@port, @echo_server)
35
+ @socket.connect_nonblock @remote_addr
36
+ rescue
37
+ raise Firebind::ScanError.new :FAILURE_ON_PAYLOAD_SEND
38
+ end
39
+ end
40
+
41
+ # Send data to the echo server, we'll send multiple copies of the same data. So long as the echo server
42
+ # receives one of these we should expect an echo response.
43
+ #
44
+ # @param [Array[]] payload - array of bytes
45
+ def send(payload,num_payloads = 10)
46
+ @payload = payload
47
+ size = payload.length
48
+ count = 0
49
+ send_start = Time.now
50
+
51
+ # send the payload this many times
52
+ payloads_sent = 0
53
+
54
+ debug "sending buffer #{payload.to_s}"
55
+ #payload.each do |byte|
56
+ while count < size && Time.now - send_start < @timeout_seconds
57
+ begin
58
+
59
+ # chomp up the payload depending upon where we left off
60
+ send_buffer = payload[count,size-count]
61
+
62
+ count += @socket.write_nonblock send_buffer.pack('C*')
63
+ debug "wrote #{count} bytes to #{@echo_server}:#{@port}"
64
+
65
+ if payloads_sent < num_payloads and count == size
66
+ # reset counters to send another payload
67
+ debug "sending datagram number #{payloads_sent}"
68
+ count = 0
69
+ payloads_sent += 1
70
+ end
71
+
72
+ rescue IO::WaitWritable, Errno::EINTR
73
+
74
+ if count == size
75
+ # we've written our payload, we're done
76
+ debug "completed #{count} byte payload to #{@echo_server}:#{@port}"
77
+ elsif Time.now - send_start > @timeout_seconds
78
+ # we've timed out of sending
79
+ raise Firebind::ScanError.new :FAILURE_ON_PAYLOAD_SEND
80
+ else
81
+ # try to write some more ? http://ruby-doc.org/core-1.9.3/IO.html#method-i-write_nonblock
82
+ retry
83
+ end
84
+
85
+ rescue
86
+ #collect all the ways a send can fail...
87
+ raise Firebind::ScanError.new(:FAILURE_ON_PAYLOAD_SEND, $!)
88
+ end
89
+
90
+ end
91
+ end
92
+
93
+ #
94
+ # Receive echo response from server. Partway through the timeout we'll call send() again to send
95
+ # more datagrams as a last ditch effort to get data across.
96
+ #
97
+ # PAYLOAD_REFUSED_ON_RECV
98
+ # PAYLOAD_ERROR_ON_RECV
99
+ # PAYLOAD_TIMED_OUT_ON_RECV
100
+ #
101
+ def receive
102
+ size = @payload.length
103
+ count = 0
104
+ receive_start = Time.now
105
+ receive_buffer = ''
106
+ halfway = @timeout_seconds/2
107
+
108
+ while Time.now - receive_start <= @timeout_seconds && count < size
109
+
110
+ begin
111
+ read_result = @socket.read_nonblock(1024)
112
+ count += read_result.length # because appending to receive_buffer won't count recv bytes via .length
113
+ # add read_result to our buffer
114
+ receive_buffer << read_result
115
+ debug "read buffer is #{count}"
116
+ rescue IO::WaitReadable
117
+ if count == size
118
+ # we're done - read all we had expected to receive
119
+ debug "completed full read of #{count} bytes"
120
+ break
121
+ elsif Time.now - receive_start > @timeout_seconds
122
+ # timeout on receive
123
+ raise Firebind::ScanError.new(:PAYLOAD_TIMED_OUT_ON_RECV)
124
+ else
125
+ # send some more datagrams?
126
+ if Time.now - receive_start > halfway
127
+ begin
128
+ debug "halfway through timeout sending more datagrams on port #{@port}"
129
+ send(@payload,5)
130
+ rescue
131
+ debug "mid-receive cycle resend resulted in #{$!} ignoring"
132
+ end
133
+ end
134
+
135
+ # keep going
136
+ IO.select([@socket],nil,nil,halfway)
137
+ retry
138
+ end
139
+ rescue EOFError => e
140
+ # connection was forcefully dropped or sent a final FIN ACK closing sequence
141
+ if count != size
142
+ raise Firebind::ScanError.new(:PAYLOAD_ERROR_ON_RECV,e)
143
+ end
144
+
145
+ rescue
146
+ #collect all the ways a receive can fail... todo:
147
+ if $debug
148
+ puts 'Caught unhandled socket error:'
149
+ p $1
150
+ puts $@
151
+ end
152
+ raise Firebind::ScanError.new(:PAYLOAD_REFUSED_ON_RECV,$!)
153
+ end
154
+
155
+ end
156
+
157
+ # we still could have timed out here, check rx buffer size first
158
+ if count < size
159
+ raise Firebind::ScanError.new(:PAYLOAD_TIMED_OUT_ON_RECV)
160
+ end
161
+
162
+ # now compare what we received with what we sent
163
+ received_array = receive_buffer.unpack('C*')
164
+ if received_array != @payload
165
+ debug "rx buffer #{received_array.to_s} is NOT equal to expected #{@payload.to_s}"
166
+ raise Firebind::ScanError.new(:PAYLOAD_MISMATCH_ON_RECV)
167
+ else
168
+ debug "rx buffer #{received_array.to_s} is equal to payload #{@payload.to_s}"
169
+ end
170
+
171
+ end
172
+
173
+ end
174
+ end