// SocketsView.cpp : implementation of the
// CSocketsView class
//
#include "stdafx.h"
#include "Sockets.h"
#include "SocketsDoc.h"
#include "SocketsView.h"
#include "HostAddr.h"
#include "Port.h"
#include "Message.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CSocketsView
IMPLEMENT_DYNCREATE(CSocketsView, CView)
BEGIN_MESSAGE_MAP(CSocketsView, CView)
//{{AFX_MSG_MAP(CSocketsView)
ON_COMMAND(ID_SOCKET_ANSWER, OnSocketAnswer)
ON_UPDATE_COMMAND_UI(ID_SOCKET_ANSWER, OnUpdateSocketAnswer)
ON_COMMAND(ID_SOCKET_CALL, OnSocketCall)
ON_UPDATE_COMMAND_UI(ID_SOCKET_CALL, OnUpdateSocketCall)
ON_COMMAND(ID_SOCKET_DISCONNECT, OnSocketDisconnect)
ON_UPDATE_COMMAND_UI(ID_SOCKET_DISCONNECT, OnUpdateSocketDisconnect)
ON_COMMAND(ID_SOCKET_SENDMESSAGE, OnSocketSendmessage)
ON_UPDATE_COMMAND_UI(ID_SOCKET_SENDMESSAGE, OnUpdateSocketSendmessage)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CSocketsView construction/destruction
CSocketsView::CSocketsView()
{
// Seet the thread handle to NULL.
m_hCallAnswerThread = NULL;
// Clear the SOCKET_INFO structure.
memset( &m_SocketInfo, 0, sizeof( SOCKET_INFO ) );
}
CSocketsView::~CSocketsView()
{
// Set our abort flag to TRUE.
m_SocketInfo.bAbort = TRUE;
// Look for the thread to end. Give it
// ten seconds.
if( m_hCallAnswerThread != NULL )
WaitForSingleObject( m_hCallAnswerThread, 10000 );
}
BOOL CSocketsView::PreCreateWindow(CREATESTRUCT& cs)
{
return CView::PreCreateWindow(cs);
}
/////////////////////////////////////////////////////////////////////////////
// CSocketsView drawing
void CSocketsView::OnDraw(CDC* pDC)
{
CSocketsDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
}
/////////////////////////////////////////////////////////////////////////////
// CSocketsView diagnostics
#ifdef _DEBUG
void CSocketsView::AssertValid() const
{
CView::AssertValid();
}
void CSocketsView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
CSocketsDoc* CSocketsView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CSocketsDoc)));
return (CSocketsDoc*)m_pDocument;
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CSocketsView message handlers
void CSocketsView::OnSocketAnswer()
{
CPort Port;
// Get the port number using the
// dialog box.
if( Port.DoModal() == IDOK ){
// Set up the SOCKET_INFO fields
// for the thread.
m_SocketInfo.bAbort = FALSE;
m_SocketInfo.bListening = TRUE;
m_SocketInfo.nPort = Port.m_nPort;
// Kick off the thread.
CWinThread *lpThread =
AfxBeginThread( CSocketsView::AnswerThread,
(LPVOID) &m_SocketInfo );
// Store the thread handle for later.
m_hCallAnswerThread = lpThread->m_hThread;
}
}
void CSocketsView::OnUpdateSocketAnswer(CCmdUI* pCmdUI)
{
// Only enable if we're not calling or
// answering or currently connected.
pCmdUI->Enable( !m_SocketInfo.bConnected &&
!m_SocketInfo.bCalling &&
!m_SocketInfo.bListening );
}
void CSocketsView::OnSocketCall()
{
CHostAddr HostAddr;
// Get the host address and port using
// the dialog box.
if( HostAddr.DoModal() == IDOK ){
// Set up the SOCKET_INFO fields
// for the thread.
m_SocketInfo.bAbort = FALSE;
m_SocketInfo.bCalling = TRUE;
m_SocketInfo.nPort = HostAddr.m_nPort;
strcpy( m_SocketInfo.szHost, HostAddr.m_strHostAddr );
// Kick off the thread.
CWinThread *lpThread =
AfxBeginThread( CSocketsView::CallThread,
(LPVOID) &m_SocketInfo );
// Store the thread handle for later.
m_hCallAnswerThread = lpThread->m_hThread;
}
}
void CSocketsView::OnUpdateSocketCall(CCmdUI* pCmdUI)
{
// Only enable if we're not calling or
// answering or currently connected.
pCmdUI->Enable( !m_SocketInfo.bConnected &&
!m_SocketInfo.bCalling &&
!m_SocketInfo.bListening );
}
void CSocketsView::OnSocketDisconnect()
{
// Set the abort flag to TRUE.
m_SocketInfo.bAbort = TRUE;
}
void CSocketsView::OnUpdateSocketDisconnect(CCmdUI* pCmdUI)
{
// Only enable if we're not calling or
// answering or currently connected.
pCmdUI->Enable( ( !m_SocketInfo.bConnected &&
!m_SocketInfo.bCalling &&
!m_SocketInfo.bListening ) );
}
void CSocketsView::OnSocketSendmessage()
{
CMessage Message;
// Get the message text via the dialog.
if( Message.DoModal() )
// Copy the message text into the
// SOCKET_INFO structure.
strcpy( m_SocketInfo.szOutgoingMessage,
Message.m_strMessage );
}
void CSocketsView::OnUpdateSocketSendmessage(CCmdUI* pCmdUI)
{
pCmdUI->Enable( m_SocketInfo.bConnected &&
m_SocketInfo.bCalling );
}
UINT CSocketsView::CallThread( LPVOID lpInf )
{
SOCKET_INFO *lpInfo = (SOCKET_INFO *) lpInf;
int nRetValue = 0;
CSocket CallSocket;
BOOL bDone = FALSE;
// Create a socket.
if( !CallSocket.Create( lpInfo->nPort ) ){
// Record the error.
lpInfo->dwLastError = GetLastError();
// Set our return value.
nRetValue = 1;
// Bail out.
goto CallEnd;
}
// Set up the SOCKADDR_IN structure.
SOCKADDR_IN Addr;
memset( &Addr, 0, sizeof( SOCKADDR_IN ) );
Addr.sin_family = AF_INET;
Addr.sin_port = htons( lpInfo->nPort );
Addr.sin_addr.s_addr = inet_addr( lpInfo->szHost );
// Connect to the remote socket.
if( !CallSocket.Connect( (LPSOCKADDR) &Addr,
sizeof( SOCKADDR_IN ) ) ){
// Record the error.
lpInfo->dwLastError = GetLastError();
// Set our return value.
nRetValue = 2;
// Bail out.
goto CallEnd;
}
// Set our connected flag to TRUE.
lpInfo->bConnected = TRUE;
// Give an audio signal that we're connected.
MessageBeep( -1 );
while( !bDone ){
// Wait so we don't chew up processor time.
Sleep( 200 );
// Check the abort flag.
if( lpInfo->bAbort )
bDone = TRUE;
// See if there's a message to send.
else if( lpInfo->szOutgoingMessage[0] != 0 ){
// Send the data.
int nBytes =
CallSocket.Send( lpInfo->szOutgoingMessage,
strlen( lpInfo->szOutgoingMessage ) );
// See if there was a problem. If so, we need
// to bail out.
if( nBytes == 0 || nBytes == SOCKET_ERROR )
bDone = TRUE;
// Zero the first character of the message
// buffer.
lpInfo->szOutgoingMessage[0] = 0;
}
}
CallEnd:
// Reset our flags.
lpInfo->bCalling =
lpInfo->bListening =
lpInfo->bConnected = FALSE;
// Return to caller.
return( nRetValue );
}
UINT CSocketsView::AnswerThread( LPVOID lpInf )
{
SOCKET_INFO *lpInfo = (SOCKET_INFO *) lpInf;
int nRetValue = 0;
CSocket ServerSocket;
BOOL bDone = FALSE;
CSocket ClientSocket;
if( !ServerSocket.Create( lpInfo->nPort ) ){
// Record the error.
lpInfo->dwLastError = GetLastError();
// Set our return value.
nRetValue = 1;
// Bail out.
goto AnswerEnd;
}
if( !ServerSocket.Listen( 1 ) ){
// Record the error.
lpInfo->dwLastError = GetLastError();
// Set our return value.
nRetValue = 2;
// Bail out.
goto AnswerEnd;
}
if( !ServerSocket.Accept( ClientSocket ) ){
// Record the error.
lpInfo->dwLastError = GetLastError();
// Set our return value.
nRetValue = 3;
// Bail out.
goto AnswerEnd;
}
// Set our connected flag to TRUE.
lpInfo->bConnected = TRUE;
// Give an audio signal that we're connected.
MessageBeep( -1 );
while( !bDone ){
// Declare a char buffer and clear it.
char cbBuffer[1000];
memset( cbBuffer, 0, sizeof( cbBuffer ) );
// Read incoming data. This function blocks. It
// won't return until it has data or there's been
// a socket err