/* * (C) COPYRIGHT Vincent S. Cojot and others 1996-1997 * All Rights Reserved * Licensed Materials - Property of Vincent S. Cojot and others. * Use, duplication or disclosure restricted by Vincent S. Cojot. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef USING_MESA #include #else #include #endif #include "defines.h" #include "daemon.h" /* ------------------------------------------------*/ /* Dans cette routine, on demarre le processus de daemon qui */ /* va etre charge des routines de reseau. Son but est d'eviter un */ /* ralentissement majeur du tank a cause de l'utilisation du */ /* reseau. */ /* ------------------------------------------------*/ GLvoid ForkIPCDaemon(GLvoid) { /* --------------------------------------------*/ /* Initialisation du shared memory segment #1. */ shmid1 = shmget( (key_t)STATUS_KEY1, sizeof(STATUS_IPC), SHM_MODE | IPC_CREAT); if (shmid1 < 0 ) { printf("Error allocating needed segment, exiting...\n"); exit(1); } GameStatus = (STATUS_IPC *) shmat (shmid1, 0, 0); if ( (int) GameStatus == -1 ) { printf("Error attaching allocated segment, exiting...\n"); exit(1); } /* --------------------------------------------*/ /* Initialisation du shared memory segment #2. */ shmid2 = shmget( (key_t)STATUS_KEY2, sizeof(PMEM), SHM_MODE | IPC_CREAT); if (shmid2 < 0 ) { printf("Error allocating needed segment, exiting...\n"); exit(1); } mem = (PMEM *) shmat (shmid2, 0, 0); if ( (int) mem == -1 ) { printf("Error attaching allocated segment, exiting...\n"); exit(1); } /* Initialisation de diverses composantes necessaires aux deux */ /* Processus crees lors de ForkIPCDaemon().. */ GameStatus->NetworkEnabled = 0; /* Separation des processus pere et fils... */ ForkPID=fork(); if (ForkPID == -1) { /* Si erreur sur le Fork.*/ printf("Error Forking child process!! exiting...\n"); exit(1); } else { /* Si le processus fils a bien ete demarre..*/ if (ForkPID == 0) { /* Corps du Processus fils... */ #ifdef DEBUG_COMM printf("I am a son of my dada!!!!!\n"); #endif /* Initialise l'element mem... */ bzero (mem, sizeof(PMEM)); /* Prepare une connection network... */ SetupNetworkConnection(); /* Prepare une reception de packets...*/ SetupReceivingPacket(); /* Tant que le joueur n'a pas donne le signal de fin de jeu..*/ while(!GameStatus->GameTerminating) { /* Attends des packets...*/ ReceiveOnePacket(); } } else { /* Corps du Processus parent... */ #ifdef DEBUG_COMM printf("Now I got a child!!!\n"); #endif /* Prepare une connection network... */ SetupNetworkConnection(); /* Prepare un envoi de packets...*/ SetupSendingPacket(); } } } /* ------------------------------------------------*/ /* Dans cette routine, on libere la memoire des segments de */ /* memoire partagee. Cette fonction est appellee dans tank.c */ /* par TerminateEntireGame() */ /* ------------------------------------------------*/ GLvoid CloseSegment(GLvoid) { if (shmctl (shmid1, IPC_RMID, 0) == -1) { printf("Error de-allocating shared memory segment, exiting...\n"); exit (1); } if (shmctl (shmid2, IPC_RMID, 0) == -1) { printf("Error de-allocating shared memory segment, exiting...\n"); exit (1); } } /* ------------------------------------------------*/ /* cette routine recopie les donnees en memoire partagee dans */ /* les matrices utilisees par le jeu pour gerer les autre tanks, */ /* les missiles et les explosions. */ /* ------------------------------------------------*/ GLvoid CopyPacketsInLocalMem(GLvoid) { int i,j; for (i=0; i_tank[i].type) /* il y a un paquet */ { Tanks[i].Posx = mem->_tank[i].pos_x; Tanks[i].Posz = mem->_tank[i].pos_y; Tanks[i].Angle = 180 * atan2(mem->_tank[i].dir_x, mem->_tank[i].dir_y) / PI; sprintf(Tanks[i].Name, mem->_tank[i].nom); Tanks[i].Valid = 1; Tanks[i].Destroyed = 0; Tanks[i].LastSeen = GameStatus->TheCurrentTime; tanks++; } else { if( (GameStatus->TheCurrentTime - Tanks[i].LastSeen) >= NETWORK_RUN_TIMEOUT ) { Tanks[i].Valid = 0; tanks--; } } } /* for i */ for (i=0; i<(MAX_MISSILES-1); i++) { if (mem->_obus[i].type) /* il y a un paquet */ { Missiles[i+1].Posx = mem->_obus[i].org_x; Missiles[i+1].Posz = mem->_obus[i].org_y; Missiles[i+1].Incx = mem->_obus[i].dir_x; Missiles[i+1].Incz = mem->_obus[i].dir_y; Missiles[i+1].Angle = 180 * atan2(mem->_obus[i].dir_x, mem->_obus[i].dir_y) / PI; sprintf(Missiles[i+1].Name, mem->_obus[i].nom); Missiles[i+1].Valid = 1; Missiles[i+1].Age = 0; FlyingMissile++; } else { Missiles[i+1].Valid = 0; } } /* for i */ for (i=0; i_expl[i].type) /* il y a un paquet */ { /* Si on n'est pas deja en train de gerer une explosion..*/ if (!Explosions[i].Valid) { Explosions[i].x = mem->_expl[i].pos_x; Explosions[i].y = 0.0; Explosions[i].z = mem->_expl[i].pos_y; sprintf(Explosions[i].Name, mem->_expl[i].nom); sprintf(Explosions[i].Destroyed, mem->_expl[i].nom_detruit); if (!strcmp(Explosions[i].Destroyed,OurName)) { KilledFromNetworkGame(mem->_expl[i].nom); } Explosions[i].Valid = 1; Explosions[i].Age = 0.0; explosion++; /* On retire le tank qui a explose...*/ for (j=0; j_tank[j].type) { if (!strcmp(Explosions[i].Destroyed,mem->_tank[j].nom)) { mem->_tank[j].type = 0; tanks--; } } } } } else { /* Si on n'est pas deja en train de gerer une explosion..*/ if (!Explosions[i].Valid) { Explosions[i].Valid = 0; } } } /* on remet les listes de mem a 0 */ /* bzero (mem, sizeof(PMEM)); */ for (i=0; i<(MAX_MISSILES-1); i++) { if (mem->_obus[i].type) /* il y a un paquet */ { mem->_obus[i].type = 0; } } for (i=0; i_expl[i].type) /* il y a un paquet */ { mem->_expl[i].type = 0; } } /* On a transfere les paquets donc on peut remettre l'indicateur */ /* de changement d'etat a 0. */ GameStatus->StatusChanged = 0; } /*------------------------ SetupNetworkConnection ------------------------*/ GLvoid SetupNetworkConnection(GLvoid) { /* Get network address */ grpaddr.s_addr = inet_addr(network_group); /* open socket */ fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { perror("socket"); exit(1); } /* build up network address for packets */ bzero(&addr, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(network_port); addrlen = sizeof(addr); } /*------------------------ SetupReceivingPacket ------------------------*/ GLvoid SetupReceivingPacket(GLvoid) { /* * Allow multiple instances of this program to listen on the same * port on the same host. By default, only 1 program can bind * to the port on a host. */ int on = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { perror("setsockopt SO_REUSEADDR"); exit(1); } if (bind(fd, &addr, sizeof(addr)) < 0) { perror("bind"); exit(1); } } /*------------------------------ ReceiveOnePacket ------------------------*/ GLvoid ReceiveOnePacket(GLvoid) { int cnt,i; PTANK *pt; PMISSILE *po; PEXPLOSION *pe; char message_recvd[MAX_MSG_LEN]; cnt = recvfrom(fd, message_recvd, sizeof(message_recvd), 0, &addr, &addrlen); if (cnt < 0) { perror("recvfrom"); exit(1); } else if (cnt==0) { /* empty packet */ printf ("\nRecu un packet vide\n"); fflush(stdout); } else /* le packet n'est pas vide */ { /* si le packet recu est un des paquets que nous avons envoye, on ne le prend pas */ if (!strcmp(OurName,message_recvd+sizeof(int))) return; /* on regarde quel est le type de packet */ if (*((int *)message_recvd) == PACKET_TANK) { /* Reception d'un paquet donc on met l'indicateur de changement */ /* d'etat a 1. */ GameStatus->StatusChanged = 1; GameStatus->NetworkEnabled = 1; GameStatus->StatusLastChangeTime = 0.0; /* on regarde si ce tank existe deja */ pt = (PTANK *)message_recvd; #ifdef DEBUG_COMM printf("\nReception d'un paquet de TANK, nom = %s",pt->nom); fflush(stdout); #endif for (i=0; i < MAX_TANKS; i++) if (!(strcmp(mem->_tank[i].nom, pt->nom))) /* meme tank */ break; if (i==MAX_TANKS) /* on n'a pas trouve ce tank */ { /* on trouve une place pour ce tank */ for (i=0; i < MAX_TANKS; i++) if (!mem->_tank[i].type) /* on a une place vide */ break; if (i==MAX_TANKS) /* on n'a pas de place */ { printf ("\nManque de memoire pour les packets de tanks\n"); exit (1); } else /* il y a une place */ bcopy (pt,&(mem->_tank[i]),sizeof (PTANK)); } else /* on a trouve le tank en memoire */ /* ecrase ce tank avec les nouvelles donnees */ bcopy (pt,&(mem->_tank[i]),sizeof (PTANK)); } else if (*((int *)message_recvd) == PACKET_OBUS) { /* Reception d'un paquet donc on met l'indicateur de changement */ /* d'etat a 1. */ GameStatus->StatusChanged = 1; GameStatus->NetworkEnabled = 1; GameStatus->StatusLastChangeTime = 0.0; po = (PMISSILE *)message_recvd; #ifdef DEBUG_COMM printf("\nReception d'un paquet d'OBUS, nom = %s",po->nom); fflush(stdout); #endif for (i=0; i < MAX_MISSILES-1; i++) if (!(strcmp(mem->_obus[i].nom, po->nom))) /* meme tank */ break; if (i==MAX_MISSILES-1) { for (i=0; i < MAX_MISSILES-1; i++) if (!mem->_obus[i].type) /* on a une place vide */ break; if (i==MAX_MISSILES-1) /* on n'a pas de place */ { printf ("\nManque de memoire pour les packets de obus\n"); exit (1); } else /* il y a une place */ bcopy (po,&(mem->_obus[i]),sizeof (PMISSILE)); } else /* on a trouve ce missile en memoire... */ /* ecrase ce missile avec les nouvelles donnees */ bcopy (po,&(mem->_obus[i]),sizeof (PMISSILE)); } else if (*((int *)message_recvd) == PACKET_EXPL) { /* Reception d'un paquet donc on met l'indicateur de changement */ /* d'etat a 1. */ GameStatus->StatusChanged = 1; GameStatus->NetworkEnabled = 1; GameStatus->StatusLastChangeTime = 0.0; pe = (PEXPLOSION *)message_recvd; #ifdef DEBUG_COMM printf("\nReception d'un paquet d'EXPLOSION, nom = %s",pe->nom); fflush(stdout); #endif for (i=0; i < MAX_EXPLOSIONS; i++) if (!mem->_expl[i].type) /* on a une place vide */ break; if (i==MAX_EXPLOSIONS) /* on n'a pas de place */ { printf ("\nManque de memoire pour les packets de expl\n"); exit (1); } else /* il y a une place */ bcopy (pe,&(mem->_expl[i]),sizeof (PEXPLOSION)); } else /* le type de packet est inconnu */ { printf ("\nRecu un packet inconnu\n"); } } } /*------------------------------ SetupSendingPacket ----------------------*/ GLvoid SetupSendingPacket(GLvoid) { /* setup socket options */ int on = 1 ; if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on))) { perror("setsockopt SO_BROADCAST"); exit(1); } addr.sin_addr = grpaddr; } /*------------------------------ SendOnePacket --------------------------*/ GLvoid SendOnePacket(GLvoid *msg) { int cnt; if (*((int *)msg) == PACKET_TANK) { cnt = sendto(fd, msg, sizeof(PTANK), 0, &addr, addrlen); #ifdef DEBUG_COMM printf("\nEnvoi d'un paquet de TANK, nom = %s",((PTANK *)msg)->nom); fflush(stdout); #endif if (cnt < 0) { perror("sendto"); exit(1); } } else if (*((int *)msg) == PACKET_OBUS) { cnt = sendto(fd, msg, sizeof(PMISSILE), 0, &addr, addrlen); #ifdef DEBUG_COMM printf("\nEnvoi d'un paquet d'OBUS, nom = %s",((PMISSILE *)msg)->nom); fflush(stdout); #endif if (cnt < 0) { perror("sendto"); exit(1); } } else if (*((int *)msg) == PACKET_EXPL) { cnt = sendto(fd, msg, sizeof(PEXPLOSION), 0, &addr, addrlen); #ifdef DEBUG_COMM printf("\nEnvoi d'un paquet d'EXPLOSION, nom = %s",((PEXPLOSION *)msg)->nom); fflush(stdout); #endif if (cnt < 0) { perror("sendto"); exit(1); } } else /* on ne reconnait pas le type de packet */ { printf ("\nSendOnePacket() packet inconnu !\n"); } } /* ------------------------------------------------*/ /* Cette routine, appellee par drawscene, envoie un paquet de Tank */ /* sur le reseau local sous la forme de broadcast. */ /* ------------------------------------------------*/ GLvoid SendMyTankPacket(GLvoid) { OneTankPacket.type = PACKET_TANK; strncpy (OneTankPacket.nom, OurName, 10); OneTankPacket.time_stamp = GameStatus->TheCurrentTime; OneTankPacket.pos_x = scenePosx; OneTankPacket.pos_y = scenePosz; OneTankPacket.dir_x = sin(PI*sceneAngle/180); OneTankPacket.dir_y = cos(PI*sceneAngle/180); OneTankPacket.vit = LongSpeed ; OneTankPacket.vit_ang = RotaSpeed ; SendOnePacket(&OneTankPacket); #ifdef DEBUG_COMM OneTankPacket.type = PACKET_TANK; strncpy (OneTankPacket.nom, "FakeTank", 10); OneTankPacket.time_stamp = GameStatus->TheCurrentTime; OneTankPacket.pos_x = 14.0; OneTankPacket.pos_y = 14.0; OneTankPacket.dir_x = sin(PI*GameStatus->TheCurrentTime/180); OneTankPacket.dir_y = cos(PI*GameStatus->TheCurrentTime/180); OneTankPacket.vit = 0 ; OneTankPacket.vit_ang = 0 ; SendOnePacket(&OneTankPacket); #endif #ifdef DEBUG_COMM OneMissilePacket.type = PACKET_OBUS; strncpy (OneMissilePacket.nom, "FakeMissile", 10); OneMissilePacket.time_stamp = GameStatus->TheCurrentTime; OneMissilePacket.org_x = 5; OneMissilePacket.org_y = 25; OneMissilePacket.dir_x = sin(GameStatus->TheCurrentTime); OneMissilePacket.dir_y = cos(GameStatus->TheCurrentTime); SendOnePacket(&OneMissilePacket); #endif } /* ------------------------------------------------*/ /* Cette routine, appellee par drawscene, envoie un paquet de Tank */ /* detruit sur le reseau local sous la forme de broadcast. */ /* ------------------------------------------------*/ GLvoid SendMyDyingTankPacket(GLvoid) { OneTankPacket.type = PACKET_TANK; strncpy (OneTankPacket.nom, OurName, 10); OneTankPacket.time_stamp = -1.0; OneTankPacket.pos_x = scenePosx; OneTankPacket.pos_y = scenePosz; OneTankPacket.dir_x = sin(PI*sceneAngle/180); OneTankPacket.dir_y = cos(PI*sceneAngle/180); OneTankPacket.vit = LongSpeed ; OneTankPacket.vit_ang = RotaSpeed ; SendOnePacket(&OneTankPacket); } /* ------------------------------------------------*/ /* Cette routine, appellee par drawscene, envoie un paquet de Missile */ /* sur le reseau local sous la forme de broadcast. */ /* ------------------------------------------------*/ GLvoid SendMyMissilePacket(GLvoid) { OneMissilePacket.type = PACKET_OBUS; strncpy (OneMissilePacket.nom, OurName, 10); OneMissilePacket.time_stamp = GameStatus->TheCurrentTime; OneMissilePacket.org_x = Missiles[0].Posx; OneMissilePacket.org_y = Missiles[0].Posz; OneMissilePacket.dir_x = sin(PI*Missiles[0].Angle/180); OneMissilePacket.dir_y = cos(PI*Missiles[0].Angle/180); SendOnePacket(&OneMissilePacket); } /* ------------------------------------------------*/ /* Cette routine, appellee par drawscene, envoie un paquet d'explosion */ /* sur le reseau local sous la forme de broadcast. */ /* ------------------------------------------------*/ GLvoid SendMyExplosionPacket(GLvoid) { gethostname( hostname, 10); OneExplosionPacket.type = PACKET_EXPL; strncpy (OneExplosionPacket.nom, OneExplosion.Name, 10); strncpy (OneExplosionPacket.nom_detruit, OneExplosion.Destroyed, 10); OneExplosionPacket.time_stamp = GameStatus->TheCurrentTime; OneExplosionPacket.pos_x = OneExplosion.x ; OneExplosionPacket.pos_y = OneExplosion.z ; SendOnePacket(&OneExplosionPacket); }