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