Coverage report for server


src/
File: src/server.c
Date: 2024-06-25 10:57:05
Lines:
0/83
0.0%
Functions:
0/10
0.0%
Branches:
0/74
0.0%

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