back to scratko.xyz
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorscratko <m@scratko.xyz>2024-12-09 23:06:34 +0300
committerscratko <m@scratko.xyz>2024-12-10 00:34:47 +0300
commite44cb50ab5964747d2d1369da378ceae804b85ef (patch)
treebde2a1b2cadf8c28d471855f0dc4a08d06f1cf3a
parentbedb024261f6539d0517430e88cfaa1e78e6e955 (diff)
downloaddurak-e44cb50ab5964747d2d1369da378ceae804b85ef.tar.gz
durak-e44cb50ab5964747d2d1369da378ceae804b85ef.tar.bz2
durak-e44cb50ab5964747d2d1369da378ceae804b85ef.zip
Added protection against botsHEADmaster
After 30 seconds a signal is sent after the first player is connected. During this period the second player must connect, otherwise the first player will be disconnected.
-rw-r--r--server/server.c71
-rw-r--r--server/server.h3
2 files changed, 61 insertions, 13 deletions
diff --git a/server/server.c b/server/server.c
index 0017888..bfc71ef 100644
--- a/server/server.c
+++ b/server/server.c
@@ -15,10 +15,17 @@
#include "card_stack.h"
#include "card_queue.h"
+static volatile sig_atomic_t timeout_is_over = 0;
+
void handler(int s)
{
- if(s == SIGPIPE)
- signal(SIGPIPE, handler);
+ switch(s) {
+ case SIGPIPE:
+ signal(SIGPIPE, handler);
+ break;
+ case SIGALRM:
+ timeout_is_over = 1;
+ }
}
static void init_session(struct session *new_session, struct sockaddr_in *from,
@@ -98,8 +105,7 @@ static void close_connection(struct server *serv)
static int check_playable_player_number(struct server *serv)
{
- return serv->connected_players_counter >= 2 &&
- serv->connected_players_counter < 8;
+ return serv->connected_players_counter >= 2;
}
static int is_max_playable_player_number(struct server *serv)
@@ -593,10 +599,21 @@ static void determine_server_state(struct server *serv)
switch(serv->state) {
case no_players:
serv->state = first_player;
+ /*
+ * The second player must connect no later than TIMEOUT.
+ * This is done to protect against bots.
+ */
+ signal(SIGALRM, handler);
+ alarm(timeout);
break;
case first_player:
- if(check_playable_player_number(serv))
+ if(check_playable_player_number(serv)) {
serv->state = confirmation_waiting;
+ /* cancel alarm */
+ alarm(0);
+ /* default disposition */
+ signal(SIGALRM, SIG_DFL);
+ }
break;
case confirmation_waiting:
set_record_status_for_all(serv);
@@ -658,7 +675,7 @@ static int new_player_tracking_condition(enum server_states state)
/*
* when accepting new players
*/
-static int server_state_change_condition(struct server *serv)
+static int check_server_state_change_conditions_before_game(struct server *serv)
{
return
serv->state == no_players ||
@@ -678,7 +695,7 @@ static int accept_new_player(struct server *serv)
}
/* update info about connected players */
set_record_status_for_all(serv);
- if(server_state_change_condition(serv))
+ if(check_server_state_change_conditions_before_game(serv))
serv->change_server_state = 1;
return 1;
}
@@ -736,7 +753,10 @@ static void set_up_player_tracking(struct server *serv, fd_set *readfds,
}
}
-static int check_server_state_change_conditions(struct server *serv)
+/*
+ * is checked after a write or read operation in make_data_transfer
+ */
+static int check_server_state_change_conditions_in_game(struct server *serv)
{
switch(serv->state) {
case start_game:
@@ -763,7 +783,7 @@ static int check_server_state_change_conditions(struct server *serv)
static void make_data_transfer(struct server *serv, fd_set *readfds,
fd_set *writefds)
{
- int i, result, close_connection_status = 0;
+ int i, result = 1, close_connection_status = 0;
for(i = 0; i < serv->max_sess_arr_size; ++i) {
if(!serv->sess_arr[i])
continue;
@@ -840,13 +860,18 @@ static void make_data_transfer(struct server *serv, fd_set *readfds,
close(i);
serv->sess_arr[i]->fd = -1;
close_connection_status = 1;
- result = 1; /* next can be reading that's not ready */
+ /*
+ * Flag reset
+ * The following clients may not have requested read or
+ * write operations
+ */
+ result = 1;
}
}
if(serv->state == start_game || serv->state == end_round ||
serv->state == end_game)
sleep(2);
- if(check_server_state_change_conditions(serv))
+ if(check_server_state_change_conditions_in_game(serv))
serv->change_server_state = 1;
/* connection is closed */
if(close_connection_status) {
@@ -856,6 +881,23 @@ static void make_data_transfer(struct server *serv, fd_set *readfds,
}
}
+static void close_bot_connection(struct server *serv)
+{
+ int i;
+
+ for(i = 0; i < serv->max_sess_arr_size; ++i) {
+ if(!serv->sess_arr[i])
+ continue;
+ close(serv->sess_arr[i]->fd);
+ serv->sess_arr[i]->fd = -1;
+ free(serv->sess_arr[i]);
+ serv->sess_arr[i] = NULL;
+ }
+ serv->change_server_state = 0;
+ serv->connected_players_counter = 0;
+ serv->state = no_players;
+}
+
int main_loop(struct server *serv)
{
int maxfd, accept_result, select_result;
@@ -875,8 +917,13 @@ int main_loop(struct server *serv)
set_up_player_tracking(serv, &readfds, &writefds, &maxfd);
select_result = select(maxfd + 1, &readfds, &writefds, NULL, NULL);
- if(select_result == -1)
+ if(select_result == -1 && !timeout_is_over)
return 3;
+ if(timeout_is_over && serv->connected_players_counter == 1) {
+ close_bot_connection(serv);
+ timeout_is_over = 0;
+ continue;
+ }
if(FD_ISSET(serv->listen_socket, &readfds)) {
accept_result = accept_new_player(serv);
diff --git a/server/server.h b/server/server.h
index a62f085..3841470 100644
--- a/server/server.h
+++ b/server/server.h
@@ -7,7 +7,8 @@
enum {
max_buffer_size = 4096,
listen_qlen = 32,
- init_sess_arr_size = 12 /* it was 32 */
+ init_sess_arr_size = 12, /* it was 32 */
+ timeout = 30
};
enum {