Codice: Seleziona tutto
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
#include <malloc.h>
#include <sys/socket.h>
#include <string.h>
#include <time.h>
#include <netinet/ip.h>
#include <sys/stat.h>
#include <fcntl.h>
typedef struct{ //definizione struttura carta
int val;
int seme;
int qta;
}cardstruct;
typedef cardstruct* carta; //carta è il puntatore a alla struttura cardstruct
// VARIABILI CONDIVISE DAI THREADS
int numplayers; //numero di giocatori
char **utenti; //vettore che conserva i nickname dei giocatori correnti
int *fd; //vettore dei file descriptor dei giocatori
int *fiches; //vettore che conserva le fiches dei giocatori
int *bet; //vettore che conserva la puntata dei giocatori
int *punteggio; //vettore che conserva il punteggio dei giocatori
time_t inizio; //variabile contenente l'inizio effettivo del gioco
struct sockaddr_in indirizzo_client; //struttura dati con informazioni sui client
socklen_t client_size=sizeof(indirizzo_client); //grandezza struttura dati informazioni sui client
pthread_mutex_t mut= PTHREAD_MUTEX_INITIALIZER; //semaforo sul numero dei giocatori
pthread_cond_t cond= PTHREAD_COND_INITIALIZER; //condizione che indica se c'e' almeno un giocatore
int fdlog; //file descriptor del file di log
// ******************************** INIZIO FUNZIONI ****************************************
//la funzione riceve in ingresso un vettore carte e lo restituisce inizializzato
carta* init_mazzo(carta* carte){
int i,j;
carte=malloc(53*sizeof(carta)); //allochiamo memoria per i puntatori
for (i=0;i<54;i++)
{
carte[i]=(carta)malloc(sizeof(cardstruct)); //allochiamo memoria per i record
}
carte[0]->val=52; //numero di carte che differiscono per seme e valore
for (i=0;i<4;i++)
{
for (j=1;j<14;j++)
{ //inizializzo i 2 mazzi prima dell'estrazione
carte[(i*13)+j]->seme=i;
carte[(i*13)+j]->val=j;
carte[(i*13)+j]->qta=2;
}
}
return carte;
}
//restituisce 0 se le carte sono meno di 52
int test_numcarte(carta* carte){
int i,temp=0;
for (i=1;i<=carte[0]->val;i++)
{
temp=temp+carte[i]->qta;
}
if (temp<=52) return 0;
else return 1;
}
//restituisce il puntatore ad un elemento di carte a caso decrementando la quantita'
carta get_carta(carta* carte){
int i;
carta temp;
i=(((rand()) % (carte[0]->val))+1); //prendi un indice i qualsiasi sul range di carte diverse rimanenti
carte[i]->qta--; //decrementa la quantita' della iesima carta perche' selezionata
if (carte[i]->qta==0) //se e' l'ultima
{
temp=carte[i]; //scambiala con l'ultima carta del mazzo
carte[i]=carte[carte[0]->val];
carte[carte[0]->val]=NULL;
carte[0]->val--; //decrementa il range
return (temp); //restituiscila
}
return (carte[i]); //altrimenti restituiscila senza toccare le rimanenti
}
//invia a tutti i client collegati un messaggio
void inviamsg(int gi,int *fd,char *buff,int len){
int i,rd;
for(i=1;i<=gi;i++)
{
rd=write(fd[i],buff,len);
if (rd<0) {perror("write");return;}
}
return;
}
//invia un messaggio a tutti tranne che a "no"
void inviamsg_mod(int g,int *fd,int no,char buff[30],int len){
int i,rd;
rd=0;
for(i=1;i<=g;i++)
{
if (i!=no)
{
rd=write(fd[i],buff,len);
}
if (rd<0) {perror("write");return;}
}
return;
}
//inpacchetta un messaggio di tipo print
void set_msg(char messaggio[30],int val,int seme){
char temp[30];
strcpy(messaggio,"print ");
sprintf(temp,"%d ",val);
strcat(messaggio,temp); //ESEMPIO MESSAGGIO "print 5 2^"
sprintf(temp,"%d",seme);
strcat(messaggio,temp);
strcat(messaggio,"^");
}
//conta il punteggio progressivo di un singolo giocatore
int calcola_punteggio(int fd,int val,int punteggio,int *assi){
char buff[30];
int rd;
if (val!=1)
{
if ((val)>10){punteggio=punteggio+10;} //le carte>10 valgono 10
else {punteggio=punteggio+val;} //altrimenti hanno il loro valore normale
}
else
{
(*assi)++; //salviamo il numero di assi usciti
punteggio+=11; //sommiamo 11 punti per ogni asso uscito
}
while(1)
{
if ((punteggio>21)&&(*assi>0)) //ora se abbiamo sballato per via di un asso
{
punteggio-=10; //possiamo sempre decidere di farlo valere 1
(*assi)--; //quindi decrementiamo e ripetiamo finche' abbiamo assi
}
else {break;}
}
if (punteggio>21) //se il precedente passaggio non basta
{
punteggio=-1; //abbiamo "sballato"
rd=write(fd,"over^",5); //informiamo il client di tale evento
if (rd<0) {perror("write");return;}
rd=read(fd,buff,3);
if (rd<0) {perror("read");return;}
return -1;
}
else
{
rd=write(fd,"ok^",3);
if (rd<0) {perror("write");return;}
rd=read(fd,buff,3);
if (rd<0) {perror("read");return;}
}
return punteggio;
}
//simula la giocata del banco
int play_banco(int *fd,int players,carta carta_server,carta* mazzo){
char tmp[30],msg[30];
int assi, punteggio, rd, i;
carta carta_tmp;
strcpy(tmp,"");
strcpy(msg,"server ");
assi=0;
punteggio=0;
while(punteggio<=17)
{
if (punteggio==0)
{
carta_tmp=carta_server;
sprintf(tmp,"%d",carta_tmp->val);
strcat(msg,tmp);
strcat(msg," ");
sprintf(tmp,"%d",carta_tmp->seme);
strcat(msg,tmp);
}
else
{
carta_tmp=get_carta(mazzo);
strcat(msg," ");
sprintf(tmp,"%d",carta_tmp->val);
strcat(msg,tmp);
strcat(msg," ");
sprintf(tmp,"%d",carta_tmp->seme);
strcat(msg,tmp);
}
if (carta_tmp->val!=1)
{
if ((carta_tmp->val)>10){punteggio=punteggio+10;}
else {punteggio=punteggio+carta_tmp->val;}
}
else
{
assi++;
punteggio+=11;
}
while(1)
{
if ((punteggio>21)&&(assi>0))
{
punteggio-=10;
assi--;
}
else{break;}
}
if (punteggio>21)
{
punteggio=-1;
break;
}
}
strcat(msg,"^");
inviamsg(players,fd,msg,strlen(msg));
for(i=1;i<=players;i++)
{
rd=read(fd[i],msg,3);
if (rd<0) {perror("read");return;}
}
return punteggio;
}
//invia ad ogni giocatore il proprio risultato
void invia_risultato(int *fd,int *punteggio,int *bet,int players,int *fiches){
int i,rd;
char msg[30],tmp[30],buffora[30];
char buff[3];
int j;
time_t ora;
int minuti, secondi;
double diff;
j=0;
for (i=1;i<=players;i++)
{
if ((punteggio[0]>punteggio[i])||(punteggio[i]==-1))
{
fiches[i]-=bet[i];
strcpy(msg,"lose ");
}
else
{
if (punteggio[0]<punteggio[i])
{
fiches[i]+=bet[i];
strcpy(msg,"win ");
}
else
{
strcpy(msg,"draw ");
}
}
sprintf(tmp,"%d",fiches[i]);
strcat(msg,tmp);
strcat(msg,"^");
rd=write(fd[i],msg,strlen(msg));
if (rd<0) {perror("write");return;}
/*STATO GIOCO*/
memset(&tmp,0,sizeof(tmp));
sprintf(tmp,"%d",players);
write(fd[i],tmp,sizeof(tmp)); //invia il numero dei giocatori
if (rd<0) {perror("write");return;}
rd=read(fd[i],tmp,sizeof(tmp)); //legge ok^
if (rd<0) {perror("read");return;}
j=1;
while (j<=players) //scorre il vettore utenti
{
write(fd[i],utenti[j],9); //invia gli utenti
if (rd<0) {perror("write");return;}
j++;
}
rd=read(fd[i],tmp,sizeof(tmp)); //legge ok^
if (rd<0) {perror("read");return;}
memset(&msg,0,sizeof(msg));
time(&ora); //calcolo tempo rimanente
diff=1200-difftime(ora,inizio);
minuti=diff/60;
secondi=(int) diff%60;
sprintf(buffora,"%d",minuti);
strcat(msg,buffora);
strcat(msg,":");
sprintf(buffora,"%d",secondi);
strcat(msg,buffora);
write(fd[i],msg,sizeof(msg)); //invia il tempo rimanente
if (rd<0) {perror("write");return;}
rd=read(fd[i],buff,3);
if (rd<0) {perror("read");return;}
}
return;
}
//funzione che accetta i client in ingresso
void *connetti_giocatore(void *x){
int players=0; //la variabile locale del numero giocatori e' inizializzata a zero
int rd,er;
int fdes;
char buff[30];
char ip[15];
int *temp;
char **temp2;
while(1)
{
if ((listen(fd[0],100))<0)
{
perror("listen");
return 0;
}
if ((fdes=(accept(fd[0],(struct sockaddr*) &indirizzo_client,&client_size)))<0)
{
perror("accept");
return 0;
}
rd=read(fdes,buff,sizeof(buff)); //legge il nome utente
if (rd<0) {perror("read");return 0;}
er=write(fdlog,buff,rd); //scrive nel file log il nome utente
if (er<0) {perror("write");return 0;}
er=write(fdlog," ",1);
if (er<0) {perror("write");return 0;}
sprintf(ip,"%d",inet_ntoa(indirizzo_client.sin_addr.s_addr));
er=write(fdlog,ip,strlen(ip)); //scrive nel file log l'indirizzo IP
if (er<0) {perror("write");return 0;}
er=write(fdlog,"\n",1);
if (er<0) {perror("write");return 0;}
pthread_mutex_lock(&mut);
numplayers++;
players=numplayers;
temp=(int *)realloc(fd, numplayers * sizeof(int));
if (temp!=NULL)
{
fd=temp;
fd[numplayers]=fdes;
}
else {perror("realloc");return 0;}
temp=(int *)realloc(fiches, numplayers * sizeof(int));
if (temp!=NULL)
{
fiches=temp;
fiches[numplayers]=10000; //assegna le fiches al nuovo giocatore
}
else {perror("realloc");return 0;}
temp=(int *)realloc(bet, numplayers * sizeof(int));
if (temp!=NULL) {bet=temp;}
else {perror("realloc");return 0;}
temp=(int *)realloc(punteggio, numplayers * sizeof(int));
if (temp!=NULL) {punteggio=temp;}
else {perror("realloc");return 0;}
temp2=(char **)realloc(utenti,numplayers * sizeof(char));
temp2[numplayers]=(char *)realloc(utenti,30 * sizeof(char));
if (temp2!=NULL)
{
utenti=temp2;
strncpy(utenti[numplayers],buff,rd); //lo scrive nel vettore
utenti[numplayers][rd]='\0';
}
else {perror("realloc");return 0;}
if (players==1){pthread_cond_broadcast(&cond);}
pthread_mutex_unlock(&mut);
}
}
//effettua il countdown per la terminazione del gioco
void *countdown (void *arg){
time_t fine;
double d;
time(&inizio); //prendo il tempo
time(&fine); //prendo il tempo
while (d=(difftime(fine,inizio)<1200))
{
time(&fine);
}
*(int *)arg=1;
}
//*********************** FINE FUNZIONI ******************************
/****MAIN*****/
int main(int argc,char *argv[]){
char tmp[30]; //stringa temporanea per concatenazione messaggi
char* tmp2; //stringa temp2
int *tmp3; //array temporaneo per il controllo dell'uscita
char msg[30]; //messaggio da comporre e inviare al client
pthread_t tid; //tid del thread che accetta le connessioni dai client
int players; //variabile locale che si riferisce a numplayers
int ingioco; //numero di giocatori che sono in gioco
int i,x; //indici per i for e while
int rd; //variabile per la gestione dei read e dei write
time_t ora; //variabile che conterrà l'ora
int *assi; //numero di assi nella mano corrente
int porta; //porta in ascolto
int flag; //variabile flag per il countdown
int *uscite; //array per le uscite
int cd; //variabile per il thread del countdown
char buff[30]; //buffer per la lettura messaggi
carta* mazzo; //array di puntatori di tipo carta
carta carta_tmp; //carta estratta
carta carta_server; //carta estratta dal server
struct sockaddr_in indirizzo; //struttura dati con informazioni sul server
//controlla il corretto inserimento della porta
if (argc<=2)
{
if (argv[1]!=NULL)
{
porta=atoi(argv[1]);
if (!((porta<=32768)&&(porta>=5000)))
{
rd=write(STDERR_FILENO,"ERRORE! La porta deve essere compresa tra 5000 e 32768.\n",57);
if (rd<0) {perror("write");return 0;}
return 0;
}
}
else
{
rd=write(STDERR_FILENO,"ERRORE! Bisogna fornire la porta su cui mettersi in ascolto (compresa tra 5000 e 32768)\nes: ./server 5200\n",106);
if (rd<0) {perror("write");return 0;}
return 0;
}
}
else
{
rd=write(STDERR_FILENO,"ERRORE DI ESECUZIONE!\nes: ./server 5200\n",40);
if (rd<0) {perror("write");return 0;}
return 0;
}
//apri e scrivi sul file di log l'orario di inizio
fdlog=open("log.txt",O_APPEND|O_CREAT|O_WRONLY,S_IRWXU);
if(fdlog<0){perror("errore di open");return 0;}
time(&ora);
ctime_r(&ora,buff);
rd=write(fdlog,buff,strlen(buff));
if (rd<0) {perror("write");return 0;}
memset(&buff,0,sizeof(buff));
//inizializzazione
players=0; //inizializza il numero dei giocatori a 0
mazzo=init_mazzo(mazzo); //inizializza il mazzo di carte
srand(time(0)); //randomizza per tutte le successive operazioni di random
//struttura della connessione
indirizzo.sin_family=AF_INET;
indirizzo.sin_port=htons(porta);
indirizzo.sin_addr.s_addr=htonl(INADDR_ANY);
fd= (int *)malloc(sizeof(int)); //allocazione memoria per l'array dei file descriptor
fd[0]=socket(PF_INET,SOCK_STREAM,0);
if (fd[0]<0)
{
perror("socket");
return 0;
}
if (bind(fd[0],(struct sockaddr *)&indirizzo,sizeof(indirizzo)) < 0 )
{
perror("bind");
return 0;
}
if ((rd=pthread_create(&tid,NULL,connetti_giocatore,NULL))!=0) //thread che accetta le connessioni
{
printf("%s",strerror(rd));
}
pthread_mutex_lock(&mut);
pthread_cond_wait(&cond,&mut); //aspetta finche' non c'e' almeno un giocatore
players=numplayers; //aggiorna i giocatori
pthread_mutex_unlock(&mut);
flag=0;
if ((cd=pthread_create(&tid,NULL,countdown,(void *)&flag))!=0) //thread che fa partire il countdown
{
printf("%s",strerror(cd));
}
assi=malloc(sizeof(int));
while(players>0)
{
tmp3=(int *)realloc(uscite,players * sizeof(int)); //allochiamo la memoria per il vettore "uscite"
if (tmp3!=NULL) {uscite=tmp3;}
else {perror("realloc"); return 0;}
ingioco=1;
carta_server=get_carta(mazzo); //estrae una carta scoperta per il server
while(ingioco<=players) //inizia a giocare col "ingioco"
{
rd=write(fd[ingioco],"play^",5); //comunica al giocatore che e' il suo turno
if (rd<0) {perror("write");return 0;}
rd=read(fd[ingioco],buff,20);
if (rd<0) {perror("read");return 0;}
if (strncmp(buff,"ready^",6)==0) // inizio gioco
{
set_msg(msg,carta_server->val,carta_server->seme); //pacchetto contenente la carta scoperta del server
rd=write(fd[ingioco],msg,strlen(msg)); //invia al giocatore ingioco la carta del server
if (rd<0) {perror("write");return 0;}
}
bet[ingioco]=5;
punteggio[ingioco]=0;
*assi=0;
strcpy(msg,"busy ");// crea il messaggio di attesa per tutti gli altri giocatori
strcat(msg,utenti[ingioco]);
strcat(msg,"^");
inviamsg_mod(players,fd,ingioco,msg,strlen(msg)); //comunica ai rimanenti client di chi e' il turno
while(1)
{
memset(&buff,0,sizeof(buff));
rd=read(fd[ingioco],buff,20);
if (rd<0) {perror("read");return 0;}
if (strncmp(buff,"get^",4)==0)
{
carta_tmp=get_carta(mazzo); //prendi carta
set_msg(msg,carta_tmp->val,carta_tmp->seme); //crea pacchetto da inviare ai giocatori
inviamsg(players,fd,msg,strlen(msg));
read(fd[ingioco],buff,3);
punteggio[ingioco]=calcola_punteggio(fd[ingioco],carta_tmp->val,punteggio[ingioco],assi);
if (punteggio[ingioco]==-1){break;}
}
if (strncmp(buff,"stop^",5)==0){break;} //usciamo dal ciclo "turno" del giocatore ingioco
if (strncmp(buff,"esci^",5)==0){
uscite[ingioco]=1;
break;}
if (strncmp(buff,"raise",5)==0) //il giocatore vuole rilanciare
{
tmp2=strtok(buff," ");
tmp2=strtok(NULL,"^");
bet[ingioco]=bet[ingioco]+atoi(tmp2); //sommiamo la puntata
if ((fiches[ingioco]-bet[ingioco])<0) //se non ci sono fiches
{
bet[ingioco]=bet[ingioco]-atoi(tmp2); //ripristiniamo
rd=write(fd[ingioco],"miss^",5); //e informiamo il client
if (rd<0) {perror("write");return 0;}
}
else
{
rd=write(fd[ingioco],"ok^",3);
if (rd<0) {perror("write");return 0;}
}
}
}
pthread_mutex_lock(&mut);
players=numplayers; //ad ogni turno aggiorniamo il numero di giocatori in gara
pthread_mutex_unlock(&mut);
ingioco++;
}
punteggio[0]=play_banco(fd,players,carta_server,mazzo);
invia_risultato(fd,punteggio,bet,players,fiches);
i=1;
while (i<=players) //controlla tutti i giocatori
{
if (flag==1) //se il tempo è scaduto
{
strcpy(buff,"temposcaduto^"); //vengono cacciati dal tavolo
rd=write(fd[i],buff,strlen(buff));
if (rd<0) {perror("write");return 0;}
pthread_mutex_lock(&mut);
close(fd[i]);
fd[i]=fd[players]; //swap giocatore I con l'ULTIMO
fiches[i]=fiches[players]; //swap giocatore I con l'ULTIMO
strcpy(utenti[i],utenti[players]); //swap giocatore I con l'ULTIMO
numplayers--;
players=numplayers;
pthread_mutex_unlock(&mut);
}
else
{
if (uscite[i]==1) //se hai scelto di uscire
{
strcpy(buff,"seiuscito^"); //vai via
rd=write(fd[i],buff,strlen(buff));
if (rd<0) {perror("write");return 0;}
uscite[i]=0;
pthread_mutex_lock(&mut);
close(fd[i]);
fd[i]=fd[players]; //swap giocatore I con l'ULTIMO
fiches[i]=fiches[players]; //swap giocatore I con l'ULTIMO
strcpy(utenti[i],utenti[players]); //swap giocatore I con l'ULTIMO
numplayers--;
players=numplayers;
pthread_mutex_unlock(&mut);
}
if (fiches[i]<5) // se hanno meno di 5 fisches
{
strcpy(buff,"gameover^"); //vengono cacciati dal tavolo
rd=write(fd[i],buff,strlen(buff));
if (rd<0) {perror("write");return 0;}
pthread_mutex_lock(&mut);
close(fd[i]);
fd[i]=fd[players]; //swap giocatore I con l'ULTIMO
fiches[i]=fiches[players]; //swap giocatore I con l'ULTIMO
strcpy(utenti[i],utenti[players]); //swap giocatore I con l'ULTIMO
numplayers--;
players=numplayers;
pthread_mutex_unlock(&mut);
}
}
i++;
}
if (test_numcarte(mazzo)==0) //se abbiamo meno di 52 carte nel mazzo
{
mazzo=init_mazzo(mazzo);
inviamsg(players,fd,"remixed^",8); //mischiamo e informiamo i client dell'accaduto
for(i=1;i<=players;i++)
{
rd=read(fd[i],buff,3);
if (rd<0) {perror("read");return;}
}
}
if (players==0) //se i giocatori finiscono anche il banco chiude
{
close(fd[0]);
break;
}
}
inviamsg(players,fd,"gameover^",9); //fine del gioco per tutti
time(&ora);
ctime_r(&ora,buff);
rd=write(fdlog,buff,strlen(buff)); //orario di fine gioco per il log
if (rd<0) {perror("write");return 0;}
close(fdlog); // chiusura log
close(fd[0]);
}