Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/WolfireGames/overgrowth.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Network/Basic/basic_net_framework.cpp')
-rw-r--r--Source/Network/Basic/basic_net_framework.cpp344
1 files changed, 344 insertions, 0 deletions
diff --git a/Source/Network/Basic/basic_net_framework.cpp b/Source/Network/Basic/basic_net_framework.cpp
new file mode 100644
index 00000000..27e928fd
--- /dev/null
+++ b/Source/Network/Basic/basic_net_framework.cpp
@@ -0,0 +1,344 @@
+//-----------------------------------------------------------------------------
+// Name: basic_net_framework.cpp
+// Developer: Wolfire Games LLC
+// Description:
+// License: Read below
+//-----------------------------------------------------------------------------
+//
+// Copyright 2022 Wolfire Games LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-----------------------------------------------------------------------------
+#include "basic_net_framework.h"
+
+#ifdef USE_BASIC_NETWORK_FRAMEWORK
+#include <Network/net_framework_common.h>
+#include <Logging/logdata.h>
+#include <Online/online.h>
+
+#include <SDL_endian.h>
+
+#include <cassert>
+#include <vector>
+#include <iostream>
+
+using std::vector;
+using std::endl;
+
+static const uint16_t default_port = 25743;
+
+static const uint16_t MESSAGE_HEADER_SIZE = 4;
+
+NetworkingMessage::NetworkingMessage() : data(nullptr), size(0) {
+}
+
+const void* NetworkingMessage::GetData() const {
+ return data;
+}
+
+uint64_t NetworkingMessage::GetSize() const {
+ return size;
+}
+
+void NetworkingMessage::Release() {
+ delete data;
+ data = nullptr;
+ size = 0;
+}
+
+NetConnectionStatus::NetConnectionStatus() : count(0) {
+ buf.resize(1024 * 4);
+}
+
+BasicNetFramework::BasicNetFramework(Online* online_callback) : online(online_callback), socket_set(nullptr) {
+
+}
+
+NetConnectionID BasicNetFramework::GetFreeConnectionID() {
+ for(int i = 1; i < 255; i++) {
+ if(connection_id_map.find(i) == connection_id_map.end()) {
+ return i;
+ }
+ }
+ LOGF << "Ran out of id's for connections, this is a fatal issue." << endl;
+ return 0;
+}
+
+NetListenSocketID BasicNetFramework::GetFreeListenSocketID() {
+ for(int i = 1; i < 255; i++) {
+ if(listen_socket_map.find(i) == listen_socket_map.end()) {
+ return i;
+ }
+ }
+ LOGF << "Ran out of id's for listening sockets, this is a fatal issue." << endl;
+ return 0;
+}
+
+
+void BasicNetFramework::Initialize() {
+ socket_set = SDLNet_AllocSocketSet(255);
+}
+
+void BasicNetFramework::Dispose() {
+ SDLNet_FreeSocketSet(socket_set);
+}
+
+void BasicNetFramework::Update() {
+ //See if there are any new incoming connections.
+ for(auto it : listen_socket_map) {
+ TCPsocket new_socket = SDLNet_TCP_Accept(it.second);
+
+ if(new_socket != nullptr) {
+ NetConnectionID new_connection_id = GetFreeConnectionID();
+ if(new_connection_id > 0) {
+ SDLNet_AddSocket(socket_set, (SDLNet_GenericSocket)new_socket);
+ connection_id_map[new_connection_id] = new_socket;
+ connection_id_map_reverse[new_socket] = new_connection_id;
+ connection_status.emplace(new_connection_id, NetConnectionStatus());
+
+ NetFrameworkConnectionStatusChanged status_changed;
+ status_changed.conn_id = new_connection_id;
+ status_changed.conn_info.connection_state = NetFrameworkConnectionState::Connecting;
+
+ //This call must result in the called either calling AcceptConnection or CloseConnection on the given socket.
+ online->OnConnectionChange(&status_changed);
+ } else {
+ LOGE << "Got an incoming connection, but there are too many already, dropping it" << std::endl;
+ SDLNet_TCP_Close(new_socket);
+ }
+ }
+ }
+
+ //Check for, get and buffer data from sockets.
+ int nr_sockets = SDLNet_CheckSockets(socket_set, 0);
+ if(nr_sockets > 0) {
+ for(auto it : connection_id_map) {
+ if(SDLNet_SocketReady(it.second)) {
+ auto conn_status = connection_status.find(it.first);
+ if(conn_status != connection_status.end()) {
+ NetConnectionStatus* ncs = &conn_status->second;
+ //If we don't have a reasonable amount of buffer space left, grow it.
+ if(ncs->buf.size() - ncs->count < 1024) {
+ ncs->buf.resize(ncs->buf.size() + 1024);
+ }
+
+ int recv_size = SDLNet_TCP_Recv(it.second, ncs->buf.data() + ncs->count, ncs->buf.size() - ncs->count);
+
+ if(recv_size > 0) {
+ /*
+ char* data_as_string = new char[recv_size+1];
+ data_as_string[recv_size] = '\0';
+ memcpy(data_as_string, ncs->buf.data() + ncs->count, recv_size);
+
+ LOGW << "Received Data: \"" << data_as_string << "\"" << endl;
+ */
+
+ ncs->count += recv_size;
+ } else {
+ LOGF << "Got an error on socket, something is broken, this should trigger a disconnect" << std::endl;
+ //TODO, set a flag to trigger a disconnect.
+ }
+
+ if(ncs->count > MESSAGE_HEADER_SIZE) {
+
+ uint32_t message_size = SDL_SwapBE16(((uint16_t*)ncs->buf.data())[0]);
+ uint32_t block_size = message_size + MESSAGE_HEADER_SIZE;
+ uint32_t remainder_size = ncs->count - block_size;
+
+ if(ncs->buf[2] != 0 || ncs->buf[3] != 0) {
+ LOGE << "Corrupt package detected, header bytes that are supposed to be zero aren't." << std::endl;
+ }
+
+ //Check if we've buffered up enough data for the next incoming message.
+ if(ncs->count >= block_size) {
+ NetworkingMessage msg;
+ msg.data = new uint8_t[message_size];
+ msg.size = message_size;
+
+ //Copy out the message data from the block.
+ memcpy(msg.data, ncs->buf.data() + MESSAGE_HEADER_SIZE, message_size);
+
+ //Shift down the next upcoming block, if there's any additional data.
+ if(remainder_size > 0) {
+ memmove(ncs->buf.data(), ncs->buf.data() + block_size, remainder_size);
+ }
+ ncs->count = remainder_size;
+ assert(remainder_size >= 0);
+
+ ncs->messages.push_back(msg);
+ }
+ }
+ } else {
+ LOGF << "Missing connection status structure." << std::endl;
+ }
+ }
+ }
+ }
+}
+
+bool BasicNetFramework::HasFriendInviteOverlay() const {
+ return false;
+}
+
+bool BasicNetFramework::ConnectByIPAddress(const string& address, NetConnectionID* id) {
+ *id = GetFreeConnectionID();
+ if(*id != 0) {
+ IPaddress addr;
+
+ int ret = SDLNet_ResolveHost(&addr, address.c_str(), default_port);
+ if(ret == 0) {
+ TCPsocket socket;
+
+ socket = SDLNet_TCP_Open(&addr);
+ if(socket != nullptr) {
+ SDLNet_AddSocket(socket_set, (SDLNet_GenericSocket)socket);
+ connection_id_map[*id] = socket;
+ connection_id_map_reverse[socket] = *id;
+ connection_status.emplace(*id, NetConnectionStatus());
+
+ NetFrameworkConnectionStatusChanged status_changed;
+ status_changed.conn_id = *id;
+ status_changed.conn_info.connection_state = NetFrameworkConnectionState::Connected;
+
+ online->OnConnectionChange(&status_changed);
+
+ return true;
+ } else {
+ LOGE << "Unable to open socket to resolved address: " << address << ":" << default_port << std::endl;
+ LOGE << "Error: " << SDLNet_GetError() << std::endl;
+ }
+ } else {
+ LOGE << "Unable to resolve host " << address << ":" << default_port << std::endl;
+ }
+ } else {
+ LOGE << "Ran out of NetConnectionID's" << std::endl;
+ }
+ *id = 0;
+ return false;
+}
+
+NetListenSocketID BasicNetFramework::CreateListenSocketIP(const string &local_address) {
+ NetListenSocketID socket_id = GetFreeListenSocketID();
+
+ if(socket_id != 0) {
+ IPaddress addr;
+ SDLNet_ResolveHost(&addr, NULL, default_port);
+
+ TCPsocket socket;
+ socket = SDLNet_TCP_Open(&addr);
+ if(socket != nullptr) {
+ listen_socket_map[socket_id] = socket;
+ listen_socket_map_reverse[socket] = socket_id;
+ return socket_id;
+ } else {
+ LOGE << "Unable to open a listen socket on port " << default_port << "(" << SDLNet_GetError() << ")" << std::endl;
+ }
+ } else {
+ LOGE << "Ran out of NetListenSocketID's" << std::endl;
+ }
+
+ return 0;
+}
+
+void BasicNetFramework::CloseListenSocket(NetListenSocketID listen_socket_id) {
+ auto socket_it = listen_socket_map.find(listen_socket_id);
+
+ if(socket_it != listen_socket_map.end()) {
+ SDLNet_TCP_Close(socket_it->second);
+ listen_socket_map_reverse.erase(socket_it->second);
+ listen_socket_map.erase(socket_it->first);
+ }
+}
+
+void BasicNetFramework::CloseConnection(NetConnectionID conn_id, ConnectionClosedReason reason) {
+ auto socket_it = connection_id_map.find(conn_id);
+ //TODO: Send the close reason before closing the socket
+
+ if(socket_it != connection_id_map.end()) {
+ SDLNet_DelSocket(socket_set, (SDLNet_GenericSocket)socket_it->second);
+ SDLNet_TCP_Close(socket_it->second);
+ connection_id_map_reverse.erase(socket_it->second);
+ connection_status.erase(socket_it->first);
+ connection_id_map.erase(socket_it->first);
+ }
+}
+
+void BasicNetFramework::GetConnectionStatus(NetConnectionID conn_id, ConnectionStatus* status) const {
+ status->ms_ping = 0;
+ status->connection_quality_local = 0;
+ status->connection_quality_remote = 0;
+ status->out_packets_per_sec = 0;
+ status->out_bytes_per_sec = 0;
+ status->in_packets_per_sec = 0;
+ status->in_bytes_per_sec = 0;
+ status->send_rate_bytes_per_second = 0;
+ status->pending_unreliable = 0;
+ status->pending_reliable = 0;
+ status->sent_unacked_reliable = 0;
+ status->usec_queue_time = 0;
+}
+
+int BasicNetFramework::ReceiveMessageOnConnection(NetConnectionID conn_id, NetworkingMessage* msg) {
+ auto status = connection_status.find(conn_id);
+
+ if(status != connection_status.end()) {
+ auto first_message = status->second.messages.begin();
+ if(first_message != status->second.messages.end()) {
+ if(msg != nullptr) {
+ *msg = *first_message;
+ }
+ status->second.messages.erase(first_message);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+bool BasicNetFramework::AcceptConnection(NetConnectionID conn_id, int* result) {
+ *result = 0;
+
+ NetFrameworkConnectionStatusChanged status_changed;
+ status_changed.conn_id = conn_id;
+ status_changed.conn_info.connection_state = NetFrameworkConnectionState::Connected;
+
+ online->OnConnectionChange(&status_changed);
+ return true;
+}
+
+void BasicNetFramework::SendMessageToConnection(NetConnectionID conn_id, char* buffer, uint32_t bytes, bool reliable, bool flush) {
+ auto conn = connection_id_map.find(conn_id);
+ uint16_t header[MESSAGE_HEADER_SIZE/2];
+ header[0] = SDL_SwapBE16(bytes);
+ header[1] = 0;
+
+ if(conn != connection_id_map.end()) {
+ int ret_count = SDLNet_TCP_Send(conn->second, header, MESSAGE_HEADER_SIZE);
+ if(ret_count != MESSAGE_HEADER_SIZE) {
+ LOGE << "ERROR ON CONNECTION" << std::endl;
+ return;
+ }
+
+ ret_count = SDLNet_TCP_Send(conn->second, buffer, bytes);
+
+ if(ret_count != bytes) {
+ LOGE << "Error when sending data to connection" << std::endl;
+ }
+ }
+}
+
+string BasicNetFramework::GetResultString(int result) {
+ return string("Unknown result code");
+}
+#endif