1887 lines
48 KiB
C
1887 lines
48 KiB
C
/******************************************************************************
|
|
*
|
|
* (c) Copyright 1998, University of Karlstad.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 1, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*
|
|
* Please report any bugs you find in this code or any improvements to:
|
|
*
|
|
* Hans Hedbom, Dept. of Computer Science,
|
|
* University of Karlstad, Sweden.
|
|
*
|
|
* Phone: +46 54 838157
|
|
* E-mail: Hans.Hedbom@hks.se
|
|
*
|
|
* ============================================================================
|
|
*
|
|
* FILE:
|
|
*
|
|
* physlayer.c [ the Data Communication I course programming project ]
|
|
*
|
|
* AUTHORS:
|
|
*
|
|
* Jonny Wiederholm
|
|
* E-mail: fr7wied@cse.hks.se or
|
|
* jonnwied@hks.se
|
|
*
|
|
* Per-Ola Gustafsson
|
|
* E-mail: fr7gust@cse.hks.se
|
|
*
|
|
* CREATION DATE:
|
|
*
|
|
* Jan, 08, 1998
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* Implementation of the Physical Layer, which is part of the example
|
|
* implementation of the Data Communication I course programming project.
|
|
*
|
|
* NOTE:
|
|
*
|
|
* All debug functions ( prefixed FDbg or FDebug ) are ignored ( at least from
|
|
* an abstract point of view ) if the constant DEBUG is undefined. The window
|
|
* debugger is only available under Linux and since it is implemented using
|
|
* Tcl-Tk and Tcl-Tk uses a different technique when polling sockets we have
|
|
* to provide two so called file event handlers, one for each socket, namely
|
|
* FDbgPESocketEventHandler() and FDbgSUSocketEventHandler(). These functions
|
|
* are not really part of the Physical Layer module ( they should have been
|
|
* included in the physdebuglib.c library ) but they were placed here since
|
|
* we wanted to avoid having global variables that could be accessed outside
|
|
* this module ( lets keep things private ).
|
|
*
|
|
* MODIFICATIONS: Date Changes
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
*/
|
|
|
|
/******************************************************************************
|
|
* INCLUDE FILES
|
|
*/
|
|
|
|
#include "systems.h"
|
|
#include "udefs.h"
|
|
#include "error.h"
|
|
#include "ustring.h"
|
|
#include "ustdlib.h"
|
|
#include "memory.h"
|
|
#include "utime.h"
|
|
#include "file.h"
|
|
#include "sockets.h"
|
|
#include "socketio.h"
|
|
#include "unixsockets.h"
|
|
#include "inetsockets.h"
|
|
#include "uselect.h"
|
|
#include "usignal.h"
|
|
#include "student.h"
|
|
#include "transmissionerror.h"
|
|
#include "physservices.h"
|
|
#include "physdebug.h"
|
|
#include "physlayer.h"
|
|
|
|
/******************************************************************************
|
|
* DEFINE CONSTANTS
|
|
*/
|
|
|
|
/*
|
|
Value returned when recieving non state transition signals when in state
|
|
idle.
|
|
*/
|
|
#define IGNORE_SIGNAL SUCCESS
|
|
|
|
/* The number of arguments required when starting as server. */
|
|
#define SERVER 5
|
|
|
|
/* The number of arguments required when starting as server. */
|
|
#define CLIENT 6
|
|
|
|
/* Position in command line of arguments. */
|
|
#define PORTPOS 1 /* Port number. */
|
|
#define HOSTNAMEPOS 2 /* Host name or ip address. */
|
|
|
|
/* Relative position of arguments in the command line counting from the end. */
|
|
#define RELLOSEBYTEPOS 1 /* Probability of loosing a byte. */
|
|
#define RELDELAYPOS 2 /* Probability of a transmission delay. */
|
|
#define RELFAULTPOS 3 /* Probability that a byte will get corrupted. */
|
|
|
|
/* Time of the delay in seconds. */
|
|
#define DELAYTIME 1
|
|
|
|
/* The maximum allowed port number. */
|
|
#define MAX_PORT 50000
|
|
|
|
/* The minimum allowed port number. */
|
|
#define MIN_PORT 1023
|
|
|
|
/* Path to the debug file. */
|
|
#define DBGLOG_NAME "./physdebug.log"
|
|
|
|
/* Path to the error log file. */
|
|
#define ERRLOG_NAME "./physerr.log"
|
|
|
|
/* Integer format. */
|
|
#define INT_FORMAT "%d"
|
|
|
|
/*
|
|
Passed as parameter to kill() to kill all processes in the same process
|
|
group.
|
|
*/
|
|
#define PROCESS_GROUP 0
|
|
|
|
/* Protocol signals.*/
|
|
#define WANT_CONNECTION 120
|
|
#define WANT_DISCONNECTION 122
|
|
#define CONNECTION_REQUEST_REPLY 124
|
|
#define DISCONNECTION_REQUEST_REPLY 126
|
|
#define INCOMING_DATA 128
|
|
#define ABORT 666
|
|
#define DEFAULT 0
|
|
|
|
/******************************************************************************
|
|
* DEFINE TYPES
|
|
*/
|
|
|
|
/*
|
|
Internal state codes. Each code represents one of the following internal
|
|
states: Idle, Under incoming connection, Under outgoing connection, Under
|
|
data transfer, Under incoming disconnection or Under outgoing disconnection.
|
|
*/
|
|
enum state {IDLE, UICON, UOCON, DATA, UIDCON, UODCON};
|
|
typedef enum state state;
|
|
|
|
/*
|
|
Abort destination code. Is used to determine where to send an abort. Each
|
|
code represents one of the following destinations of the abort : the Peer
|
|
entity, the Service user or Both.
|
|
*/
|
|
enum abortdst {PE, SU, BO};
|
|
typedef enum abortdst abortdst;
|
|
|
|
/******************************************************************************
|
|
* DECLARE FUNCTIONS
|
|
*/
|
|
|
|
/* See function definitions for documentation. */
|
|
|
|
static int FConnectRequest __P((void));
|
|
static int FConnectIndication __P((void));
|
|
static int FConnectResponse __P((void));
|
|
static int FConnectConfirm __P((void));
|
|
static int FDisconnectRequest __P((void));
|
|
static int FDisconnectIndication __P((void));
|
|
static int FDisconnectResponse __P((void));
|
|
static int FDisconnectConfirm __P((void));
|
|
static int FDataRequest __P((void));
|
|
static int FDataIndication __P((void));
|
|
static int FAbortRequest __P((void));
|
|
static int FAbortIndication __P((void));
|
|
static int FAbort __P((abortdst));
|
|
static int FSystemError __P((void));
|
|
static int FDefault __P((void));
|
|
static void FDbgPESocketEventHandler __P((void_ptr_, int));
|
|
static void FDbgSUSocketEventHandler __P((void_ptr_, int));
|
|
static void CleanUp __P((void));
|
|
static void ErrorHandler __P((string_ptr_));
|
|
static int InitSignalHandler __P((void (*) __P((int))));
|
|
static void SignalHandler __P((int));
|
|
static void MainLoop __P((void));
|
|
static void Server __P((int));
|
|
static void Client __P((int, string_ptr_));
|
|
|
|
/******************************************************************************
|
|
* DEFINE GLOBALS
|
|
*/
|
|
|
|
/* Internal state. */
|
|
static state PHYS_STATE = IDLE;
|
|
|
|
/*
|
|
Socket file descriptors. They can't be of type static since they are used
|
|
in other libraries.
|
|
*/
|
|
static int PE_FD, SU_FD, TMP_FD;
|
|
|
|
/*
|
|
Probabilities that a byte will get corrupted, that a byte will get delayed
|
|
and that a byte will get lost.
|
|
*/
|
|
static double FAULT_PROBABILITY, DELAY_PROBABILITY, LOSEBYTE_PROBABILITY;
|
|
|
|
/* Indicates when a fatal error is in progress. */
|
|
static volatile int FATAL_ERROR_IN_PROGRESS = 0;
|
|
|
|
/* Array containing the function associated with a certain signal. */
|
|
static const__ action ALIST[] = {
|
|
{ F_DATA_REQUEST , FDataRequest },
|
|
{ INCOMING_DATA , FDataIndication },
|
|
{ F_CONNECT_REQUEST , FConnectRequest },
|
|
{ WANT_CONNECTION , FConnectIndication },
|
|
{ F_CONNECT_RESPONSE , FConnectResponse },
|
|
{ CONNECTION_REQUEST_REPLY , FConnectConfirm },
|
|
{ F_DISCONNECT_REQUEST , FDisconnectRequest },
|
|
{ WANT_DISCONNECTION , FDisconnectIndication },
|
|
{ F_DISCONNECT_RESPONSE , FDisconnectResponse },
|
|
{ DISCONNECTION_REQUEST_REPLY, FDisconnectConfirm },
|
|
{ F_ABORT_REQUEST , FAbortRequest },
|
|
{ ABORT , FAbortIndication },
|
|
{ SYSTEM_FAILURE , FSystemError },
|
|
{ DEFAULT , FDefault },
|
|
};
|
|
|
|
/*
|
|
Array containing the error text message associated with a certain status
|
|
code. */
|
|
static const__ errmess ERRLIST[] = {
|
|
{ 1, "Failed to create Unix client socket\n" },
|
|
{ 2, "Port number out of range \n" },
|
|
{ 3, "System failure \n" },
|
|
{ 4, "Argument out of range \n" },
|
|
{ 5, "Failed to create Inet server socket\n" },
|
|
{ 6, "Failed to accept Inet client socket\n" },
|
|
{ 7, "Failed to create Inet client socket\n" },
|
|
{ 8, "Failed to initialize signal handler\n" },
|
|
{ 9, "Wrong number of arguments \n" },
|
|
{ 10, "Failed to poll sockets \n" },
|
|
{ 0, "Unknown error \n" },
|
|
};
|
|
|
|
/*
|
|
Array containing the debug text message associated with a certain debug
|
|
code. */
|
|
static const__ dbgmess DBGLIST[] = {
|
|
{ 1, "\nGot signal F_CONNECT_REQUEST from service user" },
|
|
{ 2, "\nSending signal WANT_CONNECTION to peer entity\n" },
|
|
{ 3, "\nIn wrong state. Sending signal ABORT to peer entity and signal \
|
|
F_ABORT_INDICATION to service user\n" },
|
|
{ 4, "\nGot signal WANT_CONNECTION from peer entity" },
|
|
{ 5, "\nSending signal F_CONNECT_INDICATION to service user\n" },
|
|
{ 6, "\nGot signal F_CONNECT_RESPONSE from service user" },
|
|
{ 7, "\nSending signal CONNECTION_REQUEST_REPLY to peer entity\n" },
|
|
{ 8, "\nIn state idle. Ignoring signal\n" },
|
|
{ 9, "\nGot signal CONNECTION_REQUEST_REPLY from peer entity" },
|
|
{ 10, "\nSending signal F_CONNECT_CONFIRM to service user\n" },
|
|
{ 11, "\nGot signal F_DISCONNECT_REQUEST from service user" },
|
|
{ 12, "\nSending signal WANT_DISCONNECTION to peer entity\n" },
|
|
{ 13, "\nGot signal WANT_DISCONNECTION from peer entity" },
|
|
{ 14, "\nSending signal F_DISCONNECT_INDICATION to service user\n" },
|
|
{ 15, "\nGot signal F_DISCONNECT_RESPONSE from service user" },
|
|
{ 16, "\nSending signal DISCONNECTION_REQUEST_REPLY to peer entity\n" },
|
|
{ 17, "\nGot signal DISCONNECTION_REQUEST_REPLY from peer entity" },
|
|
{ 18, "\nSending signal F_DISCONNECT_CONFIRM to service user\n" },
|
|
{ 19, "\nGot signal F_DATA_REQUEST from service user and a byte with the \
|
|
ascii value " },
|
|
{ 20, "\nSending signal INCOMING_DATA to peer entity along with the byte\n" },
|
|
{ 21, "\nGot signal INCOMING_DATA from peer entity and a byte with the ascii \
|
|
value " },
|
|
{ 22, "\nSending signal F_DATA_INDICATION to service user along with the \
|
|
byte\n" },
|
|
{ 23, "\nGot signal F_ABORT_REQUEST from service user" },
|
|
{ 24, "\nSending signal ABORT to peer entity\n" },
|
|
{ 25, "\nGot signal ABORT from peer entity" },
|
|
{ 26, "\nSending signal F_ABORT_INDICATION to service user\n" },
|
|
{ 27, "\nGot unknown signal from service user" },
|
|
{ 28, "\nSorry, but the byte of data got lost in cyberspace\n" },
|
|
{ 0, "\nUnknown debug prompt\n" },
|
|
};
|
|
|
|
/******************************************************************************
|
|
* DEFINE FUNCTIONS
|
|
*/
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* int FConnectRequest(void)
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* Handles a connect request from the service user by sending the signal
|
|
* WANT_CONNECTION to the peer entity and setting the internal state to under
|
|
* outgoing connection.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* void -- None.
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* int -- On success 0.
|
|
* -- Otherwise, -1.
|
|
*
|
|
* GLOBALS:
|
|
*
|
|
* PHYS_STATE specifies the internal state.
|
|
* PE_FD references the socket connected to the peer entity.
|
|
* DBGLIST contains all debug codes and their respective text messages.
|
|
*
|
|
* NOTE:
|
|
*
|
|
* If FConnectRequest() is called and the internal state is not set to idle, it
|
|
* will send an abort request to the peer entity and the service user and set
|
|
* the internal state to idle.
|
|
*
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
int FConnectRequest(void)
|
|
#else
|
|
int FConnectRequest()
|
|
#endif
|
|
{
|
|
int retval;
|
|
|
|
FDebug(DBGLOG_NAME, 1, DBGLIST, NULL, NULL, 0);
|
|
if(PHYS_STATE == IDLE){
|
|
FDebug(DBGLOG_NAME, 2, DBGLIST, NULL, NULL, 0);
|
|
retval = WriteSignaltoSocket(PE_FD, WANT_CONNECTION, SIG_LEN);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
PHYS_STATE = UOCON;
|
|
}
|
|
else{
|
|
FDebug(DBGLOG_NAME, 3, DBGLIST, NULL, NULL, 0);
|
|
retval = FAbort(BO);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* int FConnectIndication(void)
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* Handles a connect request from the peer entity by sending the signal
|
|
* F_CONNECT_INDICATION to the service user and setting the internal state to
|
|
* under incoming connection.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* void -- None.
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* int -- On success 0.
|
|
* -- Otherwise, -1.
|
|
*
|
|
* GLOBALS:
|
|
*
|
|
* PHYS_STATE specifies the internal state.
|
|
* SU_FD references the socket connected to the service user.
|
|
* DBGLIST contains all debug codes and their respective text messages.
|
|
*
|
|
* NOTE:
|
|
*
|
|
* If FConnectIndication() is called when the internal state is not set to
|
|
* idle, it will send an abort request to the peer entity and the service user
|
|
* and set the internal state to idle.
|
|
*
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
int FConnectIndication(void)
|
|
#else
|
|
int FConnectIndication()
|
|
#endif
|
|
{
|
|
int retval;
|
|
|
|
FDebug(DBGLOG_NAME, 4, DBGLIST, NULL, NULL, 0);
|
|
if(PHYS_STATE == IDLE){
|
|
FDebug(DBGLOG_NAME, 5, DBGLIST, NULL, NULL, 0);
|
|
retval = WriteSignaltoSocket(SU_FD, F_CONNECT_INDICATION, SIG_LEN);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
PHYS_STATE = UICON;
|
|
}
|
|
else{
|
|
FDebug(DBGLOG_NAME, 3, DBGLIST, NULL, NULL, 0);
|
|
retval = FAbort(BO);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* int FConnectResponse(void)
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* Handles a connect response from the service user by sending the signal
|
|
* CONNECTION_REQUEST_REPLY to the peer entity and setting the internal state
|
|
* to data transfer.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* void -- None.
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* int -- On success 0.
|
|
* -- Otherwise, -1.
|
|
*
|
|
* GLOBALS:
|
|
*
|
|
* PHYS_STATE specifies the internal state.
|
|
* PE_FD references the socket connected to the peer entity.
|
|
* DBGLIST contains all debug codes and their respective text messages.
|
|
*
|
|
* NOTE:
|
|
*
|
|
* If FConnectResponse() is called when the internal state is set to idle, it
|
|
* will ignore the request. Otherwise, if called when the internal state is not
|
|
* set to under incoming connection, it will send an abort request to the peer
|
|
* entity and the service user and set the internal state to idle.
|
|
*
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
int FConnectResponse(void)
|
|
#else
|
|
int FConnectResponse()
|
|
#endif
|
|
{
|
|
int retval;
|
|
|
|
FDebug(DBGLOG_NAME, 6, DBGLIST, NULL, NULL, 0);
|
|
if(PHYS_STATE == UICON){
|
|
FDebug(DBGLOG_NAME, 7, DBGLIST, NULL, NULL, 0);
|
|
retval = WriteSignaltoSocket(PE_FD, CONNECTION_REQUEST_REPLY, SIG_LEN);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
PHYS_STATE = DATA;
|
|
}
|
|
else if(PHYS_STATE == IDLE){
|
|
FDebug(DBGLOG_NAME, 8, DBGLIST, NULL, NULL, 0);
|
|
return IGNORE_SIGNAL;
|
|
}
|
|
else{
|
|
FDebug(DBGLOG_NAME, 3, DBGLIST, NULL, NULL, 0);
|
|
retval = FAbort(BO);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* int FConnectConfirm(void)
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* Handles a connect response from the peer entity by sending the signal
|
|
* F_CONNECT_CONFIRM to the service user and setting the internal state to data
|
|
* transfer.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* void -- None
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* int -- On success 0.
|
|
* -- Otherwise, -1.
|
|
*
|
|
* GLOBALS:
|
|
*
|
|
* PHYS_STATE specifies the internal state.
|
|
* SU_FD references the socket connected to the service user.
|
|
* DBGLIST contains all debug codes and their respective text messages.
|
|
*
|
|
* NOTE:
|
|
*
|
|
* If FConnectConfirm() is called when the internal state is set to idle, it
|
|
* will ignore the request. Otherwise, if called when the internal state is not
|
|
* set to under outgoing connection, it will send an abort request to the peer
|
|
* entity and the service user and set the internal state to idle.
|
|
*
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
int FConnectConfirm(void)
|
|
#else
|
|
int FConnectConfirm()
|
|
#endif
|
|
{
|
|
int retval;
|
|
|
|
FDebug(DBGLOG_NAME, 9, DBGLIST, NULL, NULL, 0);
|
|
if(PHYS_STATE == UOCON){
|
|
FDebug(DBGLOG_NAME, 10, DBGLIST, NULL, NULL, 0);
|
|
retval = WriteSignaltoSocket(SU_FD, F_CONNECT_CONFIRM, SIG_LEN);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
PHYS_STATE = DATA;
|
|
}
|
|
else if(PHYS_STATE == IDLE){
|
|
FDebug(DBGLOG_NAME, 8, DBGLIST, NULL, NULL, 0);
|
|
return IGNORE_SIGNAL;
|
|
}
|
|
else{
|
|
FDebug(DBGLOG_NAME, 3, DBGLIST, NULL, NULL, 0);
|
|
retval = FAbort(BO);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* int FDisconnectRequest(void)
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* Handles a disconnect request from the service user by sending the signal
|
|
* WANT_DISCONNECTION to the peer entity and setting the internal state to
|
|
* under outgoing connection.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* void -- None.
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* int -- On success 0.
|
|
* -- Otherwise -1.
|
|
*
|
|
* GLOBALS:
|
|
*
|
|
* PHYS_STATE specifies the internal state.
|
|
* PE_FD is referencing the socket connected to the peer entity.
|
|
* DBGLIST contains all debug codes and their respective text messages.
|
|
*
|
|
* NOTE:
|
|
*
|
|
* If FDisconnectRequest() is called when the internal state is set to idle it
|
|
* will ignore the request. Otherwise if called when the internal state is not
|
|
* set to data transfer it will send an abort request to the peer entity and
|
|
* the service user and set the internal state to idle.
|
|
*
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
int FDisconnectRequest(void)
|
|
#else
|
|
int FDisconnectRequest()
|
|
#endif
|
|
{
|
|
int retval;
|
|
|
|
FDebug(DBGLOG_NAME, 11, DBGLIST, NULL, NULL, 0);
|
|
if(PHYS_STATE == DATA){
|
|
FDebug(DBGLOG_NAME, 12, DBGLIST, NULL, NULL, 0);
|
|
retval = WriteSignaltoSocket(PE_FD, WANT_DISCONNECTION, SIG_LEN);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
PHYS_STATE = UODCON;
|
|
}
|
|
else if(PHYS_STATE == IDLE){
|
|
FDebug(DBGLOG_NAME, 8, DBGLIST, NULL, NULL, 0);
|
|
return IGNORE_SIGNAL;
|
|
}
|
|
else{
|
|
FDebug(DBGLOG_NAME, 3, DBGLIST, NULL, NULL, 0);
|
|
retval = FAbort(BO);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* int FDisconnectIndication(void)
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* Handles a disconnect request from the peer entity by sending the signal
|
|
* F_DISCONNECT_INDICATION to the service user and setting the internal state
|
|
* to under incoming disconnection.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* void -- None.
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* int -- On success 0.
|
|
* -- Otherwise, -1.
|
|
*
|
|
* GLOBALS:
|
|
*
|
|
* PHYS_STATE specifies the internal state.
|
|
* SU_FD is referencing the socket connected to the service user.
|
|
* DBGLIST contains all debug codes and their respective text messages.
|
|
*
|
|
* NOTE:
|
|
*
|
|
* If FDisconnectIndication() is called when the internal state is set to idle,
|
|
* it will ignore the request. Otherwise, if called when the internal state is
|
|
* not set to data transfer, it will send an abort request to the peer entity
|
|
* and the service user and set the internal state to idle.
|
|
*
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
int FDisconnectIndication(void)
|
|
#else
|
|
int FDisconnectIndication()
|
|
#endif
|
|
{
|
|
int retval;
|
|
|
|
FDebug(DBGLOG_NAME, 13, DBGLIST, NULL, NULL, 0);
|
|
if(PHYS_STATE == DATA){
|
|
FDebug(DBGLOG_NAME, 14, DBGLIST, NULL, NULL, 0);
|
|
retval = WriteSignaltoSocket(SU_FD, F_DISCONNECT_INDICATION, SIG_LEN);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
PHYS_STATE = UIDCON;
|
|
}
|
|
else if(PHYS_STATE == IDLE){
|
|
FDebug(DBGLOG_NAME, 8, DBGLIST, NULL, NULL, 0);
|
|
return IGNORE_SIGNAL;
|
|
}
|
|
else{
|
|
FDebug(DBGLOG_NAME, 3, DBGLIST, NULL, NULL, 0);
|
|
retval = FAbort(BO);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* int FDisconnectResponse(void)
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* Handles a disconnect request response from the service user by sending the
|
|
* signal DISCONNECTION_REQUEST_REPLY to the peer entity and setting the
|
|
* internal state to idle.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* void -- None.
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* int -- On success 0.
|
|
* -- Otherwise, -1.
|
|
*
|
|
* GLOBALS:
|
|
*
|
|
* PHYS_STATE specifies the internal state.
|
|
* PE_FD references the socket connected to the peer entity.
|
|
* DBGLIST contains all debug codes and their respective text messages.
|
|
*
|
|
* NOTE:
|
|
*
|
|
* If FDisconnectResponse() is called when the internal state is set to idle,
|
|
* it will ignore the request. Otherwise, if called when the internal state is
|
|
* not set to under incoming disconnection, it will send an abort request to
|
|
* the peer entity and the service user and set the internal state to idle.
|
|
*
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
int FDisconnectResponse(void)
|
|
#else
|
|
int FDisconnectResponse()
|
|
#endif
|
|
{
|
|
int retval;
|
|
|
|
FDebug(DBGLOG_NAME, 15, DBGLIST, NULL, NULL, 0);
|
|
if(PHYS_STATE == UIDCON){
|
|
FDebug(DBGLOG_NAME, 16, DBGLIST, NULL, NULL, 0);
|
|
retval = WriteSignaltoSocket(PE_FD, DISCONNECTION_REQUEST_REPLY, \
|
|
SIG_LEN);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
PHYS_STATE = IDLE;
|
|
}
|
|
else if(PHYS_STATE == IDLE){
|
|
FDebug(DBGLOG_NAME, 8, DBGLIST, NULL, NULL, 0);
|
|
return IGNORE_SIGNAL;
|
|
}
|
|
else{
|
|
FDebug(DBGLOG_NAME, 3, DBGLIST, NULL, NULL, 0);
|
|
retval = FAbort(BO);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* int FDisconnectConfirm(void)
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* Handles a disconnect response from the peer entity by sending the signal
|
|
* F_DISCONNECT_CONFIRM to the service user and setting the internal state to
|
|
* idle.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* void -- None.
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* int -- On success 0.
|
|
* -- Otherwise, -1.
|
|
*
|
|
* GLOBALS:
|
|
*
|
|
* PHYS_STATE specifies the internal state.
|
|
* SU_FD references the socket connected to the service user.
|
|
* DBGLIST contains all debug codes and their respective text messages.
|
|
*
|
|
* NOTE:
|
|
*
|
|
* If FDisconnectConfirm() is called and the internal state is set to idle, it
|
|
* will ignore the request. Otherwise, if called when the internal state is not
|
|
* set to under outgoing disconnection, it will send an abort request to the
|
|
* peer entity and the service user and set the internal state to idle.
|
|
*
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
int FDisconnectConfirm(void)
|
|
#else
|
|
int FDisconnectConfirm()
|
|
#endif
|
|
{
|
|
int retval;
|
|
|
|
FDebug(DBGLOG_NAME, 17, DBGLIST, NULL, NULL, 0);
|
|
if(PHYS_STATE == UODCON){
|
|
FDebug(DBGLOG_NAME, 18, DBGLIST, NULL, NULL, 0);
|
|
retval = WriteSignaltoSocket(SU_FD, F_DISCONNECT_CONFIRM, SIG_LEN);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
PHYS_STATE = IDLE;
|
|
}
|
|
else if(PHYS_STATE == IDLE){
|
|
FDebug(DBGLOG_NAME, 8, DBGLIST, NULL, NULL, 0);
|
|
return IGNORE_SIGNAL;
|
|
}
|
|
else{
|
|
FDebug(DBGLOG_NAME, 3, DBGLIST, NULL, NULL, 0);
|
|
retval = FAbort(BO);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* int FDataRequest(void)
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* Handles a data request from the service user by accepting a byte of data and
|
|
* transmitting that byte to the peer entity, using the signal INCOMING_DATA.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* void -- None.
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* int -- On success 0.
|
|
* -- Otherwise, -1.
|
|
*
|
|
* GLOBALS:
|
|
*
|
|
* PHYS_STATE specifies the internal state.
|
|
* PE_FD is referencing the socket connected to the peer entity.
|
|
* SU_FD is referencing the socket connected to the service user.
|
|
* FAULT_PROBABILITY specifies the probability that a byte will get corrupted.
|
|
* DELAY_PROBABILITY specifies the probability of a transmission delay.
|
|
* LOSEBYTE_PROBABILITY specifies the probability of loosing a byte.
|
|
* DBGLIST contains all debug codes and their respective text messages.
|
|
*
|
|
* NOTE:
|
|
*
|
|
* If FDataRequest() is called when the internal state is set to idle it will
|
|
* ignore the request. Otherwise if called when the internal state is not set
|
|
* to transfer data it will send an abort request to the peer entity and the
|
|
* service user and set the internal state to idle.
|
|
*
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
int FDataRequest(void)
|
|
#else
|
|
int FDataRequest()
|
|
#endif
|
|
{
|
|
int retval;
|
|
char databuf;
|
|
|
|
/*
|
|
We always read data from the socket to make sure that no pending data
|
|
exists in the socket buffer if we start a new session.
|
|
*/
|
|
retval = ReadDatafromSocket(SU_FD, &databuf, BYTE_LEN);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
FDebug(DBGLOG_NAME, 19, DBGLIST, &databuf, INT_FORMAT, BYTE_LEN);
|
|
if(PHYS_STATE == DATA){
|
|
/* The byte of data might get lost. */
|
|
retval = LoseByte(LOSEBYTE_PROBABILITY);
|
|
if(retval == BYTETRANSMITTED){
|
|
|
|
/*
|
|
If the byte is not lost we introduce delays and noice on the line.
|
|
*/
|
|
CreateNoice(FAULT_PROBABILITY, &databuf);
|
|
CreateDelays(DELAY_PROBABILITY, DELAYTIME);
|
|
FDebug(DBGLOG_NAME, 20, DBGLIST, NULL, NULL, 0);
|
|
retval = WriteSignaltoSocket(PE_FD, INCOMING_DATA, SIG_LEN);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
retval = WriteDatatoSocket(PE_FD, &databuf, BYTE_LEN);
|
|
fprintf(stderr, "databuf = %d", databuf);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
}
|
|
else{
|
|
FDebug(DBGLOG_NAME, 28, DBGLIST, NULL, NULL, 0);
|
|
}
|
|
}
|
|
else if(PHYS_STATE == IDLE){
|
|
FDebug(DBGLOG_NAME, 8, DBGLIST, NULL, NULL, 0);
|
|
return IGNORE_SIGNAL;
|
|
}
|
|
else{
|
|
FDebug(DBGLOG_NAME, 3, DBGLIST, NULL, NULL, 0);
|
|
retval = FAbort(BO);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* int FDataIndication(void)
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* Handles a data request from the peer entity by accepting a byte of data and
|
|
* transmitting that byte to the service user, using the signal
|
|
* F_DATA_INDICATION.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* void -- None.
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* int -- On success 0.
|
|
* -- Otherwise -1.
|
|
*
|
|
* GLOBALS:
|
|
*
|
|
* PHYS_STATE specifies the internal state.
|
|
* PE_FD references the socket connected to the peer entity.
|
|
* SU_FD references the socket connected to the service user.
|
|
* DBGLIST contains all debug codes and their respective text messages.
|
|
*
|
|
* NOTE:
|
|
*
|
|
* If FDataIndication() is called when the internal state is set to idle it
|
|
* will ignore the request. Otherwise if called when the internal state is not
|
|
* in state data transfer it will send an abort request to the peer entity and
|
|
* the service user and set the internal state to idle.
|
|
*
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
int FDataIndication(void)
|
|
#else
|
|
int FDataIndication()
|
|
#endif
|
|
{
|
|
int retval;
|
|
char databuf;
|
|
|
|
/*
|
|
We always read data from the socket to make sure that no pending data
|
|
exists in the socket buffer if we start a new session.
|
|
*/
|
|
retval = ReadDatafromSocket(PE_FD, &databuf, BYTE_LEN);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
fprintf(stderr, "databuf2 = %d", databuf);
|
|
FDebug(DBGLOG_NAME, 21, DBGLIST, &databuf, INT_FORMAT, BYTE_LEN);
|
|
if(PHYS_STATE == DATA){
|
|
FDebug(DBGLOG_NAME, 22, DBGLIST, NULL, NULL, 0);
|
|
retval = WriteSignaltoSocket(SU_FD, F_DATA_INDICATION, SIG_LEN);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
retval = WriteDatatoSocket(SU_FD, &databuf, BYTE_LEN);
|
|
fprintf(stderr, "sending data = %d", databuf);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
}
|
|
else if(PHYS_STATE == IDLE){
|
|
FDebug(DBGLOG_NAME, 8, DBGLIST, NULL, NULL, 0);
|
|
return IGNORE_SIGNAL;
|
|
}
|
|
else{
|
|
FDebug(DBGLOG_NAME, 3, DBGLIST, NULL, NULL, 0);
|
|
retval = FAbort(BO);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* int FAbortRequest(void)
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* Handles an abort request from the service user by sending the signal ABORT
|
|
* to the peer entity and setting the internal state to idle.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* void -- None.
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* int -- On success 0.
|
|
* -- Otherwise, -1.
|
|
*
|
|
* GLOBALS:
|
|
*
|
|
* PHYS_STATE specifies the internal state.
|
|
* PE_FD references the socket connected to the peer entity.
|
|
* DBGLIST contains all debug codes and their respective text messages.
|
|
*
|
|
* NOTE:
|
|
*
|
|
* If the internal state is set to idle, FAbortRequest() will ignore the
|
|
* request.
|
|
*
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
int FAbortRequest(void)
|
|
#else
|
|
int FAbortRequest()
|
|
#endif
|
|
{
|
|
int retval;
|
|
|
|
FDebug(DBGLOG_NAME, 23, DBGLIST, NULL, NULL, 0);
|
|
if(PHYS_STATE == IDLE){
|
|
FDebug(DBGLOG_NAME, 8, DBGLIST, NULL, NULL, 0);
|
|
return IGNORE_SIGNAL;
|
|
}
|
|
else{
|
|
FDebug(DBGLOG_NAME, 24, DBGLIST, NULL, NULL, 0);
|
|
retval = FAbort(PE);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* int FAbortIndication(void)
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* Handles an abort request from the peer entity by sending the signal
|
|
* F_ABORT_INDICATION to the service user and setting the internal state to
|
|
* idle.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* void -- None.
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* int -- On success 0.
|
|
* -- Otherwise, -1.
|
|
*
|
|
* GLOBALS:
|
|
*
|
|
* PHYS_STATE specifies the internal state.
|
|
* SU_FD is referencing the socket connected to the service user.
|
|
* DBGLIST contains all debug codes and their respective text messages.
|
|
*
|
|
* NOTE:
|
|
*
|
|
* If the internal state is set to idle FAbortIndication() will ignore the
|
|
* request.
|
|
*
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
int FAbortIndication(void)
|
|
#else
|
|
int FAbortIndication()
|
|
#endif
|
|
{
|
|
int retval;
|
|
|
|
FDebug(DBGLOG_NAME, 25, DBGLIST, NULL, NULL, 0);
|
|
if(PHYS_STATE == IDLE){
|
|
FDebug(DBGLOG_NAME, 8, DBGLIST, NULL, NULL, 0);
|
|
return IGNORE_SIGNAL;
|
|
}
|
|
else{
|
|
FDebug(DBGLOG_NAME, 26, DBGLIST, NULL, NULL, 0);
|
|
retval = FAbort(SU);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* int FAbort(abortdst dst)
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* Sends an abort request to either the peer entity, the service user or both
|
|
* depending on the value specified by the parameter `dst', and sets the
|
|
* internal state to idle.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* abortdst dst -- The destination of the abort.
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* int -- On success 0.
|
|
* -- Otherwise, -1.
|
|
*
|
|
* GLOBALS:
|
|
*
|
|
* PHYS_STATE specifies the internal state.
|
|
* PE_FD references the socket connected to the peer entity.
|
|
* SU_FD references the socket connected to the service user.
|
|
*
|
|
* NOTE:
|
|
*
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
int FAbort(abortdst dst)
|
|
#else
|
|
int FAbort(abortdst)
|
|
abortdst dst;
|
|
#endif
|
|
{
|
|
int retval;
|
|
|
|
if((dst == SU) || (dst == BO)){
|
|
retval = WriteSignaltoSocket(SU_FD, F_ABORT_INDICATION, SIG_LEN);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
}
|
|
if((dst == PE) || (dst == BO)){
|
|
retval = WriteSignaltoSocket(PE_FD, ABORT, SIG_LEN);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
}
|
|
PHYS_STATE = IDLE;
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* int FSystemError(void)
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* To be able to catch a system error when finding the correct function
|
|
* corresponding to a signal in FindAction(), FSystemError() just returns -1
|
|
* since every signal corresponds to a function and FindAction() has to return
|
|
* a pointer to a function a signal can't be returned to the calling
|
|
* environment unless its corresponding function does the job.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* void -- None.
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* int -- Always -1.
|
|
*
|
|
* NOTE:
|
|
*
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
int FSystemError(void)
|
|
#else
|
|
int FSystemError()
|
|
#endif
|
|
{
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* int FDefault(void)
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* The default function used in FindAction() as a break condition to make sure
|
|
* FindAction() won't go into an infinite loop. FDefault() is invoked when
|
|
* FindAction() encounters an undefined signal and FDefault() sends an abort
|
|
* request to the peer entity and the service user.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* void -- None.
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* int -- On success 0.
|
|
* -- Otherwise, -1.
|
|
*
|
|
* GLOBALS:
|
|
*
|
|
* DBGLIST contains all debug codes and their respective text messages.
|
|
*
|
|
* NOTE:
|
|
*
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
int FDefault(void)
|
|
#else
|
|
int FDefault()
|
|
#endif
|
|
{
|
|
int retval;
|
|
|
|
FDebug(DBGLOG_NAME, 27, DBGLIST, NULL, NULL, 0);
|
|
if(PHYS_STATE == IDLE){
|
|
FDebug(DBGLOG_NAME, 8, DBGLIST, NULL, NULL, 0);
|
|
return IGNORE_SIGNAL;
|
|
}
|
|
else{
|
|
FDebug(DBGLOG_NAME, 3, DBGLIST, NULL, NULL, 0);
|
|
retval = FAbort(BO);
|
|
if(retval < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* void FDbgPESocketEventHandler(void_ptr_ clientData, int mask)
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* This function is passed to SetFDbgSocketEventHandler() together with the
|
|
* socket file descriptor PE_FD. When the socket becomes available for reading
|
|
* this function will be invoked.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* void_ptr_ clientData -- ?.
|
|
* int mask -- ?.
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* void -- Nothing.
|
|
*
|
|
* GLOBALS:
|
|
*
|
|
* PE_FD references the socket connected to the service user.
|
|
* ALIST contains all signals and their respective function.
|
|
* ERRLIST contains all error codes and their respective text messages.
|
|
*
|
|
* NOTE:
|
|
*
|
|
* The function passed to SetFDbgSocketEventHandler() needs two in-parameters.
|
|
* The first must be of type void pointer and the second of type int.
|
|
*
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
void FDbgPESocketEventHandler(void_ptr_ clientData, int mask)
|
|
#else
|
|
void FDbgPESocketEventHandler(clientData, mask)
|
|
void_ptr_ clientData;
|
|
int mask;
|
|
#endif
|
|
{
|
|
int retval;
|
|
|
|
retval = (* FindAction(ReadSignalfromSocket(PollSocket(PE_FD, SU_FD, NULL) \
|
|
- 1 , SIG_LEN), ALIST))();
|
|
if(retval < 0){
|
|
ErrorHandler(FindErrMsgStr(3, ERRLIST));
|
|
return ;
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* void FDbgSUSocketEventHandler(void_ptr_ clientData, int mask)
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* This function is passed to SetFDbgSocketEventHandler() together with the
|
|
* socket file descriptor SU_FD. When the socket becomes available for reading
|
|
* this function will be invoked.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* void_ptr_ clientData -- ?.
|
|
* int mask -- ?.
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* void -- Nothing.
|
|
*
|
|
* GLOBALS:
|
|
*
|
|
* PE_FD references the socket connected to the service user.
|
|
* ALIST contains all signals and their respective function.
|
|
* ERRLIST contains all error codes and their respective text messages.
|
|
*
|
|
* NOTE:
|
|
*
|
|
* The function passed to SetFDbgSocketEventHandler() needs two in-parameters.
|
|
* The first must be of type void pointer and the second of type int.
|
|
*
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
void FDbgSUSocketEventHandler(void_ptr_ clientData, int mask)
|
|
#else
|
|
void FDbgSUSocketEventHandler(clientData, mask)
|
|
void_ptr_ clientData;
|
|
int mask;
|
|
#endif
|
|
{
|
|
int retval;
|
|
|
|
retval = (* FindAction(ReadSignalfromSocket(SU_FD, SIG_LEN), ALIST))();
|
|
if(retval < 0){
|
|
ErrorHandler(FindErrMsgStr(3, ERRLIST));
|
|
return ;
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* void CleanUp(void)
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* Closes all global socket file descriptors and removes all related files.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* void -- None.
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* void -- Nothing.
|
|
*
|
|
* GLOBALS:
|
|
*
|
|
* PATH is the file to which the socket connected to the service user, is
|
|
* bound.
|
|
* TMP_FD references the temporary socket needed when creating a server socket.
|
|
* PE_FD references the socket connected to the peer entity.
|
|
* SU_FD references the socket connected to the service user.
|
|
*
|
|
* NOTE:
|
|
*
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
void CleanUp(void)
|
|
#else
|
|
void CleanUp()
|
|
#endif
|
|
{
|
|
/*
|
|
We don't test any return values since this function is called just before
|
|
we exit the program so if we fail in closing any file descriptors we hope
|
|
that exit() will do it for us.
|
|
*/
|
|
unlink(F_PATH);
|
|
CloseFile(TMP_FD);
|
|
CloseFile(PE_FD);
|
|
CloseFile(SU_FD);
|
|
|
|
return ;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* void ErrorHandler(str_ptr_ errormsg)
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* Handles system errors. If possible it logs the error specified by the
|
|
* character string parameter `errormsg', closes all global socket file
|
|
* descriptors, removes all related files and kills all processes in the same
|
|
* process group before it exits.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* str_ptr_ errormsg -- Pointer to a character string containing the error
|
|
* -- message that will be written to the log.
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* void -- Nothing.
|
|
*
|
|
* GLOBALS:
|
|
*
|
|
* FATAL_ERROR_IN_PROGRESS indicates if a fatal error is in progress or not.
|
|
* ERRLIST contains all error codes and their respective text messages.
|
|
*
|
|
* NOTE:
|
|
*
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
void ErrorHandler(string_ptr_ errmsg)
|
|
#else
|
|
void ErrorHandler(errmsg)
|
|
string_ptr_ errmsg;
|
|
#endif
|
|
{
|
|
/*
|
|
FATAL_ERROR_IN_PROGRES works as a semaphore to prevent that a signal
|
|
is catched while we are terminating the program.
|
|
*/
|
|
FATAL_ERROR_IN_PROGRESS = 1;
|
|
|
|
/*
|
|
We don't test any return values since this function is called just before
|
|
we exit the program so there is no need to take care of system failures
|
|
at this point.
|
|
*/
|
|
LogError(ERRLOG_NAME, errmsg);
|
|
CleanUp();
|
|
kill(PROCESS_GROUP, SIGINT);
|
|
exit(NON_NORMAL_EXIT);
|
|
|
|
return ;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* int InitSignalHandler(void (* handler)(int))
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* Sets the signals SIGINT, SIGHUP, SIGQUIT and SIGTERM desposition, which is a
|
|
* pointer to a function taking an int and returning nothing.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* void (* handler)(int) -- Pointer to a function that takes an int and
|
|
* -- returns nothing, which is the signal handler
|
|
* -- that will be invoked when one of the signals
|
|
* -- are raised.
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* int -- On success 0.
|
|
* -- Otherwise, -1.
|
|
*
|
|
* NOTE:
|
|
*
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
int InitSignalHandler(void (* handler) __P((int)))
|
|
#else
|
|
int InitSignalHandler(handler)
|
|
void (* handler) __P((int));
|
|
#endif
|
|
{
|
|
if(SetSignalHandler(SIGINT, handler) < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
if(SetSignalHandler(SIGHUP, handler) < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
if(SetSignalHandler(SIGTERM, handler) < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
if(SetSignalHandler(SIGQUIT, handler) < 0){
|
|
return SYSTEM_FAILURE;
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* void SignalHandler(int signum)
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* Handles system signals. If a signal set by InitSignalHandler() is raised
|
|
* SignalHandler() catches that signal and if possible closes all global socket
|
|
* file descriptors, removes all related files and kills all processes in the
|
|
* same process group before it raises the signal again and lets the system
|
|
* handle the exit in it's default manner.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* int signum -- The signal that was catched.
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* void -- Nothing.
|
|
*
|
|
* GLOBALS:
|
|
*
|
|
* FATAL_ERROR_IN_PROGRESS indicates if a fatal error is in progress or not.
|
|
*
|
|
* NOTE:
|
|
*
|
|
* `signum' is set to the value of the signal that was catched, automatically
|
|
* by the system.
|
|
*
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
void SignalHandler(int signum)
|
|
#else
|
|
void SignalHandler(signum)
|
|
int signum;
|
|
#endif
|
|
{
|
|
/*
|
|
FATAL_ERROR_IN_PROGRESS works as a semaphore preventing that several
|
|
signals will be catched at the same time. If it is set we just raise
|
|
the signal again and continue the termination of the program.
|
|
*/
|
|
if(FATAL_ERROR_IN_PROGRESS){
|
|
raise(signum);
|
|
}
|
|
FATAL_ERROR_IN_PROGRESS = 1;
|
|
|
|
/*
|
|
We don't test any return values since this function is called just before
|
|
we exit the program so there is no need to take care of system failures
|
|
at this point.
|
|
*/
|
|
CleanUp();
|
|
|
|
/* Set the signal's desposition to the default signal handler. */
|
|
if(SetSignalHandler(signum, SIG_DFL) < 0){
|
|
exit(NON_NORMAL_EXIT);
|
|
}
|
|
kill(PROCESS_GROUP, SIGINT);
|
|
if(raise(signum) < 0){
|
|
exit(NON_NORMAL_EXIT);
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* void MainLoop(void)
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* Creates a client socket in the UNIX domain which will connect to the server
|
|
* socket bound to the file specified by the character-string parameter `path'.
|
|
* Then it will poll the socket connected to the peer entity and the socket
|
|
* connected to the service user for signals and take actions depending on the
|
|
* value of the signal inside an infinite loop.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* void -- None.
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* void -- Nothing.
|
|
*
|
|
* GLOBALS:
|
|
*
|
|
* PE_FD references the socket connected to the peer entity.
|
|
* SU_FD references the socket connected to the service user.
|
|
* ALIST contains all signals and their respective function.
|
|
* ERRLIST contains all error codes and their respective text messages.
|
|
*
|
|
* NOTE:
|
|
*
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
void MainLoop(void)
|
|
#else
|
|
void MainLoop()
|
|
#endif
|
|
{
|
|
int retval;
|
|
|
|
SU_FD = CreateUnixClientSocket(F_PATH);
|
|
if(SU_FD < 0){
|
|
ErrorHandler(FindErrMsgStr(1, ERRLIST));
|
|
return ;
|
|
}
|
|
SetFDbgSocketEventHandler(PE_FD, FDbgPESocketEventHandler);
|
|
SetFDbgSocketEventHandler(SU_FD, FDbgPESocketEventHandler);
|
|
FDbgMainLoop();
|
|
/*
|
|
All actions are taken place in an infinite loop (gag) and execution has
|
|
to be terminated implicitly by the user by pressing CTRL D. We do this
|
|
since we simulate a peer to peer connection and we don't want to break
|
|
the socket connections everytime we start a new ( abstract ) connection
|
|
with the peer entity and the service user.
|
|
*/
|
|
do{
|
|
retval = PollSocket(PE_FD, SU_FD, NULL);
|
|
if(retval < 0){
|
|
ErrorHandler(FindErrMsgStr(9, ERRLIST));
|
|
return ;
|
|
}
|
|
/*
|
|
We don't test the return value since a system failure will be
|
|
caught by FindAction.
|
|
*/
|
|
retval = ReadSignalfromSocket(retval - 1, SIG_LEN);
|
|
retval = (* FindAction(retval, ALIST))();
|
|
if(retval < 0){
|
|
ErrorHandler(FindErrMsgStr(3, ERRLIST));
|
|
return ;
|
|
}
|
|
}while(retval >= 0);
|
|
|
|
return ;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* void Server(int port)
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* Creates a server socket in the INET domain. The socket will listen for
|
|
* incoming connections on the port specified by the parameter `port'. Incoming
|
|
* connections are accepted and controll is passed to the main loop.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* int port -- Port on which the socket will listen for incoming
|
|
* -- connections.
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* void -- Nothing.
|
|
*
|
|
* GLOBALS:
|
|
*
|
|
* TMP_FD references the temporary socket needed when creating a server socket.
|
|
* PE_FD references the socket that will connect to the peer entity.
|
|
* ERRLIST contains all error codes and their respective text messages.
|
|
*
|
|
* NOTE:
|
|
*
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
void Server(int port)
|
|
#else
|
|
void Server(port)
|
|
int port;
|
|
#endif
|
|
{
|
|
TMP_FD = CreateInetServerSocket(port);
|
|
if(TMP_FD < 0){
|
|
ErrorHandler(FindErrMsgStr(5, ERRLIST));
|
|
return ;
|
|
}
|
|
PE_FD = AcceptConnection(TMP_FD);
|
|
if(PE_FD < 0){
|
|
ErrorHandler(FindErrMsgStr(6, ERRLIST));
|
|
return ;
|
|
}
|
|
MainLoop();
|
|
|
|
return ;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* void Client(int port, string_ptr_ serv_id)
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* Creates a client socket in the INET domain which tries to connect to the
|
|
* port specified by the parameter `port' on the host specified by the
|
|
* character string parameter `serv_id' and then controll is passed to the main
|
|
* loop.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* int port -- Port which the socket will connect to.
|
|
* string_ptr_ serv_id -- Pointer to a character-string containing the
|
|
* -- hosts name or the hosts IP address.
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* void -- Nothing.
|
|
*
|
|
* GLOBALS:
|
|
*
|
|
* PE_FD references the socket that will connect to the peer entity.
|
|
* ERRLIST contains all error codes and their respective text messages.
|
|
*
|
|
* NOTE:
|
|
*
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
void Client(int port, string_ptr_ serv_id)
|
|
#else
|
|
void Client(port, serv_id)
|
|
int port;
|
|
string_ptr_ serv_id;
|
|
#endif
|
|
{
|
|
PE_FD = CreateInetClientSocket(port, serv_id);
|
|
if(PE_FD < 0){
|
|
ErrorHandler(FindErrMsgStr(7, ERRLIST));
|
|
return ;
|
|
}
|
|
MainLoop();
|
|
|
|
return ;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* void main(int argc, char *argv[])
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* The main program. Starts as server or client depending on the number
|
|
* of arguments given in the command line.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* int argc -- The number of arguments.
|
|
* char *argv[] -- Array of pointers to character strings. Every string is
|
|
* -- associated with one command line argument.
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* void -- Nothing.
|
|
*
|
|
* GLOBALS:
|
|
*
|
|
* FAULT_PROBABILITY specifies the probability that a byte will get corrupted.
|
|
* DELAY_PROBABILITY specifies the probability of a transmission delay.
|
|
* LOSEBYTE_PROBABILITY specifies the probability of loosing a byte.
|
|
* ERRLIST contains all error codes and their respective text messages.
|
|
*
|
|
* NOTE:
|
|
*
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
void main(int argc, char *argv[])
|
|
#else
|
|
void main(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
#endif
|
|
{
|
|
int retval, port;
|
|
|
|
unlink(ERRLOG_NAME);
|
|
unlink(DBGLOG_NAME);
|
|
InitFDbg(&argc, argv);
|
|
CreateFDbgWindow();
|
|
CreateFDbgHelpDbase();
|
|
CreateFDbgHelpDbaseBrowser();
|
|
if((argc != SERVER) && (argc != CLIENT)){
|
|
ErrorHandler(FindErrMsgStr(9, ERRLIST));
|
|
return ;
|
|
}
|
|
retval = InitSignalHandler(SignalHandler);
|
|
if(retval < 0){
|
|
ErrorHandler(FindErrMsgStr(8, ERRLIST));
|
|
return ;
|
|
}
|
|
FAULT_PROBABILITY = atof(argv[argc - RELFAULTPOS]);
|
|
retval = ValidateProbability(FAULT_PROBABILITY);
|
|
if(retval == INVALID){
|
|
ErrorHandler(FindErrMsgStr(4, ERRLIST));
|
|
return ;
|
|
}
|
|
DELAY_PROBABILITY = atof(argv[argc - RELDELAYPOS]);
|
|
retval = ValidateProbability(DELAY_PROBABILITY);
|
|
if(retval == INVALID){
|
|
ErrorHandler(FindErrMsgStr(4, ERRLIST));
|
|
return ;
|
|
}
|
|
LOSEBYTE_PROBABILITY = atof(argv[argc - RELLOSEBYTEPOS]);
|
|
retval = ValidateProbability(LOSEBYTE_PROBABILITY);
|
|
if(retval == INVALID){
|
|
ErrorHandler(FindErrMsgStr(4, ERRLIST));
|
|
return ;
|
|
}
|
|
port = atoi(argv[PORTPOS]);
|
|
if((port > MAX_PORT) || (port < MIN_PORT)){
|
|
ErrorHandler(FindErrMsgStr(2, ERRLIST));
|
|
return ;
|
|
}
|
|
if(argc == SERVER){
|
|
Server(port);
|
|
}
|
|
else if(argc == CLIENT){
|
|
Client(port, argv[HOSTNAMEPOS]);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* END
|
|
*/
|
|
|
|
|
|
|
|
|