orion6_rep 0.2.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/orion6_rep/change_ip.rb +54 -0
- data/lib/orion6_rep/clock_time/get.rb +98 -0
- data/lib/orion6_rep/clock_time/set.rb +96 -0
- data/lib/orion6_rep/clock_time.rb +31 -0
- data/lib/orion6_rep/command.rb +176 -0
- data/lib/orion6_rep/communication.rb +89 -0
- data/lib/orion6_rep/detect_reps.rb +86 -0
- data/lib/orion6_rep/employee_get.rb +112 -0
- data/lib/orion6_rep/employee_quantity_get.rb +81 -0
- data/lib/orion6_rep/employee_set.rb +104 -0
- data/lib/orion6_rep/employer_get.rb +84 -0
- data/lib/orion6_rep/employer_set.rb +90 -0
- data/lib/orion6_rep/get_serial_number.rb +64 -0
- data/lib/orion6_rep/interface.rb +55 -0
- data/lib/orion6_rep/mockup.rb +118 -0
- data/lib/orion6_rep/multi_message_command.rb +113 -0
- data/lib/orion6_rep/record_id_get.rb +79 -0
- data/lib/orion6_rep/records_get.rb +89 -0
- data/lib/orion6_rep/version.rb +3 -0
- data/lib/orion6_rep.rb +199 -0
- data/test/afd_file +11 -0
- data/test/external/detect_reps_test.rb +28 -0
- data/test/external/employee_test.rb +100 -0
- data/test/external/employer_test.rb +57 -0
- data/test/external/get_serial_test.rb +31 -0
- data/test/external/record_get_test.rb +32 -0
- data/test/external/time_test.rb +84 -0
- data/test/test_helper.rb +25 -0
- data/test/time_clock.rb +13 -0
- data/test/unit/mockup_test.rb +154 -0
- metadata +125 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5395b094d49fd9ba05205ee1601a2423a0404de0
|
4
|
+
data.tar.gz: 8bd4bc765a14e7bc65b8d36661c9b79a56df12d1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7c1e613984f180b00ac2e3560efe239e87effa0e3bccf04c22beb5d63053bf285caa6f01f76e1fbd48f68e82dd03606b6e5d3708100bccefa1eca6e2fdbb9ea9
|
7
|
+
data.tar.gz: cb38f0d09d6e2eb820515b96dc5a071ef4ba0bef04201217ba0da8caf51c724f2a065349ca0b827ce7df0918d037a9dd1e34fc0961cad00e39ac305ed8c6156a
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Controle de Horas - Sistema para gestão de horas trabalhadas
|
3
|
+
# Copyright (C) 2009 O.S. Systems Softwares Ltda.
|
4
|
+
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU Affero General Public License as
|
7
|
+
# published by the Free Software Foundation, either version 3 of the
|
8
|
+
# License, or (at your option) any later version.
|
9
|
+
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU Affero General Public License for more details.
|
14
|
+
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
# Rua Clóvis Gularte Candiota 132, Pelotas-RS, Brasil.
|
19
|
+
# e-mail: contato@ossystems.com.br
|
20
|
+
|
21
|
+
require 'socket'
|
22
|
+
require 'ipaddr'
|
23
|
+
require 'orion6_rep/interface'
|
24
|
+
|
25
|
+
module Orion6Rep
|
26
|
+
class ChangeIp
|
27
|
+
UDP_PORT = 65535
|
28
|
+
|
29
|
+
def initialize(interface, new_ip, rep_data)
|
30
|
+
@broadcast_address = Orion6Rep::Interface.broadcast_address(interface)
|
31
|
+
raise "Network interface '#{interface}' not found or doesn't have a broadcast address" if @broadcast_address.nil?
|
32
|
+
|
33
|
+
@new_ip = IPAddr.new(new_ip)
|
34
|
+
# TODO: find what the REP data actually is
|
35
|
+
@rep_data = rep_data
|
36
|
+
@payload = prepare_payload_data
|
37
|
+
@socket = UDPSocket.new
|
38
|
+
@socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, true)
|
39
|
+
end
|
40
|
+
|
41
|
+
def execute
|
42
|
+
@socket.send(@payload, 0, @broadcast_address, UDP_PORT)
|
43
|
+
responses = IO.select([@socket], nil, nil, 1)
|
44
|
+
raw_data, socket_data = responses.first.first.recvfrom(1)
|
45
|
+
rep_current_ip = IPAddr.new(socket_data.last)
|
46
|
+
return (rep_current_ip == @new_ip ? true : execute)
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
def prepare_payload_data
|
51
|
+
@rep_data + "//" + @new_ip.to_s
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Controle de Horas - Sistema para gestão de horas trabalhadas
|
3
|
+
# Copyright (C) 2009 O.S. Systems Softwares Ltda.
|
4
|
+
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU Affero General Public License as
|
7
|
+
# published by the Free Software Foundation, either version 3 of the
|
8
|
+
# License, or (at your option) any later version.
|
9
|
+
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU Affero General Public License for more details.
|
14
|
+
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
# Rua Clóvis Gularte Candiota 132, Pelotas-RS, Brasil.
|
19
|
+
# e-mail: contato@ossystems.com.br
|
20
|
+
|
21
|
+
require "orion6_rep/clock_time"
|
22
|
+
|
23
|
+
module Orion6Rep
|
24
|
+
class ClockTime::Get < ClockTime
|
25
|
+
def initialize(equipment_number, host_address, tcp_port = 3000)
|
26
|
+
@equipment_number = equipment_number
|
27
|
+
@host_address = host_address
|
28
|
+
@tcp_port = tcp_port
|
29
|
+
@reponse_size = 12
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
GET_TIME_COMMAND = 146
|
34
|
+
GET_TIME_FIELD_QUANTITY = 0
|
35
|
+
|
36
|
+
def get_command
|
37
|
+
GET_TIME_COMMAND
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_field_quantity
|
41
|
+
GET_TIME_FIELD_QUANTITY
|
42
|
+
end
|
43
|
+
|
44
|
+
def generate_command_data
|
45
|
+
[]
|
46
|
+
end
|
47
|
+
|
48
|
+
def get_data_from_response(payload)
|
49
|
+
# the time comes in a array of unsigned integers, using the following
|
50
|
+
# format. The purpose of the last byte is unknown, but it is probably
|
51
|
+
# some form of data check.
|
52
|
+
#
|
53
|
+
# Example:
|
54
|
+
# | current time | DST Start | DST End |
|
55
|
+
# [yy, mm, dd, hh, mm, yy, mm, dd, yy, mm, dd]
|
56
|
+
# [11, 1, 21, 15, 17, 10, 10, 17, 11, 2, 20]
|
57
|
+
#
|
58
|
+
# These would be:
|
59
|
+
# - Current Time: 21/01/2011 15:17
|
60
|
+
# - DST Start: 17/10/2010
|
61
|
+
# - DST Start: 20/02/2011
|
62
|
+
|
63
|
+
time_payload = payload.unpack("C5")
|
64
|
+
dst_start_payload = payload[5..-1].unpack("C3")
|
65
|
+
dst_end_payload = payload[8..-1].unpack("C3")
|
66
|
+
|
67
|
+
time = parse_time(time_payload)
|
68
|
+
|
69
|
+
isDstOn = dst_start_payload.any?{|d| d > 0}
|
70
|
+
|
71
|
+
if isDstOn
|
72
|
+
start_dst = parse_date(dst_start_payload)
|
73
|
+
end_dst = parse_date(dst_end_payload)
|
74
|
+
end
|
75
|
+
[time, start_dst, end_dst]
|
76
|
+
end
|
77
|
+
|
78
|
+
def parse_date(date_array)
|
79
|
+
year = defineCentury(date_array[0].ord)
|
80
|
+
month = date_array[1].ord
|
81
|
+
day = date_array[2].ord
|
82
|
+
Date.civil(year,month,day)
|
83
|
+
end
|
84
|
+
|
85
|
+
def parse_time(date_array)
|
86
|
+
year = defineCentury(date_array[0].ord)
|
87
|
+
month = date_array[1].ord
|
88
|
+
day = date_array[2].ord
|
89
|
+
hour = date_array[3].ord
|
90
|
+
minute = date_array[4].ord
|
91
|
+
Time.local(year,month,day,hour,minute)
|
92
|
+
end
|
93
|
+
|
94
|
+
def defineCentury(year)
|
95
|
+
year > 79 ? year + 1900 : year + 2000
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# Controle de Horas - Sistema para gestão de horas trabalhadas
|
2
|
+
# Copyright (C) 2009 O.S. Systems Softwares Ltda.
|
3
|
+
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Affero General Public License as
|
6
|
+
# published by the Free Software Foundation, either version 3 of the
|
7
|
+
# License, or (at your option) any later version.
|
8
|
+
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU Affero General Public License for more details.
|
13
|
+
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
# Rua Clóvis Gularte Candiota 132, Pelotas-RS, Brasil.
|
18
|
+
# e-mail: contato@ossystems.com.br
|
19
|
+
|
20
|
+
require "orion6_rep/clock_time"
|
21
|
+
|
22
|
+
module Orion6Rep
|
23
|
+
class ClockTime::Set < ClockTime
|
24
|
+
def initialize(time, start_dst, end_dst, equipment_number, host_address, tcp_port = 3000)
|
25
|
+
if (start_dst.nil? and end_dst.is_a?(Date) or
|
26
|
+
start_dst.is_a?(Date) and end_dst.nil?)
|
27
|
+
raise "Both start and end DST dates must be dates or nil"
|
28
|
+
end
|
29
|
+
|
30
|
+
@time = time
|
31
|
+
@start_dst = start_dst
|
32
|
+
@end_dst = end_dst
|
33
|
+
@equipment_number = equipment_number
|
34
|
+
@host_address = host_address
|
35
|
+
@tcp_port = tcp_port
|
36
|
+
@reponse_size = 0
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
SET_TIME_COMMAND = 130
|
41
|
+
SET_TIME_FIELD_QUANTITY = 1
|
42
|
+
|
43
|
+
def get_time
|
44
|
+
@time
|
45
|
+
end
|
46
|
+
|
47
|
+
def get_start_dst
|
48
|
+
@start_dst
|
49
|
+
end
|
50
|
+
|
51
|
+
def get_end_dst
|
52
|
+
@end_dst
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_command
|
56
|
+
SET_TIME_COMMAND
|
57
|
+
end
|
58
|
+
|
59
|
+
def get_field_quantity
|
60
|
+
SET_TIME_FIELD_QUANTITY
|
61
|
+
end
|
62
|
+
|
63
|
+
def generate_command_data
|
64
|
+
data = get_time_as_data_param(get_time)
|
65
|
+
|
66
|
+
start_dst = get_start_dst
|
67
|
+
end_dst = get_end_dst
|
68
|
+
if start_dst and end_dst
|
69
|
+
data += get_date_as_data_param(start_dst)
|
70
|
+
data += get_date_as_data_param(end_dst)
|
71
|
+
else
|
72
|
+
data += [0, 0, 0, 0, 0, 0] # if no DST is specified just send zeros
|
73
|
+
end
|
74
|
+
data << crc_check(data)
|
75
|
+
data
|
76
|
+
end
|
77
|
+
|
78
|
+
def get_date_as_data_param(date)
|
79
|
+
year = date.year % 100 # years must be of 2 digits in the clock
|
80
|
+
month = date.month
|
81
|
+
day = date.day
|
82
|
+
[year, month, day]
|
83
|
+
end
|
84
|
+
|
85
|
+
def get_time_as_data_param(time)
|
86
|
+
data = get_date_as_data_param(time)
|
87
|
+
data << time.hour
|
88
|
+
data << time.min
|
89
|
+
data
|
90
|
+
end
|
91
|
+
|
92
|
+
def get_data_from_response(payload)
|
93
|
+
true
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# Controle de Horas - Sistema para gestão de horas trabalhadas
|
2
|
+
# Copyright (C) 2009 O.S. Systems Softwares Ltda.
|
3
|
+
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Affero General Public License as
|
6
|
+
# published by the Free Software Foundation, either version 3 of the
|
7
|
+
# License, or (at your option) any later version.
|
8
|
+
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU Affero General Public License for more details.
|
13
|
+
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
# Rua Clóvis Gularte Candiota 132, Pelotas-RS, Brasil.
|
18
|
+
# e-mail: contato@ossystems.com.br
|
19
|
+
|
20
|
+
require "orion6_rep/command"
|
21
|
+
|
22
|
+
module Orion6Rep
|
23
|
+
class ClockTime < Command
|
24
|
+
private
|
25
|
+
TIME_FIELD_SIZE = 11
|
26
|
+
|
27
|
+
def get_field_size
|
28
|
+
TIME_FIELD_SIZE
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Controle de Horas - Sistema para gestão de horas trabalhadas
|
3
|
+
# Copyright (C) 2009 O.S. Systems Softwares Ltda.
|
4
|
+
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU Affero General Public License as
|
7
|
+
# published by the Free Software Foundation, either version 3 of the
|
8
|
+
# License, or (at your option) any later version.
|
9
|
+
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU Affero General Public License for more details.
|
14
|
+
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
# Rua Clóvis Gularte Candiota 132, Pelotas-RS, Brasil.
|
19
|
+
# e-mail: contato@ossystems.com.br
|
20
|
+
|
21
|
+
require "orion6_rep/communication"
|
22
|
+
|
23
|
+
module Orion6Rep
|
24
|
+
class Command
|
25
|
+
def execute
|
26
|
+
# first set the header:
|
27
|
+
command_data = generate_header
|
28
|
+
|
29
|
+
# now comes the data:
|
30
|
+
command_data += generate_command_data
|
31
|
+
|
32
|
+
# now send it!
|
33
|
+
response = Communication.communicate(get_host_address, get_tcp_port, command_data, get_expected_response_size, get_timeout_time, get_max_attempts)
|
34
|
+
|
35
|
+
# check everything:
|
36
|
+
check_response_header(response)
|
37
|
+
check_response_payload(response)
|
38
|
+
|
39
|
+
# and then get and process the response payload:
|
40
|
+
payload = get_response_payload(response)
|
41
|
+
return get_data_from_response(payload)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
# TODO: find what is this constant. It's the size of something, perhaps?
|
46
|
+
UNKNOWN_CONSTANT = 113
|
47
|
+
|
48
|
+
HEADER_SIZE = 8
|
49
|
+
@reponse_size = 0
|
50
|
+
|
51
|
+
def get_timeout_time
|
52
|
+
3
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_max_attempts
|
56
|
+
3
|
57
|
+
end
|
58
|
+
|
59
|
+
def get_expected_response_size
|
60
|
+
HEADER_SIZE + @reponse_size
|
61
|
+
end
|
62
|
+
|
63
|
+
def get_unknown_constant
|
64
|
+
UNKNOWN_CONSTANT
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_equipment_number
|
68
|
+
@equipment_number
|
69
|
+
end
|
70
|
+
|
71
|
+
def get_host_address
|
72
|
+
@host_address
|
73
|
+
end
|
74
|
+
|
75
|
+
def get_tcp_port
|
76
|
+
@tcp_port
|
77
|
+
end
|
78
|
+
|
79
|
+
def check_response_header(response)
|
80
|
+
crc_check(response[0..6]) == response[7].ord
|
81
|
+
end
|
82
|
+
|
83
|
+
def check_response_payload(response)
|
84
|
+
crc_check(response[8..-2]) == response[-1].ord
|
85
|
+
end
|
86
|
+
|
87
|
+
def get_response_payload(response)
|
88
|
+
# TODO: other payloads might be different
|
89
|
+
response[8..-2]
|
90
|
+
end
|
91
|
+
|
92
|
+
def convert_to_integer_as_little_endian(integer_array)
|
93
|
+
self.class.convert_to_integer_as_little_endian(integer_array)
|
94
|
+
end
|
95
|
+
|
96
|
+
def convert_to_integer_as_big_endian(integer_array)
|
97
|
+
self.class.convert_to_integer_as_big_endian(integer_array)
|
98
|
+
end
|
99
|
+
|
100
|
+
def crc_size
|
101
|
+
1
|
102
|
+
end
|
103
|
+
|
104
|
+
def generate_header
|
105
|
+
field_quantity = get_field_quantity
|
106
|
+
|
107
|
+
header = [get_equipment_number^255] # TODO: find why this is needed
|
108
|
+
header << get_command
|
109
|
+
header << get_unknown_constant
|
110
|
+
header << divide_by_256(get_field_size)
|
111
|
+
header << (get_field_size & 255)
|
112
|
+
header << field_quantity
|
113
|
+
header << divide_by_256(field_quantity)
|
114
|
+
header << crc_check(header) # TODO: find why this is needed; maybe a data check?
|
115
|
+
header
|
116
|
+
end
|
117
|
+
|
118
|
+
def get_command
|
119
|
+
raise_not_implemented_error
|
120
|
+
end
|
121
|
+
|
122
|
+
def get_field_size
|
123
|
+
raise_not_implemented_error
|
124
|
+
end
|
125
|
+
|
126
|
+
def get_field_quantity
|
127
|
+
raise_not_implemented_error
|
128
|
+
end
|
129
|
+
|
130
|
+
def generate_command_data
|
131
|
+
raise_not_implemented_error
|
132
|
+
end
|
133
|
+
|
134
|
+
def get_data_from_response(payload)
|
135
|
+
raise_not_implemented_error
|
136
|
+
end
|
137
|
+
|
138
|
+
def crc_check(data)
|
139
|
+
self.class.xor(data)
|
140
|
+
end
|
141
|
+
|
142
|
+
def divide_by_256(value)
|
143
|
+
return (value >> 8 & 255)
|
144
|
+
end
|
145
|
+
|
146
|
+
class << self
|
147
|
+
def xor(data)
|
148
|
+
value = 0;
|
149
|
+
data = data.unpack("C*") if data.is_a?(String)
|
150
|
+
data.each do |integer|
|
151
|
+
value ^= integer
|
152
|
+
end
|
153
|
+
value
|
154
|
+
end
|
155
|
+
|
156
|
+
def convert_to_integer_as_little_endian(integer_array)
|
157
|
+
value = 0
|
158
|
+
integer_array.each_with_index do |byte, index|
|
159
|
+
value += (byte.to_i << 8*index)
|
160
|
+
end
|
161
|
+
value
|
162
|
+
end
|
163
|
+
|
164
|
+
# This method is the same of the little-endian one above, just with the
|
165
|
+
# input data reversed.
|
166
|
+
def convert_to_integer_as_big_endian(integer_array)
|
167
|
+
convert_to_integer_as_little_endian(integer_array.reverse)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
private
|
172
|
+
def raise_not_implemented_error
|
173
|
+
raise NotImplementedError.new "This method should be overriden by the subclass #{self.class.to_s}"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Controle de Horas - Sistema para gestão de horas trabalhadas
|
3
|
+
# Copyright (C) 2009 O.S. Systems Softwares Ltda.
|
4
|
+
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU Affero General Public License as
|
7
|
+
# published by the Free Software Foundation, either version 3 of the
|
8
|
+
# License, or (at your option) any later version.
|
9
|
+
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU Affero General Public License for more details.
|
14
|
+
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
# Rua Clóvis Gularte Candiota 132, Pelotas-RS, Brasil.
|
19
|
+
# e-mail: contato@ossystems.com.br
|
20
|
+
|
21
|
+
require 'socket'
|
22
|
+
require 'timeout'
|
23
|
+
|
24
|
+
module Orion6Rep
|
25
|
+
module Communication
|
26
|
+
include Timeout
|
27
|
+
|
28
|
+
class << self
|
29
|
+
def communicate(host_address, port, payload, expected_response_size, timeout_time=60, max_attempts = 3)
|
30
|
+
attempt = 0
|
31
|
+
|
32
|
+
while attempt < max_attempts do
|
33
|
+
socket = nil
|
34
|
+
begin
|
35
|
+
timeout(timeout_time) {
|
36
|
+
socket = TCPSocket.open(host_address, port)
|
37
|
+
}
|
38
|
+
rescue Timeout::Error => e
|
39
|
+
socket = nil
|
40
|
+
end
|
41
|
+
|
42
|
+
received_data = nil
|
43
|
+
|
44
|
+
if socket
|
45
|
+
begin
|
46
|
+
received_data = send_receive_data(socket, payload, expected_response_size, timeout_time)
|
47
|
+
rescue Timeout::Error => e
|
48
|
+
socket.close
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
break unless received_data.nil?
|
53
|
+
attempt += 1
|
54
|
+
end
|
55
|
+
|
56
|
+
raise "Timeout error" if attempt >= max_attempts
|
57
|
+
received_data
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
def send_receive_data(socket, data_to_send, expected_response_size, timeout_time)
|
62
|
+
socket.write(data_to_send.pack("C*"))
|
63
|
+
socket.flush
|
64
|
+
data_to_receive = ""
|
65
|
+
|
66
|
+
# expected_response_size can be a Fixnum, for fixed responses sizes, or
|
67
|
+
# a proc, where the response size comes inside the response itself.
|
68
|
+
if expected_response_size.is_a?(Proc)
|
69
|
+
expected_size = expected_response_size.call(data_to_receive)
|
70
|
+
else
|
71
|
+
expected_size = expected_response_size
|
72
|
+
end
|
73
|
+
|
74
|
+
while data_to_receive.size < expected_size
|
75
|
+
bytes_to_be_read = expected_size - data_to_receive.size
|
76
|
+
bytes_to_be_read = 100 if bytes_to_be_read > 100
|
77
|
+
|
78
|
+
timeout(timeout_time) {
|
79
|
+
data_to_receive += socket.readpartial( bytes_to_be_read )
|
80
|
+
}
|
81
|
+
if expected_response_size.is_a?(Proc)
|
82
|
+
expected_size = expected_response_size.call(data_to_receive)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
data_to_receive
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# Controle de Horas - Sistema para gestão de horas trabalhadas
|
2
|
+
# Copyright (C) 2009 O.S. Systems Softwares Ltda.
|
3
|
+
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Affero General Public License as
|
6
|
+
# published by the Free Software Foundation, either version 3 of the
|
7
|
+
# License, or (at your option) any later version.
|
8
|
+
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU Affero General Public License for more details.
|
13
|
+
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
# Rua Clóvis Gularte Candiota 132, Pelotas-RS, Brasil.
|
18
|
+
# e-mail: contato@ossystems.com.br
|
19
|
+
|
20
|
+
require 'socket'
|
21
|
+
require 'orion6_rep/interface'
|
22
|
+
|
23
|
+
module Orion6Rep
|
24
|
+
class DetectReps
|
25
|
+
UDP_DETECTION_PORT = 65535
|
26
|
+
UDP_DETECTION_DATA = [0x58].pack("C")
|
27
|
+
|
28
|
+
def initialize
|
29
|
+
ifaces_names = Orion6Rep::Interface.get_active_interfaces_names
|
30
|
+
# it's useless to try to detect REPs in the localhost
|
31
|
+
ifaces_names.delete("lo")
|
32
|
+
|
33
|
+
@interfaces = {}
|
34
|
+
@responses = {}
|
35
|
+
ifaces_names.each do |name|
|
36
|
+
broadcast_address = Orion6Rep::Interface.broadcast_address(name)
|
37
|
+
@interfaces[name] = {}
|
38
|
+
@interfaces[name][:broadcast_addr] = broadcast_address
|
39
|
+
end
|
40
|
+
raise "No active network interfaces found" if @interfaces.empty?
|
41
|
+
|
42
|
+
@interfaces.each_key do |name|
|
43
|
+
socket = UDPSocket.new
|
44
|
+
socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, true)
|
45
|
+
@interfaces[name][:socket] = socket
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def execute
|
50
|
+
@interfaces.each do |_, data|
|
51
|
+
data[:socket].send(UDP_DETECTION_DATA, 0, data[:broadcast_addr], UDP_DETECTION_PORT)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def pool
|
56
|
+
rep_responses = IO.select(get_sockets, nil, nil, 1)
|
57
|
+
|
58
|
+
unless rep_responses.nil? or rep_responses.empty?
|
59
|
+
rep_responses.first.each do |socket|
|
60
|
+
raw_data, socket_data = socket.recvfrom(33)
|
61
|
+
rep_data, tcp_port = raw_data.unpack("a18a4")
|
62
|
+
ip = socket_data.last
|
63
|
+
interface = get_assossiated_interface(socket)
|
64
|
+
@responses[interface] = {} if @responses[interface].nil?
|
65
|
+
@responses[interface][ip] = {:port => tcp_port.to_i, :rep_data => rep_data}
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
return @responses
|
70
|
+
end
|
71
|
+
|
72
|
+
def stop
|
73
|
+
get_sockets.each{|socket| socket.close}
|
74
|
+
true
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
def get_sockets
|
79
|
+
@interfaces.collect{|_, data| data[:socket]}
|
80
|
+
end
|
81
|
+
|
82
|
+
def get_assossiated_interface(socket)
|
83
|
+
@interfaces.each{|interface, data| return interface if data[:socket] == socket}
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|