networking 0.0.9 → 1.0.0

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.
@@ -1,7 +1,4 @@
1
1
  require 'networking/tcp'
2
2
 
3
- module BBFS
4
- module Networking
5
-
6
- end
3
+ module Networking
7
4
  end
@@ -1,217 +1,216 @@
1
1
  require 'log'
2
2
  require 'socket'
3
3
 
4
- module BBFS
5
- module Networking
6
-
7
- Params.integer('client_retry_delay', 60, 'Number of seconds before trying to reconnect.')
8
-
9
- # TODO(kolman): To get robustness, just use try catch + return 0 bytes on write +
10
- # return false on status on read.
11
- def Networking.write_to_stream(stream, obj)
12
- Log.debug3('Writing to stream.')
13
- marshal_data = Marshal.dump(obj)
14
- Log.debug2("Writing data size: #{marshal_data.length}")
15
- data_size = [marshal_data.length].pack("l")
16
- if data_size.nil? || marshal_data.nil?
17
- Log.debug3 'Send data size is nil!'
18
- end
4
+ module Networking
5
+
6
+ Params.integer('client_retry_delay', 60, 'Number of seconds before trying to reconnect.')
7
+
8
+ # TODO(kolman): To get robustness, just use try catch + return 0 bytes on write +
9
+ # return false on status on read.
10
+ def Networking.write_to_stream(stream, obj)
11
+ Log.debug3('Writing to stream.')
12
+ marshal_data = Marshal.dump(obj)
13
+ Log.debug2("Writing data size: #{marshal_data.length}")
14
+ data_size = [marshal_data.length].pack("l")
15
+ if data_size.nil? || marshal_data.nil?
16
+ Log.debug3 'Send data size is nil!'
17
+ end
18
+ begin
19
+ bytes_written = stream.write data_size
20
+ bytes_written += stream.write marshal_data
21
+ return bytes_written
22
+ rescue Exception => e
23
+ Log.warning("Could not write tcp/ip stream, #{e.to_s}")
19
24
  begin
20
- bytes_written = stream.write data_size
21
- bytes_written += stream.write marshal_data
22
- return bytes_written
23
- rescue Exception => e
24
- Log.warning("Could not write tcp/ip stream, #{e.to_s}")
25
- begin
26
- stream.close()
27
- rescue IOError => e
28
- Log.warning("Could not close stream, #{e.to_s}.")
29
- end
30
- return 0
25
+ stream.close()
26
+ rescue IOError => e
27
+ Log.warning("Could not close stream, #{e.to_s}.")
31
28
  end
29
+ return 0
32
30
  end
31
+ end
33
32
 
34
- # Returns pair [status(true/false), obj]
35
- def Networking.read_from_stream(stream)
36
- Log.debug3('Read from stream.')
33
+ # Returns pair [status(true/false), obj]
34
+ def Networking.read_from_stream(stream)
35
+ Log.debug3('Read from stream.')
36
+ begin
37
+ return [false, nil] unless size_of_data = stream.read(4)
38
+ size_of_data = size_of_data.unpack("l")[0]
39
+ Log.debug2("Reading data size:#{size_of_data}")
40
+ data = stream.read(size_of_data)
41
+ rescue Exception => e
42
+ Log.warning("Could not read tcp/ip stream, #{e.to_s}.")
37
43
  begin
38
- return [false, nil] unless size_of_data = stream.read(4)
39
- size_of_data = size_of_data.unpack("l")[0]
40
- Log.debug2("Reading data size:#{size_of_data}")
41
- data = stream.read(size_of_data)
42
- rescue Exception => e
43
- Log.warning("Could not read tcp/ip stream, #{e.to_s}.")
44
- begin
45
- stream.close()
46
- rescue IOError => e
47
- Log.warning("Could not close stream, #{e.to_s}.")
48
- end
49
- return [false, nil]
44
+ stream.close()
45
+ rescue IOError => e
46
+ Log.warning("Could not close stream, #{e.to_s}.")
50
47
  end
51
-
52
- unmarshalled_data = Marshal.load(data)
53
- Log.debug3('Read good.')
54
- return [true, unmarshalled_data]
48
+ return [false, nil]
55
49
  end
