Files
Datakomm_1/physlayer.c
2026-03-05 13:37:25 +01:00

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