Code:
#include <sys/select.h>
#include <netdb.h>
#include <unistd.h> // interfaccia Unix standard
#include <errno.h> // codici di errore
#include <sys/types.h> // tipi predefiniti
#include <arpa/inet.h> // per convertire ind. IP
#include <sys/socket.h> // socket
#include <stdio.h> // i/o
#include <stdlib.h> // utilita'standard
#include <string.h> // stringhe
#include <fcntl.h> // file a basso livello
#include <time.h> // tempo
#include "strutture.h"
#define MAX 256
#define BACKLOG 20
#define dimT FD_SETSIZE
#define MESS_SETSIZE 1024
int TotalClient = 0;
int TotalMessage = 0;
lpmess MsgList[MESS_SETSIZE];
lpclient ClientList[FD_SETSIZE];
void inserisciClient(char n[20],char p[20],int s);
int isPresente(char no[20],char pas[20]);
void stampa();
void inserisciMsg(char d[20],char o[60], char t[200], int s);
int main(int argc, char *argv[])
{
fd_set pri; // pri lista di descrittori per select()
fd_set set_lettura; // temp altra lista di descrittori
struct sockaddr_in indserv; // indirizzo del servente
struct sockaddr_in indcli; // indirizzo di un cliente
int sdgr; // numero descrittore piu' alto
int sd; // socket
int csd; // socket connesso con accept()
int destinatario;
char buf[MAX],buf2[MAX],risposta[MAX]; // buffer dei dati
int bytel;
in_port_t porta;
int val=1; // per la setsockopt()
socklen_t lind;
struct hostent *cli; // per trovare nome cliente dall'IP
struct in_addr vet[MAX]; // per mem. IP cliente (max 256 clienti)
int i, j;
printf("\033[2J\033[H");
//controlli sui parametri
if (argc!=2) {
printf("Digitare ./server porta\n");
exit(-1);
}
porta=atoi(argv[1]);
FD_ZERO(&pri); // pulizia liste descrittori
FD_ZERO(&set_lettura);
// socket
if ((sd = socket(PF_INET, SOCK_STREAM, 0))<0) {
perror("Errore nella socket");
exit(-1);
}
// rende l'indirizzo riutilizzabile
if (setsockopt(sd,SOL_SOCKET,SO_REUSEADDR,&val,sizeof(int))<0) {
perror("Errore nella setsockopt");
exit(-1);
}
// bind
indserv.sin_family = AF_INET;
indserv.sin_addr.s_addr = INADDR_ANY;
indserv.sin_port = htons(porta);
memset(&(indserv.sin_zero), '\0', 8);
if (bind(sd, (struct sockaddr *)&indserv, sizeof(indserv)) == -1) {
perror("Errore nella bind");
exit(-1);
}
// listen
if (listen(sd,BACKLOG)<0) {
perror("Errore nella listen");
exit(-1);
}
printf("server avviato; 'Ctrl+c' per chiuderlo\n\n");
// aggiunge sd al set principale
FD_SET(sd, &pri);
// conserva il descrittore di file piu' grande
sdgr = sd;
/*
* cuore del programma:
* prima della select copia la lista pri (che contiene tutti i socket
* aperti e quello tuttora in ascolto) in set_lettura in modo che pri
* non venga "sporcato" dalla select; set_lettura è usato solo nella select
* e nel successivo test per rilevare socket attivi; eventuali nuovi
* socket connessi vengono aggiunti a pri cosi' come i socket chiusi
* vengono rimossi da pri
*/
while(1) {
set_lettura = pri; // imposta set per la select()
if (select(sdgr+1, &set_lettura, NULL, NULL, NULL)<0) {
perror("Errore nella select");
exit(-1);
}
// ispeziona le connessioni per cercare dati in arrivo
for(i=0;i<=sdgr;i++) {
if (FD_ISSET(i, &set_lettura)) { // trovato un socket con dati
if (i==sd) {
lind = sizeof(indcli);
if ((csd=accept(sd,(struct sockaddr *)&indcli,&lind))<0) {
perror("Errore nella accept");
}
else {
FD_SET(csd, &pri); // aggiunge socket conn al set pri
if (csd > sdgr) {
sdgr = csd;
}
printf("server: connessione da %s sul "
"socket %d\n",inet_ntoa(indcli.sin_addr),csd);
vet[csd]=indcli.sin_addr; // conserva IP cliente
}
}
else {
if ((bytel=recv(i,buf,sizeof(buf),0))<= 0) {
if (bytel==0) {
// connessione chiusa dal cliente
printf("server: socket %d chiuso\n", i);
//implementare elimina socket e scrivi socket *****************************************************
}
else {
perror("Errore in ricezione");
}
close(i);
FD_CLR(i,&pri); // toglie il socket da pri
}
else {
if (strcmp("/registrazione",buf)==0) {
//registrazione nuovo utente
recv(i,buf,sizeof(buf),0);
printf("%s\n",buf);
char *app1=strtok(buf, "/");
char *app2=strtok(NULL, "/");
printf("%s\n",app1);
printf("%s\n",app2);
if(isPresente(app1,app2)==0){
inserisciClient(app1,app2,i);
send(i,"/ok",MAX,0);
}
else{
send(i,"/in_uso",MAX,0);
}
}
if (strcmp("/autenticazione",buf)==0) {
//autenticazione
recv(i,buf,sizeof(buf),0);
printf("%s\n",buf);
char *app1=strtok(buf, "/");
char *app2=strtok(NULL, "/");
printf("%s\n",app1);
printf("%s\n",app2);
if(isPresente(app1,app2)==1)
send(i,"/autenticato",MAX,0);
else send(i,"nome utente e password non corretti",MAX,0);
}
if (strcmp("/invia",buf)==0) {
//invio nuovo messaggio
if(recv(i,buf2,sizeof(buf2),0)){
perror("errore in ricezione");
}
}
if (strcmp("/ricezione",buf)==0) {
//ricezione nuovo messaggio
if(send(i,buf2,sizeof(buf2),0)){
perror("Errore in spedizione");
}
}
}
} // fine else: gestisce dati in arrivo
} // fine if (FD_ISSET(i.....))
} // fine for i<=sdgr
} // fine while(1)
return 0;
}
//metodi ausiliari
void inserisciClient(char n[20],char p[20], int s)
{
lpclient l;
if ((l = (lpclient) malloc(sizeof(client))) == NULL)
{
printf("[SERVER]-->** Errore: malloc() fallita\n");
return ;
}
strcpy(l->nome,n);
strcpy(l->password,p);
l->socket = s;
ClientList[TotalClient] = l;
TotalClient++;
printf("[SERVER]--> Accettato client %i nella ClientList, TotalClient=%i\n",l->socket,TotalClient);
return ;
}
int isPresente(char n[20],char p[20])
{
int i;
for(i=0;i<TotalClient;i++){
lpclient cl=ClientList[i];
if(strcmp(cl->nome,n)==0 && strcmp(cl->password,p)==0)
return 1;
}
return 0;
}
void stampa(){ //da modificare
int i;
for(i=0;i<TotalClient;i++){
lpclient cl=ClientList[i];
printf("client %d : nome %s ----- password %s ----- porta %d",i,cl->nome,cl->password,cl->socket);
}
}
void inserisciMsg(char d[20],char o[60], char t[200], int s)
{
lpmess l;
if ((l = (lpmess) malloc(sizeof(messaggio))) == NULL)
{
printf("[SERVER]-->** Errore: malloc() fallita\n");
return ;
}
strcpy(l->destinatario,d);
strcpy(l->oggetto,o);
strcpy(l->testo,t);
l->socket = s;
MsgList[TotalMessage] = l;
TotalMessage++;
printf("[SERVER]--> Accettato messaggio %i nella MsgList, TotalMessage=%i\n",l->socket,TotalMessage);
return ;
}