56
50
 
57
- # Limit on number of concurrent connections?
58
- # The TCP server is not responsible for reconnection.
59
- class TCPServer
60
- attr_reader :tcp_thread
61
-
62
- def initialize(port, obj_clb, new_clb=nil, closed_clb=nil, max_parallel=1)
63
- @port = port
64
- @obj_clb = obj_clb
65
- @new_clb = new_clb
66
- @closed_clb = closed_clb
67
- # Max parallel connections is not implemented yet.
68
- @max_parallel = max_parallel
69
- @sockets = {}
70
- @tcp_thread = run_server
71
- @tcp_thread.abort_on_exception = true
72
- end
51
+ unmarshalled_data = Marshal.load(data)
52
+ Log.debug3('Read good.')
53
+ return [true, unmarshalled_data]
54
+ end
73
55
 
74
- def send_obj(obj, addr_info=nil)
75
- Log.debug3("addr_info=#{addr_info}")
76
- unless addr_info.nil?
77
- if @sockets.key?(addr_info)
78
- Networking.write_to_stream(@sockets[addr_info], obj)
79
- else
80
- Log.warning("Could not find client socket: #{addr_info}")
81
- return 0
82
- end
56
+ # Limit on number of concurrent connections?
57
+ # The TCP server is not responsible for reconnection.
58
+ class TCPServer
59
+ attr_reader :tcp_thread
60
+
61
+ def initialize(port, obj_clb, new_clb=nil, closed_clb=nil, max_parallel=1)
62
+ @port = port
63
+ @obj_clb = obj_clb
64
+ @new_clb = new_clb
65
+ @closed_clb = closed_clb
66
+ # Max parallel connections is not implemented yet.
67
+ @max_parallel = max_parallel
68
+ @sockets = {}
69
+ @tcp_thread = run_server
70
+ @tcp_thread.abort_on_exception = true
71
+ end
72
+
73
+ def send_obj(obj, addr_info=nil)
74
+ Log.debug3("addr_info=#{addr_info}")
75
+ unless addr_info.nil?
76
+ if @sockets.key?(addr_info)
77
+ Networking.write_to_stream(@sockets[addr_info], obj)
83
78
  else
84
- out = {}
85
- @sockets.each { |key, sock| out[key] = Networking.write_to_stream(sock, obj) }
86
- return out
79
+ Log.warning("Could not find client socket: #{addr_info}")
80
+ return 0
87
81
  end
82
+ else
83
+ out = {}
84
+ @sockets.each { |key, sock| out[key] = Networking.write_to_stream(sock, obj) }
85
+ return out
88
86
  end
87
+ end
89
88
 
