ffi-enet 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3955bec45c5e95da5d98bd7517fe6957bcca3c2647dcfa3b3c44ecc53992f615
4
+ data.tar.gz: 902b7cc535d3fe42fce86e50623132a20f1f3ea353f6a3abb98d36ac4cc4d8cd
5
+ SHA512:
6
+ metadata.gz: 77091b2a373cf343fa83a31dcf8fd9780335de0353626d812265e7135caa129976ce59594e64729813bbf328a7a98a71c3ab9f6d9f17958a15853cea8313ae54
7
+ data.tar.gz: feb77626faae4c063ccb95256b6dd73343364f8a628fe042737832d42ce35985205149fb45382f5f8e0b16df83987a56928f01373a9ac7db0a5c28a778c56e15
data/.standard.yml ADDED
@@ -0,0 +1,3 @@
1
+ # For available configuration options, see:
2
+ # https://github.com/testdouble/standard
3
+ ruby_version: 2.6
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2024-03-13
4
+
5
+ - Initial release
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2023 Cyberarm
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # FFI-ENet
2
+
3
+ FFI interface to the [enet](http://sauerbraten.org/enet/) networking library.
4
+
5
+ Also includes a [rENet](https://github.com/Dahrkael/rENet/)-like API for easy usage.
6
+
7
+ ## Installation
8
+
9
+ TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
10
+
11
+ Install the gem and add to the application's Gemfile by executing:
12
+
13
+ $ bundle add UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
14
+
15
+ If bundler is not being used to manage dependencies, install the gem by executing:
16
+
17
+ $ gem install UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Development
24
+
25
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
26
+
27
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
28
+
29
+ ## Contributing
30
+
31
+ Bug reports and pull requests are welcome on GitHub at https://github.com/cyberarm/ffi-enet.
32
+
33
+ ## License
34
+
35
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << "test"
8
+ t.libs << "lib"
9
+ t.test_files = FileList["test/**/test_*.rb"]
10
+ end
11
+
12
+ require "standard/rake"
13
+
14
+ task default: %i[test standard]
data/examples/echo.rb ADDED
@@ -0,0 +1,60 @@
1
+ require_relative "../lib/ffi-enet"
2
+ require_relative "../lib/ffi-enet/renet"
3
+
4
+ Thread.abort_on_exception = true
5
+
6
+ thread = Thread.new do
7
+ @server = ENet::Server.new(host: "localhost", port: 3000, max_clients: 32, channels: 4, download_bandwidth: 0, upload_bandwidth: 0)
8
+ @server.use_compression(true)
9
+ # server.use_compression(false)
10
+
11
+ def @server.on_connection(client)
12
+ puts "[SERVER][ID #{client.id}] connected from #{client.address.host}:#{client.address.port}"
13
+ send_packet(client, "Hello World", reliable: true, channel: 1)
14
+ end
15
+
16
+ def @server.on_packet_received(client, data, channel)
17
+ puts "[SERVER][ID #{client.id}][TOTAL PACKETS: #{client.total_sent_packets}] #{data}"
18
+ send_packet(client, data, reliable: true, channel: 1)
19
+ end
20
+
21
+ def @server.on_disconnection(client)
22
+ puts "[SERVER][ID #{client.id}] disconnected from #{client.address.host}"
23
+ send_packet(client, "Goodbye World", reliable: true, channel: 1)
24
+ end
25
+
26
+ loop do
27
+ @server.update(1_000)
28
+ end
29
+ end
30
+
31
+ sleep 0.5
32
+
33
+ connection = ENet::Connection.new(host: "localhost", port: 3000, channels: 4, download_bandwidth: 0, upload_bandwidth: 0)
34
+ connection.use_compression(true)
35
+ # connection.use_compression(false)
36
+
37
+ def connection.on_connection
38
+ puts "[CONNECTION] CONNECTED TO SERVER"
39
+ send_packet("Hello World!", reliable: true, channel: 0)
40
+ end
41
+
42
+ def connection.on_packet_received(data, channel)
43
+ puts "[CONNECTION][CHANNEL #{channel}]: #{data}"
44
+
45
+ send_packet(data, reliable: true, channel: channel)
46
+ end
47
+
48
+ def connection.on_disconnection
49
+ puts "[CONNECTION] DISCONNECTED FROM SERVER"
50
+ end
51
+
52
+ connection.connect(5_000)
53
+
54
+ while connection.online?
55
+ connection.update(1_000)
56
+ connection.disconnect(2_000)
57
+ @server.shutdown
58
+ end
59
+
60
+ thread.join
@@ -0,0 +1,59 @@
1
+ module ENet
2
+ class Client
3
+ Address = Struct.new(:host, :port)
4
+
5
+ attr_reader :_peer, :id, :address
6
+ attr_reader :last_send_time, :last_receive_time, :last_round_trip_time, :round_trip_time, :packets_lost, :packet_loss,
7
+ :total_sent_packets, :total_sent_data, :total_received_packets, :total_received_data
8
+
9
+ def self.enet_host_address_to_ipv4(address)
10
+ str_ptr = FFI::MemoryPointer.new(:char, 256)
11
+ result = LibENet.enet_address_get_host_ip(address, str_ptr, str_ptr.size)
12
+ raise "Failed to get IPv4 address of enet address" unless result.zero?
13
+
14
+ str_ptr.read_string
15
+ end
16
+
17
+ def initialize(peer)
18
+ @_peer = peer
19
+
20
+ @id = @_peer[:connect_id]
21
+ @address = Address.new(Client.enet_host_address_to_ipv4(@_peer[:address]), @_peer[:address][:port])
22
+
23
+ @last_send_time = 0
24
+ @last_receive_time = 0
25
+ @last_round_trip_time = 0
26
+ @round_trip_time = 0
27
+ @packets_lost = 0
28
+ @packet_loss = 0
29
+
30
+ @total_sent_packets = 0
31
+ @total_sent_data = 0
32
+ @total_received_packets = 0
33
+ @total_received_data = 0
34
+
35
+ update_stats
36
+ end
37
+
38
+ def update_stats
39
+ # enet Peer data
40
+ @last_send_time = @_peer[:last_send_time]
41
+ @last_receive_time = @_peer[:last_send_time]
42
+ @last_round_trip_time = @_peer[:last_round_trip_time]
43
+ @round_trip_time = @_peer[:round_trip_time]
44
+ @packets_lost = @_peer[:packets_lost]
45
+ @packet_loss = @_peer[:packet_loss] # .to_f / LibENet::ENET_PEER_PACKET_LOSS_SCALE
46
+
47
+ # enet Host data
48
+ @total_sent_packets += @_peer[:host][:total_sent_packets]
49
+ @total_sent_data += @_peer[:host][:total_sent_data]
50
+ @total_received_packets += @_peer[:host][:total_received_packets]
51
+ @total_received_data += @_peer[:host][:total_received_data]
52
+
53
+ @_peer[:host][:total_sent_packets] = 0
54
+ @_peer[:host][:total_sent_data] = 0
55
+ @_peer[:host][:total_received_packets] = 0
56
+ @_peer[:host][:total_received_data] = 0
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,127 @@
1
+ module ENet
2
+ class Connection
3
+ attr_reader :client
4
+
5
+ def initialize(host:, port:, channels: 8, download_bandwidth: 0, upload_bandwidth: 0)
6
+ @host = host
7
+ @port = port
8
+ @channels = channels
9
+ @download_bandwidth = download_bandwidth
10
+ @upload_bandwidth = upload_bandwidth
11
+
12
+ @enet_event = LibENet::ENetEvent.new
13
+ @online = false
14
+
15
+ ENet.init
16
+
17
+ @_address = LibENet::ENetAddress.new
18
+ if LibENet.enet_address_set_host(@_address, @host) != 0
19
+ raise "Failed to set host"
20
+ end
21
+ @_address[:port] = @port
22
+
23
+ @_host = LibENet.enet_host_create(nil, 1, @channels, @download_bandwidth, @upload_bandwidth)
24
+
25
+ raise "Failed to create host" if @_host.nil?
26
+
27
+ @client = nil
28
+ end
29
+
30
+ def online?
31
+ @online
32
+ end
33
+
34
+ def connect(timeout_ms)
35
+ @_connection = LibENet.enet_host_connect(@_host, @_address, @channels, 0)
36
+ raise "Cannot connect to remote host" if @_connection.nil?
37
+
38
+ result = LibENet.enet_host_service(@_host, @enet_event, timeout_ms)
39
+
40
+ if result.positive? && @enet_event[:type] == :ENET_EVENT_TYPE_CONNECT
41
+ @online = true
42
+ @client = Client.new(@_connection)
43
+
44
+ on_connection
45
+ end
46
+ end
47
+
48
+ def disconnect(timeout_ms)
49
+ connected = online?
50
+
51
+ if connected
52
+ LibENet.enet_peer_disconnect(@_connection, 0)
53
+
54
+ while (result = LibENet.enet_host_service(@_host, @enet_event, 0)) && result.positive?
55
+
56
+ case @enet_event[:type]
57
+ when :ENET_EVENT_TYPE_RECEIVE
58
+ LibENet.enet_packet_destroy(@enet_event[:packet])
59
+
60
+ when :ENET_EVENT_TYPE_DISCONNECT
61
+ connected = false
62
+ end
63
+
64
+ break unless connected
65
+ end
66
+
67
+ LibENet.enet_peer_disconnect_now(@_connection, 0) if connected
68
+ end
69
+
70
+ connected
71
+ end
72
+
73
+ def send_packet(data, reliable:, channel:)
74
+ return unless online?
75
+
76
+ packet = LibENet.enet_packet_create(data, data.length, reliable ? 1 : 0)
77
+ LibENet.enet_peer_send(@_connection, channel, packet)
78
+ end
79
+
80
+ def send_queued_packets
81
+ LibENet.enet_host_flush(@_host) if online?
82
+ end
83
+
84
+ def flush
85
+ send_queued_packets
86
+ end
87
+
88
+ def update(timeout_ms)
89
+ result = LibENet.enet_host_service(@_host, @enet_event, timeout_ms)
90
+
91
+ if result.positive?
92
+ case @enet_event[:type]
93
+ when :ENET_EVENT_TYPE_RECEIVE
94
+ data = @enet_event[:packet][:data].read_string(@enet_event[:packet][:length])
95
+
96
+ on_packet_received(data, @enet_event[:channel_id])
97
+
98
+ LibENet.enet_packet_destroy(@enet_event[:packet])
99
+
100
+ when :ENET_EVENT_TYPE_DISCONNECT
101
+ @online = false
102
+ end
103
+ elsif result.negative?
104
+ warn "Connection: An error occurred: #{result}"
105
+ end
106
+
107
+ @client.update_stats if online?
108
+ end
109
+
110
+ def use_compression(bool)
111
+ if bool
112
+ LibENet.enet_host_compress_with_range_coder(@_host)
113
+ else
114
+ LibENet.enet_host_compress(@_host, nil)
115
+ end
116
+ end
117
+
118
+ def on_connection
119
+ end
120
+
121
+ def on_packet_received(data, channel)
122
+ end
123
+
124
+ def on_disconnection
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,127 @@
1
+ module ENet
2
+ class Server
3
+ def self.release(pointer)
4
+ end
5
+
6
+ def initialize(host:, port:, max_clients: 16, channels: 8, download_bandwidth: 0, upload_bandwidth: 0)
7
+ @host = host
8
+ @port = port
9
+ @max_clients = max_clients
10
+ @channels = channels
11
+ @download_bandwidth = download_bandwidth
12
+ @upload_bandwidth = upload_bandwidth
13
+
14
+ @enet_event = LibENet::ENetEvent.new
15
+ @clients = {}
16
+
17
+ ENet.init
18
+
19
+ @_address = LibENet::ENetAddress.new
20
+ if LibENet.enet_address_set_host(@_address, @host) != 0
21
+ raise "Failed to set host"
22
+ end
23
+ @_address[:port] = @port
24
+
25
+ @_host = FFI::AutoPointer.new(LibENet.enet_host_create(@_address, @max_clients, @channels, @download_bandwidth, @upload_bandwidth).to_ptr, Server.method(:release))
26
+ raise "Failed to create server" if @_host.nil?
27
+ end
28
+
29
+ def disconnect_client(client)
30
+ LibENet.enet_peer_disconnect(client._peer, 0)
31
+ end
32
+
33
+ def disconnect_client!(client)
34
+ LibENet.enet_peer_disconnect_now(client._peer, 0)
35
+
36
+ on_disconnection(client)
37
+ end
38
+
39
+ def send_packet(client, data, reliable:, channel:)
40
+ packet = LibENet.enet_packet_create(data, data.length, reliable ? 1 : 0)
41
+ LibENet.enet_peer_send(client._peer, channel, packet)
42
+
43
+ # pp [
44
+ # client.packets_sent,
45
+ # client.packets_received,
46
+ # client.data_sent,
47
+ # client.data_received,
48
+
49
+ # client.packets_lost,
50
+ # client.packet_loss,
51
+
52
+ # client.round_trip_time,
53
+ # client.last_round_trip_time,
54
+
55
+ # client.last_receive_time,
56
+ # client.last_send_time
57
+ # ]
58
+ end
59
+
60
+ def broadcast_packet(data, reliable:, channel:)
61
+ packet = LibENet.enet_packet_create(data, data.length, reliable ? 1 : 0)
62
+ LibENet.enet_host_broadcast(@_host, channel, packet)
63
+ end
64
+
65
+ def send_queued_packets
66
+ LibENet.enet_host_flush(@_host)
67
+ end
68
+
69
+ def flush
70
+ send_queued_packets
71
+ end
72
+
73
+ def update(timeout_ms)
74
+ result = LibENet.enet_host_service(@_host, @enet_event, timeout_ms)
75
+
76
+ if result.positive?
77
+ case @enet_event[:type]
78
+ when :ENET_EVENT_TYPE_CONNECT
79
+ client = Client.new(@enet_event[:peer])
80
+ @clients[client] = @enet_event[:peer]
81
+
82
+ on_connection(client)
83
+
84
+ when :ENET_EVENT_TYPE_RECEIVE
85
+ client = @clients.find { |k, peer| peer.to_ptr == @enet_event[:peer].to_ptr }.first
86
+ data = @enet_event[:packet][:data].read_string(@enet_event[:packet][:length])
87
+
88
+ client.update_stats
89
+ on_packet_received(client, data, @enet_event[:channel_id])
90
+
91
+ LibENet.enet_packet_destroy(@enet_event[:packet])
92
+
93
+ when :ENET_EVENT_TYPE_DISCONNECT
94
+ # FIXME: This might not work if peer pointer is invalid
95
+ client = @clients.find { |k, peer| peer.to_ptr == @enet_event[:peer].to_ptr }.first
96
+ @clients.delete(client)
97
+
98
+ on_disconnection(client)
99
+ end
100
+ elsif result.negative?
101
+ warn "Server: An error occurred: #{result}"
102
+ end
103
+ end
104
+
105
+ def shutdown
106
+ LibENet.enet_host_flush(@_host)
107
+ LibENet.enet_host_destroy(@_host)
108
+ end
109
+
110
+ def use_compression(bool)
111
+ if bool
112
+ LibENet.enet_host_compress_with_range_coder(@_host)
113
+ else
114
+ LibENet.enet_host_compress(@_host, nil)
115
+ end
116
+ end
117
+
118
+ def on_connection(client)
119
+ end
120
+
121
+ def on_packet_received(client, data, channel)
122
+ end
123
+
124
+ def on_disconnection(client)
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,34 @@
1
+ require_relative "renet/server"
2
+ require_relative "renet/connection"
3
+ require_relative "renet/client"
4
+
5
+ module ENet
6
+ @@initialized = false
7
+ @@at_exit_handler = false
8
+
9
+ def self.init
10
+ return true if @@initialized
11
+
12
+ return false if LibENet.enet_initialize != 0
13
+
14
+ @@initialized = true
15
+
16
+ unless @@at_exit_handler
17
+ @@at_exit_handler = true
18
+
19
+ at_exit do
20
+ shutdown
21
+ end
22
+ end
23
+
24
+ true
25
+ end
26
+
27
+ def self.shutdown
28
+ return unless @@initialized
29
+
30
+ LibENet.enet_deinitialize
31
+
32
+ @@initialized = false
33
+ end
34
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ENet
4
+ VERSION = "0.1.0"
5
+ end
data/lib/ffi-enet.rb ADDED
@@ -0,0 +1,438 @@
1
+ require "ffi"
2
+ require_relative "ffi-enet/version"
3
+
4
+ module LibENet
5
+ extend FFI::Library
6
+ ffi_lib [
7
+ "#{File.expand_path(__dir__)}#{RUBY_PLATFORM.match?(/^x86_64-/) ? "/../lib64" : ""}/libenet.so",
8
+ "#{File.expand_path(__dir__)}#{RUBY_PLATFORM.match?(/^x64-/) ? "/../lib64" : ""}/libenet.dll",
9
+ "enet"
10
+ ]
11
+
12
+ # "Constants"
13
+ ENET_PROTOCOL_MINIMUM_MTU = 576
14
+ ENET_PROTOCOL_MAXIMUM_MTU = 4096
15
+ ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS = 32
16
+ ENET_PROTOCOL_MINIMUM_WINDOW_SIZE = 4096
17
+ ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE = 65536
18
+ ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT = 1
19
+ ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT = 255
20
+ ENET_PROTOCOL_MAXIMUM_PEER_ID = 0xFFF
21
+ ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT = 1024 * 1024
22
+
23
+ ENET_BUFFER_MAXIMUM = (1 + 2 * ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS)
24
+
25
+ ENET_HOST_RECEIVE_BUFFER_SIZE = 256 * 1024,
26
+ ENET_HOST_SEND_BUFFER_SIZE = 256 * 1024,
27
+ ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL = 1000,
28
+ ENET_HOST_DEFAULT_MTU = 1392,
29
+ ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE = 32 * 1024 * 1024,
30
+ ENET_HOST_DEFAULT_MAXIMUM_WAITING_DATA = 32 * 1024 * 1024,
31
+
32
+ ENET_PEER_DEFAULT_ROUND_TRIP_TIME = 500,
33
+ ENET_PEER_DEFAULT_PACKET_THROTTLE = 32,
34
+ ENET_PEER_PACKET_THROTTLE_SCALE = 32,
35
+ ENET_PEER_PACKET_THROTTLE_COUNTER = 7,
36
+ ENET_PEER_PACKET_THROTTLE_ACCELERATION = 2,
37
+ ENET_PEER_PACKET_THROTTLE_DECELERATION = 2,
38
+ ENET_PEER_PACKET_THROTTLE_INTERVAL = 5000,
39
+ ENET_PEER_PACKET_LOSS_SCALE = (1 << 16),
40
+ ENET_PEER_PACKET_LOSS_INTERVAL = 10000,
41
+ ENET_PEER_WINDOW_SIZE_SCALE = 64 * 1024,
42
+ ENET_PEER_TIMEOUT_LIMIT = 32,
43
+ ENET_PEER_TIMEOUT_MINIMUM = 5000,
44
+ ENET_PEER_TIMEOUT_MAXIMUM = 30000,
45
+ ENET_PEER_PING_INTERVAL = 500,
46
+ ENET_PEER_UNSEQUENCED_WINDOWS = 64,
47
+ ENET_PEER_UNSEQUENCED_WINDOW_SIZE = 1024,
48
+ ENET_PEER_FREE_UNSEQUENCED_WINDOWS = 32,
49
+ ENET_PEER_RELIABLE_WINDOWS = 16,
50
+ ENET_PEER_RELIABLE_WINDOW_SIZE = 0x1000,
51
+ ENET_PEER_FREE_RELIABLE_WINDOWS = 8
52
+
53
+ # Enums
54
+ ENetEventType = enum(
55
+ :ENET_EVENT_TYPE_NONE,
56
+ :ENET_EVENT_TYPE_CONNECT,
57
+ :ENET_EVENT_TYPE_DISCONNECT,
58
+ :ENET_EVENT_TYPE_RECEIVE
59
+ )
60
+
61
+ ENetPeerState = enum(
62
+ :ENET_PEER_STATE_DISCONNECTED,
63
+ :ENET_PEER_STATE_CONNECTING,
64
+ :ENET_PEER_STATE_ACKNOWLEDGING_CONNECT,
65
+ :ENET_PEER_STATE_CONNECTION_PENDING,
66
+ :ENET_PEER_STATE_CONNECTION_SUCCEEDED,
67
+ :ENET_PEER_STATE_CONNECTED,
68
+ :ENET_PEER_STATE_DISCONNECT_LATER,
69
+ :ENET_PEER_STATE_DISCONNECTING,
70
+ :ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT,
71
+ :ENET_PEER_STATE_ZOMBIE
72
+ )
73
+
74
+ # ENetSocketOption = enum(
75
+ # :ENET_SOCKOPT_NONBLOCK,
76
+ # :ENET_SOCKOPT_BROADCAST,
77
+ # :ENET_SOCKOPT_RCVBUF,
78
+ # :ENET_SOCKOPT_SNDBUF,
79
+ # :ENET_SOCKOPT_REUSEADDR,
80
+ # :ENET_SOCKOPT_RCVTIMEO,
81
+ # :ENET_SOCKOPT_SNDTIMEO,
82
+ # :ENET_SOCKOPT_ERROR,
83
+ # :ENET_SOCKOPT_NODELAY
84
+ # )
85
+
86
+ # ENetSocketType = enum(
87
+ # :ENET_SOCKET_TYPE_STREAM,
88
+ # :ENET_SOCKET_TYPE_DATAGRAM
89
+ # )
90
+
91
+ # Structs
92
+ class ENetAddress < FFI::Struct
93
+ layout :host, :uint32,
94
+ :port, :ushort
95
+ end
96
+
97
+ class ENetPacket < FFI::Struct
98
+ layout :_ref_count, :size_t,
99
+ :flags, :uint32,
100
+ :data, :pointer,
101
+ :length, :short,
102
+ :callback, :pointer,
103
+ :user_data, :pointer
104
+ end
105
+
106
+ # Why on earth would you do this? They're the same types...
107
+ if FFI::Platform.windows?
108
+ # Windows O_o
109
+ class ENetBuffer < FFI::Struct
110
+ layout :length, :size_t,
111
+ :data, :pointer
112
+ end
113
+ else
114
+ # Unix o_O
115
+ class ENetBuffer < FFI::Struct
116
+ layout :data, :pointer,
117
+ :length, :size_t
118
+ end
119
+ end
120
+
121
+ class ENetCompressor < FFI::Struct
122
+ layout :context, :pointer,
123
+ :compress, :pointer, # FIXME: http://sauerbraten.org/enet/structENetCompressor.html
124
+ :decompress, :pointer, # FIXME
125
+ :destroy, :pointer # FIXME
126
+ end
127
+
128
+ class ENetListNode < FFI::Struct
129
+ layout :nxt, ENetListNode.by_ref,
130
+ :previous, ENetListNode.by_ref
131
+ end
132
+
133
+ class ENetList < FFI::Struct
134
+ layout :sentinel, ENetListNode
135
+ end
136
+
137
+ class ENetProtocolHeader < FFI::Struct
138
+ layout :peer_id, :ushort,
139
+ :sent_time, :ushort
140
+ end
141
+
142
+ class ENetProtocolCommandHeader < FFI::Struct
143
+ layout :command, :uchar,
144
+ :channel_id, :uchar,
145
+ :reliable_sequence_number, :ushort
146
+ end
147
+
148
+ class ENetProtocolAcknowledge < FFI::Struct
149
+ layout :header, ENetProtocolCommandHeader,
150
+ :received_reliable_sequence_number, :ushort,
151
+ :received_sent_time, :ushort
152
+ end
153
+
154
+ class ENetProtocolConnect < FFI::Struct
155
+ layout :header, ENetProtocolCommandHeader,
156
+ :outgoingPeerID, :ushort,
157
+ :incomingSessionID, :uchar,
158
+ :outgoingSessionID, :uchar,
159
+ :mtu, :uint32,
160
+ :windowSize, :uint32,
161
+ :channelCount, :uint32,
162
+ :incomingBandwidth, :uint32,
163
+ :outgoingBandwidth, :uint32,
164
+ :packetThrottleInterval, :uint32,
165
+ :packetThrottleAcceleration, :uint32,
166
+ :packetThrottleDeceleration, :uint32,
167
+ :connectID, :uint32,
168
+ :data, :uint32
169
+ end
170
+
171
+ class ENetProtocolVerifyConnect < FFI::Struct
172
+ layout :header, ENetProtocolCommandHeader,
173
+ :outgoingPeerID, :ushort,
174
+ :incomingSessionID, :uchar,
175
+ :outgoingSessionID, :uchar,
176
+ :mtu, :uint32,
177
+ :windowSize, :uint32,
178
+ :channelCount, :uint32,
179
+ :incomingBandwidth, :uint32,
180
+ :outgoingBandwidth, :uint32,
181
+ :packetThrottleInterval, :uint32,
182
+ :packetThrottleAcceleration, :uint32,
183
+ :packetThrottleDeceleration, :uint32,
184
+ :connectID, :uint32
185
+ end
186
+
187
+ class ENetProtocolBandwidthLimit < FFI::Struct
188
+ layout :header, ENetProtocolCommandHeader,
189
+ :incomingBandwidth, :uint32,
190
+ :outgoingBandwidth, :uint32
191
+ end
192
+
193
+ class ENetProtocolThrottleConfigure < FFI::Struct
194
+ layout :header, ENetProtocolCommandHeader,
195
+ :packetThrottleInterval, :uint32,
196
+ :packetThrottleAcceleration, :uint32,
197
+ :packetThrottleDeceleration, :uint32
198
+ end
199
+
200
+ class ENetProtocolDisconnect < FFI::Struct
201
+ layout :header, ENetProtocolCommandHeader,
202
+ :data, :uint32
203
+ end
204
+
205
+ class ENetProtocolPing < FFI::Struct
206
+ layout :header, ENetProtocolCommandHeader
207
+ end
208
+
209
+ class ENetProtocolSendReliable < FFI::Struct
210
+ layout :header, ENetProtocolCommandHeader,
211
+ :dataLength, :ushort
212
+ end
213
+
214
+ class ENetProtocolSendUnreliable < FFI::Struct
215
+ layout :header, ENetProtocolCommandHeader,
216
+ :unreliableSequenceNumber, :ushort,
217
+ :dataLength, :ushort
218
+ end
219
+
220
+ class ENetProtocolSendUnsequenced < FFI::Struct
221
+ layout :header, ENetProtocolCommandHeader,
222
+ :unsequencedGroup, :ushort,
223
+ :dataLength, :ushort
224
+ end
225
+
226
+ class ENetProtocolSendFragment < FFI::Struct
227
+ layout :header, ENetProtocolCommandHeader,
228
+ :startSequenceNumber, :ushort,
229
+ :dataLength, :ushort,
230
+ :fragmentCount, :uint32,
231
+ :fragmentNumber, :uint32,
232
+ :totalLength, :uint32,
233
+ :fragmentOffset, :uint32
234
+ end
235
+
236
+ class ENetProtocol < FFI::Union
237
+ layout :header, ENetProtocolCommandHeader,
238
+ :acknowledge, ENetProtocolAcknowledge,
239
+ :connect, ENetProtocolConnect,
240
+ :verifyConnect, ENetProtocolVerifyConnect,
241
+ :disconnect, ENetProtocolDisconnect,
242
+ :ping, ENetProtocolPing,
243
+ :sendReliable, ENetProtocolSendReliable,
244
+ :sendUnreliable, ENetProtocolSendUnreliable,
245
+ :sendUnsequenced, ENetProtocolSendUnsequenced,
246
+ :sendFragment, ENetProtocolSendFragment,
247
+ :bandwidthLimit, ENetProtocolBandwidthLimit,
248
+ :throttleConfigure, ENetProtocolThrottleConfigure
249
+ end
250
+
251
+ if FFI::Platform.windows?
252
+ typedef(:uint64, :ENetSocket)
253
+ else
254
+ typedef(:int, :ENetSocket) # FIXME: Test this on Linux
255
+ end
256
+
257
+ class ENetHost < FFI::Struct
258
+ layout :socket, :ENetSocket,
259
+ :address, ENetAddress,
260
+ :incoming_bandwidth, :uint32,
261
+ :outgoing_bandwidth, :uint32,
262
+ :bandwidth_throttle_epoch, :uint32,
263
+ :mtu, :uint32,
264
+ :random_seed, :uint32,
265
+ :recalculate_bandwidth_limits, :int,
266
+ :peers, :pointer, # Array of ENetPeer
267
+ :peer_count, :size_t,
268
+ :channel_limit, :size_t,
269
+ :service_time, :uint32,
270
+ :dispatch_queue, :pointer, # ENetList
271
+ :total_queued, :uint32,
272
+ :packet_size, :size_t,
273
+ :header_flags, :ushort,
274
+ :commands, [ENetProtocol, ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS],
275
+ :command_count, :size_t,
276
+ :buffers, [ENetBuffer, ENET_BUFFER_MAXIMUM],
277
+ :buffer_count, :size_t,
278
+ :checksum, :pointer, # ENetChecksumCallback
279
+ :compressor, ENetCompressor,
280
+ :packet_data, [:uchar, 2 * ENET_PROTOCOL_MAXIMUM_MTU], # NOTE: This may be wrong size/offset/length... using a 1d array here, instead of [2][ENET_PROTOCOL_MAXIMUM_MTU]; FFI docs don't seem to show how to do a multidimentional array.
281
+ :received_address, ENetAddress,
282
+ :received_data, :string,
283
+ :received_data_length, :size_t,
284
+ :total_sent_data, :uint32,
285
+ :total_sent_packets, :uint32,
286
+ :total_received_data, :uint32,
287
+ :total_received_packets, :uint32,
288
+ :intercept, :pointer, # ENetInterceptCallback
289
+ :connected_peers, :size_t,
290
+ :bandwidth_limited_peers, :size_t,
291
+ :duplicate_peers, :size_t,
292
+ :maximum_packet_size, :size_t,
293
+ :maximum_waiting_data, :size_t
294
+ end
295
+
296
+ # FIXME: Layout is wrong due to doxygen alphabetizing fields...
297
+ class ENetPeer < FFI::Struct
298
+ layout :dispatchList, ENetListNode,
299
+ :host, ENetHost,
300
+ :outgoing_peer_id, :ushort,
301
+ :incoming_peer_id, :ushort,
302
+ :connect_id, :uint32,
303
+ :outgoing_session_id, :uchar,
304
+ :incoming_session_id, :uchar,
305
+ :address, ENetAddress,
306
+ :data, :pointer,
307
+ :state, ENetPeerState,
308
+ :channels, :pointer, # ENetChannel
309
+ :channel_count, :size_t,
310
+ :incoming_bandwidth, :uint32,
311
+ :outgoing_bandwidth, :uint32,
312
+ :incoming_bandwidth_throttle_epoch, :uint32,
313
+ :outgoing_bandwidth_throttle_epoch, :uint32,
314
+ :incoming_data_total, :uint32,
315
+ :outgoing_data_total, :uint32,
316
+ :last_send_time, :uint32,
317
+ :last_receive_time, :uint32,
318
+ :next_timeout, :uint32,
319
+ :earliest_timeout, :uint32,
320
+ :packet_loss_epoch, :uint32,
321
+ :packets_sent, :uint32,
322
+ :packets_lost, :uint32,
323
+ :packet_loss, :uint32, # mean packet loss of reliable packets as a ratio with respect to the constant ENET_PEER_PACKET_LOSS_SCALE
324
+ :packet_loss_variance, :uint32,
325
+ :packet_throttle, :uint32,
326
+ :packet_throttle_limit, :uint32,
327
+ :packet_throttle_counter, :uint32,
328
+ :packet_throttle_epoch, :uint32,
329
+ :packet_throttle_acceleration, :uint32,
330
+ :packet_throttle_deceleration, :uint32,
331
+ :packet_throttle_interval, :uint32,
332
+ :ping_interval, :uint32,
333
+ :timeout_limit, :uint32,
334
+ :timeout_minimum, :uint32,
335
+ :timeout_maximum, :uint32,
336
+ :last_round_trip_time, :uint32,
337
+ :lowest_round_trip_time, :uint32,
338
+ :last_round_trip_time_variance, :uint32,
339
+ :highest_round_trip_time_variance, :uint32,
340
+ :round_trip_time, :uint32, # mean round trip time (RTT), in milliseconds, between sending a reliable packet and receiving its acknowledgement
341
+ :round_trip_time_variance, :uint32,
342
+ :mtu, :uint32,
343
+ :window_size, :uint32,
344
+ :reliable_data_in_transit, :uint32,
345
+ :outgoing_reliable_sequence_number, :ushort,
346
+ :acknowledgements, ENetList,
347
+ :sent_reliable_commands, ENetList,
348
+ :outgoing_send_reliable_commands, ENetList,
349
+ :outgoing_commands, ENetList,
350
+ :dispatched_commands, ENetList,
351
+ :flags, :ushort,
352
+ :reserved, :ushort,
353
+ :incoming_unsequenced_group, :ushort,
354
+ :outgoing_unsequenced_group, :ushort,
355
+ :unsequenced_window, [:uint32, ENET_PEER_UNSEQUENCED_WINDOW_SIZE / 32],
356
+ :event_data, :uint32,
357
+ :total_waiting_data, :size_t
358
+ end
359
+
360
+ class ENetEvent < FFI::Struct
361
+ layout :type, ENetEventType,
362
+ :peer, ENetPeer.by_ref,
363
+ :channel_id, :uchar,
364
+ :data, :uint32,
365
+ :packet, ENetPacket.by_ref
366
+ end
367
+
368
+ # Global
369
+ attach_function :enet_deinitialize, [], :void
370
+ attach_function :enet_initialize, [], :void
371
+ attach_function :enet_initialize_with_callbacks, [:uint32, :pointer], :void # FIXME
372
+ attach_function :enet_linked_version, [], :int
373
+
374
+ # Address
375
+ attach_function :enet_address_get_host, [ENetAddress.by_ref, :pointer, :size_t], :int
376
+ attach_function :enet_address_get_host_ip, [ENetAddress.by_ref, :pointer, :size_t], :int
377
+ attach_function :enet_address_set_host, [ENetAddress.by_ref, :string], :int
378
+ attach_function :enet_address_set_host_ip, [ENetAddress.by_ref, :string], :int
379
+
380
+ # Host
381
+ attach_function :enet_host_bandwidth_limit, [ENetHost, :uint32, :uint32], :void
382
+ attach_function :enet_host_broadcast, [ENetHost, :uchar, :pointer], :void
383
+ attach_function :enet_host_channel_limit, [ENetHost, :size_t], :void
384
+ attach_function :enet_host_check_events, [ENetHost, ENetEvent.by_ref], :int
385
+ attach_function :enet_host_compress, [ENetHost, ENetCompressor.by_ref], :int
386
+ attach_function :enet_host_compress_with_range_coder, [ENetHost], :int
387
+ attach_function :enet_host_connect, [ENetHost, ENetAddress.by_ref, :size_t, :uint32], ENetPeer.by_ref
388
+ attach_function :enet_host_create, [ENetAddress.by_ref, :size_t, :size_t, :uint32, :uint32], ENetHost
389
+ attach_function :enet_host_destroy, [ENetHost], :void
390
+ attach_function :enet_host_flush, [ENetHost], :void
391
+ attach_function :enet_host_service, [ENetHost, ENetEvent.by_ref, :uint32], :int, blocking: true
392
+
393
+ # Packet
394
+ attach_function :enet_crc32, [:pointer, :size_t], :uint32
395
+ attach_function :enet_packet_create, [:string, :size_t, :uint32], ENetPacket.by_ref
396
+ attach_function :enet_packet_destroy, [ENetPacket.by_ref], :void
397
+ attach_function :enet_packet_resize, [ENetHost, :size_t], :int
398
+
399
+ # Peer
400
+ attach_function :enet_peer_disconnect, [ENetPeer.by_ref, :uint32], :void
401
+ attach_function :enet_peer_disconnect_later, [ENetPeer.by_ref, :uint32], :void
402
+ attach_function :enet_peer_disconnect_now, [ENetPeer.by_ref, :uint32], :void
403
+ attach_function :enet_peer_ping, [ENetPeer.by_ref], :void
404
+ attach_function :enet_peer_ping_interval, [ENetPeer.by_ref, :uint32], :void
405
+ attach_function :enet_peer_receive, [ENetPeer.by_ref, :uchar], ENetPacket.by_ref # FIXME
406
+ attach_function :enet_peer_reset, [ENetPeer.by_ref], :void
407
+ attach_function :enet_peer_send, [ENetPeer.by_ref, :ushort, ENetPacket.by_ref], :int
408
+ attach_function :enet_peer_throttle_configure, [ENetPeer.by_ref, :uint32, :uint32, :uint32], :void
409
+ attach_function :enet_peer_timeout, [ENetPeer.by_ref, :uint32, :uint32, :uint32], :void
410
+
411
+ # Range Coder
412
+ attach_function :enet_range_coder_compress, [:pointer, ENetBuffer.by_ref, :size_t, :size_t, :uchar, :size_t], :size_t
413
+ attach_function :enet_range_coder_create, [], :pointer
414
+ attach_function :enet_range_coder_decompress, [:pointer, :ushort, :size_t, :ushort, :size_t], :size_t
415
+ attach_function :enet_range_coder_destroy, [:pointer], :void
416
+
417
+ # Socket
418
+ # typedef(:int, :ENetSocket)
419
+
420
+ # attach_function :enet_socket_accept, [:ENetSocket, ENetAddress.by_ref], :ENetSocket
421
+ # attach_function :enet_socket_bind, [:ENetSocket, ENetAddress.by_ref], :int
422
+ # attach_function :enet_socket_connect, [:ENetSocket, ENetAddress.by_ref], :int
423
+ # attach_function :enet_socket_create, [:uint32], :ENetSocket
424
+ # attach_function :enet_socket_destroy, [:ENetSocket], :void
425
+ # attach_function :enet_socket_get_address, [:ENetSocket, ENetAddress.by_ref], :int
426
+ # attach_function :enet_socket_get_option, [:ENetSocket, ENetSocketOption, :int], :int
427
+ # attach_function :enet_socket_listen, [:ENetSocket, :int], :int
428
+ # attach_function :enet_socket_receive, [:ENetSocket, ENetAddress.by_ref, ENetBuffer.by_ref, :size_t], :int
429
+ # attach_function :enet_socket_send, [:ENetSocket, ENetAddress.by_ref, ENetBuffer.by_ref, :size_t], :int
430
+ # attach_function :enet_socket_set_option, [:ENetSocket, ENetSocketOption, :pointer], :int
431
+ # attach_function :enet_socket_shutdown, [:ENetSocket, ENetSocketShutdown], :int
432
+ # attach_function :enet_socket_wait, [:ENetSocket, :pointer, :uint32], :int
433
+ # attach_function :enet_socketset_select, [:ENetSocket, ENetSocketSet.by_ref, ENetSocketSet.by_ref, :uint32], :int
434
+
435
+ # Time
436
+ attach_function :enet_time_get, [], :uint32
437
+ attach_function :enet_time_set, [:uint32], :void
438
+ end
data/lib64/libenet.dll ADDED
Binary file
data/lib64/libenet.so ADDED
Binary file
data/sig/enet.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module Enet
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ffi-enet
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Cyberarm
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-03-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ffi
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.15'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.15'
27
+ description: FFI interface to the enet networking library. Includes rENet-like API
28
+ to simplify enet usage.
29
+ email:
30
+ - matthewlikesrobots@gmail.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - ".standard.yml"
36
+ - CHANGELOG.md
37
+ - LICENSE.txt
38
+ - README.md
39
+ - Rakefile
40
+ - examples/echo.rb
41
+ - lib/ffi-enet.rb
42
+ - lib/ffi-enet/renet.rb
43
+ - lib/ffi-enet/renet/client.rb
44
+ - lib/ffi-enet/renet/connection.rb
45
+ - lib/ffi-enet/renet/server.rb
46
+ - lib/ffi-enet/version.rb
47
+ - lib64/libenet.dll
48
+ - lib64/libenet.so
49
+ - sig/enet.rbs
50
+ homepage: https://github.com/cyberarm/ffi-enet
51
+ licenses:
52
+ - MIT
53
+ metadata:
54
+ allowed_push_host: https://rubygems.org
55
+ homepage_uri: https://github.com/cyberarm/ffi-enet
56
+ source_code_uri: https://github.com/cyberarm/ffi-enet
57
+ changelog_uri: https://github.com/cyberarm/ffi-enet/blob/master/CHANGELOG.md
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ - lib64
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: 3.0.0
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ requirements: []
74
+ rubygems_version: 3.5.6
75
+ signing_key:
76
+ specification_version: 4
77
+ summary: FFI interface to the enet networking library.
78
+ test_files: []