WSA functions included: WSAStartup,
WSACleanup,
WSAGetLastError,
WSASetLastError,
inet_addr,
inet_ntoa,
ntohs,
htons,
htonl,
WSAAsyncSelect,
WSAAsyncGetHostByName,
WSACancelAsyncRequest,
closesocket,
WSAGETSELECTERROR,
WSAGETSELECTEVENT,
TCP socket,
UDP socket,
bind,
connect,
recv,
send,
recvfrom,
sendto,
ioctlsocket FIOASYNC,
ioctlsocket FIONBIO,
getsockopt,
setsockopt
BOOL CNmtApp::InitInstance ()
{
WSADATA WSA_Data;
if (WSAStartup (0x101, & WSA_Data)) {
AfxMessageBox ("No Winsock.dll in path or wrong version.", MB_ICONSTOP | MB_OK);
return FALSE;
}
// The rest is standard initialization
return TRUE;
} // Back to top of page
// mainfrm.h : Interface of the CMainFrame class
// Only the WSA related code, the rest of the code has been removed
#include "winsock.h"
#define WM_HOST_RESOLVED (WM_USER + 1)
#define WM_ASYNC_IO (WM_USER + 2)
#define WM_ASYNC_BC (WM_USER + 3)
#define WM_MAX_SESSIONS (WM_USER + 10)
#define WM_START_BC_SERVER (WM_USER + 11)
#define BC_PORTNUMBER 1234
#define WS_WRITE_SIZE 512
#define WS_READ_BUFFER 4096
#define WS_WRITE_BUFFER 8192
typedef unsigned long IP_ADDR;
typedef IP_ADDR FAR * LP_IP_ADDR;
typedef LP_IP_ADDR FAR * LPP_IP_ADDR;
/// // /
class CMainFrame : public CFrameWnd
{
protected: // Create from serialization only
CMainFrame();
DECLARE_DYNCREATE(CMainFrame)
// Attributes
public:
// Operations
public:
BOOL TraceOn () const { return m_bTrace; }
BOOL Connected () const { return m_bConnected; }
BOOL BroadcastServer () const { return m_bBroadcastServer; }
BOOL ConnectHost (LPCSTR, LPCSTR, int), DisconnectSession (),
GetIoBuffer (LPBYTE *), FlushIoBuffer (int), IpAddress (LPCSTR);
void SendBroadcaste (LPSTR),
SetStatusText (LPSTR), SetStatusText (LPSTR, int);
// Implementation
public:
virtual ~CMainFrame();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
// Attributes and Operations
protected:
// Async winsock
HANDLE m_hCancelAsyncRequest;
SOCKET m_Socket, m_ServerSocket;
struct sockaddr_in m_RemoteAddr;
// Telnet
TnState m_TelnetState;
int m_Port, m_nTnBufferCount, m_nSessions, m_wcount;
BOOL m_bConnected, m_bConnecting,
m_bBroadcastServer, m_bBroadcastMsg, m_bViolation;
LPBYTE m_rbp, m_wbp, m_tbp, m_wbufferp, m_grb, m_gwb;
char m_EntryBuffer [MAXGETHOSTSTRUCT],
m_TerminalName [MAX_TERMINAL_NAME], m_StatusPane [STATUS_PANE_SIZE];
HGLOBAL m_hSessionInformation, m_hReadBuffer, m_hWriteBuffer;
LPCSP m_pFirstCS, m_pLastCS, m_pcs;
int TelnetParser (LPBYTE, int), SetSocketBufferSize (SOCKET, int, int);
void StartBroadcastServer (), SetWinsockError (int),
LoadEntryBuffer (IP_ADDR), PostBroadcastMsg (UINT, WPARAM);
// Generated message map functions
protected:
//{{AFX_MSG(CMainFrame)
afx_msg void OnDestroy();
// Other msg functions included by ClassWizard
//}}AFX_MSG
// Msg functions included manualy
afx_msg LRESULT OnHostResolved (WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnAsyncIo (WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnAsyncBroadcast (WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnBroadcastServer (WPARAM wParam, LPARAM lParam);
DECLARE_MESSAGE_MAP()
}; // Back to top of page
// mainfrm.cpp : Implementation of the CMainFrame class
#include "stdafx.h"
#include "nmt.h"
#include "mainfrm.h" // winsock.h and tnconst.h included
IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
ON_WM_DESTROY()
// Other msg functions included by ClassWizard
//}}AFX_MSG_MAP
// Asynchronous Winsock functions
ON_MESSAGE(WM_HOST_RESOLVED, OnHostResolved)
ON_MESSAGE(WM_ASYNC_IO, OnAsyncIo)
ON_MESSAGE(WM_ASYNC_BC, OnAsyncBroadcast)
ON_MESSAGE(WM_START_BC_SERVER, OnBroadcastServer)
END_MESSAGE_MAP()
// Back to top of page
BOOL CMainFrame::ConnectHost (LPCSTR hnp, LPCSTR tnp, int port)
{
IP_ADDR ipa;
if (m_bConnected)
return FALSE;
// hnp - Host name ptr: abc | abc.def.gh | 123.45.67.98
// tnp - Terminal name ptr
WSASetLastError (0); // Reset WSA error
m_bConnecting = FALSE;
m_hCancelAsyncRequest = 0;
m_wcount = 0; m_wbp = m_gwb; m_rbp = m_grb;
TelnetSetup (tnp); m_Port = port;
if ((ipa = inet_addr (hnp)) != INADDR_NONE) {
m_bConnecting = TRUE; LoadEntryBuffer (ipa);
PostMessage (WM_HOST_RESOLVED, 0, 0); return TRUE;
}
wsprintf (m_psp, "Resolve %s", hnp); SetStatusText (m_psp);
if (! (m_hCancelAsyncRequest =
WSAAsyncGetHostByName (m_hWnd, WM_HOST_RESOLVED,
hnp, (LPSTR) & m_EntryBuffer[0], MAXGETHOSTSTRUCT))) {
wsprintf (m_psp, "Async GetHostByName error %d", WSAGetLastError ());
SetStatusText (m_psp); return FALSE;
}
return (m_bConnecting = TRUE);
} // Back to top of page
BOOL CMainFrame::DisconnectSession ()
{
CTn3270Doc * pDoc;
m_bConnecting = m_bConnected = FALSE;
m_wcount = 0; m_wbp = m_gwb; m_rbp = m_grb;
if (pDoc = ((CNmtApp *) AfxGetApp())->m_pTn3270Doc)
pDoc->SetDisconnected ();
if (m_Socket != INVALID_SOCKET) {
WSAAsyncSelect (m_Socket, m_hWnd, 0, 0);
closesocket (m_Socket); m_Socket = INVALID_SOCKET;
} else if (m_hCancelAsyncRequest) {
if (WSACancelAsyncRequest (m_hCancelAsyncRequest) == SOCKET_ERROR) {
wsprintf (m_psp, "Cancel GetHostByName error %d", WSAGetLastError ());
SetStatusText (m_psp);
} else SetStatusText ("Disconnected");
} else return FALSE;
m_hCancelAsyncRequest = 0; return TRUE;
} // Back to top of page
void CMainFrame::LoadEntryBuffer (IP_ADDR ipa)
{
LPHOSTENT phe = (LPHOSTENT) m_EntryBuffer;
LPP_IP_ADDR ppipa = (LPP_IP_ADDR) (m_EntryBuffer + sizeof (HOSTENT));
LP_IP_ADDR pipa = (LP_IP_ADDR) (m_EntryBuffer + sizeof (HOSTENT) + sizeof (LPP_IP_ADDR));
memset (phe, 0, sizeof (HOSTENT));
// LoadEntryBuffer will put the IP addr into
// m_EntryBuffer with the same format as GetHostByName
phe->h_length = sizeof (IP_ADDR);
phe->h_addr_list = (char FAR * FAR *) ppipa;
* ppipa = pipa; * pipa = ipa;
} // Back to top of page
LRESULT CMainFrame::OnHostResolved (WPARAM wParam, LPARAM lParam)
{
LPSTR ap;
HOSTENT * hp;
u_long nAsync = 1;
int nSelectError = (int) WSAGETSELECTERROR (lParam), nLastError;
CTn3270Doc * pDoc = ((CNmtApp *) AfxGetApp())->m_pTn3270Doc;
m_hCancelAsyncRequest = 0;
if (nSelectError) {
if (nSelectError == WSANO_DATA) {
SetStatusText ("Unknown host");
} else SetStatusText ("Resolve host error", WSAGetLastError ());
if (pDoc)
pDoc->SetDisconnected ();
return 0;
} else hp = (HOSTENT *) m_EntryBuffer;
if ((m_Socket = socket (PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
SetStatusText ("No more sockets"); m_bConnecting = FALSE;
if (pDoc)
pDoc->SetDisconnected ();
return 0;
} memset (& m_RemoteAddr, 0, sizeof (m_RemoteAddr));
ap = (LPSTR) & m_RemoteAddr.sin_addr.s_addr;
memcpy (ap, hp->h_addr, hp->h_length);
m_RemoteAddr.sin_family = PF_INET;
m_RemoteAddr.sin_port = htons (m_Port);
wsprintf (m_psp, "Connecting %s", inet_ntoa (m_RemoteAddr.sin_addr));
SetStatusText (m_psp);
ioctlsocket (m_Socket, FIOASYNC, (u_long FAR *) & nAsync);
if (WSAAsyncSelect (m_Socket, m_hWnd, WM_ASYNC_IO, FD_CONNECT | FD_READ | FD_WRITE | FD_CLOSE) ||
connect (m_Socket, (struct sockaddr far *) & m_RemoteAddr, sizeof (struct sockaddr_in))) {
if ((nLastError = WSAGetLastError ()) != WSAEWOULDBLOCK)
SetStatusTextAndDisconnect ("Async connect error", nLastError);
} return 0;
} // Back to top of page
LRESULT CMainFrame::OnAsyncIo (WPARAM wParam, LPARAM lParam)
{
CTn3270Doc * pDoc;
int nSelectError = (int) WSAGETSELECTERROR (lParam),
nSelectEvent = (int) WSAGETSELECTEVENT (lParam),
nLastError, rc, wc;
if (! nSelectError) {
switch (nSelectEvent) {
case FD_READ:
if (! m_bInParser) {
m_bInParser = TRUE;
if ((rc = recv (m_Socket, (LPSTR) m_rbp, WS_READ_BUFFER, 0)) > 0) {
if ((rc = TelnetParser (m_rbp, rc)) > 0) {
// Send rest of the data to the Tn3270 document
if (pDoc = ((CNmtApp *) AfxGetApp())->m_pTn3270Doc)
pDoc->HostInput (m_rbp, rc);
}
} else {
if ((nLastError = WSAGetLastError ()) != WSAECONNRESET) {
SetStatusTextAndDisconnect ("Connection closed", nLastError);
} else SetStatusTextAndDisconnect ("Connection closed by host system", 0);
} m_bInParser = FALSE;
} else PostMessage (WM_ASYNC_IO, wParam, lParam);
break;
case FD_WRITE:
if (m_wcount) {
wc = m_wcount > WS_WRITE_SIZE ? WS_WRITE_SIZE : m_wcount;
while (m_wcount && (wc = send (m_Socket, (LPSTR) m_wbp, wc, 0)) > 0) {
m_wcount -= wc; m_wbp += wc;
if (m_wcount <= 0) {
m_wcount = wc = 0; m_wbp = m_gwb;
} else
wc = m_wcount > WS_WRITE_SIZE ? WS_WRITE_SIZE : m_wcount;
}
if (wc < 0 && (nLastError = WSAGetLastError ()) != WSAEWOULDBLOCK) {
SetStatusTextAndDisconnect ("Async send error", nLastError);
} // Else wait for the next async FD_WRITE if more data in send buffer
} break;
case FD_CONNECT:
m_hCancelAsyncRequest = 0;
m_nTnBufferCount = 0; ResetStatusText ();
m_bConnecting = FALSE; m_bConnected = TRUE;
SetSocketBufferSize (m_Socket, SO_RCVBUF, 4096);
SetSocketBufferSize (m_Socket, SO_SNDBUF, 2048);
if (pDoc = ((CNmtApp *) AfxGetApp())->m_pTn3270Doc)
pDoc->SetConnected ();
break;
case FD_CLOSE:
default:
SetStatusTextAndDisconnect ("Connection closed", 0);
}
} else {
nLastError = WSAGetLastError ();
SetWinsockError (nSelectError, nLastError);
DisconnectSession (FALSE);
} return 0;
} // Back to top of page
int CMainFrame::SetSocketBufferSize (SOCKET sd, int option, int size)
{
int bsize = size, ssize = 0, sor = sizeof (int);
getsockopt (sd, SOL_SOCKET, option, (LPSTR) & ssize, & sor);
if (ssize >= size) {
return ssize;
} else sor = sizeof (int);
if (setsockopt (sd, SOL_SOCKET, option, (LPSTR) & bsize, sor) != SOCKET_ERROR) {
if (getsockopt (sd, SOL_SOCKET, option, (LPSTR) & ssize, & sor) != SOCKET_ERROR) {
if (ssize >= size)
return (ssize);
}
}
return (option == SO_SNDBUF ? WS_WRITE_SIZE : WS_READ_BUFFER);
} // Back to top of page
void CMainFrame::StartBroadcastServer ()
{
int i, ms, r;
SOCKADDR_IN ba;
u_long nNonBlocking = TRUE;
WSASetLastError (0);
m_hSessionInformation = NULL;
ms = ((CNmtApp *) AfxGetApp())->GetMaxSessions ();
if (ms < MAX_CSESSIONS) {
if ((m_ServerSocket = socket (AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET) {
ba.sin_family = AF_INET;
ba.sin_port = htons (BC_PORTNUMBER);
ba.sin_addr.s_addr = htonl (INADDR_ANY);
r = ioctlsocket (m_ServerSocket, FIONBIO, (u_long FAR *) & nNonBlocking);
if (bind (m_ServerSocket, (LPSOCKADDR) & ba, sizeof (ba)) != SOCKET_ERROR) {
if (! WSAAsyncSelect (m_ServerSocket, m_hWnd, WM_ASYNC_BC, FD_READ | FD_WRITE))
m_bBroadcastServer = TRUE;
}
}
}
} // Back to top of page
LRESULT CMainFrame::OnAsyncBroadcast (WPARAM wParam, LPARAM lParam)
{
int nSelectError = (int) WSAGETSELECTERROR (lParam),
nSelectEvent = (int) WSAGETSELECTEVENT (lParam),
nLastError, rc, alen = sizeof (SOCKADDR_IN);
IN_ADDR aa;
SOCKADDR_IN ra;
BOOL bFreeSession = FALSE;
u_short rhwnd;
char rbuffer [BC_MSG_LENGTH + 1];
if (! nSelectError) {
switch (nSelectEvent) {
case FD_READ:
memset (& ra, 0, alen);
rc = recvfrom (m_ServerSocket, rbuffer, BC_MSG_LENGTH, 0, (LPSOCKADDR) & ra, & alen);
if (rc == BC_MSG_LENGTH) {
rbuffer [BC_MSG_LENGTH] = 0x00;
memcpy (& aa, & ra.sin_addr.s_addr, 4);
TRACE ("Addr %d.%d.%d.%d port %d\n",
aa.S_un.S_un_b.s_b1, aa.S_un.S_un_b.s_b2,
aa.S_un.S_un_b.s_b3, aa.S_un.S_un_b.s_b4, ntohs (ra.sin_port));
} break;
case FD_WRITE:
case FD_CLOSE:
break;
}
} else {
nLastError = WSAGetLastError ();
} return 0;
} // Back to top of page
void CMainFrame::SendBroadcast (LPSTR pMsg)
{
int r, wc;
SOCKET bcs;
SOCKADDR_IN aa, ba;
BOOL bBroadCast = TRUE;
WSASetLastError (0);
if (pMsg && ((bcs = socket (AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET)) {
memset (& aa, 0, sizeof (SOCKADDR_IN));
aa.sin_family = AF_INET;
aa.sin_port = htons (0);
ba.sin_addr.s_addr = htonl (INADDR_ANY);
if (bind (bcs, (LPSOCKADDR) & aa, sizeof (aa)) != SOCKET_ERROR) {
ba.sin_family = AF_INET;
ba.sin_port = htons (BC_PORTNUMBER);
ba.sin_addr.s_addr = htonl (INADDR_BROADCAST);
r = setsockopt (bcs, SOL_SOCKET, SO_BROADCAST, (LPSTR) & bBroadCast, sizeof (BOOL));
wc = sendto (bcs, pMsg, BC_MSG_LENGTH, 0, (LPSOCKADDR) & ba, sizeof (ba));
}
closesocket (bcs);
}
} // Back to top of page
void CMainFrame::OnDestroy ()
{
BOOL bRestartServer = FALSE;
if (m_Socket != INVALID_SOCKET)
closesocket (m_Socket); // Close telnet socket
if (m_ServerSocket != INVALID_SOCKET) {
bRestartServer = TRUE;
// Close licence control server socket
closesocket (m_ServerSocket);
}
WSACleanup (); // Terminate WSA interface
if (bRestartServer)
PostBroadcastMsg (WM_START_BC_SERVER, 0);
CFrameWnd::OnDestroy();
} // Back to top of page