minitcp 0.10.0 → 0.15.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.txt +20 -0
- data/README.md +37 -1
- data/VERSION +1 -1
- data/lib/minitcp.rb +47 -7
- data/samples/pxy.rb +429 -0
- data/samples/relay/README.md +24 -1
- data/samples/relay/relai_config.data +2 -1
- data/samples/relay/relaiproxy.rb +167 -68
- data/test.rb +38 -2
- metadata +13 -15
- data/samples/pingpongplot.rb +0 -26
- data/samples/plot.rb +0 -190
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 40c86e0923a11e1d1399840594700ed14d087f5b
|
4
|
+
data.tar.gz: 25fc9a740519e40ed6ccf029cb986bb85e0e0a13
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1e59ae815447e1bd2639a3a49a8c536f9af7856c88a6c0861e643e671f78f68973eeec0ecb1cc1c067c6730e88d1bd3ee61b9633d7844550f4c09fcdee72d445
|
7
|
+
data.tar.gz: b204d6cb22237371a6bb93e449ee977564d7e8d9931ed86b0d1c76b15c1b310f726611f8f7168a6627f7a834fde673f6366361cdd933358ed6c3f433a0f962c5
|
data/CHANGELOG.txt
CHANGED
@@ -1,3 +1,23 @@
|
|
1
|
+
0.15.0 : 2015-04-02 15:51:14 +0200
|
2
|
+
minitcp.rb : force data received to encding BINARY
|
3
|
+
0.14.0 : 2015-01-13 20:56:17 +0100
|
4
|
+
minitcp.rb : no audit, no log for tcp server
|
5
|
+
relaiproxy.rb : notraces
|
6
|
+
relai_config.data : test1 aded
|
7
|
+
minitcp.rb : no traces
|
8
|
+
0.13.0 : 2014-11-28 13:35:33 +0100
|
9
|
+
plot.rb : window resize enable
|
10
|
+
pingpongplot.rb : multiple url test
|
11
|
+
README.md : message agent expample
|
12
|
+
README.md : massage agent expalple
|
13
|
+
README.md : example message
|
14
|
+
README.md : example for agent message
|
15
|
+
0.12.0 : 2014-10-30 21:31:33 +0100
|
16
|
+
0.11.0 : 2014-10-30 21:30:28 +0100
|
17
|
+
README.md : ocpp
|
18
|
+
README.md : plugin doc
|
19
|
+
Rakefile.rb : version management
|
20
|
+
README.md : plugin ocpp description
|
1
21
|
0.10.0 : 2014-09-24 20:18:54 +0200
|
2
22
|
minitcp.rb : reveive_n_byte correction
|
3
23
|
0.9.0 : 2014-09-18 22:38:31 +0200
|
data/README.md
CHANGED
@@ -61,6 +61,28 @@ A UDP sender :
|
|
61
61
|
)
|
62
62
|
```
|
63
63
|
|
64
|
+
A Message agent :
|
65
|
+
Message Client:
|
66
|
+
```ruby
|
67
|
+
MClientAgent.run("localhost",2222) do |chan|
|
68
|
+
chan.send_message({date: Time.now.to_f})
|
69
|
+
chan.on_message do |mess|
|
70
|
+
puts "cli: receive: #{mess.inspect}"
|
71
|
+
chan.close
|
72
|
+
nil
|
73
|
+
end
|
74
|
+
chan.on_timeout(10_000) { p "timeout" ; chan.close rescue nil }
|
75
|
+
chan.wait_end
|
76
|
+
end
|
77
|
+
```
|
78
|
+
|
79
|
+
Message Server:
|
80
|
+
```ruby
|
81
|
+
MServerAgent.run(2222,"localhost",22) do |chan|
|
82
|
+
chan.on_message { |mess| p mess ; "ok" }
|
83
|
+
chan.wait_end
|
84
|
+
end
|
85
|
+
```
|
64
86
|
|
65
87
|
Docs: http://rubydoc.info/gems/minitcp
|
66
88
|
|
@@ -126,13 +148,27 @@ UDP
|
|
126
148
|
* **send_datagram(host,port,message)** : create a socket, send mesage and close socket (ca'nt receive a reply)
|
127
149
|
* **send_datagram_on_socket(socket,host,port,message)** : use existant socket for send a message to ip:port
|
128
150
|
|
151
|
+
Messages
|
152
|
+
===
|
153
|
+
Serveur and client ```MServerAgent``` and ```MClientAgent``` define a 'agent ' which
|
154
|
+
can communicate by messages.
|
155
|
+
|
156
|
+
Messages are ```ruby-data.inspect```, max size is 1 MByte.
|
157
|
+
* MClientAgent.run(host,port) : connect to a MServerAgent, for communicate by message
|
158
|
+
* MServerAgent.run(port,host,max-connections) : message server
|
159
|
+
|
160
|
+
in Agent, socket are extended with this capability :
|
161
|
+
* socket.send_message(data)
|
162
|
+
* socket.on_message { |data| .... ; ret_data} will send ret_data to sender if not nil
|
163
|
+
|
164
|
+
See test.rb for an example
|
129
165
|
|
130
166
|
TODO
|
131
167
|
==
|
132
168
|
|
133
169
|
* Serial line
|
134
170
|
* more socket primitive
|
135
|
-
|
171
|
+
* messages Agent : use Marchal instead of inspect/eval ....
|
136
172
|
|
137
173
|
Tests case
|
138
174
|
==
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.15.0
|
data/lib/minitcp.rb
CHANGED
@@ -11,9 +11,9 @@ require 'gserver'
|
|
11
11
|
|
12
12
|
|
13
13
|
module SocketReactive
|
14
|
-
|
14
|
+
def strempty() ''.force_encoding Encoding::BINARY end
|
15
15
|
def data_readed=(v) @data_readed=v end
|
16
|
-
def data_readed() @data_readed||=
|
16
|
+
def data_readed() @data_readed||=strempty end
|
17
17
|
|
18
18
|
# read n byte, block the caller, return nil if socket if close
|
19
19
|
# if block is defined, it is yield with data, method return whith the value of yield
|
@@ -29,7 +29,7 @@ module SocketReactive
|
|
29
29
|
loop do
|
30
30
|
#p ["waiting ",s,data_readed]
|
31
31
|
sd=s>1024 ? 1024 : s
|
32
|
-
data=(self.recv(sd) rescue nil)
|
32
|
+
data=(self.recv(sd) rescue (p $!;nil))
|
33
33
|
#p "nrec: w#{sizemax}/ rec:#{(data||'').size} / #{sd} old=#{data_readed.size} /// #{(data||'').size<70 ? data : "."}"
|
34
34
|
if data && data.size>0
|
35
35
|
self.data_readed=self.data_readed+data
|
@@ -75,7 +75,7 @@ module SocketReactive
|
|
75
75
|
Thread.new() do
|
76
76
|
begin
|
77
77
|
if self.data_readed.size>0
|
78
|
-
buff,self.data_readed=self.data_readed,
|
78
|
+
buff,self.data_readed=self.data_readed,strempty
|
79
79
|
yield(buff)
|
80
80
|
end
|
81
81
|
loop do
|
@@ -317,16 +317,16 @@ end
|
|
317
317
|
# Run a TCP serveur, with a max connection simultaneous,
|
318
318
|
# When connection succes, call the bloc given with socket (extended by SocketReactive).
|
319
319
|
#
|
320
|
-
# MServer( "8080" , "0.0.0.0" ,1) { |socket| loop { p socket.gets} }
|
320
|
+
# MServer.new( "8080" , "0.0.0.0" ,1) { |socket| loop { p socket.gets} }
|
321
321
|
class MServer < GServer
|
322
322
|
def self.service(port,host,max,&b)
|
323
323
|
srv=new(port,host,max,&b)
|
324
|
-
srv.audit =
|
324
|
+
srv.audit = false
|
325
325
|
srv.start
|
326
326
|
srv
|
327
327
|
end
|
328
328
|
def initialize(port,host,max=1,&b)
|
329
|
-
super(port,host,max)
|
329
|
+
super(port,host,max,nil)
|
330
330
|
@bloc=b
|
331
331
|
end
|
332
332
|
def serve( io )
|
@@ -339,3 +339,43 @@ class MServer < GServer
|
|
339
339
|
end
|
340
340
|
end
|
341
341
|
|
342
|
+
##########################################################
|
343
|
+
# messages stream
|
344
|
+
##########################################################
|
345
|
+
|
346
|
+
module SocketMessage
|
347
|
+
def on_message(timeout=nil,&b)
|
348
|
+
on_n_receive(6) do |head|
|
349
|
+
len=head.to_i
|
350
|
+
received_n_timeout(len,10_000) do |data|
|
351
|
+
response=b.call(eval(data))
|
352
|
+
send(response) if response
|
353
|
+
end
|
354
|
+
end
|
355
|
+
end
|
356
|
+
def send_message(message)
|
357
|
+
data=message.inspect
|
358
|
+
send(("%6d" % data.size)+data,0)
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
class MClientAgent
|
363
|
+
def self.run(host,port,&b)
|
364
|
+
me=MClientAgent.new
|
365
|
+
MClient.run_continious(host,port,10_000) do |so|
|
366
|
+
so.extend(SocketMessage)
|
367
|
+
me.instance_eval { b.call(so) }
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
class MServerAgent
|
373
|
+
def self.run(port,host,n,&b)
|
374
|
+
me=MClientAgent.new
|
375
|
+
MServer.service( port , host ,n) do |so|
|
376
|
+
so.extend(SocketMessage)
|
377
|
+
me.instance_eval { b.call(so) }
|
378
|
+
end
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
data/samples/pxy.rb
ADDED
@@ -0,0 +1,429 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# LGPL
|
3
|
+
####################################################
|
4
|
+
# proxy.rb : pure tcp proxy, for dev/admin/fun :)
|
5
|
+
#
|
6
|
+
# Usage :
|
7
|
+
# > ruby proxy.rb target-hostname target-port [mode]
|
8
|
+
# mode= ascii/bin/none : style of printing
|
9
|
+
####################################################
|
10
|
+
# LGPL, Author: Regis d'Aubarede <regis.aubarede@gmail.com>
|
11
|
+
#
|
12
|
+
##################################################### start minitcp
|
13
|
+
|
14
|
+
##############################################################
|
15
|
+
# minitcp.rb
|
16
|
+
##############################################################
|
17
|
+
|
18
|
+
require 'thread'
|
19
|
+
require 'timeout'
|
20
|
+
require 'socket'
|
21
|
+
require 'gserver'
|
22
|
+
|
23
|
+
|
24
|
+
module SocketReactive
|
25
|
+
|
26
|
+
def data_readed=(v) @data_readed=v end
|
27
|
+
def data_readed() @data_readed||="" end
|
28
|
+
|
29
|
+
# read n byte, block the caller, return nil if socket if close
|
30
|
+
# if block is defined, it is yield with data, method return whith the value of yield
|
31
|
+
# if looping is true, the method loop until socket close, (or current thread is killed)
|
32
|
+
def receive_n_bytes(sizemax,looping=false,&b)
|
33
|
+
s=sizemax
|
34
|
+
if self.data_readed.size>=sizemax
|
35
|
+
buff,self.data_readed=self.data_readed[0..sizemax-1],self.data_readed[sizemax..-1]
|
36
|
+
buff=b.call(buff) if block_given?
|
37
|
+
return buff unless looping
|
38
|
+
end
|
39
|
+
s=sizemax-self.data_readed.size
|
40
|
+
loop do
|
41
|
+
#p ["waiting ",s,data_readed]
|
42
|
+
sd=s>1024 ? 1024 : s
|
43
|
+
data=(self.recv(sd) rescue (p $!;nil))
|
44
|
+
#p "nrec: w#{sizemax}/ rec:#{(data||'').size} / #{sd} old=#{data_readed.size} /// #{(data||'').size<70 ? data : "."}"
|
45
|
+
if data && data.size>0
|
46
|
+
self.data_readed=self.data_readed+data
|
47
|
+
s=sizemax-self.data_readed.size
|
48
|
+
if s<=0
|
49
|
+
buff,self.data_readed=self.data_readed,""
|
50
|
+
s=sizemax
|
51
|
+
buff=b.call(buff) if block_given?
|
52
|
+
return buff unless looping
|
53
|
+
end
|
54
|
+
else
|
55
|
+
close rescue nil
|
56
|
+
break # socket close
|
57
|
+
end
|
58
|
+
end #loop
|
59
|
+
end
|
60
|
+
# wait n byte or timeout. if block is defined, it is yielded with data
|
61
|
+
# return nil if timeout/socket closed, or data if no bloc, or yield value
|
62
|
+
def received_n_timeout(sizemax,timeout_ms,&b)
|
63
|
+
timeout(timeout_ms/1000.0) {
|
64
|
+
ret=receive_n_bytes(sizemax,false,&b)
|
65
|
+
return ret
|
66
|
+
}
|
67
|
+
rescue Timeout::Error
|
68
|
+
return nil
|
69
|
+
rescue Exception => e
|
70
|
+
$stdout.puts "#{e} :\n #{e.backtrace.join("\n ")}"
|
71
|
+
end
|
72
|
+
|
73
|
+
def received_any_timeout(sizemax,timeout_ms)
|
74
|
+
timeout(timeout_ms/1000.0) {
|
75
|
+
return recv(sizemax)
|
76
|
+
}
|
77
|
+
rescue Timeout::Error
|
78
|
+
return nil
|
79
|
+
rescue Exception => e
|
80
|
+
$stdout.puts "#{e} :\n #{e.backtrace.join("\n ")}"
|
81
|
+
end
|
82
|
+
|
83
|
+
# async wait and read data on socket, yield values readed,
|
84
|
+
# return thread spawned, which can be kill
|
85
|
+
def on_any_receive()
|
86
|
+
Thread.new() do
|
87
|
+
begin
|
88
|
+
if self.data_readed.size>0
|
89
|
+
buff,self.data_readed=self.data_readed,""
|
90
|
+
yield(buff)
|
91
|
+
end
|
92
|
+
loop do
|
93
|
+
data=(self.recv(64*1024) rescue nil)
|
94
|
+
data && data.size>0 ? yield(data) : break
|
95
|
+
end
|
96
|
+
rescue Exception => e
|
97
|
+
$stdout.puts "#{e} :\n #{e.backtrace.join("\n ")}"
|
98
|
+
end
|
99
|
+
close rescue nil
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
# async yield on received n bytes
|
105
|
+
# return thread spawned, which can be kill
|
106
|
+
def on_n_receive(sizemax=1,&b)
|
107
|
+
Thread.new() do
|
108
|
+
begin
|
109
|
+
receive_n_bytes(sizemax,true,&b)
|
110
|
+
rescue Exception => e
|
111
|
+
$stdout.puts "#{e} :\n #{e.backtrace.join("\n ")}"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# read until separator reached, block the caller, return nil if socket is close
|
117
|
+
# if block is defined, it is yield with data, method return whith the value of yield
|
118
|
+
# if looping is true, the method loop until socket close, (or current thread is killed)
|
119
|
+
# this read some extra data. they can be retrieve with in socket.data_readed.
|
120
|
+
# data_readed is use for next calls to receives_n_byte/receive_sep
|
121
|
+
def receive_sep(separator,sizemax=1024,looping=false,&b)
|
122
|
+
if self.data_readed.size>0
|
123
|
+
a=self.data_readed.split(separator,2)
|
124
|
+
while a.size>1
|
125
|
+
buff= a.size>2 ? a[0..-2] : a.first
|
126
|
+
self.data_readed=a.last
|
127
|
+
buff=b.call(buff) if block_given?
|
128
|
+
return buff unless looping
|
129
|
+
a=self.data_readed.split(separator,2)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
loop do
|
133
|
+
data=(self.recv(sizemax-self.data_readed.size) rescue nil)
|
134
|
+
if data && data.size>0
|
135
|
+
self.data_readed=self.data_readed+data
|
136
|
+
a=(self.data_readed).split(separator,2)
|
137
|
+
while a.size>1
|
138
|
+
buff= a.size>2 ? a[0..-2] : a.first
|
139
|
+
self.data_readed=a.last
|
140
|
+
buff=b.call(buff) if block_given?
|
141
|
+
return buff unless looping
|
142
|
+
a=(self.data_readed).split(separator,2)
|
143
|
+
end
|
144
|
+
else
|
145
|
+
close rescue nil
|
146
|
+
break
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# async yield on received data until end-buffer string
|
152
|
+
# end-buffer can be string or regexp (args of data.split(,2))
|
153
|
+
# return thread spawned, which can be kill
|
154
|
+
# this read some extra data. they can be retrieve with in socket.data_readed.
|
155
|
+
# data_readed is use for next calls to receives_n_byte/receive_sep
|
156
|
+
def on_receive_sep(separator,sizemax=1024,&b)
|
157
|
+
Thread.new() do
|
158
|
+
begin
|
159
|
+
receive_sep(separator,sizemax,looping=true,&b)
|
160
|
+
rescue Exception => e
|
161
|
+
$stdout.puts "#{e} :\n #{e.backtrace.join("\n ")}"
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# async yield after a duration, if socket is open
|
167
|
+
# return thread spawned, which can be kill
|
168
|
+
def after(duration_ms)
|
169
|
+
Thread.new() do
|
170
|
+
begin
|
171
|
+
sleep(duration_ms/1000.0)
|
172
|
+
yield unless self.connected?()
|
173
|
+
rescue Exception => e
|
174
|
+
$stdout.puts "#{e} :\n #{e.backtrace.join("\n ")}"
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
# async yield periodicaly, if socket is open
|
180
|
+
# return thread spawned, which can be kill
|
181
|
+
def on_timer(value=1000)
|
182
|
+
Thread.new() {
|
183
|
+
begin
|
184
|
+
nbtick=(value/TICK)+1
|
185
|
+
loop do
|
186
|
+
i=0
|
187
|
+
sleep(TICK/1000.0) while self.connected?() && (i+=1)<nbtick
|
188
|
+
self.connected?() ? yield() : break
|
189
|
+
end
|
190
|
+
rescue Exception => e
|
191
|
+
$stdout.puts "#{e} :\n #{e.backtrace.join("\n ")}"
|
192
|
+
end
|
193
|
+
}
|
194
|
+
end
|
195
|
+
|
196
|
+
# wait until curent socket is close.
|
197
|
+
def wait_end()
|
198
|
+
begin
|
199
|
+
loop do
|
200
|
+
sleep(TICK/1000.0) while (self.connected?() rescue nil)
|
201
|
+
break
|
202
|
+
end
|
203
|
+
rescue Exception => e
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# Test if a socket is open. (use socket.remote_address() !)
|
208
|
+
def connected?()
|
209
|
+
(self.remote_address rescue nil) ? true : false
|
210
|
+
end
|
211
|
+
# duration of sleep when active wait (wait_end,on_timer...)
|
212
|
+
TICK=600
|
213
|
+
|
214
|
+
def self.make_socket_reactive(socket)
|
215
|
+
socket.extend(SocketReactive)
|
216
|
+
socket.data_readed=""
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
# Assure connection to server, extend socket connection by SocketReactive module.
|
221
|
+
#
|
222
|
+
# MClient.run_one_shot("localhost",2200) do |socket| .. end.join
|
223
|
+
#
|
224
|
+
# MClient.run_continous("localhost",2200,6000) do |socket| .. end.join
|
225
|
+
#
|
226
|
+
class MClient
|
227
|
+
# maintain a conntection to a TCP serveur, sleep timer_interconnection_ms millisecondes
|
228
|
+
# beetwen each reconnections
|
229
|
+
def self.run_continious(host,port,timer_interconnection_ms,&b)
|
230
|
+
Thread.new do
|
231
|
+
loop { run_one_shot(host,port,&b).join ; sleep timer_interconnection_ms/1000.0 }
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
def self.run_continous(host,port,timer_interconnection,&b)
|
236
|
+
self.run_continious(host,port,timer_interconnection,&b)
|
237
|
+
end
|
238
|
+
|
239
|
+
# Connecte to a TCP server, call block with client socket if connection sucess.
|
240
|
+
# enssure close connection after end of block
|
241
|
+
def self.run_one_shot(host="localhost",port=80)
|
242
|
+
begin
|
243
|
+
sleep(0.03) # give some time for server ready (for test...)
|
244
|
+
socket = TCPSocket.new(host,port)
|
245
|
+
rescue
|
246
|
+
puts "not connected to #{host}:#{port}: " + $!.to_s
|
247
|
+
return (Thread.new {})
|
248
|
+
end
|
249
|
+
SocketReactive::make_socket_reactive(socket)
|
250
|
+
Thread.new do
|
251
|
+
begin
|
252
|
+
yield(socket)
|
253
|
+
rescue Exception => e
|
254
|
+
puts "#{e}\n #{e.backtrace.join("\n ")}"
|
255
|
+
ensure
|
256
|
+
socket.close() rescue nil
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
|
263
|
+
# Assure connection to server, extend socket connection by SocketReactive module.
|
264
|
+
#
|
265
|
+
# MClient.run_one_shot("localhost",2200) do |socket| .. end.join
|
266
|
+
#
|
267
|
+
# MClient.run_continous("localhost",2200,6000) do |socket| .. end.join
|
268
|
+
#
|
269
|
+
class UDPAgent
|
270
|
+
# maintain a conntection to a TCP serveur, sleep timer_interconnection_ms millisecondes
|
271
|
+
# beetwen each reconnections
|
272
|
+
def self.send_datagram(host,port,mess)
|
273
|
+
sock = UDPSocket.new
|
274
|
+
#p ["sock.send",mess, 0, host, port]
|
275
|
+
sock.send(mess, 0, host, port)
|
276
|
+
sock.close
|
277
|
+
end
|
278
|
+
def self.send_datagram_on_socket(socket,host,port,mess)
|
279
|
+
socket.send(mess, 0, host, port)
|
280
|
+
end
|
281
|
+
|
282
|
+
Thread.abort_on_exception=true
|
283
|
+
|
284
|
+
# send datagram on timer
|
285
|
+
def self.on_timer(periode,options)
|
286
|
+
Thread.new do
|
287
|
+
sleep periode/1000.0
|
288
|
+
sock = UDPSocket.new
|
289
|
+
if options[:port]
|
290
|
+
sock.bind("0.0.0.0", options[:port])
|
291
|
+
end
|
292
|
+
loop do
|
293
|
+
rep=IO.select([sock],nil,nil,periode/1000.0)
|
294
|
+
#puts "IO.SELECT => #{rep}"
|
295
|
+
if rep
|
296
|
+
Thread.new {
|
297
|
+
data,peer=sock.recvfrom(1024)
|
298
|
+
options[:on_receive].call(data,peer,sock)
|
299
|
+
} if options[:on_receive]
|
300
|
+
elsif options[:on_timer]
|
301
|
+
h=options[:on_timer].call()
|
302
|
+
self.send_datagram_on_socket(sock,h[:host], h[:port],h[:mess]) if h && h[:mess] && h[:host] && h[:port]
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
307
|
+
# recieved UDP datagramme, bloc can ellaborate a reply, which will be sending to client
|
308
|
+
def self.on_datagramme(host,port)
|
309
|
+
serv = UDPSocket.new
|
310
|
+
serv.bind(host, port)
|
311
|
+
Thread.new do
|
312
|
+
loop do
|
313
|
+
begin
|
314
|
+
Thread.new(*serv.recvfrom(1024)) do |data,peer| # peer=["AF_INET", 59340, "127.0.0.1", "127.0.0.1"]
|
315
|
+
proto,cli_port,srv_addr,cli_addr=*peer
|
316
|
+
response=yield(data,cli_addr,cli_port)
|
317
|
+
self.send_datagram_on_socket(serv,cli_addr,cli_port,response) if response
|
318
|
+
end
|
319
|
+
rescue Exception => e
|
320
|
+
puts "#{e}\n #{e.backtrace.join("\n ")}"
|
321
|
+
ensure
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
# Run a TCP serveur, with a max connection simultaneous,
|
329
|
+
# When connection succes, call the bloc given with socket (extended by SocketReactive).
|
330
|
+
#
|
331
|
+
# MServer.new( "8080" , "0.0.0.0" ,1) { |socket| loop { p socket.gets} }
|
332
|
+
class MServer < GServer
|
333
|
+
def self.service(port,host,max,&b)
|
334
|
+
srv=new(port,host,max,&b)
|
335
|
+
srv.audit = true
|
336
|
+
srv.start
|
337
|
+
srv
|
338
|
+
end
|
339
|
+
def initialize(port,host,max=1,&b)
|
340
|
+
super(port,host,max)
|
341
|
+
@bloc=b
|
342
|
+
end
|
343
|
+
def serve( io )
|
344
|
+
SocketReactive::make_socket_reactive(io)
|
345
|
+
begin
|
346
|
+
@bloc.call(io)
|
347
|
+
rescue Exception => e
|
348
|
+
puts "Error in Mserver block: #{e} :\n #{e.backtrace.join("\n ")}"
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
##########################################################
|
354
|
+
# messages stream
|
355
|
+
##########################################################
|
356
|
+
|
357
|
+
module SocketMessage
|
358
|
+
def on_message(timeout=nil,&b)
|
359
|
+
on_n_receive(6) do |head|
|
360
|
+
len=head.to_i
|
361
|
+
received_n_timeout(len,10_000) do |data|
|
362
|
+
response=b.call(eval(data))
|
363
|
+
send(response) if response
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|
367
|
+
def send_message(message)
|
368
|
+
data=message.inspect
|
369
|
+
send(("%6d" % data.size)+data,0)
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
class MClientAgent
|
374
|
+
def self.run(host,port,&b)
|
375
|
+
me=MClientAgent.new
|
376
|
+
MClient.run_continious(host,port,10_000) do |so|
|
377
|
+
so.extend(SocketMessage)
|
378
|
+
me.instance_eval { b.call(so) }
|
379
|
+
end
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
class MServerAgent
|
384
|
+
def self.run(port,host,n,&b)
|
385
|
+
me=MClientAgent.new
|
386
|
+
MServer.service( port , host ,n) do |so|
|
387
|
+
so.extend(SocketMessage)
|
388
|
+
me.instance_eval { b.call(so) }
|
389
|
+
end
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
##################################################### end minitcp
|
394
|
+
|
395
|
+
$host,$port,$opt=ARGV[0]||"localhost",ARGV[1]||80,ARGV[2]||"ascii"
|
396
|
+
puts "Server on port 2200, proxy to #{$host}:#{$port}..."
|
397
|
+
|
398
|
+
|
399
|
+
MServer.service(2200,"0.0.0.0",22) do |s_cli|
|
400
|
+
puts "> ======== client Connected ========"
|
401
|
+
srv=MClient.run_one_shot($host,$port) do |s_srv|
|
402
|
+
puts "< ======== server Concected ========"
|
403
|
+
s_srv.on_any_receive { |data| spy 1,data; s_cli.print data }
|
404
|
+
s_cli.on_any_receive { |data| spy 2,data; s_srv.print data}
|
405
|
+
s_srv.wait_end
|
406
|
+
s_cli.close rescue nil
|
407
|
+
end
|
408
|
+
s_cli.wait_end
|
409
|
+
p "end cli, stop proxy"
|
410
|
+
srv.kill
|
411
|
+
end
|
412
|
+
|
413
|
+
def spy(sens,data)
|
414
|
+
return if $opt=="none"
|
415
|
+
prefix=(sens==1 ? "< " : "> ")
|
416
|
+
if $opt=="ascii"
|
417
|
+
data.each_line {|line| puts "#{prefix}#{line.chomp}" }
|
418
|
+
else
|
419
|
+
data.chars.each_slice(16) do |aline|
|
420
|
+
a=(aline.map { |char| "%02X " % char.ord }).join.ljust(16*3)+prefix+
|
421
|
+
aline.map { |char| (char.ord>30 ? char : "~") }.join()
|
422
|
+
puts "#{prefix}#{a}"
|
423
|
+
end
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
sleep
|
428
|
+
|
429
|
+
|
data/samples/relay/README.md
CHANGED
@@ -26,16 +26,39 @@ Server ---------------> | proxy-relai | <------//--------| relai | -----------
|
|
26
26
|
internet server server-in-intranet intranet hosts
|
27
27
|
```
|
28
28
|
|
29
|
+
Plugin
|
30
|
+
======
|
31
|
+
|
32
|
+
Relai receive http request for an intranet server.
|
33
|
+
Plugin must be writing for find ip:port/path for the host target.
|
34
|
+
this can varying with http-subprotocole used.
|
35
|
+
|
36
|
+
occp plugin is the first plugin used :
|
37
|
+
* requests servied by this plugin are SOAP, header contain a field ```<ChargeBoxId>name-equipment</ChargeBoxId>```
|
38
|
+
* a local config file give url for each id
|
39
|
+
* the plugin will :
|
40
|
+
1) parse the request for finding the value of ChargeBoxId (regexp)
|
41
|
+
2) find ip:port/path for the itranet-server adressed
|
42
|
+
3) modify the path in the GET http command
|
29
43
|
|
30
44
|
Usage
|
31
45
|
=====
|
32
46
|
Extranet:
|
47
|
+
|
48
|
+
```
|
33
49
|
> ruby relaiproxy.rb proxyhttp proxy-hostname proxy-port
|
50
|
+
```
|
34
51
|
|
35
52
|
Intranet:
|
53
|
+
|
54
|
+
```
|
36
55
|
> vi relai_config.rb
|
56
|
+
```
|
57
|
+
|
58
|
+
```
|
37
59
|
> ruby relaiproxy.rb relai proxy-ip proxy-port plugin-name
|
60
|
+
```
|
38
61
|
|
39
|
-
(actualy ocpp is
|
62
|
+
(actualy 'ocpp' is only plugin disponible)
|
40
63
|
|
41
64
|
|
data/samples/relay/relaiproxy.rb
CHANGED
@@ -27,67 +27,106 @@ Server ---------------> | proxy-relai | <------//--------| relai | -----------
|
|
27
27
|
internet server server-in-intranet intranet hosts
|
28
28
|
=end
|
29
29
|
|
30
|
-
|
31
|
-
require_relative 'minitcp/lib/minitcp.rb'
|
30
|
+
require 'minitcp'
|
31
|
+
#require_relative 'minitcp/lib/minitcp.rb'
|
32
32
|
|
33
33
|
if ARGV.size<1
|
34
34
|
puts"Usage>"
|
35
|
-
puts" #{$0} type
|
35
|
+
puts" #{$0} type hostname port"
|
36
36
|
puts" #{$0} proxyhttp proxy-hostname proxy-port"
|
37
|
-
puts" #{$0} relai proxy-saia-ip proxy-
|
37
|
+
puts" #{$0} relai proxy-saia-ip proxy-port plugin"
|
38
38
|
exit(1)
|
39
39
|
end
|
40
40
|
|
41
41
|
$opt,$host,$port=ARGV[0]||"proxyhttp",ARGV[1]||"localhost",ARGV[2]||80
|
42
42
|
|
43
43
|
NBDIGITHEAD=8
|
44
|
-
QUEUE_SIZE=
|
44
|
+
QUEUE_SIZE=10
|
45
45
|
|
46
46
|
def sformat(socket,mess)
|
47
|
-
|
47
|
+
puts "sformat message len=#{mess.size} #{mess.inspect[0..30]}..."
|
48
|
+
data=("%-#{NBDIGITHEAD}d%s" % [mess.size,mess])
|
49
|
+
socket.send(data,0)
|
50
|
+
end
|
51
|
+
|
52
|
+
def sformat0(socket,mess)
|
53
|
+
data=("%-#{NBDIGITHEAD}d%s" % [mess.size,mess])
|
54
|
+
l=socket.send(data,0)
|
48
55
|
end
|
49
56
|
def receive(socket)
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
57
|
+
log "r1 len=#{NBDIGITHEAD} #{socket}"
|
58
|
+
resp_length= socket.receive_n_bytes(NBDIGITHEAD)
|
59
|
+
return nil unless resp_length
|
60
|
+
len =resp_length.strip.to_i
|
61
|
+
log "header: #{resp_length} => #{len}"
|
62
|
+
(len>0) ? socket.receive_n_bytes(len) : ""
|
63
|
+
end
|
64
|
+
def receive_to(socket,to=1000)
|
65
|
+
begin
|
66
|
+
timeout(to/1000.0) {
|
67
|
+
#log "r1 len=#{NBDIGITHEAD} #{socket}"
|
68
|
+
resp_length= socket.receive_n_bytes(NBDIGITHEAD)
|
69
|
+
return nil unless resp_length
|
70
|
+
len =resp_length.strip.to_i
|
71
|
+
#log "header: #{resp_length} => #{len}"
|
72
|
+
(len>0) ? socket.receive_n_bytes(len) : ""
|
73
|
+
}
|
74
|
+
rescue Exception => e
|
75
|
+
return(nil)
|
76
|
+
end
|
54
77
|
end
|
55
78
|
def log(t) puts "%10s | %s" % [Time.now.to_s,t] end
|
56
79
|
|
57
80
|
if $opt=="proxyhttp"
|
58
81
|
##################################################################################
|
59
|
-
## P R O X Y
|
82
|
+
## P R O X Y : extranet side
|
60
83
|
##################################################################################
|
61
84
|
|
62
85
|
$client_sockets ={}
|
63
86
|
$queue=Queue.new
|
64
87
|
############# Proxy serveur http saia >>> machine distante #######################
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
begin relai=$queue.pop end until $client_sockets[relai]
|
88
|
+
def relai_command(mess)
|
89
|
+
relai=nil
|
69
90
|
begin
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
log("wait response...")
|
80
|
-
response= (timeout(5) { receive(relai) } rescue nil)
|
81
|
-
log(response!=nil ? "response ok" : "timeout") unless response
|
82
|
-
s_cli.write(response ? response : "HTTP/1.0 500 NOK\r\n\r\n")
|
83
|
-
else
|
84
|
-
s_cli.write( "HTTP/1.0 501 NOK\r\n\r\n")
|
85
|
-
end
|
91
|
+
loop {
|
92
|
+
begin relai=$queue.pop end until $client_sockets[relai]
|
93
|
+
sformat(relai,"SDV")
|
94
|
+
break if receive_to(relai,1000)!=nil
|
95
|
+
}
|
96
|
+
log("getted relai #{relai}")
|
97
|
+
sformat(relai,mess)
|
98
|
+
log("wait response...")
|
99
|
+
receive_to(relai,9000)
|
86
100
|
ensure
|
87
|
-
$queue.push(relai)
|
101
|
+
$queue.push(relai) if relai
|
88
102
|
end
|
89
103
|
end
|
90
104
|
|
105
|
+
MServer.service($port.to_i,"0.0.0.0",22) do |s_cli|
|
106
|
+
log("telecommande")
|
107
|
+
timeout(10) {
|
108
|
+
begin
|
109
|
+
header=s_cli.receive_sep("\r\n\r\n")
|
110
|
+
#log("request header=#{header.inspect}")
|
111
|
+
if header.match(/^Content-Length: (\d+)/i) || "0"=~/(.)/
|
112
|
+
length=$1.strip.to_i
|
113
|
+
#log("length body==#{length}")
|
114
|
+
body= length>0 ? s_cli.receive_n_bytes(length) : ""
|
115
|
+
#log("request body=#{body.inspect}")
|
116
|
+
mess="#{header}\r\n\r\n#{body}"
|
117
|
+
log("transmit request...")
|
118
|
+
response=relai_command(mess)
|
119
|
+
log(response!=nil ? "response ok" : "timeout") unless response
|
120
|
+
s_cli.write(response ? response : "HTTP/1.0 500 NOK\r\n\r\n")
|
121
|
+
else
|
122
|
+
s_cli.write( "HTTP/1.0 501 NOK\r\n\r\n")
|
123
|
+
end
|
124
|
+
rescue Exception => e
|
125
|
+
puts "global error: #{e} #{}"
|
126
|
+
end
|
127
|
+
}
|
128
|
+
end
|
129
|
+
|
91
130
|
############# serveur http machine distante #######################
|
92
131
|
|
93
132
|
MServer.service($port.to_i+1,"0.0.0.0",22) do |s_cli|
|
@@ -99,17 +138,48 @@ MServer.service($port.to_i+1,"0.0.0.0",22) do |s_cli|
|
|
99
138
|
$client_sockets.delete(s_cli)
|
100
139
|
end
|
101
140
|
|
141
|
+
#-- signe de vie sur chaque socket du pool
|
142
|
+
|
143
|
+
Thread.new { loop {
|
144
|
+
begin relai=$queue.pop end until $client_sockets[relai]
|
145
|
+
#puts "testing #{relai}..."
|
146
|
+
sformat0(relai,"SDV")
|
147
|
+
receive_to(relai,1000)
|
148
|
+
sleep(0.1)
|
149
|
+
if $client_sockets[relai]
|
150
|
+
$queue.push(relai)
|
151
|
+
sleep 5
|
152
|
+
else
|
153
|
+
puts "testing socket pool: nok"
|
154
|
+
end
|
155
|
+
} }
|
102
156
|
else
|
103
157
|
|
104
158
|
##################################################################################
|
105
|
-
## R E L A Y
|
159
|
+
## R E L A Y : intranet side
|
106
160
|
##################################################################################
|
107
161
|
CONF="relai_config.data"
|
108
|
-
plugin=ARGV.last||"ocpp"
|
109
|
-
p plugin
|
162
|
+
$plugin=ARGV.last||"ocpp"
|
110
163
|
$config=nil
|
111
164
|
$configtime=nil
|
112
|
-
|
165
|
+
=begin
|
166
|
+
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
|
167
|
+
<soap:Header>
|
168
|
+
<chargeBoxIdentity xmlns="urn://Ocpp/Cp/2012/06/">TEST1</chargeBoxIdentity>
|
169
|
+
<Action xmlns="http://www.w3.org/2005/08/addressing">/ChangeAvailability</Action>
|
170
|
+
<MessageID xmlns="http://www.w3.org/2005/08/addressing">urn:uuid:4efc4b17-6fc0-4a91-bf0b-153ecbc03cd0</MessageID>
|
171
|
+
<To xmlns="http://www.w3.org/2005/08/addressing">http://localhost:7700/</To>
|
172
|
+
<ReplyTo xmlns="http://www.w3.org/2005/08/addressing">
|
173
|
+
<Address>http://www.w3.org/2005/08/addressing/anonymous</Address>
|
174
|
+
</ReplyTo>
|
175
|
+
</soap:Header>
|
176
|
+
<soap:Body><changeAvailabilityRequest xmlns="urn://Ocpp/Cp/2012/06/">
|
177
|
+
<connectorId>1</connectorId>
|
178
|
+
<type>Operative</type>
|
179
|
+
</changeAvailabilityRequest>
|
180
|
+
</soap:Body>
|
181
|
+
</soap:Envelope>
|
182
|
+
=end
|
113
183
|
def load_config()
|
114
184
|
return if $configtime!=nil && $configtime.to_f == File.mtime(CONF).to_f
|
115
185
|
begin
|
@@ -121,58 +191,87 @@ def load_config()
|
|
121
191
|
log("Error loading configration : #{$!}")
|
122
192
|
end
|
123
193
|
end
|
124
|
-
|
194
|
+
def verify_request_ocpp(request)
|
195
|
+
(log("request does not contain ChargeBoxId0");return false) unless request =~/chargeBoxIdentity/i
|
196
|
+
return(true)
|
197
|
+
end
|
125
198
|
def transform_ocpp(request)
|
126
199
|
load_config
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
200
|
+
(log("request does not contain valid ChargeBoxId");return nil) unless request =~ /chargeBoxIdentity.*?>(.*?)<\/.*?chargeBoxIdentity/
|
201
|
+
chargeboxIdentity=$1.strip
|
202
|
+
ip=$config[chargeboxIdentity] # [ip,port,path]
|
203
|
+
unless ip
|
204
|
+
p request
|
205
|
+
log("unknown CS #{chargeboxIdentity} in config")
|
206
|
+
nil
|
207
|
+
else
|
208
|
+
#request.gsub!(
|
209
|
+
# %r{(<To[^>]*>http://)([^<]*)(</To>)},
|
210
|
+
# "\\1#{ip[0]}:#{ip[1]}#{ip[2]}\\3"
|
211
|
+
#)
|
212
|
+
#puts request
|
213
|
+
ip+[request] # return [ip, port, path, request]
|
214
|
+
end
|
137
215
|
end
|
138
216
|
|
139
217
|
def transmit(ip,port=nil,path=nil,request=nil)
|
140
|
-
return "HTTP/1.0 404 NOK\r\n\r\n"
|
141
|
-
|
218
|
+
return "HTTP/1.0 404 NOK\r\n\r\n" unless request
|
219
|
+
|
220
|
+
#log("send data <#{request.inspect[0..70]}...\n > to #{ip}:#{port}#{path} len=#{request.size}")
|
142
221
|
response=nil
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
222
|
+
begin
|
223
|
+
timeout(5) do
|
224
|
+
MClient.run_one_shot(ip,port) { |client|
|
225
|
+
client.send(request,0)
|
226
|
+
header=client.receive_sep("\r\n\r\n")
|
227
|
+
if header=~/Content-Length: (\d+)/i && $1.to_i>0
|
228
|
+
log( "receive data with content-length #{$1}")
|
229
|
+
begin
|
230
|
+
data_response=client.received_timeout($1.to_i,3000)
|
231
|
+
rescue
|
232
|
+
log($!.to_s)
|
233
|
+
data_response="ERROR_TIMEOUT"
|
234
|
+
end
|
235
|
+
else
|
236
|
+
puts "until close"
|
237
|
+
rep=""
|
238
|
+
rep+=(a=client.receive_any(1000_000)) until a==nil
|
239
|
+
data_response=rep
|
240
|
+
end
|
241
|
+
#log( "data_response="+data_response)
|
242
|
+
response=header+"\r\n\r\n" + data_response
|
243
|
+
}.join
|
244
|
+
response
|
155
245
|
end
|
156
|
-
|
157
|
-
|
246
|
+
rescue Exception => e
|
247
|
+
p e
|
248
|
+
nil
|
249
|
+
end
|
158
250
|
end
|
159
251
|
|
160
252
|
QUEUE_SIZE.times do
|
161
253
|
MClient.run_continious($host,$port.to_i+1,1000) do |socket|
|
162
254
|
nbr=0
|
255
|
+
puts "connected..."
|
163
256
|
socket.on_n_receive(NBDIGITHEAD) do |header|
|
164
|
-
p header
|
257
|
+
#p header
|
165
258
|
nbr+=1
|
166
259
|
len=header.strip.to_i
|
167
260
|
#p len
|
168
261
|
request=socket.receive_n_bytes(len)
|
169
262
|
#p request
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
263
|
+
if request!="SDV" && send("verify_request_#{$plugin}",request)
|
264
|
+
ip,port,path,request=send("transform_#{$plugin}",request)
|
265
|
+
response= transmit(ip,port,path,request)
|
266
|
+
puts "\n\nreplay with len=#{(response||"").size} <<<\n#{(response.inspect||"")[0..150]}..#{(response.inspect||"")[-40..-1]}\n>>"
|
267
|
+
sformat( socket, response ? response : "NOK #{Time.now}\r\n")
|
268
|
+
else
|
269
|
+
sformat(socket,"OK")
|
270
|
+
print "."
|
271
|
+
end
|
174
272
|
end
|
175
273
|
socket.wait_end
|
274
|
+
puts "deconnected."
|
176
275
|
end
|
177
276
|
end
|
178
277
|
|
data/test.rb
CHANGED
@@ -42,7 +42,7 @@ if ARGV.size==0 || ARGV[0]=="2"
|
|
42
42
|
(socket.close; next) if s!="e"
|
43
43
|
size=data.to_i
|
44
44
|
puts " Server waiting for #{size} Bytes of data"
|
45
|
-
socket.
|
45
|
+
socket.received_n_timeout(size,100_000) do |data|
|
46
46
|
puts " Server recieved buffer : #{data.size} Bytes"
|
47
47
|
puts " emit ack..."
|
48
48
|
socket.send("o",0)
|
@@ -61,7 +61,7 @@ if ARGV.size==0 || ARGV[0]=="2"
|
|
61
61
|
s,data=data[0..(1024-1)],data[1024..-1]
|
62
62
|
socket.send s,0
|
63
63
|
end
|
64
|
-
p socket.
|
64
|
+
p socket.received_n_timeout(1,[size/1000,1000].max) ? "ack ok" : "!!! timeout ack"
|
65
65
|
#puts "\n"*7
|
66
66
|
}
|
67
67
|
p "end client"
|
@@ -189,4 +189,40 @@ if ARGV.size==0 || ARGV[0]=="5"
|
|
189
189
|
sleep 10
|
190
190
|
end
|
191
191
|
|
192
|
+
if ARGV.size==0 || ARGV[0]=="6"
|
193
|
+
th=MServerAgent.run(2222,"localhost",22) do |chan|
|
194
|
+
puts "sv: connect"
|
195
|
+
@lchan||={}
|
196
|
+
@lchan[chan]=chan
|
197
|
+
chan.on_message do |mess|
|
198
|
+
puts "sv: broadcast #{mess.inspect}..."
|
199
|
+
@lchan.keys.each {|chan1| chan1.send_message(mess) if chan1!=chan }
|
200
|
+
nil
|
201
|
+
end
|
202
|
+
chan.wait_end
|
203
|
+
@lchan.delete(chan)
|
204
|
+
end
|
205
|
+
lth=[]
|
206
|
+
5.times {
|
207
|
+
puts "####################### Run Client ########################"
|
208
|
+
lth << MClientAgent.run("localhost",2222) do |chan|
|
209
|
+
nb=0
|
210
|
+
chan.on_timer(100*rand(5..15)) {
|
211
|
+
chan.send_message(["C",1,2,1.2,Time.now.to_f,true])
|
212
|
+
nb+=1
|
213
|
+
(chan.close rescue nil)if nb>50
|
214
|
+
}
|
215
|
+
chan.on_message { |mess| p "cli: receive: #{mess.inspect}" ; nil}
|
216
|
+
chan.wait_end
|
217
|
+
puts "client closed"
|
218
|
+
end
|
219
|
+
sleep rand(1..2)
|
220
|
+
}
|
221
|
+
sleep 10
|
222
|
+
puts "\n\n############# Kill all agents...\n\n"
|
223
|
+
lth.each { |th| th.kill}
|
224
|
+
th.shutdown
|
225
|
+
sleep 2
|
226
|
+
end
|
227
|
+
|
192
228
|
puts "Test End !"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: minitcp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.15.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Regis d'Aubarede
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-04-02 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |
|
14
14
|
A DSL for programming little Tcp client and server
|
@@ -18,25 +18,24 @@ extensions: []
|
|
18
18
|
extra_rdoc_files: []
|
19
19
|
files:
|
20
20
|
- CHANGELOG.txt
|
21
|
-
- lib/minitcp.rb
|
22
21
|
- LICENSE
|
23
|
-
- minitcp.gemspec
|
24
|
-
- Rakefile.rb
|
25
22
|
- README.md
|
23
|
+
- Rakefile.rb
|
24
|
+
- VERSION
|
25
|
+
- lib/minitcp.rb
|
26
|
+
- minitcp.gemspec
|
27
|
+
- samples/README.md
|
26
28
|
- samples/name_server.rb
|
27
|
-
- samples/pingpongplot.rb
|
28
|
-
- samples/plot.rb
|
29
29
|
- samples/proxy.rb
|
30
|
-
- samples/
|
31
|
-
- samples/relay
|
30
|
+
- samples/pxy.rb
|
31
|
+
- samples/relay.rb
|
32
32
|
- samples/relay/README.md
|
33
|
-
- samples/relay/
|
33
|
+
- samples/relay/c.rb
|
34
34
|
- samples/relay/relai_config.data
|
35
|
-
- samples/relay.rb
|
35
|
+
- samples/relay/relaiproxy.rb
|
36
36
|
- samples/spdy.rb
|
37
37
|
- samples/statcpu.rb
|
38
38
|
- test.rb
|
39
|
-
- VERSION
|
40
39
|
homepage: https://github.com/glurp/minitcp
|
41
40
|
licenses:
|
42
41
|
- LGPL
|
@@ -57,15 +56,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
57
56
|
version: '0'
|
58
57
|
requirements: []
|
59
58
|
rubyforge_project:
|
60
|
-
rubygems_version: 2.
|
59
|
+
rubygems_version: 2.4.6
|
61
60
|
signing_key:
|
62
61
|
specification_version: 3
|
63
62
|
summary: A DSL for programming little Tcp client and server
|
64
63
|
test_files:
|
65
64
|
- samples/name_server.rb
|
66
|
-
- samples/pingpongplot.rb
|
67
|
-
- samples/plot.rb
|
68
65
|
- samples/proxy.rb
|
66
|
+
- samples/pxy.rb
|
69
67
|
- samples/README.md
|
70
68
|
- samples/relay.rb
|
71
69
|
- samples/spdy.rb
|
data/samples/pingpongplot.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
# LGPL, Author: Regis d'Aubarede <regis.aubarede@gmail.com>
|
2
|
-
#################################################################
|
3
|
-
# pingpongplot.rb : measure pingpong time on google, plot it
|
4
|
-
#
|
5
|
-
# Usage :
|
6
|
-
# > ruby pingpongplot.rb | ruby plot.rb 0 0 300 pingpong auto
|
7
|
-
#################################################################
|
8
|
-
require_relative '../lib/minitcp.rb'
|
9
|
-
|
10
|
-
|
11
|
-
$stdout.sync=true
|
12
|
-
|
13
|
-
MClient.run_continious("google.com",80,100) do |socket|
|
14
|
-
s=Time.now.to_f
|
15
|
-
socket.on_receive_sep("\r\n") do |data|
|
16
|
-
$stdout.puts("#{(Time.now.to_f-s)*1000}")
|
17
|
-
socket.close rescue nil
|
18
|
-
Thread.current.kill
|
19
|
-
end
|
20
|
-
s=Time.now.to_f
|
21
|
-
socket.print "GET /blabla HTTP/1.0\r\n\r\n"
|
22
|
-
socket.wait_end
|
23
|
-
end
|
24
|
-
|
25
|
-
|
26
|
-
sleep
|
data/samples/plot.rb
DELETED
@@ -1,190 +0,0 @@
|
|
1
|
-
# LGPL
|
2
|
-
###############################################################
|
3
|
-
# plot.rb plot data(s) of stdin to Gui display
|
4
|
-
# Usage:
|
5
|
-
# > vmstat 1 | ruby plot.rb -2 0-value 100%-value cpu -- 10 0 5000 io auto
|
6
|
-
# ^input-column ^label ^in-column .. ^auto-scale
|
7
|
-
#
|
8
|
-
###############################################################
|
9
|
-
|
10
|
-
require 'Ruiby'
|
11
|
-
$bgcolor=::Gdk::Color.parse("#023")
|
12
|
-
$fgcolor=[
|
13
|
-
::Gdk::Color.parse("#FFAA00"),
|
14
|
-
::Gdk::Color.parse("#99DDFF"),
|
15
|
-
::Gdk::Color.parse("#00FF00"),
|
16
|
-
::Gdk::Color.parse("#0000FF"),
|
17
|
-
::Gdk::Color.parse("#FFFF00"),
|
18
|
-
::Gdk::Color.parse("#00FFFF"),
|
19
|
-
::Gdk::Color.parse("#FF00FF"),
|
20
|
-
::Gdk::Color.parse("#999"),
|
21
|
-
]
|
22
|
-
class Measure
|
23
|
-
class << self
|
24
|
-
def create(argv)
|
25
|
-
noc=argv.shift.to_i
|
26
|
-
y0=(argv.shift||"0.0").to_f
|
27
|
-
y1=(argv.shift||"100.0").to_f
|
28
|
-
label=argv.shift||"?"
|
29
|
-
autoscale=argv.size>0
|
30
|
-
@lcurve||=[]
|
31
|
-
@lcurve << Measure.new(noc,y0,y1,label,autoscale)
|
32
|
-
@lcurve.size-1
|
33
|
-
end
|
34
|
-
def add(noc,y0,y1,label,autoscale)
|
35
|
-
@lcurve << Measure.new(noc,y0,y1,label,autoscale)
|
36
|
-
@lcurve.size-1
|
37
|
-
end
|
38
|
-
def scan_line(line)
|
39
|
-
nums=line.scan(/[\d+.]+/)
|
40
|
-
@lcurve.each { |m| m.register_value(nums) }
|
41
|
-
end
|
42
|
-
def add_value(index,value)
|
43
|
-
@lcurve[index].register_value(value)
|
44
|
-
end
|
45
|
-
def draw_measures(ctx)
|
46
|
-
@lcurve.each_with_index { |m,index| m.plot_curve(index,ctx) }
|
47
|
-
@lcurve.each_with_index { |m,index| m.plot_label(index,ctx) }
|
48
|
-
end
|
49
|
-
end
|
50
|
-
def initialize(noc,min,max,label,auto_scale)
|
51
|
-
@noc=noc
|
52
|
-
@div,@offset=calc_coef(min,0.0,max,1.0)
|
53
|
-
@name=label
|
54
|
-
@value= 0
|
55
|
-
@curve=[]
|
56
|
-
@label=@name
|
57
|
-
@autoscale=auto_scale
|
58
|
-
end
|
59
|
-
def register_value(data)
|
60
|
-
if data.is_a? Array
|
61
|
-
svalue=data[@noc]
|
62
|
-
return if !svalue || svalue !~ /[\d.]+/
|
63
|
-
@value=svalue.to_f
|
64
|
-
else
|
65
|
-
@value=data
|
66
|
-
end
|
67
|
-
@label = "%s %5.2f" % [@name,@value]
|
68
|
-
v= @value * @div + @offset
|
69
|
-
py=[0.0,(H-HHEAD)*1.0,(H-HHEAD)*(1.0-v)].sort[1]+HHEAD
|
70
|
-
@curve << [W+PAS,py,v,@value]
|
71
|
-
@curve.select! {|pt| pt[0]-=PAS; pt[0]>=0}
|
72
|
-
p [i,@value,v,py] if $DEBUG
|
73
|
-
auto_scale if @autoscale && @curve.size>5
|
74
|
-
end
|
75
|
-
def auto_scale()
|
76
|
-
min,max=@curve.minmax_by {|pt| pt[2]}
|
77
|
-
if min!=max && (min[2]<-0.01 || max[2]>1.01)
|
78
|
-
p "correction1 #{@name} #{min} // #{max}"
|
79
|
-
@div,@offset=calc_coef(min[3],0.0,max[3],1.0)
|
80
|
-
@curve.each {|a| a[2]=a[3]*@div+@offset ; a[1] = (H-HHEAD)*(1-a[2])}
|
81
|
-
elsif (d=(max[2]-min[2]))< 0.1 && (@curve.size-1) >= W/PAS && d>0.0001
|
82
|
-
p "correction2 #{@name} #{min} // #{max}"
|
83
|
-
@div,@offset=calc_coef(min[3],min[2]-3*d,max[3],max[2]+3*d)
|
84
|
-
@curve.each {|a| a[2]=a[3]*@div+@offset ; a[1] = (H-HHEAD)*(1.0-a[2])}
|
85
|
-
end
|
86
|
-
end
|
87
|
-
def calc_coef(x0,y0,x1,y1)
|
88
|
-
y0=[0.0,1.0,y0].sort[1]
|
89
|
-
y1=[0.0,1.0,y1].sort[1]
|
90
|
-
a=1.0*(y0-y1)/(x0-x1)
|
91
|
-
b= (y0+y1-(x0+x1)*a)/2
|
92
|
-
[a,b]
|
93
|
-
end
|
94
|
-
def plot_curve(index,ctx)
|
95
|
-
return if @curve.size<2
|
96
|
-
a,*l=@curve
|
97
|
-
style(ctx,3,$fgcolor.last) ; draw(ctx,a,l)
|
98
|
-
style(ctx,1,$fgcolor[index]) ; draw(ctx,a,l)
|
99
|
-
end
|
100
|
-
def style(ctx,width,color)
|
101
|
-
ctx.set_line_width(width)
|
102
|
-
ctx.set_source_rgba(color.red/65000.0,color.green/65000.0,color.blue/65000.0, 1.0)
|
103
|
-
end
|
104
|
-
def draw(ctx,h,t)
|
105
|
-
ctx.move_to(h.first,h[1])
|
106
|
-
t.each {|x,y,*q| ctx.line_to(x,y) }
|
107
|
-
ctx.stroke
|
108
|
-
end
|
109
|
-
def plot_label(index,ctx)
|
110
|
-
style(ctx,3,$fgcolor[index])
|
111
|
-
ctx.move_to(5+60*index,HHEAD-5)
|
112
|
-
ctx.show_text(@label)
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
|
117
|
-
def run(app)
|
118
|
-
$str=$stdin.gets
|
119
|
-
if $str
|
120
|
-
p $str if $DEBUG
|
121
|
-
Measure.scan_line($str)
|
122
|
-
gui_invoke { @cv.redraw }
|
123
|
-
else
|
124
|
-
exit!(0)
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
def run_window()
|
129
|
-
Ruiby.app width: W, height: H, title: "Curve" do
|
130
|
-
stack do
|
131
|
-
@cv=canvas(W,H) do
|
132
|
-
on_canvas_draw { |w,ctx| expose(w,ctx) }
|
133
|
-
end
|
134
|
-
popup(@cv) do
|
135
|
-
pp_item(" Plot ") { }
|
136
|
-
pp_separator
|
137
|
-
pp_item("htop") { system("lxterminal", "-e", "htop") }
|
138
|
-
pp_item("Gnome Monitor") { Process.spawn("gnome-system-monitor") }
|
139
|
-
pp_item("Terminal") { system("lxterminal") }
|
140
|
-
pp_separator
|
141
|
-
pp_item("Exit") { ask("Exit ?") && exit(0) }
|
142
|
-
end
|
143
|
-
end
|
144
|
-
chrome(false)
|
145
|
-
move($posxy[0],$posxy[1])
|
146
|
-
@ow,@oh=size
|
147
|
-
def expose(cv,ctx)
|
148
|
-
ctx.set_source_rgba($bgcolor.red/65000.0, $bgcolor.green/65000.0, $bgcolor.blue/65000.0, 1)
|
149
|
-
ctx.rectangle(0,0,W,H)
|
150
|
-
ctx.fill()
|
151
|
-
ctx.set_source_rgba($bgcolor.red/65000.0, $bgcolor.green/65000.0, 05+$bgcolor.blue/65000.0, 0.3)
|
152
|
-
ctx.rectangle(0,0,W,HHEAD)
|
153
|
-
ctx.fill()
|
154
|
-
Measure.draw_measures(ctx)
|
155
|
-
(puts "source modified!!!";exit!(0)) if File.mtime(__FILE__)!=$mtime
|
156
|
-
end
|
157
|
-
$mtime=File.mtime(__FILE__)
|
158
|
-
|
159
|
-
Thread.new(self) { |app| loop { run(app) } }
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
############################### Main #################################
|
164
|
-
|
165
|
-
if $0==__FILE__
|
166
|
-
trap("TERM") { exit!(0) }
|
167
|
-
|
168
|
-
PAS=2
|
169
|
-
HHEAD=20
|
170
|
-
$posxy=[0,0]
|
171
|
-
|
172
|
-
if ARGV.size>=2 && ARGV[0]=="--pos"
|
173
|
-
_,posxy=ARGV.shift,ARGV.shift
|
174
|
-
$posxy=posxy.split(/[x,:]/).map(&:to_i)
|
175
|
-
end
|
176
|
-
if ARGV.size>=2 && ARGV[0]=="--dim"
|
177
|
-
_,geom=ARGV.shift,ARGV.shift
|
178
|
-
W,H=geom.split(/[x,:]/).map(&:to_i)
|
179
|
-
else
|
180
|
-
W,H=200,100
|
181
|
-
end
|
182
|
-
|
183
|
-
while ARGV.size>0
|
184
|
-
argv=[]
|
185
|
-
argv << ARGV.shift while ARGV.size>0 && ARGV.first!="--"
|
186
|
-
Measure.create(argv)
|
187
|
-
ARGV.shift if ARGV.size>0 && ARGV.first=="--"
|
188
|
-
end
|
189
|
-
run_window
|
190
|
-
end
|