#include "protoSocket.h"
#include "protoSimAgent.h"
#include "protoDebug.h"
#include <errno.h>
#ifdef SIMULATE
const ProtoSocket::Handle ProtoSocket::INVALID_HANDLE = NULL;
#endif
ProtoSocket::ProtoSocket(ProtoSocket::Protocol theProtocol)
: domain(SIM), protocol(theProtocol), state(CLOSED), handle(INVALID_HANDLE),
port(-1),
#ifdef HAVE_IPV6
flow_label(0),
#endif notifier(NULL), notify_output(false),
listener(NULL), user_data(NULL)
{
}
ProtoSocket::~ProtoSocket()
{
Close();
if (listener)
{
delete listener;
listener = NULL;
}
}
bool ProtoSocket::SetNotifier(ProtoSocket::Notifier* theNotifier)
{
ASSERT(!IsOpen());
notifier = theNotifier;
return true;
}
bool ProtoSocket::Open(UINT16 thePort,
ProtoAddress::Type ,
bool bindOnOpen)
{
if (IsOpen()) Close();
ProtoSimAgent* simAgent = static_cast<ProtoSimAgent*>(notifier);
ASSERT(simAgent);
if ((handle = simAgent->OpenSocket(*this)))
{
state = IDLE;
if (bindOnOpen)
{
if (!Bind(thePort))
{
Close();
return false;
}
}
return true;
}
else
{
fprintf(stderr, "ProtoSocket::Open() error creating socketAgent\n");
return false;
}
}
void ProtoSocket::Close()
{
PLOG(PL_DETAIL, "ProtoSocket::Destructor Entering ...\n");
if (IsOpen())
{
ProtoSimAgent* simAgent = dynamic_cast<ProtoSimAgent*>(notifier);
ASSERT(simAgent);
simAgent->CloseSocket(*this);
handle = INVALID_HANDLE;
state = CLOSED;
port = -1;
}
PLOG(PL_DETAIL, "ProtoSocket::Destructor Leaving ...\n");
}
bool ProtoSocket::Shutdown()
{
if (!IsOpen()) return false;
PLOG(PL_DETAIL, "ProtoSocket::Shutting socket down ... \n");
if (static_cast<ProtoSimAgent::SocketProxy*>(handle)->Shutdown())
{
return true;
}
else
{
return false;
}
}
bool ProtoSocket::Bind(UINT16 thePort, const ProtoAddress* )
{
if (!IsOpen()) Open(thePort, ProtoAddress::SIM, FALSE);
if (static_cast<ProtoSimAgent::SocketProxy*>(handle)->Bind(thePort))
{
port = thePort;
return true;
}
else
{
return false;
}
}
bool ProtoSocket::Connect(const ProtoAddress& theAddress)
{
if (!IsOpen()) Open(0, ProtoAddress::SIM, TRUE);
state = CONNECTING;
PLOG(PL_DETAIL, "ProtoSocket::Connect Connecting ... \n");
if (static_cast<ProtoSimAgent::SocketProxy*>(handle)->Connect(theAddress))
{
destination=theAddress;
return true;
}
else
{
state=IDLE;
return false;
}
}
void ProtoSocket::Disconnect()
{
state = CLOSED;
}
bool ProtoSocket::Listen(UINT16 thePort)
{
if (!IsOpen()) Open(thePort, ProtoAddress::SIM, TRUE);
state = LISTENING;
if (static_cast<ProtoSimAgent::SocketProxy*>(handle)->Listen(thePort))
{
return true;
}
else
{
return false;
}
}
bool ProtoSocket::Accept(ProtoSocket* theSocket)
{
if (static_cast<ProtoSimAgent::SocketProxy*>(handle)->Accept(theSocket))
{
theSocket->state = CONNECTED; return true;
}
else
{
return false;
}
}
bool ProtoSocket::Send(const char* buffer,
unsigned int& numBytes)
{
if (IsConnected())
{
PLOG(PL_DETAIL, "ProtoSocket::Send - sending now ... \n");
return static_cast<ProtoSimAgent::SocketProxy*>(handle)->SendTo(buffer, numBytes, destination);
}
else
{
fprintf(stderr, "ProtoSocket::Send() error: socket not connected\n");
return false;
}
}
bool ProtoSocket::Recv(char* buffer,
unsigned int& numBytes)
{
if (IsOpen())
{
PLOG(PL_DETAIL, "ProtoSocket::Recv receiving data ...\n");
ProtoAddress srcAddr;
bool ret = static_cast<ProtoSimAgent::SocketProxy*>(handle)->RecvFrom(buffer, numBytes, srcAddr);
PLOG(PL_DETAIL, "ProtoSocket::Recv data received ...\n");
destination=srcAddr; PLOG(PL_DETAIL, "ProtoSocket::Recv leaving ...\n");
return ret;
}
else
{
fprintf(stderr, "ProtoSocket::Recv() error: socket not open\n");
return false;
}
}
bool ProtoSocket::SendTo(const char* buffer,
unsigned int buflen,
const ProtoAddress& dstAddr)
{
if (!IsOpen())
{
if (!Open())
{
fprintf(stderr, "ProtoSocket::SendTo() error opening socket\n");
return false;
}
}
else if (TCP == protocol)
{
if (!IsConnected() || dstAddr.IsEqual(destination)) Connect(dstAddr);
if (IsConnected())
{
unsigned int put = 0;
while (put < buflen)
{
unsigned int numBytes = buflen - put;
if (Send(buffer+put, numBytes))
{
put += numBytes;
}
else
{
fprintf(stderr, "ProtoSocket::SendTo() error sending to connected socket\n");
return false;
}
}
return true;
}
}
PLOG(PL_DETAIL, "ProtoSocket::SendTo sending data to Proxy ...\n");
return (static_cast<ProtoSimAgent::SocketProxy*>(handle))->SendTo(buffer, buflen, dstAddr);
}
bool ProtoSocket::RecvFrom(char* buffer,
unsigned int& numBytes,
ProtoAddress& srcAddr)
{
if (IsOpen())
{
PLOG(PL_DETAIL, "ProtoSocket::RecvFrom receiving data from Proxy ...\n");
return static_cast<ProtoSimAgent::SocketProxy*>(handle)->RecvFrom(buffer, numBytes, srcAddr);
}
else
{
fprintf(stderr, "ProtoSocket::RecvFrom() error: socket not open\n");
return false;
}
}
bool ProtoSocket::JoinGroup(const ProtoAddress& groupAddr,
const char* ,
const ProtoAddress* )
{
if (!IsOpen())
{
if (!Open())
{
fprintf(stderr, "ProtoSocket::JoinGroup() error opening socket\n");
return false;
}
}
return static_cast<ProtoSimAgent::SocketProxy*>(handle)->JoinGroup(groupAddr);
}
bool ProtoSocket::LeaveGroup(const ProtoAddress& groupAddr,
const char* ,
const ProtoAddress* )
{
if (IsOpen())
{
return static_cast<ProtoSimAgent::SocketProxy*>(handle)->LeaveGroup(groupAddr);
}
else
{
return true; }
}
bool ProtoSocket::GetInterfaceAddressList(const char* interfaceName,
ProtoAddress::Type addressType,
ProtoAddressList& addrList,
unsigned int* ifIndex)
{
return false;
}
unsigned int ProtoSocket::GetInterfaceIndex(const char* interfaceName)
{
return 0;
}
bool ProtoSocket::FindLocalAddress(ProtoAddress::Type addrType, ProtoAddress& theAddress)
{
return false;
}
bool ProtoSocket::GetInterfaceName(unsigned int index, char* buffer, unsigned int buflen)
{
return false;
}
bool ProtoSocket::GetInterfaceName(const ProtoAddress& ifAddr, char* buffer, unsigned int buflen)
{
return false;
}
bool ProtoSocket::SetTTL(unsigned char ttl)
{
static_cast<ProtoSimAgent::SocketProxy*>(handle)->SetTTL(ttl);
return true;
}
bool ProtoSocket::SetTOS(unsigned char tos)
{
return false;
}
bool ProtoSocket::SetBroadcast(bool broadcast)
{
return true;
}
bool ProtoSocket::SetLoopback(bool loopback)
{
static_cast<ProtoSimAgent::SocketProxy*>(handle)->SetLoopback(loopback);
return true;
}
bool ProtoSocket::SetMulticastInterface(const char* )
{
return true;
}
bool ProtoSocket::SetReuse(bool state)
{
return true;
}
bool ProtoSocket::SetEcnCapable(bool state)
{
static_cast<ProtoSimAgent::SocketProxy*>(handle)->SetEcnCapable(state);
return true;
}
bool ProtoSocket::GetEcnStatus() const
{
return static_cast<ProtoSimAgent::SocketProxy*>(handle)->GetEcnStatus();
}
bool ProtoSocket::SetTxBufferSize(unsigned int bufferSize)
{
static_cast<ProtoSimAgent::SocketProxy*>(handle)->SetTxBufferSize(bufferSize); return true;
}
unsigned int ProtoSocket::GetTxBufferSize()
{
return static_cast<ProtoSimAgent::SocketProxy*>(handle)->GetTxBufferSize(); }
bool ProtoSocket::SetRxBufferSize(unsigned int bufferSize)
{
static_cast<ProtoSimAgent::SocketProxy*>(handle)->SetRxBufferSize(bufferSize); return false;
}
unsigned int ProtoSocket::GetRxBufferSize()
{
return static_cast<ProtoSimAgent::SocketProxy*>(handle)->GetRxBufferSize(); }
bool ProtoSocket::SetBlocking(bool )
{
return true;
}
bool ProtoSocket::SetFragmentation(bool )
{
return true;
}
ProtoAddress::Type ProtoSocket::GetAddressType()
{
return ProtoAddress::SIM;
}
bool ProtoSocket::UpdateNotification()
{
if (handle==NULL) return notify_output;
else
return static_cast<ProtoSimAgent::SocketProxy*>(handle)->SetOutputNotification(notify_output); }
void ProtoSocket::OnNotify(ProtoSocket::Flag theFlag)
{
#ifndef OPNET
#endif PLOG(PL_MAX, "ProtoSimSocket::OnNotify() called with flag %i and state = %i\n", theFlag, state);
Event event = INVALID_EVENT;
if (NOTIFY_INPUT == theFlag)
{
switch (state)
{
case CLOSED:
PLOG(PL_MAX, "ProtoSimSocket::OnNotify() State - Socket is closed\n");
break;
case IDLE:
PLOG(PL_MAX, "ProtoSimSocket::OnNotify() State - Socket is idle, ready to receive\n");
event = RECV;
break;
case CONNECTING:
PLOG(PL_MAX, "ProtoSimSocket::OnNotify() State - Socket is connecting\n");
break;
case LISTENING:
PLOG(PL_MAX, "ProtoSimSocket::OnNotify() State - Socket is waiting for accept\n");
event = ACCEPT;
break;
case CONNECTED:
PLOG(PL_MAX, "ProtoSimSocket::OnNotify() State - Socket is connected, ready to receive\n");
event = RECV;
break;
}
}
else if (NOTIFY_OUTPUT == theFlag)
{
ASSERT(NOTIFY_OUTPUT == theFlag);
switch (state)
{
case CLOSED:
break;
case IDLE:
event = SEND; break;
case CONNECTING:
event= CONNECT;
state = CONNECTED; break;
case LISTENING:
break;
case CONNECTED:
event = SEND; break;
}
}
else {
switch(state)
{
case CONNECTING:
case CONNECTED:
event = DISCONNECT;
state = IDLE;
break;
default:
break;
}
}
if (NULL != listener)
{
ASSERT(INVALID_EVENT != event);
listener->on_event(*this, event);
}
}
ProtoSocket::List::List()
: head(NULL)
{
}
ProtoSocket::List::~List()
{
Destroy();
}
void ProtoSocket::List::Destroy()
{
Item* next = head;
while (next)
{
Item* current = next;
next = next->GetNext();
delete current->GetSocket();
delete current;
}
}
bool ProtoSocket::List::AddSocket(ProtoSocket& theSocket)
{
Item* item = new Item(&theSocket);
if (item)
{
item->SetNext(head);
head = item;
return true;
}
else
{
PLOG(PL_ERROR, "ProtoSocket::List::AddSocket() new Item error: %s\n", strerror(errno));
return false;
}
}
void ProtoSocket::List::RemoveSocket(ProtoSocket& theSocket)
{
Item* item = head;
while (item)
{
if (&theSocket == item->GetSocket())
{
Item* prev = item->GetPrev();
Item* next = item->GetNext();
if (prev)
prev->SetNext(next);
else
head = next;
if (next) next->SetPrev(prev);
delete item;
break;
}
item = item->GetNext();
}
}
ProtoSocket::List::Item::Item(ProtoSocket* theSocket)
: socket(theSocket), prev(NULL), next(NULL)
{
}
ProtoSocket::List::Iterator::Iterator(const ProtoSocket::List& theList)
: next(theList.head)
{
}