steam-condenser 0.10.1 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION.yml +2 -2
- data/lib/datagram_channel.rb +30 -33
- data/lib/exceptions/packet_format_exception.rb +7 -3
- data/lib/exceptions/rcon_ban_exception.rb +7 -5
- data/lib/exceptions/rcon_no_auth_exception.rb +8 -6
- data/lib/exceptions/timeout_exception.rb +10 -4
- data/lib/socket_channel.rb +11 -17
- data/lib/steam/community/cacheable.rb +5 -7
- data/lib/steam/community/css/css_map.rb +31 -0
- data/lib/steam/community/css/css_stats.rb +116 -0
- data/lib/steam/community/css/css_weapon.rb +33 -0
- data/lib/steam/community/dods/dods_stats.rb +3 -3
- data/lib/steam/community/game_stats.rb +14 -13
- data/lib/steam/community/game_weapon.rb +3 -5
- data/lib/steam/community/l4d/abstract_l4d_stats.rb +4 -2
- data/lib/steam/community/l4d/l4d_explosive.rb +2 -2
- data/lib/steam/community/l4d/l4d_map.rb +3 -3
- data/lib/steam/community/steam_group.rb +2 -4
- data/lib/steam/community/steam_id.rb +2 -2
- data/lib/steam/community/tf2/tf2_class.rb +17 -17
- data/lib/steam/community/tf2/tf2_class_factory.rb +17 -17
- data/lib/steam/community/tf2/tf2_engineer.rb +9 -9
- data/lib/steam/community/tf2/tf2_medic.rb +9 -9
- data/lib/steam/community/tf2/tf2_sniper.rb +7 -7
- data/lib/steam/community/tf2/tf2_spy.rb +9 -9
- data/lib/steam/community/tf2/tf2_stats.rb +9 -9
- data/lib/steam/packets/a2a_ack_packet.rb +11 -9
- data/lib/steam/packets/a2a_ping_packet.rb +5 -4
- data/lib/steam/packets/a2m_get_servers_batch2_packet.rb +13 -12
- data/lib/steam/packets/a2s_info_packet.rb +8 -7
- data/lib/steam/packets/a2s_player_packet.rb +6 -6
- data/lib/steam/packets/a2s_rules_packet.rb +5 -5
- data/lib/steam/packets/a2s_serverquery_getchallenge_packet.rb +4 -3
- data/lib/steam/packets/m2a_server_batch_packet.rb +20 -22
- data/lib/steam/packets/rcon/rcon_auth_request.rb +5 -5
- data/lib/steam/packets/rcon/rcon_auth_response.rb +6 -6
- data/lib/steam/packets/rcon/rcon_exec_request.rb +5 -5
- data/lib/steam/packets/rcon/rcon_exec_response.rb +2 -2
- data/lib/steam/packets/rcon/rcon_goldsrc_request.rb +7 -7
- data/lib/steam/packets/rcon/rcon_goldsrc_response.rb +8 -8
- data/lib/steam/packets/rcon/rcon_packet.rb +12 -16
- data/lib/steam/packets/rcon/rcon_packet_factory.rb +19 -19
- data/lib/steam/packets/request_with_challenge.rb +5 -5
- data/lib/steam/packets/s2a_info2_packet.rb +28 -30
- data/lib/steam/packets/s2a_info_base_packet.rb +11 -16
- data/lib/steam/packets/s2a_info_detailed_packet.rb +30 -28
- data/lib/steam/packets/s2a_player_packet.rb +7 -9
- data/lib/steam/packets/s2a_rules_packet.rb +8 -12
- data/lib/steam/packets/s2c_challenge_packet.rb +7 -6
- data/lib/steam/packets/steam_packet.rb +7 -6
- data/lib/steam/packets/steam_packet_factory.rb +37 -38
- data/lib/steam/servers/game_server.rb +76 -86
- data/lib/steam/servers/goldsrc_server.rb +5 -5
- data/lib/steam/servers/master_server.rb +24 -24
- data/lib/steam/servers/source_server.rb +17 -19
- data/lib/steam/sockets/goldsrc_socket.rb +43 -46
- data/lib/steam/sockets/master_server_socket.rb +11 -13
- data/lib/steam/sockets/rcon_socket.rb +15 -17
- data/lib/steam/sockets/source_socket.rb +21 -21
- data/lib/steam/sockets/steam_socket.rb +25 -28
- data/lib/steam/steam_player.rb +3 -1
- data/lib/stringio_additions.rb +48 -0
- data/test/datagram_channel_tests.rb +8 -8
- data/test/query_tests.rb +15 -14
- data/test/rcon_tests.rb +32 -31
- data/test/socket_channel_tests.rb +7 -7
- data/test/steam/communtiy/steam_community_test_suite.rb +5 -2
- data/test/steam_community_tests.rb +4 -3
- data/test/stringio_additions_tests.rb +77 -0
- metadata +15 -8
- data/lib/byte_buffer.rb +0 -126
- data/lib/exceptions/buffer_underflow_exception.rb +0 -8
- data/test/byte_buffer_tests.rb +0 -76
@@ -1,12 +1,12 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under the
|
2
2
|
# terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2008-
|
4
|
+
# Copyright (c) 2008-2010, Sebastian Staudt
|
5
5
|
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
6
|
+
require 'stringio_additions'
|
7
|
+
require 'steam/packets/steam_packet_factory'
|
8
|
+
require 'steam/packets/rcon/rcon_goldsrc_request'
|
9
|
+
require 'steam/sockets/steam_socket'
|
10
10
|
|
11
11
|
# The SourceSocket class is a sub class of SteamSocket respecting the
|
12
12
|
# specifications of the Source query protocol.
|
@@ -21,18 +21,18 @@ class GoldSrcSocket < SteamSocket
|
|
21
21
|
# maximum packet size of 1400 byte. Greater packets will be split over several
|
22
22
|
# UDP packets. This method reassembles split packets into single packet
|
23
23
|
# objects.
|
24
|
-
def
|
25
|
-
bytes_read =
|
26
|
-
|
27
|
-
if @buffer.
|
28
|
-
split_packets =
|
24
|
+
def reply
|
25
|
+
bytes_read = receive_packet 1400
|
26
|
+
|
27
|
+
if @buffer.long == 0xFFFFFFFE
|
28
|
+
split_packets = []
|
29
29
|
begin
|
30
30
|
# Parsing of split packet headers
|
31
|
-
request_id = @buffer.
|
32
|
-
packet_number_and_count = @buffer.
|
31
|
+
request_id = @buffer.long
|
32
|
+
packet_number_and_count = @buffer.byte.to_i
|
33
33
|
packet_count = packet_number_and_count & 0xF
|
34
34
|
packet_number = (packet_number_and_count >> 4) + 1
|
35
|
-
|
35
|
+
|
36
36
|
# Caching of split packet data
|
37
37
|
split_packets[packet_number - 1] = @buffer.get
|
38
38
|
|
@@ -41,68 +41,65 @@ class GoldSrcSocket < SteamSocket
|
|
41
41
|
# Receiving the next packet
|
42
42
|
if split_packets.size < packet_count
|
43
43
|
begin
|
44
|
-
bytes_read =
|
44
|
+
bytes_read = receive_packet
|
45
45
|
rescue TimeoutException
|
46
46
|
bytes_read = 0
|
47
47
|
end
|
48
48
|
else
|
49
49
|
bytes_read = 0
|
50
50
|
end
|
51
|
-
end while bytes_read > 0 && @buffer.
|
52
|
-
|
51
|
+
end while bytes_read > 0 && @buffer.long == 0xFFFFFFFE
|
52
|
+
|
53
53
|
packet = SteamPacketFactory.reassemble_packet(split_packets)
|
54
|
-
|
55
54
|
else
|
56
|
-
packet = SteamPacketFactory.
|
55
|
+
packet = SteamPacketFactory.packet_from_data(@buffer.get)
|
57
56
|
end
|
58
57
|
|
59
58
|
puts "Got reply of type \"#{packet.class.to_s}\"." if $DEBUG
|
60
59
|
|
61
|
-
|
60
|
+
packet
|
62
61
|
end
|
63
|
-
|
62
|
+
|
64
63
|
def rcon_exec(password, command)
|
65
|
-
|
66
|
-
|
67
|
-
|
64
|
+
rcon_challenge if @rcon_challenge.nil? or @is_hltv
|
65
|
+
|
66
|
+
rcon_send "rcon #{@rcon_challenge} #{password} #{command}"
|
68
67
|
if @is_hltv
|
69
68
|
begin
|
70
|
-
response =
|
69
|
+
response = reply.response
|
71
70
|
rescue TimeoutException
|
72
|
-
response =
|
71
|
+
response = ''
|
73
72
|
end
|
74
73
|
else
|
75
|
-
response =
|
74
|
+
response = reply.response
|
76
75
|
end
|
77
|
-
|
78
|
-
if response.strip ==
|
79
|
-
raise RCONNoAuthException
|
76
|
+
|
77
|
+
if response.strip == 'Bad rcon_password.' or response.strip == 'You have been banned from this server.'
|
78
|
+
raise RCONNoAuthException
|
80
79
|
end
|
81
|
-
|
80
|
+
|
82
81
|
begin
|
83
|
-
|
84
|
-
response_part =
|
82
|
+
loop do
|
83
|
+
response_part = reply.response
|
85
84
|
response << response_part
|
86
85
|
end
|
87
86
|
rescue TimeoutException
|
88
87
|
end
|
89
|
-
|
90
|
-
|
88
|
+
|
89
|
+
response
|
91
90
|
end
|
92
|
-
|
93
|
-
def
|
94
|
-
|
95
|
-
response =
|
96
|
-
|
97
|
-
if response ==
|
98
|
-
|
99
|
-
end
|
100
|
-
|
91
|
+
|
92
|
+
def rcon_challenge
|
93
|
+
rcon_send 'challenge rcon'
|
94
|
+
response = reply.response.strip
|
95
|
+
|
96
|
+
raise RCONNoAuthException if response == 'You have been banned from this server.'
|
97
|
+
|
101
98
|
@rcon_challenge = response[14..-1]
|
102
99
|
end
|
103
|
-
|
100
|
+
|
104
101
|
def rcon_send(command)
|
105
|
-
|
102
|
+
send RCONGoldSrcRequest.new(command)
|
106
103
|
end
|
107
|
-
|
104
|
+
|
108
105
|
end
|
@@ -1,20 +1,18 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under the
|
2
2
|
# terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2008-
|
4
|
+
# Copyright (c) 2008-2010, Sebastian Staudt
|
5
5
|
|
6
|
-
require
|
6
|
+
require 'steam/sockets/steam_socket'
|
7
7
|
|
8
8
|
class MasterServerSocket < SteamSocket
|
9
|
-
|
10
|
-
def
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
return SteamPacketFactory.get_packet_from_data(@buffer.get)
|
9
|
+
|
10
|
+
def reply
|
11
|
+
receive_packet 1500
|
12
|
+
|
13
|
+
raise Exception.new("Master query response has wrong packet header.") unless @buffer.long == 0xFFFFFFFF
|
14
|
+
|
15
|
+
SteamPacketFactory.packet_from_data(@buffer.get)
|
18
16
|
end
|
19
|
-
|
20
|
-
end
|
17
|
+
|
18
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under the
|
2
2
|
# terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2008-
|
4
|
+
# Copyright (c) 2008-2010, Sebastian Staudt
|
5
5
|
|
6
6
|
require 'socket_channel'
|
7
7
|
require 'exceptions/rcon_ban_exception'
|
@@ -17,35 +17,33 @@ class RCONSocket < SteamSocket
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def send(data_packet)
|
20
|
-
|
21
|
-
@channel.connect @remote_socket
|
22
|
-
end
|
20
|
+
@channel.connect @remote_socket unless @channel.connected?
|
23
21
|
|
24
|
-
@buffer =
|
22
|
+
@buffer = StringIO.new data_packet.bytes
|
25
23
|
@channel.write @buffer
|
26
24
|
end
|
27
25
|
|
28
|
-
def
|
29
|
-
if
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
26
|
+
def reply
|
27
|
+
raise RCONBanException if receive_packet(1440) == 0
|
28
|
+
|
29
|
+
packet_data = @buffer.get
|
30
|
+
packet_size = @buffer.long + 4
|
31
|
+
@buffer.rewind
|
34
32
|
|
35
33
|
if packet_size > 1440
|
36
|
-
remaining_bytes = packet_size - @buffer.
|
34
|
+
remaining_bytes = packet_size - @buffer.size
|
37
35
|
begin
|
38
36
|
if remaining_bytes < 1440
|
39
|
-
|
37
|
+
receive_packet remaining_bytes
|
40
38
|
else
|
41
|
-
|
39
|
+
receive_packet 1440
|
42
40
|
end
|
43
|
-
packet_data << @buffer.
|
44
|
-
remaining_bytes -= @buffer.
|
41
|
+
packet_data << @buffer.get
|
42
|
+
remaining_bytes -= @buffer.size
|
45
43
|
end while remaining_bytes > 0
|
46
44
|
end
|
47
45
|
|
48
|
-
|
46
|
+
RCONPacketFactory.packet_from_data(packet_data)
|
49
47
|
end
|
50
48
|
|
51
49
|
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under the
|
2
2
|
# terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2008-
|
4
|
+
# Copyright (c) 2008-2010, Sebastian Staudt
|
5
5
|
|
6
|
-
require
|
7
|
-
require
|
6
|
+
require 'stringio_additions'
|
7
|
+
require 'steam/sockets/steam_socket'
|
8
8
|
|
9
9
|
# The SourceSocket class is a sub class of SteamSocket respecting the
|
10
10
|
# specifications of the Source query protocol.
|
@@ -14,24 +14,24 @@ class SourceSocket < SteamSocket
|
|
14
14
|
# maximum packet size of 1400 byte. Greater packets will be split over several
|
15
15
|
# UDP packets. This method reassembles split packets into single packet
|
16
16
|
# objects.
|
17
|
-
def
|
18
|
-
bytes_read =
|
17
|
+
def reply
|
18
|
+
bytes_read = receive_packet 1400
|
19
19
|
is_compressed = false
|
20
20
|
|
21
|
-
if @buffer.
|
22
|
-
split_packets =
|
21
|
+
if @buffer.long == 0xFFFFFFFE
|
22
|
+
split_packets = []
|
23
23
|
begin
|
24
24
|
# Parsing of split packet headers
|
25
|
-
request_id = @buffer.
|
25
|
+
request_id = @buffer.long
|
26
26
|
is_compressed = ((request_id & 0x80000000) != 0)
|
27
|
-
packet_count = @buffer.
|
28
|
-
packet_number = @buffer.
|
29
|
-
|
27
|
+
packet_count = @buffer.byte.to_i
|
28
|
+
packet_number = @buffer.byte.to_i + 1
|
29
|
+
|
30
30
|
if is_compressed
|
31
|
-
|
32
|
-
packet_checksum = @buffer.
|
31
|
+
@buffer.long
|
32
|
+
packet_checksum = @buffer.long
|
33
33
|
else
|
34
|
-
|
34
|
+
@buffer.short
|
35
35
|
end
|
36
36
|
|
37
37
|
# Caching of split packet data
|
@@ -42,22 +42,22 @@ class SourceSocket < SteamSocket
|
|
42
42
|
# Receiving the next packet
|
43
43
|
if split_packets.size < packet_count
|
44
44
|
begin
|
45
|
-
bytes_read =
|
45
|
+
bytes_read = receive_packet
|
46
46
|
rescue TimeoutException
|
47
47
|
bytes_read = 0
|
48
48
|
end
|
49
49
|
else
|
50
50
|
bytes_read = 0
|
51
51
|
end
|
52
|
-
end while bytes_read > 0 && @buffer.
|
53
|
-
|
52
|
+
end while bytes_read > 0 && @buffer.long == 0xFFFFFFFE
|
53
|
+
|
54
54
|
if is_compressed
|
55
55
|
packet = SteamPacketFactory.reassemble_packet(split_packets, true, packet_checksum)
|
56
56
|
else
|
57
57
|
packet = SteamPacketFactory.reassemble_packet(split_packets)
|
58
58
|
end
|
59
59
|
else
|
60
|
-
packet = SteamPacketFactory.
|
60
|
+
packet = SteamPacketFactory.packet_from_data(@buffer.get)
|
61
61
|
end
|
62
62
|
|
63
63
|
if is_compressed
|
@@ -65,8 +65,8 @@ class SourceSocket < SteamSocket
|
|
65
65
|
else
|
66
66
|
puts "Got reply of type \"#{packet.class.to_s}\"." if $DEBUG
|
67
67
|
end
|
68
|
-
|
69
|
-
|
68
|
+
|
69
|
+
packet
|
70
70
|
end
|
71
|
-
|
71
|
+
|
72
72
|
end
|
@@ -1,60 +1,57 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under the
|
2
2
|
# terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2008-
|
4
|
+
# Copyright (c) 2008-2010, Sebastian Staudt
|
5
5
|
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
6
|
+
require 'abstract_class'
|
7
|
+
require 'datagram_channel'
|
8
|
+
require 'ipaddr'
|
9
|
+
require 'stringio_additions'
|
10
|
+
require 'exceptions/timeout_exception'
|
11
11
|
|
12
|
-
#
|
13
|
-
#
|
12
|
+
# Defines common methods for sockets used to connect to game and master
|
13
|
+
# servers.
|
14
14
|
class SteamSocket
|
15
|
-
|
15
|
+
|
16
16
|
include AbstractClass
|
17
|
-
|
17
|
+
|
18
18
|
def initialize(*args)
|
19
19
|
@channel = DatagramChannel.open
|
20
20
|
@channel.connect *args
|
21
21
|
@channel.configure_blocking false
|
22
|
-
|
22
|
+
|
23
23
|
@remote_socket = Socket.getaddrinfo args[0].to_s, args[1]
|
24
24
|
end
|
25
25
|
|
26
|
-
# Abstract
|
27
|
-
def
|
26
|
+
# Abstract +reply+ method
|
27
|
+
def reply
|
28
28
|
raise NotImplementedError
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
def receive_packet(buffer_length = 0)
|
32
|
-
if select([@channel.socket], nil, nil, 1)
|
33
|
-
raise TimeoutException.new
|
34
|
-
end
|
32
|
+
raise TimeoutException if select([@channel.socket], nil, nil, 1).nil?
|
35
33
|
|
36
34
|
if buffer_length == 0
|
37
|
-
@buffer.
|
35
|
+
@buffer.truncate @buffer.size
|
38
36
|
else
|
39
|
-
@buffer =
|
37
|
+
@buffer = StringIO.allocate buffer_length
|
40
38
|
end
|
41
|
-
|
42
|
-
bytes_read = @channel.read
|
39
|
+
|
40
|
+
bytes_read = @channel.read @buffer
|
43
41
|
@buffer.rewind
|
44
|
-
|
45
|
-
|
42
|
+
|
46
43
|
bytes_read
|
47
44
|
end
|
48
|
-
|
45
|
+
|
49
46
|
def send(data_packet)
|
50
47
|
puts "Sending data packet of type \"#{data_packet.class.to_s}\"." if $DEBUG
|
51
48
|
|
52
|
-
@buffer =
|
53
|
-
@channel.write
|
49
|
+
@buffer = StringIO.new data_packet.to_s
|
50
|
+
@channel.write @buffer
|
54
51
|
end
|
55
|
-
|
52
|
+
|
56
53
|
def finalize
|
57
54
|
@channel.close
|
58
55
|
end
|
59
|
-
|
56
|
+
|
60
57
|
end
|
data/lib/steam/steam_player.rb
CHANGED
@@ -25,7 +25,9 @@ class SteamPlayer
|
|
25
25
|
def add_info(real_id, name, steam_id, *player_data)
|
26
26
|
@extended = true
|
27
27
|
|
28
|
-
|
28
|
+
unless name == @name
|
29
|
+
raise SteamCondenserException.new('Information to add belongs to a different player.')
|
30
|
+
end
|
29
31
|
|
30
32
|
@real_id = real_id
|
31
33
|
@steam_id = steam_id
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# This code is free software; you can redistribute it and/or modify it under the
|
2
|
+
# terms of the new BSD License.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2010, Sebastian Staudt
|
5
|
+
|
6
|
+
require 'stringio'
|
7
|
+
|
8
|
+
class StringIO
|
9
|
+
|
10
|
+
alias_method :data, :string
|
11
|
+
|
12
|
+
def self.allocate(size)
|
13
|
+
new "\0" * size
|
14
|
+
end
|
15
|
+
|
16
|
+
def byte
|
17
|
+
read(1)[0]
|
18
|
+
end
|
19
|
+
|
20
|
+
def float
|
21
|
+
read(4).unpack('e')[0]
|
22
|
+
end
|
23
|
+
|
24
|
+
def get
|
25
|
+
read remaining
|
26
|
+
end
|
27
|
+
|
28
|
+
def long
|
29
|
+
read(4).unpack('V')[0]
|
30
|
+
end
|
31
|
+
|
32
|
+
def remaining
|
33
|
+
size - pos
|
34
|
+
end
|
35
|
+
|
36
|
+
def short
|
37
|
+
read(2).unpack('v')[0]
|
38
|
+
end
|
39
|
+
|
40
|
+
def signed_long
|
41
|
+
read(4).unpack('l')[0]
|
42
|
+
end
|
43
|
+
|
44
|
+
def string
|
45
|
+
gets("\0")[0..-2]
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|