www.pudn.com > mod_rssim6.zip > DDKSrvSocket.cpp
// DDKSrvSocket.cpp: implementation of the CDDKSrvSocket class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
// # of times a connected server socket will loop for without getting any RX data
// before it closes and gets ready to accept new connections again.
#define MAX_IDLE_LOOPS 10
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNAMIC( CDDKSrvSocket, CDDKSocket);
// This server socket object will construct a listen socket of accept a pointer to an existing socket.
CDDKSrvSocket::CDDKSrvSocket(unsigned short port,unsigned long IPAddrULONG /*= ADDR_ANY*/, SOCKET * pServerSocket /*=NULL*/) : CDDKSocket()
{
int error;
CHAR errStr[180],debugStr[180];
INT sockoptEnable = TRUE;
m_serverObject = TRUE;
m_pSocket = NULL;
int check1 = 0x1234;
m_buffer = new char[m_serverBufferSize];
int check2 = 0x1234;
// server stuff
// Create a Thread and then a Server-end socket to listen on later
// create the listening thread
m_listenThreadStatus = SOCKET_EX_PENDING;
m_pWorkerThread = AfxBeginThread((AFX_THREADPROC)SockAsyncFriend,
this,
THREAD_PRIORITY_TIME_CRITICAL, 0,
CREATE_SUSPENDED
);
// construct with IP and port or with an existing socket
if (NULL == pServerSocket)
{
// Setup local addressing for listen socket
m_localSockaddr_in.sin_family = PF_INET;
m_localSockaddr_in.sin_addr.S_un.S_addr = INADDR_ANY; //usually default
if ((m_localSockaddr_in.sin_port = htons((u_short) port)) == 0)
{
sprintf(debugStr, "Cannot use port %ld", port);
OutputDebugString(debugStr);
// Fail the connection process
m_socketStatus = SOCKET_UNCONFIGURED;
return;
}
// Map protocol name to protocol number
if ((m_ppe = getprotobyname("tcp")) == NULL)
{
GetSockError(errStr);
sprintf(debugStr,"Driver cannot connect for listen :%s",errStr);
OutputDebugString(debugStr);
// Fail the connection process
m_socketStatus = SOCKET_UNCONFIGURED;
return;
}
// Allocate a listen socket
m_socket = socket(PF_INET, SOCK_STREAM, m_ppe->p_proto);
// If we could not allocate a socket, we must fail the connection process
if (INVALID_SOCKET == m_socket) // recommended NT error check
{
GetSockError(errStr);
sprintf(debugStr, "Cannot create Listen socket :%s",errStr);
OutputDebugString(debugStr);
// Fail the connection process
m_socketStatus = SOCKET_UNCONFIGURED;
return;
}
// now to bind socket to local address+port
if (0 != bind(m_socket, (sockaddr *)&(m_localSockaddr_in), sizeof(m_localSockaddr_in) ) )
{
GetSockError(errStr);
sprintf(debugStr, "Cannot Bind to Listen socket :%s",errStr);
OutputDebugString(debugStr);
// Fail the connection process
m_socketStatus = SOCKET_UNCONFIGURED;
return;
}
// Set the socket to not delay any sends
error = setsockopt(m_socket, IPPROTO_TCP, TCP_NODELAY, (CHAR FAR * ) &m_sockoptEnable, sizeof (INT));
// If we could not set the socket parameters, we must fail the connection process
if (error == (LONG) SOCKET_ERROR)
{
int lastError = WSAGetLastError();
sprintf(debugStr, "Cannot setsockopt error (%ld)", lastError);
OutputDebugString(debugStr);
// Fail the connection process
m_socketStatus = SOCKET_UNCONFIGURED;
return;
}
m_pSocket = &m_socket;
m_socketStatus = SOCKET_INITIALISED;
}
else
{
// use a socket provided to us.
// do this when many threads listen and accept connections on the same socket.
m_pSocket = pServerSocket;
}
m_socketStatus = SOCKET_INITIALISED;
strcpy(debugStr, "Socket created OK.");
SockDataMessage(debugStr);
m_listenThreadStatus = SOCKET_EX_RUNNING;
}
CDDKSrvSocket::~CDDKSrvSocket()
{
// get the thread to die off
//delete(m_buffer);
//OutputDebugString("In Server socket destructor\n");
m_listenThreadStatus = SOCKET_EX_TERMINATE;
// abort any listen in progress, this only executes on 1st comms thread's socket, since it created it
if (INVALID_SOCKET != m_socket)
{
closesocket(m_socket);
m_socket = INVALID_SOCKET;
}
// wait for thread to die off
CSingleLock lk(&m_threadDeadEvent);
lk.Lock(5000); // wait max 5 seconds
if (NULL != AcceptedAsyncSocket)
{
closesocket(AcceptedAsyncSocket); //kill accepted instance immediately
accepted = FALSE;
OutputDebugString("Server socket closing normally.\n");
SockStateChanged(SOCKETCURRENTLY_CLOSING);
}
}
#ifdef _DEBUG
VOID CDDKSrvSocket::Dump(CDumpContext& dc) const
{
// call the base class first
CDDKSocket::Dump(dc);
// dump our object to the debuggers output
// all important members can be dumped at this stage.
dc << "Server socket: " << "\n";
} // Dump
#endif // _DEBUG
// ------------------------------ SockSockAsyncFriend ------------------------------
UINT SockAsyncFriend(LPVOID pParam)
{
CHAR debugStr2[MAX_DEBUG_STR_LEN];
CHAR debugStr[MAX_DEBUG_STR_LEN];
CDDKSrvSocket* DDKSockPtr;
Sleep(500);
// OK now since everyone will be asking me what is this sleep doing here. So I am
// going to tell U. We are being naughty, this thread actually starts executing
// while the parent class is constructing, consequently all calls to virtual functions
// are made before the parent has initialized completely (constructor body has not yet run)
// and U ned up using un-initialized variables EEK.
DDKSockPtr = (CDDKSrvSocket*)pParam;
try
{
// call the function the thread will run in
if (DDKSockPtr->IsKindOf(RUNTIME_CLASS( CDDKSrvSocket)))
{
CString msgStartup;
// wait untill the Application is ready for us
CSingleLock lk(&DDKSockPtr->m_threadStartupEvent);
lk.Lock(5000); // wait max 5 seconds
msgStartup.Format("Socket %d listen thread ID=%d running",
DDKSockPtr->m_socket,
GetCurrentThreadId());
DDKSockPtr->SockDataMessage(msgStartup);
DDKSockPtr->SockStateChanged(SOCKETCURRENTLY_VOID);
DDKSockPtr->Poll(debugStr);
}
else
{
sprintf(debugStr2, "CDDKSrvSocket SockAsyncFriend pointer corruption!!!!\n");
OutputDebugString(debugStr2);
}
}
catch (...)
{
OutputDebugString( "Catch\n" );
sprintf(debugStr2, "CDDKSrvSocket SockAsyncFriend Exception !!!!\n");
OutputDebugString(debugStr2);
}
try
{
DDKSockPtr->m_listenThreadStatus = SOCKET_EX_TERMINATED;
{
CString d;
d.Format("[Thread %4d Terminating.]\n", GetCurrentThreadId());
OutputDebugString(d);
}
DDKSockPtr->m_threadDeadEvent.SetEvent();// CEvent
}
catch (...)
{
CString msg;
msg.Format("INTERNAL APPLICATION ERROR FILE %s LINE: %d\n%s\n%s",
__FILE__, __LINE__, __MY_APPVERSION__, __DATE__);
OutputDebugString(msg);
}
//AfxEndThread(0);
return(0);
} // SockAsyncFriend
// ------------------------------- Poll -----------------------------------
//
void CDDKSrvSocket::Poll(CHAR * debugStr)
{
CHAR * msgPtr = m_buffer; //rxMessage;
CHAR * debugStrPtr = debugStr;
BOOL incommingMsgOK = FALSE;
BOOL outgoingMsgOK = FALSE;
// Socket "notification" setup variables
u_int retCode;
int errorCode;
BOOL exitFlag;
sockaddr acceptedAsyncSocketAddr, ackSocketAddr;
int addrlength;
unsigned long numBytes=0;
CString debuggerString;
LONG numIdleLoops = MAX_IDLE_LOOPS;
m_debuggerStep = 0;
accepted = FALSE;
exitFlag = false;
*debugStr = NULL;//zero string
if (SOCKET_EX_TERMINATE == m_listenThreadStatus) //termination routine
{
sprintf(debugStr, "EX_TERMINATE recieved, terminating!");
OutputDebugString(debugStr);
exitFlag = true;
}
AcceptedAsyncSocket = INVALID_SOCKET;
// We want to read the asynchronous data responses
// ..........Thread Control Loop
while ( (SOCKET_EX_RUNNING == m_listenThreadStatus)
&& (false == exitFlag)
)
{
exitFlag = false;
m_debuggerStep = 1;
if (SOCKET_EX_TERMINATE == m_listenThreadStatus) //termination routine
{
exitFlag = true;
break;
}
if (!accepted)
{
m_debuggerStep = 2;
numIdleLoops = MAX_IDLE_LOOPS;
SockStateChanged(SOCKETCURRENTLY_LISTENING);
debuggerString.Format("%4d Listen for connection...\n", GetCurrentThreadId());
OutputDebugString(debuggerString);
// Send to debugger list-box
SockDataMessage(debuggerString);
errorCode = listen(*m_pSocket, SOMAXCONN); //listen with backlog maximum reasonable
if (SOCKET_ERROR == errorCode)
{
sprintf(debugStr, "Listen returned with a socket error : %s\n", sys_wsaerrlist[wsaerrno]);
OutputDebugString(debugStr);
exitFlag = true;
}
//now listening - no error !!!!
addrlength = sizeof(acceptedAsyncSocketAddr);//for now
WSASetLastError(0);
if (AcceptedAsyncSocket == INVALID_SOCKET)
accepted = FALSE;
//------------------------- Listen Control Loop -------------------//
do
{
m_debuggerStep = 3;
//Beep(3000,50);
debuggerString.Format("%4d Accept connection...\n", GetCurrentThreadId());
OutputDebugString(debuggerString);
AcceptedAsyncSocket = accept(*m_pSocket, //listen away returns immediatly
&acceptedAsyncSocketAddr,
&addrlength
);
if (INVALID_SOCKET !=AcceptedAsyncSocket)
{
m_debuggerStep = 4;
debuggerString.Format("%4d Connection accepted.\n", GetCurrentThreadId());
OutputDebugString(debuggerString);
SockDataMessage(debuggerString);
// copy the IP address
memcpy(&ackSocketAddr, &acceptedAsyncSocketAddr, sizeof(acceptedAsyncSocketAddr));
int test = h_errno;
if ( (INVALID_SOCKET == AcceptedAsyncSocket) //check for fails
&& (h_errno != WSAEWOULDBLOCK) //no connection avail to be accepted
)
{
m_debuggerStep = 5;
sprintf(debugStr, "Listen Accept returned with a socket error : %s\n",sys_wsaerrlist[wsaerrno]);
OutputDebugString(debugStr);
exitFlag = true;
continue; //skip the rest of this loopy
}
accepted = TRUE;
}
else
{
LONG temp;
// get the error.
m_debuggerStep = 6;
temp = wsaerrno;
(temp >= 0) ? (sprintf(debugStrPtr, "Accept() Error on Listen socket : %s\n",sys_wsaerrlist[temp]))
: (sprintf(debugStrPtr, "Unknown Accept() error on Listen socket\n"));
OutputDebugString(debugStrPtr);
SockDataMessage(debugStrPtr);
WSASetLastError(0);
}
}//Listen
while ( (SOCKET_EX_RUNNING == m_listenThreadStatus)
&& (false == exitFlag)
&& (AcceptedAsyncSocket == INVALID_SOCKET)
&& (h_errno == WSAEWOULDBLOCK)
);
}
if (INVALID_SOCKET !=AcceptedAsyncSocket)
{
m_debuggerStep = 7;
debuggerString.Format("%4d Currently connected.\n", GetCurrentThreadId());
OutputDebugString(debuggerString);
//Beep(1000,100);
DWORD initialTicks = GetTickCount();
do
{
m_debuggerStep = 8;
retCode = ioctlsocket(AcceptedAsyncSocket, FIONREAD, &numBytes);
if (0==numBytes)
Sleep(1);
else
SockStateChanged(SOCKETCURRENTLY_READING);
if ((GetTickCount() - initialTicks) > 10000)
{
break; // time out
}
if (SOCKET_EX_TERMINATE == m_listenThreadStatus) //termination routine
{
exitFlag = true;
break;
}
}
while (0 == numBytes); //delay until an actual data bearing packet is brought in
//remembering only 1 packet per transaction allways
if ( (SOCKET_ERROR != retCode)
&& (0 != numBytes)
)
{ //Yup got a message
m_debuggerStep = 9;
numIdleLoops = MAX_IDLE_LOOPS;
debuggerString.Format("%4d Server socket thread reading.\n", GetCurrentThreadId());
OutputDebugString(debuggerString);
incommingMsgOK = (Recieve(AcceptedAsyncSocket, numBytes, msgPtr, debugStrPtr)==(LONG)numBytes);
m_debuggerStep = 10;
if (SOCKET_EX_RUNNING != m_listenThreadStatus) //termination routine
{
//exitFlag = true;
break;
}
// process this message as valid data from a PLC
if (incommingMsgOK)
{
DWORD bufSize;
m_debuggerStep = 11;
bufSize = numBytes; //ok so all bytes were read
msgPtr[bufSize] = '\0'; // append a null for neatness
m_debuggerStep = 12;
if (FALSE == ProcessData(AcceptedAsyncSocket, msgPtr, bufSize))
{
m_debuggerStep = 13;
// close the server socket
closesocket(AcceptedAsyncSocket); //kill accepted instance immediatly
accepted = FALSE;
OutputDebugString("Closing socket normally.\n");
SockStateChanged(SOCKETCURRENTLY_CLOSING);
SockDataMessage(debuggerString);
// 13 Rembrandt st Petervale
}
m_debuggerStep = 14;
}
}
else
{ //We may have a problem please be a patient
if (SOCKET_ERROR == retCode)
{
sprintf(debugStr, "Listen Poll Failed on rx, BytesRx'd : %d\n",numBytes);
OutputDebugString(debugStr);
// close this PLC connection so that new data still comes in
closesocket(AcceptedAsyncSocket); //kill accepted instance immediatly
accepted = FALSE;
OutputDebugString("Closing socket after error.\n");
SockStateChanged(SOCKETCURRENTLY_CLOSING);
}
else
{ // no problem at all, socket was just idle.
numIdleLoops--;
if (numIdleLoops > 0)
{
debuggerString.Format("%4d Listen Poll idle.\n", GetCurrentThreadId());
OutputDebugString(debuggerString);
SockStateChanged(SOCKETCURRENTLY_IDLE);
}
else
{
debuggerString.Format("%4d Closing socket idle for too long.\n", GetCurrentThreadId());
OutputDebugString(debuggerString);
SockDataMessage(debuggerString);
closesocket(AcceptedAsyncSocket); //kill accepted instance immediatly
accepted = FALSE;
SockStateChanged(SOCKETCURRENTLY_CLOSING);
}
}
}
}
} //Thread
//This is where we go to Terminate the Thread.
m_listenThreadStatus = SOCKET_EX_TERMINATED;
} // Poll