summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar B3n302017-07-07 21:34:15 +0200
committerGravatar bunnei2017-07-07 15:34:15 -0400
commit2e37ce01c9dcdc5932cf5fe47a1ade0e0d2b7cf8 (patch)
treeb5298b3c528d9acc1f3fa48f19c9f9c19c97d036
parentMerge pull request #2814 from Kloen/macro-remove (diff)
downloadyuzu-2e37ce01c9dcdc5932cf5fe47a1ade0e0d2b7cf8.tar.gz
yuzu-2e37ce01c9dcdc5932cf5fe47a1ade0e0d2b7cf8.tar.xz
yuzu-2e37ce01c9dcdc5932cf5fe47a1ade0e0d2b7cf8.zip
Implement basic virtual Room support based on enet (#2803)
* Added support for network with ENet lib, connecting is possible, but data can't be sent, yet. * fixup! Added support for network with ENet lib, * fixup! CLang * fixup! Added support for network with ENet lib, * fixup! Added support for network with ENet lib, * fixup! Clang format * More fixups! * Moved ENetHost* and ENetPeer* into pimpl classes * fixup! Moved ENetHost* and ENetPeer* into pimpl classes * fixup! Clang again * fixup! Moved ENetHost* and ENetPeer* into pimpl classes * fixup! Moved ENetHost* and ENetPeer* into pimpl classes * fixup! Moved ENetHost* and ENetPeer* into pimpl classes
-rw-r--r--.gitmodules3
-rw-r--r--externals/CMakeLists.txt4
m---------externals/enet0
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/citra_qt/CMakeLists.txt2
-rw-r--r--src/citra_qt/bootmanager.cpp3
-rw-r--r--src/common/logging/backend.cpp1
-rw-r--r--src/common/logging/log.h1
-rw-r--r--src/network/CMakeLists.txt16
-rw-r--r--src/network/network.cpp50
-rw-r--r--src/network/network.h25
-rw-r--r--src/network/room.cpp60
-rw-r--r--src/network/room.h60
-rw-r--r--src/network/room_member.cpp74
-rw-r--r--src/network/room_member.h65
15 files changed, 364 insertions, 1 deletions
diff --git a/.gitmodules b/.gitmodules
index 36caa59f8..ac0df914d 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -25,3 +25,6 @@
25[submodule "fmt"] 25[submodule "fmt"]
26 path = externals/fmt 26 path = externals/fmt
27 url = https://github.com/fmtlib/fmt.git 27 url = https://github.com/fmtlib/fmt.git
28[submodule "externals/enet"]
29 path = externals/enet
30 url = https://github.com/lsalzman/enet
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index 02e02350c..cc47166fc 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -48,3 +48,7 @@ if (ARCHITECTURE_x86_64)
48 target_include_directories(xbyak INTERFACE ./xbyak/xbyak) 48 target_include_directories(xbyak INTERFACE ./xbyak/xbyak)
49 target_compile_definitions(xbyak INTERFACE XBYAK_NO_OP_NAMES) 49 target_compile_definitions(xbyak INTERFACE XBYAK_NO_OP_NAMES)
50endif() 50endif()
51
52# ENet
53add_subdirectory(enet)
54target_include_directories(enet INTERFACE ./enet/include)
diff --git a/externals/enet b/externals/enet
new file mode 160000
Subproject 9d9ba122d4818f7ae1aef2197933ac696edb233
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index a45439481..655bd83aa 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -5,6 +5,7 @@ add_subdirectory(common)
5add_subdirectory(core) 5add_subdirectory(core)
6add_subdirectory(video_core) 6add_subdirectory(video_core)
7add_subdirectory(audio_core) 7add_subdirectory(audio_core)
8add_subdirectory(network)
8add_subdirectory(input_common) 9add_subdirectory(input_common)
9add_subdirectory(tests) 10add_subdirectory(tests)
10if (ENABLE_SDL2) 11if (ENABLE_SDL2)
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt
index 4841cbf05..9572d3e28 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -91,7 +91,7 @@ if (APPLE)
91else() 91else()
92 add_executable(citra-qt ${SRCS} ${HEADERS} ${UI_HDRS}) 92 add_executable(citra-qt ${SRCS} ${HEADERS} ${UI_HDRS})
93endif() 93endif()
94target_link_libraries(citra-qt PRIVATE audio_core common core input_common video_core) 94target_link_libraries(citra-qt PRIVATE audio_core common core input_common network video_core)
95target_link_libraries(citra-qt PRIVATE Boost::boost glad nihstro-headers Qt5::OpenGL Qt5::Widgets) 95target_link_libraries(citra-qt PRIVATE Boost::boost glad nihstro-headers Qt5::OpenGL Qt5::Widgets)
96target_link_libraries(citra-qt PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) 96target_link_libraries(citra-qt PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
97 97
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index a8a4aed8b..30554890f 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -17,6 +17,7 @@
17#include "core/settings.h" 17#include "core/settings.h"
18#include "input_common/keyboard.h" 18#include "input_common/keyboard.h"
19#include "input_common/main.h" 19#include "input_common/main.h"
20#include "network/network.h"
20 21
21EmuThread::EmuThread(GRenderWindow* render_window) 22EmuThread::EmuThread(GRenderWindow* render_window)
22 : exec_step(false), running(false), stop_run(false), render_window(render_window) {} 23 : exec_step(false), running(false), stop_run(false), render_window(render_window) {}
@@ -110,10 +111,12 @@ GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread)
110 setWindowTitle(QString::fromStdString(window_title)); 111 setWindowTitle(QString::fromStdString(window_title));
111 112
112 InputCommon::Init(); 113 InputCommon::Init();
114 Network::Init();
113} 115}
114 116
115GRenderWindow::~GRenderWindow() { 117GRenderWindow::~GRenderWindow() {
116 InputCommon::Shutdown(); 118 InputCommon::Shutdown();
119 Network::Shutdown();
117} 120}
118 121
119void GRenderWindow::moveContext() { 122void GRenderWindow::moveContext() {
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 42f6a9918..0e4b85a76 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -72,6 +72,7 @@ namespace Log {
72 SUB(Audio, DSP) \ 72 SUB(Audio, DSP) \
73 SUB(Audio, Sink) \ 73 SUB(Audio, Sink) \
74 CLS(Input) \ 74 CLS(Input) \
75 CLS(Network) \
75 CLS(Loader) 76 CLS(Loader)
76 77
77// GetClassName is a macro defined by Windows.h, grrr... 78// GetClassName is a macro defined by Windows.h, grrr...
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
index 1b905f66c..8f13b80b3 100644
--- a/src/common/logging/log.h
+++ b/src/common/logging/log.h
@@ -90,6 +90,7 @@ enum class Class : ClassType {
90 Audio_Sink, ///< Emulator audio output backend 90 Audio_Sink, ///< Emulator audio output backend
91 Loader, ///< ROM loader 91 Loader, ///< ROM loader
92 Input, ///< Input emulation 92 Input, ///< Input emulation
93 Network, ///< Network emulation
93 Count ///< Total number of logging classes 94 Count ///< Total number of logging classes
94}; 95};
95 96
diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt
new file mode 100644
index 000000000..aeabe430e
--- /dev/null
+++ b/src/network/CMakeLists.txt
@@ -0,0 +1,16 @@
1set(SRCS
2 network.cpp
3 room.cpp
4 room_member.cpp
5 )
6
7set(HEADERS
8 network.h
9 room.h
10 room_member.h
11 )
12
13create_directory_groups(${SRCS} ${HEADERS})
14
15add_library(network STATIC ${SRCS} ${HEADERS})
16target_link_libraries(network PRIVATE common enet)
diff --git a/src/network/network.cpp b/src/network/network.cpp
new file mode 100644
index 000000000..51b5d6a9f
--- /dev/null
+++ b/src/network/network.cpp
@@ -0,0 +1,50 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/assert.h"
6#include "common/logging/log.h"
7#include "enet/enet.h"
8#include "network/network.h"
9
10namespace Network {
11
12static std::shared_ptr<RoomMember> g_room_member; ///< RoomMember (Client) for network games
13static std::shared_ptr<Room> g_room; ///< Room (Server) for network games
14// TODO(B3N30): Put these globals into a networking class
15
16bool Init() {
17 if (enet_initialize() != 0) {
18 LOG_ERROR(Network, "Error initalizing ENet");
19 return false;
20 }
21 g_room = std::make_shared<Room>();
22 g_room_member = std::make_shared<RoomMember>();
23 LOG_DEBUG(Network, "initialized OK");
24 return true;
25}
26
27std::weak_ptr<Room> GetRoom() {
28 return g_room;
29}
30
31std::weak_ptr<RoomMember> GetRoomMember() {
32 return g_room_member;
33}
34
35void Shutdown() {
36 if (g_room_member) {
37 if (g_room_member->IsConnected())
38 g_room_member->Leave();
39 g_room_member.reset();
40 }
41 if (g_room) {
42 if (g_room->GetState() == Room::State::Open)
43 g_room->Destroy();
44 g_room.reset();
45 }
46 enet_deinitialize();
47 LOG_DEBUG(Network, "shutdown OK");
48}
49
50} // namespace Network
diff --git a/src/network/network.h b/src/network/network.h
new file mode 100644
index 000000000..6d002d693
--- /dev/null
+++ b/src/network/network.h
@@ -0,0 +1,25 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include "network/room.h"
9#include "network/room_member.h"
10
11namespace Network {
12
13/// Initializes and registers the network device, the room, and the room member.
14bool Init();
15
16/// Returns a pointer to the room handle
17std::weak_ptr<Room> GetRoom();
18
19/// Returns a pointer to the room member handle
20std::weak_ptr<RoomMember> GetRoomMember();
21
22/// Unregisters the network device, the room, and the room member and shut them down.
23void Shutdown();
24
25} // namespace Network
diff --git a/src/network/room.cpp b/src/network/room.cpp
new file mode 100644
index 000000000..48de2f5cb
--- /dev/null
+++ b/src/network/room.cpp
@@ -0,0 +1,60 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "enet/enet.h"
6#include "network/room.h"
7
8namespace Network {
9
10/// Maximum number of concurrent connections allowed to this room.
11static constexpr u32 MaxConcurrentConnections = 10;
12
13class Room::RoomImpl {
14public:
15 ENetHost* server = nullptr; ///< Network interface.
16
17 std::atomic<State> state{State::Closed}; ///< Current state of the room.
18 RoomInformation room_information; ///< Information about this room.
19};
20
21Room::Room() : room_impl{std::make_unique<RoomImpl>()} {}
22
23Room::~Room() = default;
24
25void Room::Create(const std::string& name, const std::string& server_address, u16 server_port) {
26 ENetAddress address;
27 address.host = ENET_HOST_ANY;
28 enet_address_set_host(&address, server_address.c_str());
29 address.port = server_port;
30
31 room_impl->server = enet_host_create(&address, MaxConcurrentConnections, NumChannels, 0, 0);
32 // TODO(B3N30): Allow specifying the maximum number of concurrent connections.
33 room_impl->state = State::Open;
34
35 room_impl->room_information.name = name;
36 room_impl->room_information.member_slots = MaxConcurrentConnections;
37
38 // TODO(B3N30): Start the receiving thread
39}
40
41Room::State Room::GetState() const {
42 return room_impl->state;
43}
44
45const RoomInformation& Room::GetRoomInformation() const {
46 return room_impl->room_information;
47}
48
49void Room::Destroy() {
50 room_impl->state = State::Closed;
51 // TODO(B3n30): Join the receiving thread
52
53 if (room_impl->server) {
54 enet_host_destroy(room_impl->server);
55 }
56 room_impl->room_information = {};
57 room_impl->server = nullptr;
58}
59
60} // namespace Network
diff --git a/src/network/room.h b/src/network/room.h
new file mode 100644
index 000000000..70c64d5f1
--- /dev/null
+++ b/src/network/room.h
@@ -0,0 +1,60 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <atomic>
8#include <memory>
9#include <string>
10#include "common/common_types.h"
11
12namespace Network {
13
14constexpr u16 DefaultRoomPort = 1234;
15constexpr size_t NumChannels = 1; // Number of channels used for the connection
16
17struct RoomInformation {
18 std::string name; ///< Name of the server
19 u32 member_slots; ///< Maximum number of members in this room
20};
21
22/// This is what a server [person creating a server] would use.
23class Room final {
24public:
25 enum class State : u8 {
26 Open, ///< The room is open and ready to accept connections.
27 Closed, ///< The room is not opened and can not accept connections.
28 };
29
30 Room();
31 ~Room();
32
33 /**
34 * Gets the current state of the room.
35 */
36 State GetState() const;
37
38 /**
39 * Gets the room information of the room.
40 */
41 const RoomInformation& GetRoomInformation() const;
42
43 /**
44 * Creates the socket for this room. Will bind to default address if
45 * server is empty string.
46 */
47 void Create(const std::string& name, const std::string& server = "",
48 u16 server_port = DefaultRoomPort);
49
50 /**
51 * Destroys the socket
52 */
53 void Destroy();
54
55private:
56 class RoomImpl;
57 std::unique_ptr<RoomImpl> room_impl;
58};
59
60} // namespace Network
diff --git a/src/network/room_member.cpp b/src/network/room_member.cpp
new file mode 100644
index 000000000..c87f009f4
--- /dev/null
+++ b/src/network/room_member.cpp
@@ -0,0 +1,74 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/assert.h"
6#include "enet/enet.h"
7#include "network/room_member.h"
8
9namespace Network {
10
11constexpr u32 ConnectionTimeoutMs = 5000;
12
13class RoomMember::RoomMemberImpl {
14public:
15 ENetHost* client = nullptr; ///< ENet network interface.
16 ENetPeer* server = nullptr; ///< The server peer the client is connected to
17
18 std::atomic<State> state{State::Idle}; ///< Current state of the RoomMember.
19
20 std::string nickname; ///< The nickname of this member.
21};
22
23RoomMember::RoomMember() : room_member_impl{std::make_unique<RoomMemberImpl>()} {
24 room_member_impl->client = enet_host_create(nullptr, 1, NumChannels, 0, 0);
25 ASSERT_MSG(room_member_impl->client != nullptr, "Could not create client");
26}
27
28RoomMember::~RoomMember() {
29 ASSERT_MSG(!IsConnected(), "RoomMember is being destroyed while connected");
30 enet_host_destroy(room_member_impl->client);
31}
32
33RoomMember::State RoomMember::GetState() const {
34 return room_member_impl->state;
35}
36
37void RoomMember::Join(const std::string& nick, const char* server_addr, u16 server_port,
38 u16 client_port) {
39 ENetAddress address{};
40 enet_address_set_host(&address, server_addr);
41 address.port = server_port;
42
43 room_member_impl->server =
44 enet_host_connect(room_member_impl->client, &address, NumChannels, 0);
45
46 if (!room_member_impl->server) {
47 room_member_impl->state = State::Error;
48 return;
49 }
50
51 ENetEvent event{};
52 int net = enet_host_service(room_member_impl->client, &event, ConnectionTimeoutMs);
53 if (net > 0 && event.type == ENET_EVENT_TYPE_CONNECT) {
54 room_member_impl->nickname = nick;
55 room_member_impl->state = State::Joining;
56 // TODO(B3N30): Send a join request with the nickname to the server
57 // TODO(B3N30): Start the receive thread
58 } else {
59 room_member_impl->state = State::CouldNotConnect;
60 }
61}
62
63bool RoomMember::IsConnected() const {
64 return room_member_impl->state == State::Joining || room_member_impl->state == State::Joined;
65}
66
67void RoomMember::Leave() {
68 enet_peer_disconnect(room_member_impl->server, 0);
69 room_member_impl->state = State::Idle;
70 // TODO(B3N30): Close the receive thread
71 enet_peer_reset(room_member_impl->server);
72}
73
74} // namespace Network
diff --git a/src/network/room_member.h b/src/network/room_member.h
new file mode 100644
index 000000000..177622b69
--- /dev/null
+++ b/src/network/room_member.h
@@ -0,0 +1,65 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <atomic>
8#include <memory>
9#include <string>
10#include "common/common_types.h"
11#include "network/room.h"
12
13namespace Network {
14
15/**
16 * This is what a client [person joining a server] would use.
17 * It also has to be used if you host a game yourself (You'd create both, a Room and a
18 * RoomMembership for yourself)
19 */
20class RoomMember final {
21public:
22 enum class State : u8 {
23 Idle, ///< Default state
24 Error, ///< Some error [permissions to network device missing or something]
25 Joining, ///< The client is attempting to join a room.
26 Joined, ///< The client is connected to the room and is ready to send/receive packets.
27 LostConnection, ///< Connection closed
28
29 // Reasons why connection was rejected
30 NameCollision, ///< Somebody is already using this name
31 MacCollision, ///< Somebody is already using that mac-address
32 CouldNotConnect ///< The room is not responding to a connection attempt
33 };
34
35 RoomMember();
36 ~RoomMember();
37
38 /**
39 * Returns the status of our connection to the room.
40 */
41 State GetState() const;
42
43 /**
44 * Returns whether we're connected to a server or not.
45 */
46 bool IsConnected() const;
47
48 /**
49 * Attempts to join a room at the specified address and port, using the specified nickname.
50 * This may fail if the username is already taken.
51 */
52 void Join(const std::string& nickname, const char* server_addr = "127.0.0.1",
53 const u16 serverPort = DefaultRoomPort, const u16 clientPort = 0);
54
55 /**
56 * Leaves the current room.
57 */
58 void Leave();
59
60private:
61 class RoomMemberImpl;
62 std::unique_ptr<RoomMemberImpl> room_member_impl;
63};
64
65} // namespace Network