diff --git a/client/client.c b/client/client.c index b5a201c..acdb831 100644 --- a/client/client.c +++ b/client/client.c @@ -363,39 +363,41 @@ int main(int argc, char *argv[]) continue; } - // Raccourci: si l'utilisateur tape juste un nombre 0..5, traiter comme PLAY/MOVE -if (tk0 && !tk1) { - int numeric = 1; - for (const char* p = tk0; *p; ++p) { - if (!isdigit((unsigned char)*p)) { numeric = 0; break; } - } - if (numeric) { - if (!g_en_partie) { - printf("[CLIENT] Vous n'etes pas en partie. Ignorer entree numerique.\n"); - } else { - int trou = atoi(tk0); - if (trou < 0 || trou >= NB_TROUS_CAMP) { - printf("[CLIENT] Trou invalide (0..5).\n"); - } else if (g_partie.joueur_courant != g_role_local) { - printf("[CLIENT] Ce n'est pas votre tour.\n"); - } else if (!awale_verifier_legalite(&g_partie, trou)) { - printf("[CLIENT] Coup illegal localement.\n"); - } else if (!awale_jouer_coup(&g_partie, trou)) { - printf("[CLIENT] Echec lors de l'application locale du coup.\n"); - } else { - printf("\n=== Votre coup joue localement (trou %d) ===\n", trou); - awale_afficher_plateau(&g_partie); - - char out[32]; - int len = snprintf(out, sizeof(out), "MOVE %d", trou); - nbytes = write(sockfd, out, len); - write(sockfd, "\n", 1); - if (nbytes < 0) erreur("Erreur ecriture socket (MOVE)"); + // Raccourci: si l'utilisateur tape juste un nombre 0..5, traiter comme PLAY/MOVE + if (tk0 && !tk1) { + int numeric = 1; + for (const char* p = tk0; *p; ++p) { + if (!isdigit((unsigned char)*p)) { numeric = 0; break; } + } + if (numeric) { + if (!g_en_partie) { + printf("[CLIENT] Vous n'etes pas en partie. Ignorer entree numerique.\n"); + } + else { + int trou = atoi(tk0); + if (trou < 0 || trou >= NB_TROUS_CAMP) { + printf("[CLIENT] Trou invalide (0..5).\n"); + } else if (g_partie.joueur_courant != g_role_local) { + printf("[CLIENT] Ce n'est pas votre tour.\n"); + } else if (!awale_verifier_legalite(&g_partie, trou)) { + printf("[CLIENT] Coup illegal localement.\n"); + } else if (!awale_jouer_coup(&g_partie, trou)) { + printf("[CLIENT] Echec lors de l'application locale du coup.\n"); + } else { + printf("\n=== Votre coup joue localement (trou %d) ===\n", trou); + awale_afficher_plateau(&g_partie); + + char out[32]; + int len = snprintf(out, sizeof(out), "MOVE %d", trou); + nbytes = write(sockfd, out, len); + write(sockfd, "\n", 1); + if (nbytes < 0) erreur("Erreur ecriture socket (MOVE)"); + } + } + continue; + } } - } - continue; - } -} + // Envoi par défaut tel quel au serveur (DEFI, ACCEPT, REFUSE, QUIT, etc.) int cmd_len = strlen(buffer); nbytes = write(sockfd, buffer, cmd_len); diff --git a/server/chat.c b/server/chat.c new file mode 100644 index 0000000..733b206 --- /dev/null +++ b/server/chat.c @@ -0,0 +1,7 @@ +#include "events.h" +#include "matches.h" + +void handle_message(int sock, int argc, char** argv, int pipe_write_to_p) +{ + +} diff --git a/server/defi.c b/server/defi.c new file mode 100644 index 0000000..1841533 --- /dev/null +++ b/server/defi.c @@ -0,0 +1,113 @@ +#include "events.h" + +/*void handle_defi(int sock, int argc, char** argv, int pipe_write_to_p) { + // argv[0] = "DEFI", argv[1] = pseudo_local, argv[2] = adversaire + if (argc < 3) { + envoyer_message(sock, "ERREUR_PROTOCOLE Commande DEFI incomplete. Usage: DEFI "); + return; + } + + const char *pseudo_local = argv[1]; + const char *adversaire = argv[2]; + + if (strcmp(pseudo_local, adversaire) == 0) { + envoyer_message(sock, "ERREUR_DEFI Vous ne pouvez pas vous defier vous-meme."); + return; + } + + // ENVOI AU PÈRE VIA IPC : DEFI + char ipc_msg[MAX_BUFFER]; + snprintf(ipc_msg, MAX_BUFFER, "DEFI %s %s", pseudo_local, adversaire); + + envoyer_ipc(pipe_write_to_p, ipc_msg); + + printf("FIL (%s): Defi envoye au PERE pour repartition vers %s.\n", pseudo_local, adversaire); + envoyer_message(sock, "DEFI_ENVOYE En attente de la reponse de l'adversaire..."); +}*/ + +void handle_defi(int sock, int argc, char** argv, int pipe_write_to_p) +{ + const char *defiante = argv[1]; + const char *adversaire = argv[2]; + + printf("%s %s\n", defiante, adversaire); + int idx_defiante = trouver_index_joueur(defiante); + int idx_adversaire = trouver_index_joueur(adversaire); + + if (idx_adversaire == -1) { + // Le joueur ciblé n'est pas actif + if (idx_defiante != -1) { + char notif[MAX_BUFFER]; + snprintf(notif, MAX_BUFFER, "ERREUR_DEFI Le joueur %s n'est pas actif.", adversaire); + envoyer_ipc(joueurs_actifs[idx_defiante].pipe_p_to_f, notif); + } + } else if (idx_defiante != -1 && joueurs_actifs[idx_defiante].en_partie) { + // Le défieur est déjà en partie + char notif[MAX_BUFFER]; + snprintf(notif, MAX_BUFFER, "ERREUR_DEFI Vous etes deja en partie."); + envoyer_ipc(joueurs_actifs[idx_defiante].pipe_p_to_f, notif); + } else if (joueurs_actifs[idx_adversaire].en_partie) { + // Le joueur défié est occupé + if (idx_defiante != -1) { + char notif[MAX_BUFFER]; + snprintf(notif, MAX_BUFFER, "ERREUR_DEFI Le joueur %s est deja en partie.", adversaire); + envoyer_ipc(joueurs_actifs[idx_defiante].pipe_p_to_f, notif); + } + } else { + // Relayer le défi au fils de l'adversaire + char notif[MAX_BUFFER]; + snprintf(notif, MAX_BUFFER, "DEFI_RECU %s", defiante); + envoyer_ipc(joueurs_actifs[idx_adversaire].pipe_p_to_f, notif); + printf("PÈRE: Défi de %s relayé à %s.\n", defiante, adversaire); + } +} + +void handle_refuse(int sock, int argc, char** argv, int pipe_write_to_p) { + // argv[0] = "REFUSE", argv[1] = pseudo_local, argv[2] = defiante + + if (argc < 3) { + envoyer_message(sock, "ERREUR_PROTOCOLE Commande REFUSE incomplete. Usage: REFUSE "); + return; + } + + const char *pseudo_local = argv[1]; + const char *defiante = argv[2]; + + if (strcmp(pseudo_local, defiante) == 0) { + envoyer_message(sock, "ERREUR_REFUSE Vous ne pouvez pas vous refuser vous-meme."); + return; + } + + // ENVOI AU PÈRE VIA IPC : REFUSE + char ipc_msg[MAX_BUFFER]; + snprintf(ipc_msg, MAX_BUFFER, "REFUSE %s %s", pseudo_local, defiante); + + envoyer_ipc(pipe_write_to_p, ipc_msg); + + printf("FIL (%s): Refus de defi envoye au PERE pour notification vers %s.\n", pseudo_local, defiante); + envoyer_message(sock, "DEFI_REFUSE_ENVOYE Refus du defi envoye."); +} + +void handle_accept(int sock, int argc, char** argv, int pipe_write_to_p) { + // argv[0] = "ACCEPT", argv[1] = pseudo_local (défié), argv[2] = defiante (défiant) + if (argc < 3) { + envoyer_message(sock, "ERREUR_PROTOCOLE Commande ACCEPT incomplete. Usage: ACCEPT "); + return; + } + + const char *pseudo_local = argv[1]; + const char *defiante = argv[2]; + + if (strcmp(pseudo_local, defiante) == 0) { + envoyer_message(sock, "ERREUR_ACCEPT Vous ne pouvez pas accepter votre propre defi."); + return; + } + + // ENVOI AU PÈRE VIA IPC : ACCEPT + char ipc_msg[MAX_BUFFER]; + snprintf(ipc_msg, MAX_BUFFER, "ACCEPT %s %s", pseudo_local, defiante); + envoyer_ipc(pipe_write_to_p, ipc_msg); + + // Accusé de réception côté client (le père enverra ensuite les notifications aux 2 joueurs) + envoyer_message(sock, "DEFI_ACCEPT_ENVOYE Acceptation envoyee. En attente de synchronisation..."); +} \ No newline at end of file diff --git a/server/event_interceptor.c b/server/event_interceptor.c new file mode 100644 index 0000000..01b9ef7 --- /dev/null +++ b/server/event_interceptor.c @@ -0,0 +1,6 @@ +#include "event_interceptor.h" + +void intercep_event(int sock, int pipe) +{ + +} \ No newline at end of file diff --git a/server/event_interceptor.h b/server/event_interceptor.h new file mode 100644 index 0000000..b582c70 --- /dev/null +++ b/server/event_interceptor.h @@ -0,0 +1,7 @@ +#include "../shared/socket.h" + +/** + * Intercept an event received by one of the child processes. + * The goal of this method is to transmit it to the main process that will deal with received data. + */ +void intercept_event(int sock, int pipe); \ No newline at end of file diff --git a/server/events.h b/server/events.h new file mode 100644 index 0000000..b992e04 --- /dev/null +++ b/server/events.h @@ -0,0 +1,25 @@ +#ifndef EVENTS_H +#define EVENTS_H + +#include +#include +#include +#include "matches.h" +#include "models.h" +#include "../shared/socket.h" + +// Events related to challenges +void handle_quit(int sock, int argc, char** argv, int pipe_write_to_p); +void handle_defi(int sock, int argc, char** argv, int pipe_write_to_p); +void handle_accept(int sock, int argc, char** argv, int pipe_write_to_p); + +// Events related to game itself + +void handle_move(int sock, int argc, char** argv, int pipe_write_to_p); +void handle_quit(int sock, int argc, char** argv, int pipe_write_to_p); + +// Events related to communication between players + +void handle_message(int sock, int argc, char** argv, int pipe_write_to_p); + +#endif \ No newline at end of file diff --git a/server/game.c b/server/game.c new file mode 100644 index 0000000..d8025e8 --- /dev/null +++ b/server/game.c @@ -0,0 +1,31 @@ +#include "events.h" + +void handle_quit(int sock, int argc, char** argv, int pipe_write_to_p) { + // Le fils doit informer le père de la déconnexion + envoyer_ipc(pipe_write_to_p, "QUIT"); +} + +void handle_move(int sock, int argc, char** argv, int pipe_write_to_p) { + // argv[0] = "MOVE", argv[1] = pseudo_local, argv[2] = trou_idx + if (argc < 3) { + envoyer_message(sock, "ERREUR_PROTOCOLE Commande MOVE incomplete. Usage: MOVE "); + return; + } + + const char *pseudo_local = argv[1]; + const char *trou_str = argv[2]; + + // Validation simple locale (format) + int trou_idx = atoi(trou_str); + if (trou_idx < 0 || trou_idx >= NB_TROUS_CAMP) { + envoyer_message(sock, "ERREUR_COUP Trou invalide (0..5)."); + return; + } + + // ENVOI AU PÈRE VIA IPC : MOVE + char ipc_msg[MAX_BUFFER]; + snprintf(ipc_msg, MAX_BUFFER, "MOVE %s %d", pseudo_local, trou_idx); + envoyer_ipc(pipe_write_to_p, ipc_msg); + + // L'ACK et la synchronisation seront gérées par le PÈRE +} \ No newline at end of file diff --git a/server/joueur.h b/server/joueur.h deleted file mode 100644 index e69de29..0000000 diff --git a/server/matches.c b/server/matches.c new file mode 100644 index 0000000..e205a3e --- /dev/null +++ b/server/matches.c @@ -0,0 +1,60 @@ +#include "matches.h" + +int trouver_index_joueur(const char* pseudo) +{ + for (int i = 0; i < nb_joueurs_actifs; i++) + { + if (strcmp(joueurs_actifs[i].pseudo, pseudo) == 0) + { + return i; + } + } + + return -1; +} + +int trouver_match_index(const char* sud, const char* nord) { + for (int i = 0; i < nb_matches; i++) { + if (matches[i].actif && + strcmp(matches[i].sud, sud) == 0 && + strcmp(matches[i].nord, nord) == 0) { + return i; + } + } + return -1; +} + +int creer_match(const char* sud, const char* nord) { + int idx = trouver_match_index(sud, nord); + if (idx != -1) { + // Déjà créé et actif + return idx; + } + + // Tenter de réutiliser un slot inactif + int free_idx = -1; + for (int i = 0; i < nb_matches; i++) { + if (!matches[i].actif) { + free_idx = i; + break; + } + } + + // Sinon, allouer un nouveau slot si possible + if (free_idx == -1) { + if (nb_matches >= MAX_MATCHES) { + return -1; + } + free_idx = nb_matches++; + } + + // Initialiser le match + strncpy(matches[free_idx].sud, sud, MAX_PSEUDO_LEN - 1); + matches[free_idx].sud[MAX_PSEUDO_LEN - 1] = '\0'; + strncpy(matches[free_idx].nord, nord, MAX_PSEUDO_LEN - 1); + matches[free_idx].nord[MAX_PSEUDO_LEN - 1] = '\0'; + + awale_init(&matches[free_idx].partie); // Initialise partie locale serveur + matches[free_idx].actif = 1; + return free_idx; +} diff --git a/server/matches.h b/server/matches.h new file mode 100644 index 0000000..9774791 --- /dev/null +++ b/server/matches.h @@ -0,0 +1,26 @@ +#ifndef JOUEURS_H +#define JOUEURS_H + +#include +#include "models.h" + +#define MAX_JOUEURS 100 +#define MAX_MATCHES 100 + +/** + * Trouver un joueur actif à l'aide de son pseudo + */ +int trouver_index_joueur(const char* pseudo); + +/** + * Trouver un match entre 2 joueurs actifs + */ +int trouver_match_index(const char* sud, const char* nord); + +/** + * Creer un match entre 2 joueurs. Retourne l'index du match. + * Si le match existe déjà entre ces 2 joueurs, la fonction retourne l'index du match courant. + */ +int creer_match(const char* sud, const char* nord); + +#endif \ No newline at end of file diff --git a/server/models.h b/server/models.h new file mode 100644 index 0000000..5aae43c --- /dev/null +++ b/server/models.h @@ -0,0 +1,38 @@ +#ifndef MODEL_H +#define MODEL_H + +#include +#include "../shared/awale.h" + +// Constants +#define MAX_PSEUDO_LEN 32 +#define MAX_BUFFER 256 + + +// Structure pour stocker les informations des joueurs actifs, qui sont connectés au serveur. +typedef struct JoueurActif { + char pseudo[MAX_PSEUDO_LEN]; + pid_t pid; + int pipe_p_to_f; // Descripteur d'écriture du PÈRE (pour envoyer au FILS) + int pipe_f_to_p; // Descripteur de lecture du PÈRE (pour recevoir du FILS) + int en_partie; // 1 si le joueur est en partie, 0 sinon + int match_id; // Identifiant du match en cours, -1 sinon + char adversaire[MAX_PSEUDO_LEN]; // Pseudo de l'adversaire si en partie + int victoires; // Compteur de victoires (runtime) +} JoueurActif; + + +typedef struct { + char sud[MAX_PSEUDO_LEN]; + char nord[MAX_PSEUDO_LEN]; + AwalePartie partie; // Partie locale au serveur + int actif; // 1 si match actif +} Match; + +extern JoueurActif joueurs_actifs[]; +extern int nb_joueurs_actifs; + +extern Match matches[]; +extern int nb_matches; + +#endif \ No newline at end of file diff --git a/server/server.c b/server/server.c index e53db30..f8bfef1 100644 --- a/server/server.c +++ b/server/server.c @@ -3,10 +3,8 @@ */ #include -#include "../shared/event_handler.h" #include #include -#include #include #include #include @@ -16,110 +14,56 @@ #include #include #include // Pour fcntl et O_NONBLOCK -#include "awale.h" +#include "events.h" +#include "matches.h" +#include "models.h" +#include "../shared/event_handler.h" +#include "../shared/socket.h" // --- Constantes et structures --- -#define MAX_JOUEURS 100 -#define MAX_PSEUDO_LEN 32 -#define MAX_BUFFER 256 #define MAX_TOKENS 12 -// Structure pour stocker les informations des joueurs actifs (géré par le père) -typedef struct { - char pseudo[MAX_PSEUDO_LEN]; - pid_t pid; - int pipe_p_to_f; // Descripteur d'écriture du PÈRE (pour envoyer au FILS) - int pipe_f_to_p; // Descripteur de lecture du PÈRE (pour recevoir du FILS) - int en_partie; // 1 si le joueur est en partie, 0 sinon - int match_id; // Identifiant du match en cours, -1 sinon - char adversaire[MAX_PSEUDO_LEN]; // Pseudo de l'adversaire si en partie - int victoires; // Compteur de victoires (runtime) -} JoueurActif; - +// Define global variables, stored in events.h JoueurActif joueurs_actifs[MAX_JOUEURS]; int nb_joueurs_actifs = 0; -// ================== Gestion des Parties côté Serveur (PÈRE) ================== - -#define MAX_MATCHES 100 - -typedef struct { - char sud[MAX_PSEUDO_LEN]; - char nord[MAX_PSEUDO_LEN]; - AwalePartie partie; // Partie locale au serveur - int actif; // 1 si match actif -} Match; - Match matches[MAX_MATCHES]; int nb_matches = 0; -int trouver_match_index(const char* sud, const char* nord) { - for (int i = 0; i < nb_matches; i++) { - if (matches[i].actif && - strcmp(matches[i].sud, sud) == 0 && - strcmp(matches[i].nord, nord) == 0) { - return i; - } - } - return -1; -} - -int creer_match(const char* sud, const char* nord) { - int idx = trouver_match_index(sud, nord); - if (idx != -1) { - // Déjà créé et actif - return idx; - } +void handle_refuse(int sock, int argc, char** argv, int pipe_write_to_p); +void handle_msg(int sock, int argc, char** argv, int pipe_write_to_p); +void handle_brc(int sock, int argc, char** argv, int pipe_write_to_p); +void handle_surr(int sock, int argc, char** argv, int pipe_write_to_p); - // Tenter de réutiliser un slot inactif - int free_idx = -1; - for (int i = 0; i < nb_matches; i++) { - if (!matches[i].actif) { - free_idx = i; - break; - } - } +// Information related to event handling. The client send events to the server that handle them by matching one event label with a reaction function. +char* events[] = {"DEFI", "QUIT", "ACCEPT", "REFUSE", "MOVE", "MSG", "BRC", "SURR", NULL}; - // Sinon, allouer un nouveau slot si possible - if (free_idx == -1) { - if (nb_matches >= MAX_MATCHES) { - return -1; - } - free_idx = nb_matches++; - } +cmd_handler_func functions[] = { + handle_defi, + handle_quit, + handle_accept, + handle_refuse, + handle_move, + handle_msg, + handle_brc, + handle_surr, + NULL +}; - // Initialiser le match - strncpy(matches[free_idx].sud, sud, MAX_PSEUDO_LEN - 1); - matches[free_idx].sud[MAX_PSEUDO_LEN - 1] = '\0'; - strncpy(matches[free_idx].nord, nord, MAX_PSEUDO_LEN - 1); - matches[free_idx].nord[MAX_PSEUDO_LEN - 1] = '\0'; +int eventCount = 8; - awale_init(&matches[free_idx].partie); // Initialise partie locale serveur - matches[free_idx].actif = 1; - return free_idx; -} +// ================== Gestion des Parties côté Serveur (PÈRE) ================== // --- Prototypes des fonctions --- int ajouter_pseudo(const char *pseudo, pid_t fils_pid, int p_to_f_fd, int f_to_p_fd); void retirer_pseudo(const char *pseudo); void envoyer_message(int sock, const char *msg); -void envoyer_ipc(int pipe_fd, const char *msg); -int trouver_index_joueur(const char *pseudo); void handle_inscription_and_fork(int sockfd_ecoute, int newsockfd, const struct sockaddr_in *cli_addr); // Ajout des descripteurs de pipe pour handle_client void handle_client(int newsockfd, const char *pseudo, const char *ip_client, int pipe_read_from_p, int pipe_write_to_p); -void handle_quit(int sock, int argc, char** argv, int pipe_write_to_p); -void handle_defi(int sock, int argc, char** argv, int pipe_write_to_p); -void handle_accept(int sock, int argc, char** argv, int pipe_write_to_p); -void handle_move(int sock, int argc, char** argv, int pipe_write_to_p); -void handle_refuse(int sock, int argc, char** argv, int pipe_write_to_p); -void handle_msg(int sock, int argc, char** argv, int pipe_write_to_p); -void handle_brc(int sock, int argc, char** argv, int pipe_write_to_p); -void handle_surr(int sock, int argc, char** argv, int pipe_write_to_p); - // Gestionnaire de signal pour nettoyer les processus fils terminés (zombies) void sigchld_handler(int s) @@ -139,14 +83,7 @@ void sigchld_handler(int s) // LOGIQUE DE GESTION DES PSEUDOS (PÈRE) // ========================================================================= -int trouver_index_joueur(const char *pseudo) { - for (int i = 0; i < nb_joueurs_actifs; i++) { - if (strcmp(joueurs_actifs[i].pseudo, pseudo) == 0) { - return i; - } - } - return -1; -} + int ajouter_pseudo(const char *pseudo, pid_t fils_pid, int p_to_f_fd, int f_to_p_fd) { if (nb_joueurs_actifs >= MAX_JOUEURS) return 2; @@ -208,126 +145,6 @@ void retirer_pseudo(const char *pseudo) { // COMMUNICATION (IPC & SOCKETS) // ========================================================================= -void envoyer_message(int sock, const char *msg) { - write(sock, msg, strlen(msg)); - write(sock, "\n", 1); -} - -void envoyer_ipc(int pipe_fd, const char *msg) { - if (write(pipe_fd, msg, strlen(msg)) < 0) { - perror("Erreur ecriture IPC"); - } - write(pipe_fd, "\n", 1); // Délimiteur -} - - -// --- Fonctions de gestion des commandes (FILS) --- - -void handle_quit(int sock, int argc, char** argv, int pipe_write_to_p) { - // Le fils doit informer le père de la déconnexion - envoyer_ipc(pipe_write_to_p, "QUIT"); -} - -void handle_defi(int sock, int argc, char** argv, int pipe_write_to_p) { - // argv[0] = "DEFI", argv[1] = pseudo_local, argv[2] = adversaire - - if (argc < 3) { - envoyer_message(sock, "ERREUR_PROTOCOLE Commande DEFI incomplete. Usage: DEFI "); - return; - } - - const char *pseudo_local = argv[1]; - const char *adversaire = argv[2]; - - if (strcmp(pseudo_local, adversaire) == 0) { - envoyer_message(sock, "ERREUR_DEFI Vous ne pouvez pas vous defier vous-meme."); - return; - } - - // ENVOI AU PÈRE VIA IPC : DEFI - char ipc_msg[MAX_BUFFER]; - snprintf(ipc_msg, MAX_BUFFER, "DEFI %s %s", pseudo_local, adversaire); - - envoyer_ipc(pipe_write_to_p, ipc_msg); - - printf("FIL (%s): Defi envoye au PERE pour repartition vers %s.\n", pseudo_local, adversaire); - envoyer_message(sock, "DEFI_ENVOYE En attente de la reponse de l'adversaire..."); -} - -void handle_refuse(int sock, int argc, char** argv, int pipe_write_to_p) { - // argv[0] = "REFUSE", argv[1] = pseudo_local, argv[2] = defiante - - if (argc < 3) { - envoyer_message(sock, "ERREUR_PROTOCOLE Commande REFUSE incomplete. Usage: REFUSE "); - return; - } - - const char *pseudo_local = argv[1]; - const char *defiante = argv[2]; - - if (strcmp(pseudo_local, defiante) == 0) { - envoyer_message(sock, "ERREUR_REFUSE Vous ne pouvez pas vous refuser vous-meme."); - return; - } - - // ENVOI AU PÈRE VIA IPC : REFUSE - char ipc_msg[MAX_BUFFER]; - snprintf(ipc_msg, MAX_BUFFER, "REFUSE %s %s", pseudo_local, defiante); - - envoyer_ipc(pipe_write_to_p, ipc_msg); - - printf("FIL (%s): Refus de defi envoye au PERE pour notification vers %s.\n", pseudo_local, defiante); - envoyer_message(sock, "DEFI_REFUSE_ENVOYE Refus du defi envoye."); -} - -void handle_accept(int sock, int argc, char** argv, int pipe_write_to_p) { - // argv[0] = "ACCEPT", argv[1] = pseudo_local (défié), argv[2] = defiante (défiant) - if (argc < 3) { - envoyer_message(sock, "ERREUR_PROTOCOLE Commande ACCEPT incomplete. Usage: ACCEPT "); - return; - } - - const char *pseudo_local = argv[1]; - const char *defiante = argv[2]; - - if (strcmp(pseudo_local, defiante) == 0) { - envoyer_message(sock, "ERREUR_ACCEPT Vous ne pouvez pas accepter votre propre defi."); - return; - } - - // ENVOI AU PÈRE VIA IPC : ACCEPT - char ipc_msg[MAX_BUFFER]; - snprintf(ipc_msg, MAX_BUFFER, "ACCEPT %s %s", pseudo_local, defiante); - envoyer_ipc(pipe_write_to_p, ipc_msg); - - // Accusé de réception côté client (le père enverra ensuite les notifications aux 2 joueurs) - envoyer_message(sock, "DEFI_ACCEPT_ENVOYE Acceptation envoyee. En attente de synchronisation..."); -} - -void handle_move(int sock, int argc, char** argv, int pipe_write_to_p) { - // argv[0] = "MOVE", argv[1] = pseudo_local, argv[2] = trou_idx - if (argc < 3) { - envoyer_message(sock, "ERREUR_PROTOCOLE Commande MOVE incomplete. Usage: MOVE "); - return; - } - - const char *pseudo_local = argv[1]; - const char *trou_str = argv[2]; - - // Validation simple locale (format) - int trou_idx = atoi(trou_str); - if (trou_idx < 0 || trou_idx >= NB_TROUS_CAMP) { - envoyer_message(sock, "ERREUR_COUP Trou invalide (0..5)."); - return; - } - - // ENVOI AU PÈRE VIA IPC : MOVE - char ipc_msg[MAX_BUFFER]; - snprintf(ipc_msg, MAX_BUFFER, "MOVE %s %d", pseudo_local, trou_idx); - envoyer_ipc(pipe_write_to_p, ipc_msg); - - // L'ACK et la synchronisation seront gérées par le PÈRE -} // --- Table de Dispatch --- @@ -386,21 +203,6 @@ void handle_surr(int sock, int argc, char** argv, int pipe_write_to_p) { envoyer_ipc(pipe_write_to_p, ipc_msg); } -char* tableau_evenements[] = {"DEFI", "QUIT", "ACCEPT", "REFUSE", "MOVE", "MSG", "BRC", "SURR", NULL}; - -cmd_handler_func tableau_fonctions[] = { - handle_defi, - handle_quit, - handle_accept, - handle_refuse, - handle_move, - handle_msg, - handle_brc, - handle_surr, - NULL -}; - - // ========================================================================= // GESTION CLIENTS & FORK (PÈRE) // ========================================================================= @@ -509,53 +311,10 @@ void handle_client(int newsockfd, const char *pseudo, const char *ip_client, int int nbytes = read(newsockfd, buffer, sizeof(buffer) - 1); if (nbytes <= 0) break; // Client déconnecté buffer[nbytes] = '\0'; - - // Logique de Parsing et de Dispatch (comme précédemment) - char* buffer_copy = strdup(buffer); - if (!buffer_copy) break; - char* raw_tokens[MAX_TOKENS]; - int raw_token_count = 0; - char* token = strtok(buffer_copy, " \n\r\t"); - while (token != NULL && raw_token_count < MAX_TOKENS) { - raw_tokens[raw_token_count++] = token; - token = strtok(NULL, " \n\r\t"); - } - - if (raw_token_count > 0) { - int function_index = -1; - for (int i = 0; tableau_evenements[i] != NULL; i++) { - if (strcmp(tableau_evenements[i], raw_tokens[0]) == 0) { - function_index = i; - break; - } - } - - if (function_index >= 0 && tableau_fonctions[function_index] != NULL) { - - // Préparation des arguments pour la fonction de gestion - char* final_tokens[MAX_TOKENS + 1]; - int final_argc = raw_token_count + 1; - - final_tokens[0] = raw_tokens[0]; - final_tokens[1] = (char*)pseudo; // PSEUDO LOCAL EN argv[1] - for(int i = 1; i < raw_token_count; i++) { - final_tokens[i+1] = raw_tokens[i]; - } - final_tokens[final_argc] = NULL; - - if (strcmp(final_tokens[0], "QUIT") == 0) { - free(buffer_copy); - handle_quit(newsockfd, final_argc, final_tokens, pipe_write_to_p); - break; - } - - // Appel avec (socket, argc, argv, pipe_write_to_p) - tableau_fonctions[function_index](newsockfd, final_argc, final_tokens, pipe_write_to_p); - } else { - envoyer_message(newsockfd, "ERREUR_COMMANDE Commande non reconnue."); - } - } - free(buffer_copy); + + // Propagate the received content to the parent. We already check that the buffer contains data. + // The parent process will handle game events. + envoyer_ipc(pipe_write_to_p, buffer); } // --- 2. GESTION DES NOTIFICATIONS PÈRE -> FILS (pipe_read_from_p) --- @@ -699,6 +458,17 @@ void gerer_ipc_fils(int sock_ecoute) { char *newline = strchr(ipc_buffer, '\n'); if (newline) *newline = '\0'; + // Handle directive read from pipe stream. + printf("buffer: %s\n", ipc_buffer); + tryCallFunction( + joueurs_actifs[i].pipe_f_to_p, + events, + functions, + eventCount, + ipc_buffer + ); + + printf("PÈRE: Message IPC de %s: %s\n", joueurs_actifs[i].pseudo, ipc_buffer); // Gestion prioritaire des messages de chat (préserve les espaces du contenu) @@ -754,41 +524,8 @@ void gerer_ipc_fils(int sock_ecoute) { char *commande = strtok(ipc_buffer, " "); char *arg1 = strtok(NULL, " "); char *arg2 = strtok(NULL, " "); - - if (commande && strcmp(commande, "DEFI") == 0 && arg1 && arg2) { - const char *defiante = arg1; - const char *adversaire = arg2; - - int idx_defiante = trouver_index_joueur(defiante); - int idx_adversaire = trouver_index_joueur(adversaire); - - if (idx_adversaire == -1) { - // Le joueur ciblé n'est pas actif - if (idx_defiante != -1) { - char notif[MAX_BUFFER]; - snprintf(notif, MAX_BUFFER, "ERREUR_DEFI Le joueur %s n'est pas actif.", adversaire); - envoyer_ipc(joueurs_actifs[idx_defiante].pipe_p_to_f, notif); - } - } else if (idx_defiante != -1 && joueurs_actifs[idx_defiante].en_partie) { - // Le défieur est déjà en partie - char notif[MAX_BUFFER]; - snprintf(notif, MAX_BUFFER, "ERREUR_DEFI Vous etes deja en partie."); - envoyer_ipc(joueurs_actifs[idx_defiante].pipe_p_to_f, notif); - } else if (joueurs_actifs[idx_adversaire].en_partie) { - // Le joueur défié est occupé - if (idx_defiante != -1) { - char notif[MAX_BUFFER]; - snprintf(notif, MAX_BUFFER, "ERREUR_DEFI Le joueur %s est deja en partie.", adversaire); - envoyer_ipc(joueurs_actifs[idx_defiante].pipe_p_to_f, notif); - } - } else { - // Relayer le défi au fils de l'adversaire - char notif[MAX_BUFFER]; - snprintf(notif, MAX_BUFFER, "DEFI_RECU %s", defiante); - envoyer_ipc(joueurs_actifs[idx_adversaire].pipe_p_to_f, notif); - printf("PÈRE: Défi de %s relayé à %s.\n", defiante, adversaire); - } - } else if (commande && strcmp(commande, "REFUSE") == 0 && arg1 && arg2) { + + if (commande && strcmp(commande, "REFUSE") == 0 && arg1 && arg2) { const char *defie = arg1; const char *defiante = arg2; @@ -1054,47 +791,47 @@ void gerer_ipc_fils(int sock_ecoute) { int main(int argc, char** argv) { - int sockfd; - struct sockaddr_in serv_addr; + int sockfd; + struct sockaddr_in serv_addr; - if (argc != 2) { - fprintf(stderr, "Usage: %s port\n", argv[0]); - exit(1); - } + if (argc != 2) { + fprintf(stderr, "Usage: %s port\n", argv[0]); + exit(1); + } - printf("Serveur (concurrent) démarré...\n"); + printf("Serveur (concurrent) démarré...\n"); - sockfd = socket(AF_INET, SOCK_STREAM, 0); - if (sockfd < 0) { perror("Erreur ouverture socket"); exit(1); } + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) { perror("Erreur ouverture socket"); exit(1); } - int optval = 1; - if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) { - perror("Erreur setsockopt (SO_REUSEADDR)"); - } + int optval = 1; + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) { + perror("Erreur setsockopt (SO_REUSEADDR)"); + } - bzero((char*) &serv_addr, sizeof(serv_addr)); - serv_addr.sin_family = AF_INET; - serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); - serv_addr.sin_port = htons(atoi(argv[1])); + bzero((char*) &serv_addr, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); + serv_addr.sin_port = htons(atoi(argv[1])); - if (bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) { - perror("Erreur bind"); - exit(1); - } + if (bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) { + perror("Erreur bind"); + exit(1); + } - listen(sockfd, 5); + listen(sockfd, 5); - struct sigaction sa; - sa.sa_handler = sigchld_handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - if (sigaction(SIGCHLD, &sa, NULL) == -1) { perror("sigaction"); exit(1); } + struct sigaction sa; + sa.sa_handler = sigchld_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + if (sigaction(SIGCHLD, &sa, NULL) == -1) { perror("sigaction"); exit(1); } - printf("Serveur prêt. En attente de connexions sur le port %s...\n", argv[1]); + printf("Serveur prêt. En attente de connexions sur le port %s...\n", argv[1]); - // Boucle principale utilisant select() pour gérer les nouvelles connexions et l'IPC - gerer_ipc_fils(sockfd); + // Boucle principale utilisant select() pour gérer les nouvelles connexions et l'IPC + gerer_ipc_fils(sockfd); - close(sockfd); - return 0; + close(sockfd); + return 0; } \ No newline at end of file diff --git a/shared/awale.c b/shared/awale.c index a09e0e1..9e90c72 100644 --- a/shared/awale.c +++ b/shared/awale.c @@ -26,8 +26,7 @@ static bool is_camp_vide(const AwalePartie *partie, int joueur) { * @param trou_idx L'index du trou a jouer (0 a 5). * @param graines_capturable Pointeur ou stocker le nombre de graines qui seraient capturees. */ -static void simuler_coup(const AwalePartie *partie_src, AwalePartie *partie_simul, - int trou_idx, int *graines_capturable) +static void simuler_coup(const AwalePartie *partie_src, AwalePartie *partie_simul, int trou_idx, int *graines_capturable) { // Copie de l'etat source pour la simulation memcpy(partie_simul, partie_src, sizeof(AwalePartie)); diff --git a/shared/event_handler.c b/shared/event_handler.c index 7bb82bf..b132d30 100644 --- a/shared/event_handler.c +++ b/shared/event_handler.c @@ -1,51 +1,68 @@ #include "event_handler.h" -void tryCallFunction(int socket, char** events, cmd_handler_func functions[], int size, char* input) +void tryCallFunction(int fd, char** events, cmd_handler_func functions[], int size, char* input) { - // Logique de Parsing et de Dispatch (comme précédemment) - char* buffer_copy = strdup(input); - if (!buffer_copy) return; + SocketParams socketParams = extractArguments(input); + if (socketParams.argc > 0) { + int function_index = -1; + for (int i = 0; events[i] != NULL; i++) { + if (strcmp(events[i], socketParams.argv[0]) == 0) { + function_index = i; + break; + } + } + + if (function_index >= 0 && functions[function_index] != NULL) + { + // Actually, the pipe is not provided. + printf("Appel d'une directive: %s\n", events[function_index]); + functions[function_index](fd, socketParams.argc, socketParams.argv, 0); + } + else + { + printf("Erreur: Impossible de trouver une fonction à appeler pour la directive %s\n", socketParams.argv[0]); + printf("Original input: %s\n", input); + printf("Directives disponibles: \n"); + for (int i = 0; i < socketParams.argc; i++) + { + printf("%s\n", events[i]); + } + } + } +} + +SocketParams extractArguments(char* input) +{ + // Logique de Parsing et de Dispatch (comme précédemment) + char* buffer_copy = strdup(input); + if (!buffer_copy) + { + struct SocketParams emptyParams = { 0, NULL }; + return emptyParams; + } + char* raw_tokens[ARGS_MAX_SIZE]; int raw_token_count = 0; char* token = strtok(buffer_copy, " \n\r\t"); - while (token != NULL && raw_token_count < ARGS_MAX_SIZE) { + while (token != NULL && raw_token_count < ARGS_MAX_SIZE) + { raw_tokens[raw_token_count++] = token; token = strtok(NULL, " \n\r\t"); } - if (raw_token_count > 0) { - int function_index = -1; - for (int i = 0; events[i] != NULL; i++) { - if (strcmp(events[i], raw_tokens[0]) == 0) { - function_index = i; - break; - } - } + if (raw_token_count > 0) + { + raw_tokens[raw_token_count] = NULL; + } - if (function_index >= 0 && functions[function_index] != NULL) { - - // Préparation des arguments pour la fonction de gestion - // char* final_tokens[MAX_TOKENS + 1]; - // int final_argc = raw_token_count + 1; + //free(buffer_copy) Cannot do it at the moment. - raw_tokens[raw_token_count] = NULL; + struct SocketParams params = { + raw_token_count, + raw_tokens + }; - /*final_tokens[0] = raw_tokens[0]; - final_tokens[1] = (char*)pseudo; // PSEUDO LOCAL EN argv[1] - for(int i = 1; i < raw_token_count; i++) { - final_tokens[i+1] = raw_tokens[i]; - } - final_tokens[final_argc] = NULL;*/ - - - // Actually, the pipe is not provided. - functions[function_index](socket, raw_token_count, raw_tokens, 0); - } - /*else { - envoyer_message(socket, "ERREUR_COMMANDE Commande non reconnue."); - }*/ - } - free(buffer_copy); + return params; } \ No newline at end of file diff --git a/shared/event_handler.h b/shared/event_handler.h index 31a7db2..2640c4a 100644 --- a/shared/event_handler.h +++ b/shared/event_handler.h @@ -1,3 +1,6 @@ +#ifndef EVENT_HANDLER_C +#define EVENT_HANDLER_C + #include #include #include @@ -7,9 +10,21 @@ typedef void (*cmd_handler_func)(int, int, char**, int); +typedef struct SocketParams { + int argc; + char** argv; +} SocketParams; + /** * Try to find the function associated to the event list, based on an event * received from the server. * Call it using known parameters. */ -void tryCallFunction(int socket, char** events, cmd_handler_func functions[], int size, char* input); \ No newline at end of file +void tryCallFunction(int fd, char** events, cmd_handler_func functions[], int size, char* input); + +/** + * From a string input, split words separated by spaces and return a structure representing the words + */ +SocketParams extractArguments(char* input); + +#endif // EVENT_HANDLER_C \ No newline at end of file diff --git a/shared/socket.c b/shared/socket.c new file mode 100644 index 0000000..3447b76 --- /dev/null +++ b/shared/socket.c @@ -0,0 +1,13 @@ +#include "socket.h" + +void envoyer_message(int sock, const char *msg) { + write(sock, msg, strlen(msg)); + write(sock, "\n", 1); +} + +void envoyer_ipc(int pipe_fd, const char *msg) { + if (write(pipe_fd, msg, strlen(msg)) < 0) { + perror("Erreur ecriture IPC"); + } + write(pipe_fd, "\n", 1); // Délimiteur +} \ No newline at end of file diff --git a/shared/socket.h b/shared/socket.h new file mode 100644 index 0000000..bcda9ab --- /dev/null +++ b/shared/socket.h @@ -0,0 +1,6 @@ +#include +#include +#include + +void envoyer_message(int sock, const char *msg); +void envoyer_ipc(int pipe_fd, const char *msg); \ No newline at end of file