networking 0.0.9 → 1.0.0

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