/*********************************************************/ /* 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*/ }