diff options
author | Manuel Palenzuela <manuelpalenzuelamerino@gmail.com> | 2020-06-02 20:53:46 +0000 |
---|---|---|
committer | Manuel Palenzuela <manuelpalenzuelamerino@gmail.com> | 2020-06-02 20:53:46 +0000 |
commit | b7b3d05512165e4db9142cdbc64805246909357f (patch) | |
tree | e842ac261b5e08e027c51e6c8e0ec53dac8ef097 /server.cpp | |
download | test-multiplayer-game-b7b3d05512165e4db9142cdbc64805246909357f.tar.gz test-multiplayer-game-b7b3d05512165e4db9142cdbc64805246909357f.tar.bz2 test-multiplayer-game-b7b3d05512165e4db9142cdbc64805246909357f.zip |
Release
Diffstat (limited to 'server.cpp')
-rw-r--r-- | server.cpp | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/server.cpp b/server.cpp new file mode 100644 index 0000000..71034be --- /dev/null +++ b/server.cpp @@ -0,0 +1,197 @@ +#include <iostream> +#include <cstdlib> +#include <cstring> +#include <algorithm> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <unistd.h> + +#include "utils.hpp" + +#define LOCALHOST (char*) "127.0.0.1" +#define PUBLIC (char*) "0.0.0.0" + +#define IP PUBLIC +#define PORT (char*) "4444" + +int main(int argc, char** argv); +int game_server(int* max_players, std::vector<Player*>* players, const char* ip, const char* port, int* sockfd); +void* server_handler(void* psockaddr); +void* client_handler(void* client_fd); +int waiting_loop(std::vector<Player*>* players, int fps, bool* visual); +int notify_players( std::vector<Player*>* players, Player* sender_player, Packet* packet); +int manual_disconnect(Player* player, std::vector<Player*>* players); + + std::vector<Player*> players; +int max_players; +const int server = 1; +int client_id = 0; +bool visual = false; +int fps = 10; +int sockfd; +std::mutex mutex; + +int main(int argc, char** argv) +{ + max_players = -1; + + char* port = PORT; + + if(argv[1]) + max_players = atoi(argv[1]); + if(argv[2]) + port = argv[2]; + if(argv[3]) + if(!strcmp(argv[3], "-visual")) + visual = true; + + std::cout << "Starting server with access for " << max_players << " players. (" << IP << ":" << port << ")" << std::endl; + + int result = game_server(&max_players, &players, IP, port, &sockfd); + if(result) + std::cout << "[!] Server failed to start! [" << IP << ":" << port << "] (" << result << ")" << std::endl; + else + waiting_loop(&players, fps, &visual); + + return 0; +} + +int game_server(int* max_players, std::vector<Player*>* players, const char* ip, const char* port, int* sockfd) +{ + *sockfd = socket(AF_INET, SOCK_STREAM , 0); + if(*sockfd < 0) + return 1; + + sockaddr_in sockaddr; + sockaddr.sin_family = AF_INET; + sockaddr.sin_addr.s_addr = inet_addr(ip); + sockaddr.sin_port = htons(atoi(port)); + + if(bind(*sockfd, (struct sockaddr*)&sockaddr, sizeof(sockaddr))) + return 2; + + if (listen(*sockfd, 1)) + return 3; + + if(visual) + { + pthread_t server_thread; + if(pthread_create(&server_thread, NULL, server_handler, (void*)&sockaddr)) + return 5; + } + else + server_handler((void*)&sockaddr); + + return 0; +} + +void* server_handler(void* psockaddr) +{ + sockaddr_in* sockaddr = (sockaddr_in*)psockaddr; + socklen_t addrlen = sizeof(*sockaddr); + int connection; + while((connection = accept(sockfd, (struct sockaddr*)sockaddr, &addrlen))) + { + if (connection < 0) + return 0; + + if((int)(&players)->size() == *(&max_players)) + { + std::cout << "[-] Player limit has been reached. Incoming player has been kicked" << std::endl; + fflush(stdout); + close(connection); + continue; + } + + pthread_t sniffer_thread; + if(pthread_create(&sniffer_thread, NULL, client_handler, (void*)(intptr_t)connection)) + return 0; + } + + return 0; +} + +void* client_handler(void* pclient_fd) +{ + struct sockaddr_in client; + socklen_t addrlen = sizeof(client); + getpeername((intptr_t)pclient_fd, (struct sockaddr*)&client, &addrlen); + + Player player {}; + player.fd = (intptr_t)pclient_fd; + strncpy(player.ip, inet_ntoa(client.sin_addr), sizeof(player.ip)); + + Packet incoming_packet {}; + + int read_size = 0; + while((read_size = recv(player.fd, &incoming_packet, sizeof(incoming_packet), 0) > 0)) + { + int result = handle_incoming_packet(&player, &incoming_packet, &players); + if(result > 0) + { + if(strlen(player.name)) + std::cout << "[!] Invalid packet from player! [" << player.name << "] (" << player.ip << ")" << std::endl; + else + std::cout << "[!] Someone tried to connect without using the game's client! (" << player.ip << ")" << std::endl; + + fflush(stdout); + break; + } + + if(result != -1) + notify_players(&players, &player, &incoming_packet); + } + + manual_disconnect(&player, &players); + close((intptr_t)pclient_fd); + + return 0; +} + +int waiting_loop(std::vector<Player*>* players, int fps, bool* visual) +{ + if(*visual) + { + setup_ncurses(); + + while(1) + { + if(getch() == 'q') + goto end; + + draw_game(players); + usleep(1000000 / fps); + } + + end: + endwin(); + } + + return 0; +} + +int notify_players( std::vector<Player*>* players, Player* sender_player, Packet* packet) +{ + for(Player* player : *players) + { + if(player->sender_id != sender_player->sender_id) + if(send(player->fd, (const char*)packet, sizeof(*packet), 0) < 0) + manual_disconnect(player, players); + } + + return 0; +} + +int manual_disconnect(Player* player, std::vector<Player*>* players) +{ + Packet packet {}; + packet.type = PacketType::packet_disconnect; + packet.sender_id = player->sender_id; + packet.data.packet_disconnect.player = *player; + + int result = handle_incoming_packet(player, &packet, players); + notify_players(players, player, &packet); + + return result; +} |