/*********************************************************/
/* Autori: */
/* Pelosi Giovanni, 346787, pelosi */
/* Pesce Agatino, 456868, pesce */
/* */
/* Progetto: Sistemi 2: biblioteca */
/* Data Pr.: 9/2/96 */
/* File: server.c */
/* */
/*********************************************************/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "system.h"
#include "libro.h"
#include "message.h"
#include "socket.h"
#include "support.h"
#include "hstdio.h"
#define LINE_LEN 80
typedef enum RcHandle_tag
{
RC_Continue = 1, /* continua operazioni su socket */
RC_CloseSocket = 0, /* fine operazioni su socket -> close */
RC_Error = -1 /* errore su trattamento socket -> close */
} RcHandle_t;
/**********************/
/*** tabella server ***/
/**********************/
#define HOST_MAX 3
#define HOST_BIBLIO_MAX 20
#define HOST_NAME_MAX 40
static Biblio_t ServerBiblio="LocalBiblio";
static int rc;
static int ListenSocket=0; /* Su questa aspetto il client */
/*
************************************************************************
*
* funzioni trattamento condizione di completamento scrittura
*
************************************************************************
*/
int HandleWrite(int Socket)
{
SocketInfo_t* Info = RetrieveSockInfo(Socket);
ResetWriteToken(Socket); /* Intanto mi tiro via, se necessario mi ci rimetto */
/* Nota: Fatto per motivi di pulizia */
switch (Info->Type)
{
case SockTypeClient:
{
switch(Info->Control)
{
case SockCtrlLocalServer: /* stato iniziale dopo accept */
Info->Offset = SearchLibro(&Info->Libro,Info->Offset);
if (Info->Offset > 0)
{
PutMsgReply(Socket,RetrieveHostInfo(0)->Biblio,
RetrieveLibro());
SetWriteToken(Socket);
return RC_Continue;
}
else
{
if (Info->NoForward == FALSE)
{
Info->Control = SockCtrlNextServer;
PutMsgNil(Socket);
SetWriteToken(Socket);
return RC_Continue;
}
else
return RC_CloseSocket;
}
case SockCtrlNextServer: /* inizializzazione */
/* Info->Request = -1 */
for (++Info->Request; Info->Request < GetHostCount();Info->Request++)
{
int newServer;
SocketInfo_t* newInfo;
HostInfo_t* HostInfo = RetrieveHostInfo(Info->Request);
if (HostInfo->Inactive) /* salta host disconnessi */
continue;
newServer = CreateConnectSocket();
newInfo = RetrieveSockInfo(newServer);
newInfo->Type = SockTypeServer;
newInfo->Linked = Socket;
Info->Linked = newServer;
rc = connect(newServer,(struct sockaddr*) &HostInfo->Peer,
sizeof(struct sockaddr_in));
if ((rc == ERROR) && (errno != EWOULDBLOCK)) /*come gestire condizioni */
/*di errore successive (ETIMEOUT)?*/
{
Info->Linked = 0;
DestroySocket(newServer); /* A chiudere col server ci penso quando */
continue; /* becco eof su socket control */
}
PutMsgQuery(newServer, TRUE, &Info->Libro); /*no forward = TRUE */
SetWriteToken(newServer);
Info->Control = SockCtrlContinue; /* stato passacarte da s2 a client*/
return RC_Continue;
}
return RC_CloseSocket; /* devo chiudere per fine richieste*/
case SockCtrlContinue: /* stato passacarte da s2 a client*/
{
SetReadToken(Info->Linked);
return RC_Continue;
}
} /* Info->Control */
} /* SockTypeClient */
case SockTypeServer: /* dopo connect e write request a server */
SetReadToken(Socket); /* imposta attesa risposta da server */
return RC_Continue;
case SockTypeControl:
/* ho scritto il mio indirizzo e aspetto ormai solo eof su sconnessione */
SetReadToken(Socket);
return RC_Continue;
}
return RC_Error; /* Non ci dovrei arrivare */
}
/*
************************************************************************
*
* funzioni trattamento messaggio in lettura
*
************************************************************************
*/
int HandleRead(int Socket, Message_t* Msg)
{
SocketInfo_t* Info = RetrieveSockInfo(Socket);
ResetReadToken(Socket); /* comporta FD_CLR in read */
switch (Info->Type)
{
case SockTypeUnknown: /* direttamente da accept */
switch(Msg->Type)
{
case MsgTypeControl: /* registrazione host remoto */
{
Info->Type = SockTypeControl;
AddAcceptedPeer(Socket, &Msg->Body.Control.Sin);
SetReadToken(Socket); /* per riconoscere caduta server*/
return RC_Continue;
}
break;
case MsgTypeQuery:
{
Info->Type = SockTypeClient;
/* imposta prossima ricerca locale */
Info->Control = SockCtrlLocalServer;
/* reset progressivo server */
Info->Request = 0;
/* offset ricerca locale*/
Info->Offset = 0;
/* da server locale, senza successivo inoltro */
Info->NoForward = Msg->Body.Query.NoForward;
/* salvataggio dati query */
Info->Libro = Msg->Body.Query.Libro;
/* mette a zero ToWrite e Len */
PutMsgNil(Socket); /* per i cicli nulli di write */
SetWriteToken(Socket); /* (quelli usati per protocollo) */
/* comporta FD_SET in write */
return RC_Continue;
}
case MsgTypeError:
case MsgTypeEof:
default:
return RC_Error;
}
break; /* SockTypeUnknown: */
case SockTypeServer:
switch(Msg->Type)
{
case MsgTypeReply:
{
PutMsgReply(Info->Linked, Msg->Body.Reply.Biblio,
&Msg->Body.Reply.Libro);
SetWriteToken(Info->Linked);
return RC_Continue;
}
case MsgTypeError:
case MsgTypeEof:
{
SocketInfo_t* Client = RetrieveSockInfo(Info->Linked);
/* end of server -> ricerca successivo*/
Client->Control = SockCtrlNextServer;
Client->ToWrite = 0;
/* ritorna controllo a client con FD_SET(write)*/
SetWriteToken(Info->Linked);
return RC_CloseSocket; /* close server socket */
}
}
break; /* SockTypeServer: */
/* teoricamente non viene eseguita FD_SET per read client */
case SockTypeClient:
return RC_Error;
/*
Qui return RC_CloseSocket; fa si' che venga chiusa la socket di controllo.
Le eventuali socket in read sul server che e' andato giu' si chiudono
automaticamente da sole alla ricezione di EOF
*/
case SockTypeControl:
RetrieveHostBySocket(Socket)->Inactive = TRUE;
return RC_CloseSocket;
};
return RC_Error; /* se sono qui qualcosa s'e' impallato */
}
/*
************************************************************************
*
* inizializzazione server con open listen e connect a server da args
*
************************************************************************
*/
int InitServer(Biblio_t BiblioName )
{
int ContServ=0;
HostInfo_t * hostinfo = NULL;
struct sockaddr_in Sin;
int sockaddr_in_size=sizeof(Sin);
strcpy(RetrieveHostInfo(0)->Biblio, BiblioName);
/*---(Listen Socket)-------------------------------------------*/
ListenSocket=PassiveSocket(0, 5);
FD_SET(0, GetActiveReadFds()); /* stdin */
FD_SET(ListenSocket, GetActiveReadFds());
/*---(Avviso gli altri server)----------------------------------*/
hostinfo = RetrieveHostInfo(0); /* mi serve per i MsgControl */
for (ContServ = 1 ; ContServ < GetHostCount() ; ContServ++)
{
int newServer;
SocketInfo_t* newInfo;
hostinfo = RetrieveHostInfo(ContServ);
newServer = CreateConnectSocket();
newInfo = RetrieveSockInfo(newServer);
hostinfo->Socket = newServer;
newInfo->Type = SockTypeControl;
newInfo->State = SockStateWriting;
rc = connect(newServer,(struct sockaddr*) &hostinfo->Peer,
sizeof(struct sockaddr_in));
if ((rc == ERROR) && (errno != EWOULDBLOCK)) /*come gestire condizioni */
/*di errore successive (ETIMEOUT)?*/
{
DestroySocket(newServer); /* A chiudere col server ci penso quando */
continue; /* becco eof su socket control */
}
PutMsgControl(newServer, &RetrieveHostInfo(0)->Peer);
SetWriteToken(newServer);
}
printf("Server \"%s\" Listening on Port:%d\n",RetrieveHostInfo(0)->Biblio,
GetSocketPort(ListenSocket));
return 0;
}
/*
************************************************************************
*
* chiusura server
*
************************************************************************
*/
int ExitServer(void)
{
return 0;
}
/*
************************************************************************
*
* server
*
************************************************************************
*/
void Server(void)
{
int ExitRequest=FALSE; /* Richiesta terminazione del server */
int Socket=0;
struct sockaddr_in Sin;
int sockaddr_in_size=sizeof(Sin);
while(!ExitRequest)
{
/* BCOPY(src,dest,n) */
LoadSelectFds();
rc = select(GetFdSetSize(),FDS(GetSelectReadFds()), FDS(GetSelectWriteFds()),
FDS((struct fd_set*)0), (struct timeval*)0 );
if ( rc == ERROR )
ErrExit("Main:Errore nella select");
/*---(Listen Socket)-------------------------------------------*/
if ( FD_ISSET(ListenSocket, GetSelectReadFds())) /* Richiesta di connessione */
{
int AcceptedSocket=accept(ListenSocket, (struct sockaddr *)&Sin,
&sockaddr_in_size);
if (AcceptedSocket == ERROR)
ErrExit("Main: Errore nell'accept");
CreateAcceptedSocket(AcceptedSocket);
SetReadToken(AcceptedSocket);
}
/*---(Standard Input)-------------------------------------------*/
if (FD_ISSET(0, GetSelectReadFds())) /* stdin */
{
if ( HandleStdin() == -1 )
{
ExitRequest = TRUE;
break;
}
}
/*---(Select Socket)-------------------------------------------*/
for(Socket=0; Socket < GetFdSetSize(); Socket++)
{
if(Socket == 0) continue; /* stdin */
if(Socket == ListenSocket) continue;
/*** READ ***/
if (FD_ISSET(Socket,GetSelectReadFds()))
{
Message_t Msg;
if (ReadMessage(Socket,&Msg) == 0)
continue;
switch (HandleRead(Socket,&Msg))
{
case RC_Error:
case RC_CloseSocket:
DestroySocket(Socket);
continue;
default:
continue;
};
}
/*** WRITE ***/
if (FD_ISSET(Socket,GetSelectWriteFds()))
{
if (WriteMessage(Socket) == 0)
continue;
switch (HandleWrite(Socket))
{
case RC_Error:
case RC_CloseSocket:
DestroySocket(Socket);
continue;
default:
continue;
};
}
}
} /*!ExitRequested*/
}