/*********************************************************/
/* Autori: */
/* Pelosi Giovanni, 346787, pelosi */
/* Pesce Agatino, 456868, pesce */
/* */
/* Progetto: Sistemi 2: biblioteca */
/* Data Pr.: 9/2/96 */
/* File: message.c */
/* */
/*********************************************************/
#include <string.h>
#include <assert.h>
#include <signal.h>
#include "system.h"
#include "message.h"
#include "socket.h"
#ifdef __cplusplus
typedef void (*fptr)(int);
#else
typedef void (*fptr)();
#endif
static int _sigpipe = 0;
/*
************************************************************************
*
* handler per sigpipe in caso di write su socket chiusa
*
************************************************************************
*/
void SigPipeHandler(int sig)
{
sig ++; /* causa compilatore idiota*/
signal(SIGPIPE,(fptr) SigPipeHandler);
_sigpipe ++;
return;
}
/*
************************************************************************
*
* funzioni comuni per trattamento struttura libro in messaggi
*
************************************************************************
*/
int SizeRawLibro(void)
{
int size=0;
Libro_t Libro; /* Orribile, casomai ripensarci */
size += sizeof(Libro.Titolo);
size += sizeof(Libro.Autore);
size += sizeof(Libro.Anno);
return size;
}
int PutRawLibro(char* t, Libro_t* Libro)
{
char *p = t;
strncpy(p, Libro->Titolo, sizeof(Libro->Titolo)); p += sizeof(Libro->Titolo);
strncpy(p, Libro->Autore, sizeof(Libro->Autore)); p += sizeof(Libro->Autore);
strncpy(p, Libro->Anno, sizeof(Libro->Anno)); p += sizeof(Libro->Anno);
return (int)(p - t);
}
int GetRawLibro(Libro_t* Libro, char* t)
{
char *p = t;
strncpy(Libro->Titolo, p, sizeof(Libro->Titolo)); p += sizeof(Libro->Titolo);
strncpy(Libro->Autore, p, sizeof(Libro->Autore)); p += sizeof(Libro->Autore);
strncpy(Libro->Anno, p, sizeof(Libro->Anno)); p += sizeof(Libro->Anno);
return (int)(p - t);
}
/*
************************************************************************
*
* funzioni trattamento messaggi "control"
*
************************************************************************
*/
int SizeMsgControl(void)
{
int size=0;
size++; /* Type */
size+=sizeof(struct in_addr);
size+=sizeof(unsigned short);
return size;
}
int GetMsgControl(MessageControl_t* Msg ,char* t)
{
char *p = t;
memcpy(&Msg->Sin.sin_addr, p, sizeof(struct in_addr));
p+=sizeof(struct in_addr);
memcpy(&Msg->Sin.sin_port, p, sizeof(unsigned short));
p+=sizeof(unsigned short);
return (int)(p - t);
}
int PutMsgControl(int Socket, struct sockaddr_in * Sin)
{
SocketInfo_t* Info=RetrieveSockInfo(Socket);
char *p = Info->Text;
memset(Info->Text,0,sizeof(MessageText_t));
*p = MsgTypeControl; p++;
memcpy(p, &Sin->sin_addr, sizeof(struct in_addr));
p+=sizeof(struct in_addr);
memcpy(p, &Sin->sin_port, sizeof(unsigned short));
p+=sizeof(unsigned short);
Info->Len = Info->ToWrite = (int)(p - Info->Text);
return Info->Len;
}
/*
************************************************************************
*
* funzioni trattamento messaggi "query"
*
************************************************************************
*/
int SizeMsgQuery(void)
{
int size=0;
size++; /*Type*/
size++; /*NoForward*/
size+=SizeRawLibro();
return size;
}
int ClPutMsgQuery(MessageText_t Text, char NoForward, Libro_t* Libro)
{
char *p = Text;
memset(Text,0,sizeof(MessageText_t));
*p = MsgTypeQuery; p++;
*p = NoForward; p++;
p += PutRawLibro(p,Libro);
return (int)(p - Text);
}
int PutMsgQuery(int Socket, char NoForward, Libro_t* Libro)
{
SocketInfo_t* Info=RetrieveSockInfo(Socket);
Info->Len = Info->ToWrite = ClPutMsgQuery(Info->Text, NoForward, Libro);
return Info->Len;
}
int GetMsgQuery(MessageQuery_t* Msg, char* t)
{
char *p = t;
Msg->NoForward = *p; p++;
p += GetRawLibro(&Msg->Libro,p);
return (int)(p - t);
}
/*
************************************************************************
*
* funzioni trattamento messaggi "replay"
*
************************************************************************
*/
int SizeMsgReply(void)
{
int size=0;
size++; /*Type*/
size += sizeof(Biblio_t);
size += SizeRawLibro();
return size;
}
int PutMsgReply(int Socket, Biblio_t Biblio, Libro_t* Libro)
{
SocketInfo_t* Info=RetrieveSockInfo(Socket);
char *p = Info->Text;
memset(Info->Text,0,sizeof(MessageText_t));
*p = MsgTypeReply; p++;
strncpy(p,(char*) Biblio, sizeof(Biblio_t)); p += sizeof(Biblio_t);
p += PutRawLibro(p,Libro);
Info->Len = Info->ToWrite = (int)(p - Info->Text);
return Info->Len;
}
int ClGetMsgReply(MessageReply_t* Msg, char* t)
{
char *p = t;
memset(Msg, 0, sizeof(MessageReply_t));
strncpy(Msg->Biblio,p, sizeof(Biblio_t)); p += sizeof(Biblio_t);
p += GetRawLibro(&Msg->Libro,p);
return (int)(p - t);
}
int GetMsgReply(MessageReply_t* Msg, char* t)
{
return ClGetMsgReply(Msg, t);
}
/*
************************************************************************
*
* funzioni per impostazione ciclo nullo di ritorno select()
*
************************************************************************
*/
int PutMsgNil(int Socket)
{
SocketInfo_t* Info=RetrieveSockInfo(Socket);
Info->Len= Info->ToWrite = 0;
return 0;
}
/*
************************************************************************
*
* funzioni generale per lettura messaggi da socket in buffer
*
************************************************************************
*/
/* restituisce:
* -1 su errore o eof
* 0 su messaggio non ancora completato
* 1 su messaggio completato
*/
int ReadMessage( int Socket, Message_t* Msg )
{
int n;
SocketInfo_t* Info = RetrieveSockInfo(Socket);
char *p=Info->Text; p++;
memset(Msg,0,sizeof(Message_t));
assert(Info->State==SockStateReading || Info->State==SockStateWaitRead);
n = read(Socket, &Info->Text[Info->Len - Info->ToRead], Info->ToRead );
if ( n < 0 ) /* if (n < 0) --> (err) */
{
Msg->Type = MsgTypeError;
return -1; /*valutare utilizzo rc type/len*/
}
if ( n == 0 ) /* if (n == 0) --> (eof) */
{
if (Info->Len == Info->ToRead)
Msg->Type = MsgTypeEof;
else
Msg->Type = MsgTypeError;
return -1; /*valutare utilizzo rc type/len*/
}
Info->ToRead -= n;
switch(Info->Text[0])
{
case MsgTypeQuery:
Msg->Type = MsgTypeQuery;
break;
case MsgTypeReply:
Msg->Type = MsgTypeReply;
break;
case MsgTypeControl:
Msg->Type = MsgTypeControl;
break;
default:
Msg->Type = MsgTypeError;
return -1;
}
if(Info->State==SockStateWaitRead)
{
Info->State = SockStateReading;
Info->Len = MessageLen(Msg->Type);
Info->ToRead = Info->Len - 1;
}
if ( Info->ToRead > 0 )
return 0;
switch (Msg->Type)
{
case MsgTypeQuery:
GetMsgQuery(&Msg->Body.Query,p);
return 1;
case MsgTypeReply:
GetMsgReply(&Msg->Body.Reply,p);
return 1;
case MsgTypeControl:
GetMsgControl(&Msg->Body.Control,p);
return 1;
default: /* per casi strani tipo errore formato messaggio */
Msg->Type = MsgTypeError;
return -1;
}
}
/*
************************************************************************
*
* funzioni generale per scrittura messaggi a socket da buffer
*
************************************************************************
*/
/*
* restituisce:
* -1 su errore o eof
* 0 su messaggio non ancora completato
* 1 su messaggio completato
*/
int WriteMessage( int Socket )
{
int n; /* n.bytes letti */
SocketInfo_t * Info = RetrieveSockInfo(Socket);
assert(Info->State==SockStateWriting);
if( Info->ToWrite == 0 ) /* per i casi in cui la write serve solo a */
return 1; /* dare il via alla read */
signal(SIGPIPE,(fptr)SigPipeHandler); _sigpipe = 0;
n = write(Socket, &Info->Text[Info->Len - Info->ToWrite], Info->ToWrite );
signal(SIGPIPE,SIG_DFL);
if ( _sigpipe !=0 )
return -1;
if ( n <= 0 ) /* if (n < 0) --> (err) */
return -1; /* errore perche non EWOULDBLOCK da select*/
Info->ToWrite -= n;
if ( Info->ToWrite > 0 )
return 0; /* incompleta -> continue */
return 1; /**End of Write*/
}
/*
************************************************************************
*
* funzioni generale per determinare lunghezza messaggio
*
************************************************************************
*/
int MessageLen(int Type)
{
switch(Type)
{
case MsgTypeQuery:
return SizeMsgQuery();
case MsgTypeReply:
return SizeMsgReply();
case MsgTypeControl:
return SizeMsgControl();
}
return -1;
}