90
- private
91
- # Creates new thread/pool
92
- def run_server
93
- Log.debug3('run_server')
94
- return Thread.new do
95
- Log.debug3('run_server2')
96
- loop {
97
- begin
98
- Socket.tcp_server_loop(@port) do |sock, addr_info|
99
- Log.debug3("----- #{@port} -----")
100
- Log.debug3("tcp_server_loop... #{sock} #{addr_info.inspect}")
101
- @sockets[addr_info] = sock
102
- @new_clb.call(addr_info) if @new_clb != nil
103
- loop do
104
- # Blocking read.
105
- Log.debug3('read_from_stream')
106
- stream_ok, obj = Networking.read_from_stream(sock)
107
- Log.debug3("Server returned from read: #{stream_ok}")
108
- @obj_clb.call(addr_info, obj) if @obj_clb != nil && stream_ok
109
- break if !stream_ok
110
- end
111
- Log.warning("Connection broken, #{addr_info.inspect}")
112
- begin
113
- @sockets[addr_info].close() unless @sockets[addr_info].nil?
114
- rescue IOError => e
115
- Log.warning("Could not close socket, #{e.to_s}.")
116
- end
117
- @sockets.delete(addr_info)
118
- @closed_clb.call(addr_info) if @closed_clb != nil
89
+ private
90
+ # Creates new thread/pool
91
+ def run_server
92
+ Log.debug3('run_server')
93
+ return Thread.new do
94
+ Log.debug3('run_server2')
95
+ loop {
96
+ begin
97
+ Socket.tcp_server_loop(@port) do |sock, addr_info|
98
+ Log.debug3("----- #{@port} -----")
99
+ Log.debug3("tcp_server_loop... #{sock} #{addr_info.inspect}")
100
+ @sockets[addr_info] = sock
101
+ @new_clb.call(addr_info) if @new_clb != nil
102
+ loop do
103
+ # Blocking read.
104
+ Log.debug3('read_from_stream')
105
+ stream_ok, obj = Networking.read_from_stream(sock)
106
+ Log.debug3("Server returned from read: #{stream_ok}")
107
+ @obj_clb.call(addr_info, obj) if @obj_clb != nil && stream_ok
108
+ break if !stream_ok
109
+ end
110
+ Log.warning("Connection broken, #{addr_info.inspect}")
111
+ begin
112
+ @sockets[addr_info].close() unless @sockets[addr_info].nil?
113
+ rescue IOError => e
114
+ Log.warning("Could not close socket, #{e.to_s}.")
119
115
  end
116
+ @sockets.delete(addr_info)
117
+ @closed_clb.call(addr_info) if @closed_clb != nil
118
+ end
120
119
  # !!! note this break is needed for tests only !!!! server loop should never end.
121
120
  # and if it ends, it will fail, and rescue will work.
122
121
  break
123
- rescue IOError => e
124
- Log.info("Connection broken during tcp_server_loop. Restarting server loop " \
122
+ rescue IOError => e
123
+ Log.info("Connection broken during tcp_server_loop. Restarting server loop " \
125
124
  "port:#{port}.")
126
- end
127
- }
128
- end
129
- end
130
- end # TCPServer
131
-
132
- class TCPClient
133
- attr_reader :tcp_thread
134
-
135
- def initialize(host, port, obj_clb=nil, reconnected_clb=nil)
136
- @host = host
137
- @port = port
138
- @tcp_socket = nil
139
- @obj_clb = obj_clb
140
- @reconnected_clb = reconnected_clb
141
- Log.debug1('TCPClient init.')
142
- Log.debug1("TCPClient init...#{@obj_clb}...")
143
- if @obj_clb != nil
144
- @tcp_thread = start_reading
145
- @tcp_thread.abort_on_exception = true
146
- end
147
- # Variable to signal when remote server is ready.
148
- @remote_server_available = ConditionVariable.new
149
- @remote_server_available_mutex = Mutex.new
150
- open_socket unless socket_good?
125
+ end
126
+ }
151
127
  end
128
+ end
129
+ end # TCPServer
152
130
 
153
- def send_obj(obj)
154
- Log.debug1('send_obj')
155
- open_socket unless socket_good?
156
- Log.debug1('after open')
157
- if !socket_good?
158
- Log.warning('Socket not opened for writing, skipping send.')
159
- return false
160
- end
161
- Log.debug1('writing...')
162
- #Log.debug3("socket port: #{@tcp_socket.peeraddr}")
163
- bytes_written = Networking.write_to_stream(@tcp_socket, obj)
164
- return bytes_written
131
+ class TCPClient
132
+ attr_reader :tcp_thread
133
+
134
+ def initialize(host, port, obj_clb=nil, reconnected_clb=nil)
135
+ @host = host
136
+ @port = port
137
+ @tcp_socket = nil
138
+ @obj_clb = obj_clb
139
+ @reconnected_clb = reconnected_clb
140
+ Log.debug1('TCPClient init.')
141
+ Log.debug1("TCPClient init...#{@obj_clb}...")
142
+ if @obj_clb != nil
143
+ @tcp_thread = start_reading
144
+ @tcp_thread.abort_on_exception = true
165
145
  end
146
+ # Variable to signal when remote server is ready.
147
+ @remote_server_available = ConditionVariable.new
148
+ @remote_server_available_mutex = Mutex.new
149
+ open_socket unless socket_good?
150
+ end
166
151
 
167
- # This function may be executed only from one thread!!! or in synchronized manner.
168
- # private
169
- def open_socket
170
- Log.debug1("Connecting to content server #{@host}:#{@port}.")
171
- begin
172
- @tcp_socket = TCPSocket.new(@host, @port)
173
- rescue Errno::ECONNREFUSED
174
- Log.warning('Connection refused')
175
- end
176
- Log.debug1("Reconnect clb: '#{@reconnected_clb.nil? ? 'nil' : @reconnected_clb}'")
177
- if socket_good?
178
- @remote_server_available_mutex.synchronize {
179
- @remote_server_available.signal
180
- }
181
- @reconnected_clb.call if @reconnected_clb != nil && socket_good?
182
- end
152
+ def send_obj(obj)
153
+ Log.debug1('send_obj')
154
+ open_socket unless socket_good?
155
+ Log.debug1('after open')
156
+ if !socket_good?
157
+ Log.warning('Socket not opened for writing, skipping send.')
158
+ return false
183
159
  end
160
+ Log.debug1('writing...')
161
+ #Log.debug3("socket port: #{@tcp_socket.peeraddr}")
162
+ bytes_written = Networking.write_to_stream(@tcp_socket, obj)
163
+ return bytes_written
164
+ end
184
165
 
185
- private
186
- def socket_good?
187
- Log.debug1 "socket_good? #{@tcp_socket != nil && !@tcp_socket.closed?}"
188
- return @tcp_socket != nil && !@tcp_socket.closed?
166
+ # This function may be executed only from one thread!!! or in synchronized manner.
167
+ # private
168
+ def open_socket
169
+ Log.debug1("Connecting to content server #{@host}:#{@port}.")
170
+ begin
171
+ @tcp_socket = TCPSocket.new(@host, @port)
172
+ rescue Errno::ECONNREFUSED
173
+ Log.warning('Connection refused')
174
+ end
175
+ Log.debug1("Reconnect clb: '#{@reconnected_clb.nil? ? 'nil' : @reconnected_clb}'")
176
+ if socket_good?
177
+ @remote_server_available_mutex.synchronize {
178
+ @remote_server_available.signal
179
+ }
180
+ @reconnected_clb.call if @reconnected_clb != nil && socket_good?
189
181
  end
182
+ end
183
+
184
+ private
185
+ def socket_good?
186
+ Log.debug1 "socket_good? #{@tcp_socket != nil && !@tcp_socket.closed?}"
187
+ return @tcp_socket != nil && !@tcp_socket.closed?
188
+ end
190
189
 
191
- private
192
- def start_reading
193
- Log.debug1('start_reading (TCPClient).')
194
- return Thread.new do
195
- loop do
196
- Log.debug3('Start blocking read (TCPClient).')
197
- # Blocking read.
198
- if !socket_good?
199
- Log.warning("Socket not good, waiting for reconnection with " \
190
+ private
191
+ def start_reading
192
+ Log.debug1('start_reading (TCPClient).')
193
+ return Thread.new do
194
+ loop do
195
+ Log.debug3('Start blocking read (TCPClient).')
196
+ # Blocking read.
197
+ if !socket_good?
198
+ Log.warning("Socket not good, waiting for reconnection with " \
200
199
  "#{Params['client_retry_delay']} seconds timeout.")
201
- @remote_server_available_mutex.synchronize {
202
- @remote_server_available.wait(@remote_server_available_mutex,
203
- Params['client_retry_delay'])
204
- }
205
- else
206
- read_ok, obj = Networking.read_from_stream(@tcp_socket)
207
- Log.debug3("Client returned from read: #{read_ok}")
208
- # Handle case when socket is closed in middle.
209
- # In that case we should not call obj_clb.
210
- @obj_clb.call(obj) if (read_ok && @obj_clb != nil)
211
- end
200
+ @remote_server_available_mutex.synchronize {
201
+ @remote_server_available.wait(@remote_server_available_mutex,
202
+ Params['client_retry_delay'])
203
+ }
204
+ else
205
+ read_ok, obj = Networking.read_from_stream(@tcp_socket)
206
+ Log.debug3("Client returned from read: #{read_ok}")
207
+ # Handle case when socket is closed in middle.
208
+ # In that case we should not call obj_clb.
209
+ @obj_clb.call(obj) if (read_ok && @obj_clb != nil)
212
210
  end
213
211
  end
214
212
  end
215
- end # TCPClient
216
- end
213
+ end
214
+ end # TCPClient
217
215
  end
216
+
@@ -1,5 +1,3 @@
1
- module BBFS
2
- module Networking
3
- VERSION = "0.0.9"
4
- end
1
+ module Networking
2
+ VERSION = "1.0.0"
5
3
  end
@@ -6,91 +6,90 @@ require 'stringio'
6
6
  require_relative '../../lib/networking/tcp'
7
7
 
8
8
  # Uncomment to debug spec.
9
- BBFS::Params['log_write_to_console'] = true
10
- BBFS::Params['log_debug_level'] = 0
11
- BBFS::Log.init
12
-
13
- module BBFS
14
- module Networking
15
- module Spec
16
-
17
- describe 'TCPClient' do
18
- it 'should warn when destination host+port are bad' do
19
- data = 'kuku!!!'
20
- stream = StringIO.new
21
- stream.close()
22
- ::TCPSocket.stub(:new).and_return(stream)
23
- BBFS::Log.should_receive(:warning).with('Socket not opened for writing, skipping send.')
24
-
25
- # Send data first.
26
- tcp_client = TCPClient.new('kuku', 5555)
27
- # Send has to fail.
28
- tcp_client.send_obj(data).should be(false)
29
- end
30
-
31
- it 'should send data and server should receive callback function' do
32
- info = 'info'
33
- data = 'kuku!!!'
34
- stream = StringIO.new
35
- ::Socket.stub(:tcp_server_loop).and_yield(stream, info)
36
- ::TCPSocket.stub(:new).and_return(stream)
37
-
38
- # Send data first.
39
- tcp_client = TCPClient.new('kuku', 5555)
40
- # Send has to be successful.
41
- tcp_client.send_obj(data).should be(21)
42
-
43
- # Note this is very important so that reading the stream from beginning.
9
+ Params['log_write_to_console'] = true
10
+ Params['log_debug_level'] = 0
11
+ Log.init
12
+
13
+ module Networking
14
+ module Spec
15
+
16
+ describe 'TCPClient' do
17
+ it 'should warn when destination host+port are bad' do
18
+ data = 'kuku!!!'
19
+ stream = StringIO.new
20
+ stream.close()
21
+ ::TCPSocket.stub(:new).and_return(stream)
22
+ Log.should_receive(:warning).with('Socket not opened for writing, skipping send.')
23
+
24
+ # Send data first.
25
+ tcp_client = TCPClient.new('kuku', 5555)
26
+ # Send has to fail.
27
+ tcp_client.send_obj(data).should be(false)
28
+ end
29
+
30
+ it 'should send data and server should receive callback function' do
31
+ info = 'info'
32
+ data = 'kuku!!!'
33
+ stream = StringIO.new
34
+ ::Socket.stub(:tcp_server_loop).and_yield(stream, info)
35
+ ::TCPSocket.stub(:new).and_return(stream)
36
+
37
+ # Send data first.
38
+ tcp_client = TCPClient.new('kuku', 5555)
39
+ # Send has to be successful.
40
+ tcp_client.send_obj(data).should be(21)
41
+
42
+ # Note this is very important so that reading the stream from beginning.
43
+ stream.rewind
44
+
45
+ func = lambda { |info, data| Log.info("info, data: #{info}, #{data}") }
46
+ # Check data is received.
47
+ func.should_receive(:call).with(info, data)
48
+
49
+ tcp_server = TCPServer.new(5555, func)
50
+ # Wait on server thread.
51
+ tcp_server.tcp_thread.join
52
+ end
53
+
54
+ # TODO(kolman): Don't work, missing client send_obj/open_socket execution in
55
+ # the correct place.
56
+ it 'should connect and receive callback from server' do
57
+ info = 'info'
58
+ data = 'kuku!!!'
59
+ stream = StringIO.new
60
+ ::Socket.stub(:tcp_server_loop).once.and_yield(stream, info)
61
+ ::TCPSocket.stub(:new).and_return(stream)
62
+
63
+ tcp_server = nil
64
+ new_clb = lambda { |i|
65
+ Log.info("#2 - After after @sockets is filled. Send has to be successful.")
66
+ tcp_server.send_obj(data).should eq({info => 21})
67
+
44
68
  stream.rewind
45
69
 
46
- func = lambda { |info, data| Log.info("info, data: #{info}, #{data}") }
47
- # Check data is received.
48
- func.should_receive(:call).with(info, data)
49
-
50
- tcp_server = TCPServer.new(5555, func)
51
- # Wait on server thread.
52
- tcp_server.tcp_thread.join
53
- end
54
-
55
- # TODO(kolman): Don't work, missing client send_obj/open_socket execution in
56
- # the correct place.
57
- it 'should connect and receive callback from server' do
58
- info = 'info'
59
- data = 'kuku!!!'
60
- stream = StringIO.new
61
- ::Socket.stub(:tcp_server_loop).once.and_yield(stream, info)
62
- ::TCPSocket.stub(:new).and_return(stream)
63
-
64
- tcp_server = nil
65
- new_clb = lambda { |i|
66
- Log.info("#2 - After after @sockets is filled. Send has to be successful.")
67
- tcp_server.send_obj(data).should eq({info => 21})
68
-
69
- stream.rewind
70
-
71
- func = lambda { |d|
72
- Log.info("#6, After client initialized, it should send object.")
73
- Log.info("data: #{d}")
74
- # Validate received data.
75
- d.should eq(data)
76
- # Exit tcp client reading loop thread.
77
- Thread.exit
78
- }
79
-
80
- Log.info("#4 - Create client and wait for read data.")
81
- tcp_client = TCPClient.new('kuku', 5555, func)
82
- tcp_client.tcp_thread.abort_on_exception = true
83
- tcp_client.tcp_thread.join()
84
- # We can finish now. Exit tcp server listening loop.
70
+ func = lambda { |d|
71
+ Log.info("#6, After client initialized, it should send object.")
72
+ Log.info("data: #{d}")
73
+ # Validate received data.
74
+ d.should eq(data)
75
+ # Exit tcp client reading loop thread.
85
76
  Thread.exit
86
77
  }
87
78
 
88
- Log.info("#1 - Create server, send data and wait.")
89
- tcp_server = TCPServer.new(5555, nil, new_clb)
90
- tcp_server.tcp_thread.abort_on_exception = true
91
- tcp_server.tcp_thread.join()
92
- end
79
+ Log.info("#4 - Create client and wait for read data.")
80
+ tcp_client = TCPClient.new('kuku', 5555, func)
81
+ tcp_client.tcp_thread.abort_on_exception = true
82
+ tcp_client.tcp_thread.join()
83
+ # We can finish now. Exit tcp server listening loop.
84
+ Thread.exit
85
+ }
86
+
87
+ Log.info("#1 - Create server, send data and wait.")
88
+ tcp_server = TCPServer.new(5555, nil, new_clb)
89
+ tcp_server.tcp_thread.abort_on_exception = true
90
+ tcp_server.tcp_thread.join()
93
91
  end
94
92
  end
95
93
  end
96
94
  end
95
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: networking
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 1.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-13 00:00:00.000000000 Z
12
+ date: 2013-05-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: params
@@ -28,7 +28,7 @@ dependencies:
28
28
  - !ruby/object:Gem::Version
29
29
  version: '0'
30
30
  description: Easy to use simple tools for networking (tcp/ip, ect,...).
31
- email: kolmanv@gmail.com
31
+ email: bbfsdev@gmail.com
32
32
  executables: []
33
33
  extensions: []
34
34
  extra_rdoc_files: []
@@ -37,7 +37,7 @@ files:
37
37
  - lib/networking/tcp.rb
38
38
  - lib/networking/version.rb
39
39
  - spec/networking/tcp_spec.rb
40
- homepage: http://github.com/kolmanv/bbfs
40
+ homepage: http://github.com/bbfsdev/bbfs
41
41
  licenses: []
42
42
  post_install_message:
43
43
  rdoc_options: []