Line |
Branch |
Exec |
Source |
1 |
|
|
/* |
2 |
|
|
** EPITECH PROJECT, 2024 |
3 |
|
|
** zappy |
4 |
|
|
** File description: |
5 |
|
|
** server.c |
6 |
|
|
*/ |
7 |
|
|
|
8 |
|
|
#include "server.h" |
9 |
|
|
#include <time.h> |
10 |
|
|
#include <stdio.h> |
11 |
|
|
#include <signal.h> |
12 |
|
|
#include <stdlib.h> |
13 |
|
|
#include <string.h> |
14 |
|
|
#include <unistd.h> |
15 |
|
|
|
16 |
|
✗ |
void signint_handler(int sig) |
17 |
|
|
{ |
18 |
|
|
char c; |
19 |
|
|
|
20 |
|
✗ |
signal(sig, SIG_IGN); |
21 |
|
|
printf("OUCH, did you hit Ctrl-C?\n" |
22 |
|
|
"Do you really want to quit? [y/n] "); |
23 |
|
✗ |
c = getchar(); |
24 |
|
✗ |
if (c == 'y' || c == 'Y') |
25 |
|
✗ |
exit(0); |
26 |
|
|
else |
27 |
|
✗ |
signal(SIGINT, signint_handler); |
28 |
|
|
getchar(); |
29 |
|
✗ |
} |
30 |
|
|
|
31 |
|
✗ |
void sigpipe_handler(int sig) |
32 |
|
|
{ |
33 |
|
|
(void)sig; |
34 |
|
✗ |
} |
35 |
|
|
|
36 |
|
✗ |
static int handle_connections(server_t *server, int fd) |
37 |
|
|
{ |
38 |
|
✗ |
if (FD_ISSET(fd, &server->ready_sockets)) { |
39 |
|
✗ |
if (fd == server->fd && create_new_client(server) == ERROR_STATUS) |
40 |
|
|
return ERROR_STATUS; |
41 |
|
✗ |
if (fd != server->fd && |
42 |
|
✗ |
handle_client_data(server, fd) == ERROR_STATUS) |
43 |
|
✗ |
return ERROR_STATUS; |
44 |
|
|
} |
45 |
|
|
return OK_STATUS; |
46 |
|
|
} |
47 |
|
|
|
48 |
|
✗ |
static int check_connections(server_t *server) |
49 |
|
|
{ |
50 |
|
✗ |
for (int i = 0; i < FD_SETSIZE; i++) { |
51 |
|
✗ |
if (handle_connections(server, i) == ERROR_STATUS) |
52 |
|
|
return ERROR_STATUS; |
53 |
|
|
} |
54 |
|
|
return OK_STATUS; |
55 |
|
|
} |
56 |
|
|
|
57 |
|
✗ |
static double get_interval(int command, double freq) |
58 |
|
|
{ |
59 |
|
✗ |
const interval_t intervals[NB_COMMANDS_TO_SEND] = { |
60 |
|
|
{FORWARD, FORWARD_TLIMIT}, |
61 |
|
|
{RIGHT, RIGHT_TLIMIT}, |
62 |
|
|
{LEFT, LEFT_TLIMIT}, |
63 |
|
|
{LOOK, LOOK_TLIMIT}, |
64 |
|
|
{INVENTORY, INVENTORY_TLIMIT}, |
65 |
|
|
{BROADCAST, BROADCAST_TLIMIT}, |
66 |
|
|
{FORK, FORK_TLIMIT}, |
67 |
|
|
{EJECT, EJECT_TLIMIT}, |
68 |
|
|
{TAKE, TAKE_TLIMIT}, |
69 |
|
|
{SET, SET_TLIMIT}, |
70 |
|
|
{INCANTATION, INCANTATION_TLIMIT} |
71 |
|
|
}; |
72 |
|
|
|
73 |
|
✗ |
for (unsigned char i = 0; i < NB_COMMANDS_TO_SEND; i++) { |
74 |
|
✗ |
if (intervals[i].command == command) |
75 |
|
✗ |
return freq > 0.0f ? intervals[i].frequency / freq : -1.0f; |
76 |
|
|
} |
77 |
|
|
return -1.0f; |
78 |
|
|
} |
79 |
|
|
|
80 |
|
✗ |
static void print_egg_graphic(client_t *client, server_t *server) |
81 |
|
|
{ |
82 |
|
✗ |
if (client->is_incanting == true) |
83 |
|
|
return; |
84 |
|
✗ |
if (client->tclient[0].available_request) |
85 |
|
✗ |
dprintf(client->fd, "%s", client->tclient[0].payload); |
86 |
|
✗ |
if (client->tclient[0].command == FORK) |
87 |
|
✗ |
message_to_graphicals(server, "enw %d %s %d %d\n", client->egg_id, |
88 |
|
✗ |
client->id, client->x, client->y); |
89 |
|
✗ |
for (unsigned char idx = 0; idx < NB_REQUESTS_HANDLEABLE; idx++) { |
90 |
|
✗ |
if (idx + 1 < NB_REQUESTS_HANDLEABLE) |
91 |
|
✗ |
client->tclient[idx] = client->tclient[idx + 1]; |
92 |
|
|
else { |
93 |
|
✗ |
client->tclient[idx].command = -1; |
94 |
|
✗ |
client->tclient[idx].available_request = false; |
95 |
|
|
} |
96 |
|
✗ |
if (client->tclient[idx].available_request) |
97 |
|
✗ |
clock_gettime(CLOCK_REALTIME, &client->tclient[idx].future_time); |
98 |
|
|
else |
99 |
|
✗ |
client->tclient[idx].command = 0; |
100 |
|
|
} |
101 |
|
|
} |
102 |
|
|
|
103 |
|
✗ |
static bool send_command( |
104 |
|
|
client_t *client, |
105 |
|
|
struct timespec *curr, |
106 |
|
|
server_t *server |
107 |
|
|
) |
108 |
|
|
{ |
109 |
|
|
struct timespec cmd_start_time; |
110 |
|
|
double interval; |
111 |
|
|
double elapsed; |
112 |
|
|
unsigned char cmd_idx = 0; |
113 |
|
|
|
114 |
|
✗ |
if (client->tclient[cmd_idx].available_request) { |
115 |
|
✗ |
cmd_start_time = client->tclient[cmd_idx].future_time; |
116 |
|
✗ |
interval = get_interval(client->tclient[cmd_idx].command, |
117 |
|
✗ |
server->proprieties.frequency); |
118 |
|
✗ |
elapsed = (curr->tv_sec - cmd_start_time.tv_sec) + ((curr |
119 |
|
✗ |
->tv_nsec - cmd_start_time.tv_nsec) / NANOSECONDS_IN_SECOND); |
120 |
|
✗ |
if (elapsed >= interval |
121 |
|
✗ |
&& client->tclient[cmd_idx].command == INCANTATION) |
122 |
|
✗ |
incantation_callback_end_of_command(client, server); |
123 |
|
✗ |
if (client->level == LAST_LEVEL) |
124 |
|
|
return true; |
125 |
|
✗ |
if (elapsed >= interval) |
126 |
|
✗ |
print_egg_graphic(client, server); |
127 |
|
|
} |
128 |
|
|
return false; |
129 |
|
|
} |
130 |
|
|
|
131 |
|
✗ |
static bool check_response_client_time( |
132 |
|
|
struct client_tailq *clients, |
133 |
|
|
server_t *server, |
134 |
|
|
struct timespec *current |
135 |
|
|
) |
136 |
|
|
{ |
137 |
|
|
client_list_t *item; |
138 |
|
|
|
139 |
|
✗ |
TAILQ_FOREACH(item, clients, entries) { |
140 |
|
✗ |
if (send_command(item->client, current, server) == true) |
141 |
|
|
return true; |
142 |
|
|
} |
143 |
|
|
return false; |
144 |
|
|
} |
145 |
|
|
|
146 |
|
✗ |
static int start_server(server_t *s) |
147 |
|
|
{ |
148 |
|
✗ |
fd_set writefds; |
149 |
|
✗ |
fd_set exceptfds; |
150 |
|
|
|
151 |
|
|
while (true) { |
152 |
|
✗ |
s->ready_sockets = s->current_sockets; |
153 |
|
✗ |
FD_ZERO(&writefds); |
154 |
|
✗ |
FD_ZERO(&exceptfds); |
155 |
|
✗ |
clock_gettime(CLOCK_REALTIME, &s->current_time); |
156 |
|
✗ |
if (handle_client_life(s) == true) |
157 |
|
✗ |
continue; |
158 |
|
✗ |
handle_meteors(s); |
159 |
|
✗ |
if (check_response_client_time(&s->clients, s, &s->current_time)) |
160 |
|
|
break; |
161 |
|
✗ |
if (select(FD_SETSIZE, &s->ready_sockets, |
162 |
|
|
&writefds, &exceptfds, &s->timeout) < 0) |
163 |
|
✗ |
return ERROR_STATUS; |
164 |
|
✗ |
if (check_connections(s) == ERROR_STATUS) |
165 |
|
|
return ERROR_STATUS; |
166 |
|
|
} |
167 |
|
|
return OK_STATUS; |
168 |
|
|
} |
169 |
|
|
|
170 |
|
✗ |
int server(const char **args) |
171 |
|
|
{ |
172 |
|
|
int status = OK_STATUS; |
173 |
|
✗ |
server_t server = {0}; |
174 |
|
|
|
175 |
|
✗ |
signal(SIGINT, signint_handler); |
176 |
|
✗ |
signal(SIGPIPE, sigpipe_handler); |
177 |
|
✗ |
srand(time(NULL)); |
178 |
|
✗ |
if (!init_server(&server, args)) { |
179 |
|
✗ |
destroy_server(server); |
180 |
|
✗ |
return helper(ERROR_STATUS); |
181 |
|
|
} |
182 |
|
✗ |
if (bind(server.fd, (struct sockaddr *)&server.info, server.addrlen) < 0) |
183 |
|
✗ |
perror("Bind failed: Address already in use"), exit(ERROR_STATUS); |
184 |
|
✗ |
if (status == OK_STATUS && listen(server.fd, FD_SETSIZE) < 0) |
185 |
|
✗ |
perror("Unable to continue connection"), exit(ERROR_STATUS); |
186 |
|
✗ |
if (status == OK_STATUS && start_server(&server) == ERROR_STATUS) |
187 |
|
|
status = ERROR_STATUS; |
188 |
|
|
if (status == ERROR_STATUS) |
189 |
|
✗ |
close(server.fd); |
190 |
|
✗ |
destroy_server(server); |
191 |
|
|
return status; |
192 |
|
|
} |
193 |
|
|
|