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