/*********************************************************/ /* Autori: */ /* Pelosi Giovanni, 346787, pelosi */ /* Pesce Agatino, 456868, pesce */ /* */ /* Progetto: Sistemi 2: biblioteca */ /* Data Pr.: 9/2/96 */ /* File: socket.c */ /* */ /*********************************************************/ #include <stdio.h> #include <string.h> #include <errno.h> #include <stdlib.h> #include "system.h" #include "socket.h" #include "support.h" /* ************************************************************************ * * Array di puntatori a descrittori dinamici di socket SocketInfo_t * ************************************************************************ */ static SocketInfo_t* SockInfo[FD_MAX]; /* ************************************************************************ * * Array statico di descrittori dei server HostInfo_t * ************************************************************************ */ #define HOST_MAX 20 static HostInfo_t HostInfo[HOST_MAX]; static int HostCount=1; /* server locale HostInfo[0] */ /* ************************************************************************ * * Array fd_set utilizzati per select() * ************************************************************************ */ static fd_set ActiveReadFds; static fd_set SelectReadFds; static fd_set ActiveWriteFds; static fd_set SelectWriteFds; static int NumFds=FD_MAX; /* ************************************************************************ * * Alloca e inizializza una SocketInfo_t * ************************************************************************ */ int CreateSocketInfo(int Socket) { SocketInfo_t* Info; Info = (SocketInfo_t*) malloc(sizeof(SocketInfo_t)); memset(Info,0,sizeof(SocketInfo_t)); Info->Type = SockTypeUnknown; Info->State = SockStateIdle; Info->Linked = -1; SockInfo[Socket] = Info; return Socket; } /* ************************************************************************ * * Crea Socket per Connect e relativo Descrittore * ************************************************************************ */ int CreateConnectSocket(void) { int Socket; Socket = socket(PF_INET, SOCK_STREAM, 0); if(Socket == ERROR) ErrExit("Richiesta socket"); #if defined(__HPUX_D__) || defined(_LINUS_D_) if (fcntl(Socket,F_SETFL,fcntl(Socket,F_GETFL) | O_NONBLOCK) == ERROR) ErrExit("Errore fcntl"); #endif CreateSocketInfo(Socket); return Socket; } /* ************************************************************************ * * Crea Descrittore per Socket Accettata * ************************************************************************ */ int CreateAcceptedSocket(int Socket) { #if defined(__HPUX_D__) || defined(_LINUS_D_) if (fcntl(Socket,F_SETFL,fcntl(Socket,F_GETFL) | O_NONBLOCK) == ERROR) ErrExit("Errore fcntl"); #endif CreateSocketInfo(Socket); return Socket; } /* ************************************************************************ * * Rilascia Descrittore Socket e chiude socket * ************************************************************************ */ void DestroySocket(int Socket) { SocketInfo_t* Info = SockInfo[Socket]; if(Info == 0) return; if ( Info->Linked > 0 ) SockInfo[Info->Linked]->Linked = 0; free(Info); SockInfo[Socket] = 0; FD_CLR(Socket, &ActiveReadFds); FD_CLR(Socket, &ActiveWriteFds); close(Socket); } /* ************************************************************************ * * ritorna contatore server * ************************************************************************ */ int GetHostCount(void) { return HostCount; } /* ************************************************************************ * * ritorna desctittore relativo a socket * ************************************************************************ */ SocketInfo_t* RetrieveSockInfo(int Socket) { return SockInfo[Socket]; } /* ************************************************************************ * * Converte host,port in struttura sockaddr_in * ************************************************************************ */ static int GetRemoteHost(struct sockaddr_in* Sin,char* Hostname, char* Hostport) { struct hostent * pHE; struct servent * pSE; int Port; /* 1 Cerca ed imposta la porta da usare */ Port = atoi(Hostport); if (Port>0) /*Se viene specificata la porta usa quella*/ Sin->sin_port=htons(Port); else /*Se no sceglila in base al servizio ed al protocollo*/ if((pSE = getservbyname(Hostport, "tcp")) != 0 ) Sin->sin_port=pSE->s_port; else { ErrMess("Non trovo la porta per il servizio con tcp"); return -1; } /* 2 Cerca ed imposta il nome del server */ if( (pHE=gethostbyname(Hostname)) != 0) /*Nome Simbolico*/ { memcpy((char*)&Sin->sin_addr, pHE->h_addr, pHE->h_length); printf("Host: %s\n", pHE->h_name); } else /*Dotted Decimal*/ if ((Sin->sin_addr.s_addr=inet_addr(Hostname)) == INADDR_NONE) { ErrMess("GetRemoteHost: gethostbyname"); return -1; } Sin->sin_family=AF_INET; return 0; } /* ************************************************************************ * * Restituisce Port associato a Socket * ************************************************************************ */ int GetSocketPort(int Sock) { struct sockaddr_in Sin; int sockaddr_in_size=sizeof(Sin); if(getsockname(Sock, (struct sockaddr*)&Sin, &sockaddr_in_size) < 0) ErrExit("GetSocketPort: getsockname Fallita"); return ntohs(Sin.sin_port); } /* ************************************************************************ * * aggiunge host a tabella server * ************************************************************************ */ int AddRemoteHost(char* Hostname, char* Hostport) { int h = HostCount; if (h >= sizeof(HostInfo)/sizeof(HostInfo[0])) return -1; if (GetRemoteHost(&HostInfo[h].Peer,Hostname,Hostport)) return -1; HostInfo[h].State = HostStateConnectable; HostInfo[h].Inactive = FALSE; HostInfo[h].Socket = -1; HostCount++; return 0; } /* ************************************************************************ * * aggiunge host a tabella host dopo accept messaggio registrazione * ************************************************************************ */ int AddAcceptedPeer(int Socket, struct sockaddr_in * Sin) { int h; for(h=1; h < HostCount ; h++) if (HostInfo[h].Inactive == TRUE) break; if (h >= sizeof(HostInfo)/sizeof(HostInfo[0])) return -1; HostInfo[h].State = HostStateAccepted; HostInfo[h].Inactive = FALSE; HostInfo[h].Peer = * Sin; HostInfo[h].Peer = * Sin; HostInfo[h].Peer.sin_family = AF_INET; HostInfo[h].Socket = Socket; if (h == HostCount) HostCount++; return 0; } /* ************************************************************************ * * prepara una socket in listen * ************************************************************************ */ int PassiveSocket(int Port, int Qlen) { struct sockaddr_in Sin; int sockaddr_in_size=sizeof(Sin); int Socket; memset( (char*)&Sin,0, sizeof(Sin) ); /* 1 Imposta l'indirizzo a zero * vuol dire che se la macchina ha 2 o piu' schede di rete * accetto richieste su tutte */ Sin.sin_addr.s_addr=INADDR_ANY; /* 0 */ /* 2 Imposta la porta voluta */ if (Port>0) /*Se viene specificata la porta usala*/ Sin.sin_port=htons(Port); /* 4 Apri una socket */ Socket=socket(PF_INET, SOCK_STREAM, 0); if(Socket<0) ErrExit("Passive Socket: Apertura Socket fallita"); /* 5 Connetti la socket alla porta */ /* if ((sp = getservbyname ("example", "tcp")) != NULL) Sin.sin_port = sp->s_port; */ if( bind(Socket, (struct sockaddr*)&Sin, sizeof(Sin)) < 0) ErrExit("Passive Socket: Fallita la Bind"); /* 6 Se e' stata la bind a scegliere la porta la stampo a video */ /* 7 Prepara la porta in ricezione */ if( listen(Socket, Qlen) < 0) ErrExit("Passive Socket: Fallita la Listen"); /* 8 Initializza l'entry 0 in HostInfo */ { if(getsockname(Socket, (struct sockaddr*)&HostInfo[0].Peer, &sockaddr_in_size) < 0) ErrExit("PassiveSocket: getsocknamr Fallita"); } /* 8 Ora la socket e' pronta */ return Socket; } /* ************************************************************************ * * prepara e connette una socket * ************************************************************************ */ int ActiveSocket(char* Host, char * Port) { struct hostent * pHE; /* struct servent * pSE;*/ struct sockaddr_in Sin; int Socket; int nPort=0; memset( (char*) &Sin, 0, sizeof(Sin) ); /* 1 Cerca ed imposta la porta da usare */ nPort=atoi(Port); if (nPort > 0) /*Se viene specificata la porta usa quella*/ Sin.sin_port=htons(atoi(Port)); else { ErrMess("ActiveSocket: Porta = 0"); return -1; } printf("Sin.sin_port: %d\n", ntohs(Sin.sin_port)); /* 2 Cerca ed imposta il nome del server */ if( (pHE=gethostbyname(Host)) != 0) /*Nome Simbolico*/ { memcpy(&Sin.sin_addr, pHE->h_addr, pHE->h_length); } else /*Dotted Decimal*/ if ((Sin.sin_addr.s_addr=inet_addr(Host)) == INADDR_NONE) { ErrMess("Host sconosciuto"); return -1; } /* 3 Imposta la famiglia */ Sin.sin_family=AF_INET; /* 4 Apri una socket */ Socket=socket(PF_INET, SOCK_STREAM, 0); if(Socket<0) { ErrMess("Richiesta socket"); return -1; } /* 5 Connetti la socket alla porta, con famiglia e host scelti */ if ( connect(Socket, (struct sockaddr*)&Sin, sizeof(Sin)) < 0) { ErrMess("Richiesta connect"); return -1; } /* 6 Ora la socket e' pronta */ return Socket; } /* ************************************************************************ * * inizializza/rilascia strutture statiche * ************************************************************************ */ int InitSocket(void) { memset(SockInfo,0,sizeof(SockInfo)); memset(&ActiveReadFds,0,sizeof(fd_set)); memset(&ActiveWriteFds,0,sizeof(fd_set)); return 0; } int ExitSocket(void) { int Socket=0; for(Socket=0; Socket < GetFdSetSize(); Socket++) DestroySocket(Socket); /* se Socket non c'era non fa nulla */ } /* ************************************************************************ * * copia active in select per fd_set * ************************************************************************ */ void LoadSelectFds(void) { memcpy(&SelectReadFds, &ActiveReadFds, sizeof(fd_set)); memcpy(&SelectWriteFds, &ActiveWriteFds, sizeof(fd_set)); } int GetFdSetSize(void) { return NumFds; } /* ************************************************************************ * * accesso a array fd_set * ************************************************************************ */ fd_set* GetActiveWriteFds(void) { return &ActiveWriteFds; } fd_set* GetActiveReadFds(void) { return &ActiveReadFds; } fd_set* GetSelectWriteFds(void) { return &SelectWriteFds; } fd_set* GetSelectReadFds(void) { return &SelectReadFds; } /* ************************************************************************ * * impostazione token * ************************************************************************ */ void SetWriteToken(int Socket) { SocketInfo_t * Info = RetrieveSockInfo(Socket); Info->State =SockStateWriting; FD_SET(Socket,GetActiveWriteFds()); } void ResetWriteToken(int Socket) { SocketInfo_t * Info = RetrieveSockInfo(Socket); Info->State =SockStateIdle; FD_CLR(Socket,GetActiveWriteFds()); } void SetReadToken(int Socket) { SocketInfo_t * Info = RetrieveSockInfo(Socket); Info->State =SockStateWaitRead; Info->ToRead = Info->Len = 1; FD_SET(Socket,GetActiveReadFds()); } void ResetReadToken(int Socket) { SocketInfo_t * Info = RetrieveSockInfo(Socket); Info->State =SockStateIdle; Info->ToRead = Info->Len = 0; FD_CLR(Socket,GetActiveReadFds()); } /* ************************************************************************ * * accesso tabella server * ************************************************************************ */ HostInfo_t * RetrieveHostInfo(int Host) { return &HostInfo[Host]; } HostInfo_t * RetrieveHostBySocket(int Socket) { int i; for ( i = 0; i < HostCount; i++ ) if (HostInfo[i].Inactive == FALSE) if (HostInfo[i].Socket == Socket) return &HostInfo[i]; return NULL; }