ソースを参照

Ajout mutex pour protection des données

Arthur Brandao 6 年 前
コミット
920a80a498
4 ファイル変更145 行追加58 行削除
  1. 114 56
      Serveur/game.c
  2. 5 1
      Serveur/game.h
  3. 22 0
      Serveur/handler.c
  4. 4 1
      Serveur/main.c

+ 114 - 56
Serveur/game.c

@@ -17,8 +17,11 @@
 /* --- Extern --- */
 Game game[MAXGAME];
 int nbGame = 0;
+pthread_mutex_t gameMutex[MAXGAME];
+pthread_mutex_t playerMutex[MAXGAME * MAXPLAYER];
 
 /* --- Fonctions privées --- */
+
 /**
  * Transforme le fichier map en un tableau 2D
  * @param char* Le contenu du fichier map
@@ -26,15 +29,15 @@ int nbGame = 0;
  * @param int Hauteur de la map
  * @return char** La map parser
  */
-char** parse_map(char* mapContent, int width, int height){
-    char** map = malloc(sizeof(char*) * width);
+char** parse_map(char* mapContent, int width, int height) {
+    char** map = malloc(sizeof (char*) * width);
     //Creation des colonnes
-    for(int i = 0; i < width; i++){
-        map[i] = malloc(sizeof(char) * height);
+    for (int i = 0; i < width; i++) {
+        map[i] = malloc(sizeof (char) * height);
     }
     //Remplissage
-    for(int i = 0; i < height; i++){
-        for(int j = 0; j < width; j++){
+    for (int i = 0; i < height; i++) {
+        for (int j = 0; j < width; j++) {
             map[j][i] = *mapContent;
             mapContent++;
         }
@@ -44,36 +47,55 @@ char** parse_map(char* mapContent, int width, int height){
 }
 
 /* --- Fonctions publiques --- */
-void ini_games(){
-    for(int i = 0; i < MAXGAME; i++){
+boolean ini_games() {
+    //Ini les games
+    for (int i = 0; i < MAXGAME; i++) {
         game[i].active = false;
+        game[i].index = i;
+    }
+    //Ini les mutex des games
+    for (int i = 0; i < MAXGAME; i++) {
+        if (pthread_mutex_init(&gameMutex[i], NULL) != 0) {
+            adderror("Impossible d'initialiser les mutex des games");
+            return false;
+        }
     }
+    //Ini les mutex des joueurs des games
+    for (int i = 0; i < MAXGAME * MAXPLAYER; i++) {
+        if (pthread_mutex_init(&playerMutex[i], NULL) != 0) {
+            adderror("Impossible d'initialiser les mutex des joueurs");
+            return false;
+        }
+    }
+    return true;
 }
 
-void list_map(JsonArray* res){
+void list_map(JsonArray* res) {
     char** result;
     int nbResult;
     //Regarde les fichiers dans le dossier
     result = file_list(MAPDIR, &nbResult);
-    for(int i = 0; i < nbResult; i++){
+    for (int i = 0; i < nbResult; i++) {
         add_array_string(res, result[i]);
         free(result[i]);
     }
     free(result);
 }
 
-int list_game(JsonArray* res){
+int list_game(JsonArray* res) {
     JsonEncoder gameJson;
     int compteur = 0, i = 0;
     //Si il n' y a aucune game
-    if(nbGame == 0){
+    if (nbGame == 0) {
         return 0;
     }
     //Initialisation json
     ini_encoder(&gameJson);
     //Ajoute chaque game
-    while(compteur < nbGame && i < MAXGAME){
-        if(!game[i].active){
+    while (compteur < nbGame && i < MAXGAME) {
+        pthread_mutex_lock(&gameMutex[i]);
+        if (!game[i].active) {
+            pthread_mutex_unlock(&gameMutex[i]);
             i++;
             continue;
         }
@@ -86,29 +108,30 @@ int list_game(JsonArray* res){
         //Nettoyage encoder objet
         clean_json_encoder(&gameJson);
         //Incremente
+        pthread_mutex_unlock(&gameMutex[i]);
         i++;
         compteur++;
     }
     return nbGame;
 }
 
-int* map_size(char* map){
+int* map_size(char* map) {
     int* res;
-    res = malloc(sizeof(int) * 2);
+    res = malloc(sizeof (int) * 2);
     res[WIDTH] = 0;
     res[HEIGHT] = 1;
     //Parcours la 1er ligne pour compter le nombre de caractère
-    while(*map != '\n' && *map != '\0'){
+    while (*map != '\n' && *map != '\0') {
         res[WIDTH]++;
         map++;
     }
-    if(*map == '\0'){
+    if (*map == '\0') {
         return res;
     }
     //Compte les lignes
     map++;
-    while(*map != '\0'){
-        if(*map == '\n'){
+    while (*map != '\0') {
+        if (*map == '\n') {
             res[HEIGHT]++;
         }
         map++;
@@ -116,19 +139,21 @@ int* map_size(char* map){
     return res;
 }
 
-int create_game(char* name, char* map){
+int create_game(char* name, char* map) {
     int length, index = 0;
     char* path;
     int* size;
     //Regarde si il reste une game de disponnible
-    if(nbGame == MAXGAME){
+    if (nbGame == MAXGAME) {
         return ERR;
     }
     //Cherche une game libre
-    while(index < MAXGAME){
-        if(game[index].active == false){
+    while (index < MAXGAME) {
+        pthread_mutex_lock(&gameMutex[index]);
+        if (game[index].active == false) {
             break;
         }
+        pthread_mutex_unlock(&gameMutex[index]);
         index++;
     }
     //Recup la map
@@ -146,10 +171,11 @@ int create_game(char* name, char* map){
     game[index].width = size[WIDTH];
     game[index].height = size[HEIGHT];
     game[index].map = parse_map(game[index].mapContent, size[WIDTH], size[HEIGHT]);
-    for(int i = 0; i < MAXPLAYER; i++){
-        game[index].player[i] = malloc(sizeof(Player));
+    for (int i = 0; i < MAXPLAYER; i++) {
+        game[index].player[i] = malloc(sizeof (Player));
         game[index].player[i]->ini = false;
     }
+    pthread_mutex_unlock(&gameMutex[index]);
     //Retourne la position de la partie dans le tableau
     nbGame++;
     free(path);
@@ -157,32 +183,40 @@ int create_game(char* name, char* map){
     return index;
 }
 
-int add_player(Game* g, int cliId){
+int add_player(Game* g, int cliId) {
     int index = 0;
     Client* cli;
     //Verif que la game n'est pas deja pleine
-    if(g->nbPlayer >= MAXPLAYER){
+    pthread_mutex_lock(&gameMutex[g->index]);
+    if (g->nbPlayer >= MAXPLAYER) {
+        pthread_mutex_unlock(&gameMutex[g->index]);
         return ERR;
     }
     //Cherche un joueur non initialisé
-    while(index < MAXPLAYER){
-        if(!g->player[index]->ini){
+    while (index < MAXPLAYER) {
+        pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + index]);
+        if (!g->player[index]->ini) {
             break;
         }
+        pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]);
         index++;
     }
     //Recup du client
     cli = get_client(cliId);
-    if(cli == NULL){
+    if (cli == NULL) {
+        pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]);
+        pthread_mutex_unlock(&gameMutex[g->index]);
         return ERR;
     }
     //Creation du joueur
     create_player(g->player[index], cli);
     g->nbPlayer++;
+    pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + index]);
+    pthread_mutex_unlock(&gameMutex[g->index]);
     return index;
 }
 
-void describe_game(Game* g, int playerIndex, JsonEncoder* desc){
+void describe_game(Game* g, int playerIndex, JsonEncoder* desc) {
     JsonEncoder player;
     JsonEncoder map;
     JsonArray players;
@@ -192,6 +226,7 @@ void describe_game(Game* g, int playerIndex, JsonEncoder* desc){
     ini_encoder(&map);
     ini_array_encoder(&players);
     //Info map
+    pthread_mutex_lock(&gameMutex[g->index]);
     content = remove_char(g->mapContent, '\n'); //La map sans \n car interdit en JSON
     add_integer(&map, "width", g->width);
     add_integer(&map, "height", g->height);
@@ -202,82 +237,105 @@ void describe_game(Game* g, int playerIndex, JsonEncoder* desc){
     add_object(desc, "map", &map);
     //Ajout info courte joueur
     //printf("Add players\n");
-    for(int i = 0; i < MAXPLAYER; i++){
-        if(g->player[i]->ini){
+    for (int i = 0; i < MAXPLAYER; i++) {
+        pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + i]);
+        if (g->player[i]->ini) {
             describe_short_player(g->player[i], &player);
             add_array_object(&players, &player);
-            clean_json_encoder(&player);  
+            clean_json_encoder(&player);
         }
+        pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + i]);
     }
     //printf("Fin Add players\n");
     add_array(desc, "players", &players);
     //Si besoins ajout un joueur
-    if(playerIndex >= 0 && playerIndex < MAXPLAYER && g->player[playerIndex]->ini){
-        describe_player(g->player[playerIndex], &player);
-        add_object(desc, "player", &player);
-        clean_json_encoder(&player);
+    if (playerIndex >= 0 && playerIndex < MAXPLAYER) {
+        pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]);
+        if (g->player[playerIndex]->ini) {
+            describe_player(g->player[playerIndex], &player);
+            add_object(desc, "player", &player);
+            clean_json_encoder(&player);
+        }
+        pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]);
     }
     //Nettoyage
+    pthread_mutex_unlock(&gameMutex[g->index]);
     clean_json_encoder(&map);
     clean_json_array(&players);
 }
 
-boolean notify_player(Game* g, char* method, char* ressource, JsonEncoder* param, int excludePlayerId){
+boolean notify_player(Game* g, char* method, char* ressource, JsonEncoder* param, int excludePlayerId) {
     boolean res = true;
+    pthread_mutex_lock(&gameMutex[g->index]);
     //Regarde si la game est active
-    if(!g->active){
+    if (!g->active) {
+        pthread_mutex_unlock(&gameMutex[g->index]);
         return false;
     }
     //Parcours les joeurs de la game
-    for(int i = 0; i < MAXPLAYER; i++){
+    for (int i = 0; i < MAXPLAYER; i++) {
         //Si joueur actif
-        if(g->player[i]->ini && g->player[i]->id != excludePlayerId){
+        pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + i]);
+        if (g->player[i]->ini && g->player[i]->id != excludePlayerId) {
             res = res && notify_client(g->player[i]->cli, method, ressource, param);
         }
+        pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + i]);
     }
+    pthread_mutex_unlock(&gameMutex[g->index]);
     return res;
 }
 
-boolean player_collision(Game* g, int x, int y){
-    for(int i = 0; i < MAXPLAYER; i++){
-        if(g->player[i]->ini){
-            if(g->player[i]->x == x && g->player[i]->y == y){
+boolean player_collision(Game* g, int x, int y) {
+    for (int i = 0; i < MAXPLAYER; i++) {
+        pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + i]);
+        if (g->player[i]->ini) {
+            if (g->player[i]->x == x && g->player[i]->y == y) {
+                pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + i]);
                 return true;
             }
         }
+        pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + i]);
     }
-    return  false;
+    return false;
 }
 
-void remove_player(Game* g, int playerIndex){
+void remove_player(Game* g, int playerIndex) {
+    pthread_mutex_lock(&gameMutex[g->index]);
+    pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]);
     g->nbPlayer--;
     delete_player(g->player[playerIndex]);
+    pthread_mutex_unlock(&gameMutex[g->index]);
+    pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + playerIndex]);
 }
 
-void stop_game(Game* g){
+void stop_game(Game* g) {
+    pthread_mutex_lock(&gameMutex[g->index]);
     //Indique comme inactive
     g->active = false;
     //Suppr les joueurs
-    for(int i = 0; i < MAXPLAYER; i++){
-        if(g->player[i]->ini){
+    for (int i = 0; i < MAXPLAYER; i++) {
+        pthread_mutex_lock(&playerMutex[(g->index * MAXPLAYER) + i]);
+        if (g->player[i]->ini) {
             delete_player(g->player[i]);
         }
         free(g->player[i]);
+        pthread_mutex_unlock(&playerMutex[(g->index * MAXPLAYER) + i]);
     }
     //Libere la memoire
-    for(int i = 0; i < g->width; i++){
+    for (int i = 0; i < g->width; i++) {
         free(g->map[i]);
     }
     free(g->map);
     free(g->mapName);
     free(g->mapContent);
+    pthread_mutex_unlock(&gameMutex[g->index]);
     //Retire une game
     nbGame--;
 }
 
-void clean_games(){
-    for(int i = 0; i < MAXGAME; i++){
-        if(game[i].active){
+void clean_games() {
+    for (int i = 0; i < MAXGAME; i++) {
+        if (game[i].active) {
             stop_game(&game[i]);
         }
     }

+ 5 - 1
Serveur/game.h

@@ -9,6 +9,7 @@
 #define GAME_H
 
 /* --- Include --- */
+#include <pthread.h>
 #include "constante.h"
 #include "player.h"
 #include "json.h"
@@ -20,6 +21,7 @@
 /* --- Struct --- */
 typedef struct{
     boolean active;
+    int index;
     char* name; //Nom
     int nbPlayer; //Nombre de joueur
     char* mapName; //Nom de la map
@@ -33,12 +35,14 @@ typedef struct{
 /* --- Extern --- */
 extern Game game[MAXGAME];
 extern int nbGame;
+extern pthread_mutex_t gameMutex[MAXGAME];
+extern pthread_mutex_t playerMutex[MAXGAME * MAXPLAYER];
 
 /* --- Fonctions --- */
 /**
  * Initialise les structures des parties
  */
-void ini_games();
+boolean ini_games();
 
 /**
  * Liste le nom de toutes les maps sous forme de JSON

+ 22 - 0
Serveur/handler.c

@@ -17,6 +17,8 @@
 /* --- Extern --- */
 extern Game game[MAXGAME];
 extern int nbGame;
+pthread_mutex_t gameMutex[MAXGAME];
+pthread_mutex_t playerMutex[MAXGAME * MAXPLAYER];
 
 /* --- Fonctions privées --- */
 
@@ -28,20 +30,25 @@ extern int nbGame;
 int search_client_game(int cliId) {
     int index = ERR;
     for (int i = 0; i < MAXGAME; i++) {
+        pthread_mutex_lock(&gameMutex[i]);
         //Regarde si la game est active et avec des joueurs
         if (game[i].active && game[i].nbPlayer > 0) {
             //Parcours les joueurs
             for (int j = 0; j < MAXPLAYER; j++) {
+                pthread_mutex_lock(&playerMutex[(i * MAXPLAYER) + j]);
                 //Si le joueur est actif
                 if (game[i].player[j]->ini) {
                     //Si l'id est le bon
                     if (game[i].player[j]->id == cliId) {
                         index = i;
+                        pthread_mutex_unlock(&playerMutex[(i * MAXPLAYER) + j]);
                         break;
                     }
                 }
+                pthread_mutex_unlock(&playerMutex[(i * MAXPLAYER) + j]);
             }
         }
+        pthread_mutex_unlock(&gameMutex[i]);
         //Si on a un resultat
         if (index != ERR) {
             break;
@@ -59,11 +66,14 @@ int search_client_game(int cliId) {
 int search_game(char* name) {
     int index = ERR;
     for (int i = 0; i < MAXGAME; i++) {
+        pthread_mutex_lock(&gameMutex[i]);
         //Regarde si la game est active et le nom
         if (game[i].active && strncmp(game[i].name, name, strlen(game[i].name)) == 0) {
             index = i;
+            pthread_mutex_unlock(&gameMutex[i]);
             break;
         }
+        pthread_mutex_unlock(&gameMutex[i]);
     }
     return index;
 }
@@ -85,9 +95,13 @@ int handler_client_end(int cliId, JsonParser* json) {
     printf("Deconnexion du client %d\n", cliId);
     //Cherche le client dans les parties
     for (int i = 0; i < MAXGAME; i++) {
+        pthread_mutex_lock(&gameMutex[i]);
         if (game[i].active) {
             for (int j = 0; j < MAXPLAYER; j++) {
+                pthread_mutex_lock(&playerMutex[(i * MAXPLAYER) + j]);
                 if (game[i].player[j]->ini && game[i].player[j]->id == cliId) {
+                    pthread_mutex_unlock(&playerMutex[(i * MAXPLAYER) + j]);
+                    pthread_mutex_unlock(&gameMutex[i]);
                     find = true;
                     remove_player(&game[i], j);
                     //Avertit les autres joueurs
@@ -99,11 +113,13 @@ int handler_client_end(int cliId, JsonParser* json) {
                     free(notif);
                     break;
                 }
+                pthread_mutex_unlock(&playerMutex[(i * MAXPLAYER) + j]);
             }
             if (find) {
                 break;
             }
         }
+        pthread_mutex_unlock(&gameMutex[i]);
     }
     remove_client(cliId);
     return SUCCESS;
@@ -300,11 +316,15 @@ int handler_player_move(int cliId, JsonParser* json) {
         return FAIL;
     }
     //Recup le joueur
+    pthread_mutex_lock(&gameMutex[index]);
     for(int i = 0; i < MAXPLAYER; i++){
+        pthread_mutex_lock(&playerMutex[(index * MAXPLAYER) + i]);
         if(game[index].player[i]->ini && game[index].player[i]->id == cliId){
             p = game[index].player[i];
+            pthread_mutex_unlock(&playerMutex[(index * MAXPLAYER) + i]);
             break;
         }
+        pthread_mutex_unlock(&playerMutex[(index * MAXPLAYER) + i]);
     }
     if(p == NULL){
         free(move);
@@ -360,11 +380,13 @@ int handler_player_move(int cliId, JsonParser* json) {
             }
         }
     } else {
+        pthread_mutex_unlock(&gameMutex[index]);
         free(move);
         send_err_client(cliId, EREQUEST);
         adderror("Le json du client est incorrect");
         return FAIL; 
     }
+    pthread_mutex_unlock(&gameMutex[index]);
     //Notifie les joueurs
     ini_encoder(&reponse);
     add_integer(&reponse, "player", cliId);

+ 4 - 1
Serveur/main.c

@@ -62,7 +62,10 @@ int main(){
     signal(SIGPIPE, SIG_IGN); //Ignore les signaux SIGPIPE (on est pas sur d'en recevoir à chaque coupure socket + Impossible de determnier quelle socket est fermé (on laisse la méthode du timeout pour la trouver)
     //Initialisation des composants
     ini_handler();
-    ini_games();
+    if(!ini_games()){
+        error.print("Impossible d'initialiser le serveur");
+        error.exit_err();
+    }
     //Lance le serveur UDP
     printf("Lancement serveur UDP\n");
     if(!launch_udp_server(PORT_UDP)){