home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Network Support Encyclopedia 96-1
/
novell-nsepro-1996-1-cd2.iso
/
download
/
netware
/
gchats.exe
/
GRPCHATS.C
< prev
next >
Wrap
Text File
|
1995-09-08
|
15KB
|
472 lines
/*
Copyright (c) 1992 Novell, Inc. All Rights Reserved.
THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
TREATIES. USE AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO THE
LICENSE AGREEMENT ACCOMPANYING THE SOFTWARE DEVELOPMENT KIT (SDK)
THAT CONTAINS THIS WORK.
Pursuant to the SDK License Agreement, Novell hereby grants to
Developer a royalty-free, non-exclusive license to include the
sample code GRPCHATS.C and derivative binaries in its product.
Novell grants to Developer worldwide distribution rights to market,
distribute or sell the sample code GRPCHATS.C and derivative
binaries as a component of Developer's product(s). Novell shall
have no obligations to Developer or Developer's customers with
respect to this code.
DISCLAIMER:
Novell, Inc. makes no representations or warranties with respect
to the contents or use of this code, and specifically disclaims any
express or implied warranties of merchantability or fitness for any
particular purpose. Further, Novell, Inc. reserves the right to revise
this publication and to make changes to its content, at any time,
without obligation to notify any person or entity of such revisions or
changes.
Further, Novell, Inc. makes no representations or warranties with
respect to any software, and specifically disclaims any express or
implied warranties of merchantability or fitness for any particular
purpose. Further, Novell, Inc. reserves the right to make changes to
any and all parts of the software, at any time, without obligation to
notify any person or entity of such changes.
***************************************************************************
GRPCHATS.C
**************************************************************************/
/**************************************************************************
** Description: This sample code demonstates how to use TLI to build a
** non-dedicated chat server that supports up to 15 clients
** simultaneously. All of the connections are opened in
** non-blocking mode to allow this server application to be
** switched-away from in Windows. The partner application to
** this one is GRPCHATC.EXE which demonstates how to write the
** client that connects with this application. A timer is used
** to check for connection requests and received data from the
** connected clients. Once this server application successfully
** loads, it's network address is displayed at the top of the
** top of the window. It is this network address that the client
** partner GRPCHATC.EXE requires to connect to this server.
** Enter the address exactly as it is displayed by this application.
**
** Compiler: Borland C++ v4.5
**
** Programmer : Karl Bunnell
** Date: 08/24/1995
**
*/
#include <windows.h>
#define NWWIN
#include <nwipxspx.h> /* I'm using the fixed header file NXTW.H */
#include <mem.h>
#include <string.h>
#include "grpchats.h"
//#include "nxtw.h"
#include <ctype.h>
#include <tispxipx.h>
#include <tiuser.h>
#define SPX_SOCKET 31 // arbitrary socket
#define MAX_MESSAGE_SIZE 1024
#define ID_TIMER 1
long FAR PASCAL _export WndProc(HWND, UINT, UINT, LONG);
BOOL Terminate(int connections, int *fd, int *ndf);
BOOL SPXDisconReason(int fd, HWND hwnd, int count);
static char globalMessage[1024];
char displayMessage[1024];
char tempMessage[1024];
/*-----------------------------------------------------------------------------
**
*/
int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
static char szGRPCHATS[] = "GRPCHATS";
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
if(!hPrevInstance)
{
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = DLGWINDOWEXTRA;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = COLOR_WINDOW + 1;
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szGRPCHATS;
RegisterClass(&wndclass);
}
hwnd = CreateDialog(hInstance, "MainDialog", 0, NULL);
while (!SetTimer (hwnd, ID_TIMER, 55, NULL))
if(IDCANCEL == MessageBox(hwnd, "Too many clocks or timers!", "GRPCHATS",
MB_ICONEXCLAMATION | MB_RETRYCANCEL))
return FALSE;
SendMessage(hwnd, WM_INITWINDOW, NULL, NULL);
ShowWindow(hwnd, nCmdShow);
while(GetMessage(&msg, NULL, 0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
/*-----------------------------------------------------------------------------
** Function: WndProc -- called by windows.
*/
long far PASCAL _export WndProc ( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam )
{
static IPX_ADDR spx_addr;
static SPX_OPTS spx_options;
static struct t_bind tbind;
static struct t_call tcall;
char buf[ 1024 ];
static WORD connections = 0;
static int fd, nfd[15];
int flags, listenResult;
int bytesSent, bytesLeft, nBytes, cnt;
int connectionCount, rcvCount;
WORD psize;
IPXAddress internetworkAddr;
DWORD IPXTaskID = 0L;
WORD ccode;
static initComplete = 0;
int j;
switch (message)
{
case WM_INITWINDOW:
/*-----------------------------------------------------------------------------
** The only reason the NWIPXSPX.LIB is included in the project is so I can
** use IPXGetInternetworkAddress(). It is NOT necessary to include this LIB or
** to initialize IPX with IPXInitialize() if only TLI functions are used!
*/
psize = IPXGetMaxPacketSize();
ccode = IPXInitialize(&IPXTaskID, 4, (WORD)psize);
if(ccode)
{
wsprintf(displayMessage, "IPXInitialize: %02X", ccode);
MessageBox(GetFocus(),displayMessage, "IPXInitialize", MB_ICONASTERISK | MB_OK);
return 1;
}
IPXGetInternetworkAddress(IPXTaskID, (BYTE far *)&internetworkAddr);
wsprintf(displayMessage, " Address: %02X%02X%02X%02X:%02X%02X%02X%02X%02X%02X",
internetworkAddr.network[0],
internetworkAddr.network[1],
internetworkAddr.network[2],
internetworkAddr.network[3],
internetworkAddr.node[0],
internetworkAddr.node[1],
internetworkAddr.node[2],
internetworkAddr.node[3],
internetworkAddr.node[4],
internetworkAddr.node[5]
);
SendDlgItemMessage(hwnd, IDC_DISPLAY_ADDR, WM_SETTEXT, 0,
(LONG) (LPSTR)displayMessage );
if ( ( fd = t_open( "/dev/nspx", O_RDWR | O_NDELAY, ( struct t_info * )0 ) ) == -1 )
{ t_error( "Open of /dev/nspx failed" );
return FALSE;
}
spx_addr.ipxa_socket[ 0 ] = 0; // Step 2
spx_addr.ipxa_socket[ 1 ] = SPX_SOCKET;
tbind.addr.len = sizeof( spx_addr );
tbind.addr.maxlen = sizeof( spx_addr );
tbind.addr.buf = ( char * ) &spx_addr;
tbind.qlen = 15;
if ( t_bind( fd, &tbind, &tbind ) == -1 )
{ t_error( "Bind failed!" );
return FALSE;
}
tcall.addr.buf = ( char * ) &spx_addr; // Step 3
tcall.addr.maxlen = sizeof( spx_addr );
tcall.addr.len = sizeof( spx_addr );
spx_options.spx_connectionID[ 0 ] = 0;
spx_options.spx_connectionID[ 1 ] = 0;
spx_options.spx_allocationNumber[ 0 ] = 0;
spx_options.spx_allocationNumber[ 1 ] = 0;
tcall.opt.buf = ( char * )&spx_options;
tcall.opt.len = sizeof( spx_options );
tcall.opt.maxlen = sizeof( spx_options );
tcall.udata.buf = ( char * )0;
tcall.udata.maxlen = 0;
tcall.udata.len = 0;
initComplete = 1;
break;
case WM_TIMER:
/*-----------------------------------------------------------------------------------
** I use a flag to wait until initialization is complete before checking for
** connection requests or received data.
*/
if(!initComplete)
break;
/*-----------------------------------------------------------------------------------
** Send a message to check for pending received data on each timer message
*/
if(connections > 0)
PostMessage(hwnd, WM_CHECK_RECEIVE, 0, 0);
listenResult = t_listen( fd, &tcall );
if ((listenResult == -1) && (t_errno == TNODATA))
break;
if ( listenResult != -1 )
{ if ( ( nfd[connections] = t_open( "/dev/nspx", O_RDWR | O_NDELAY, ( struct t_info * )0 ) ) == -1 )
{ t_error( "t_open after listen failed" );
return FALSE; /* connections not incremented */
/* so array entry is reused */
}
if ( t_bind( nfd[connections], ( struct t_bind * )0, ( struct t_bind * )0 ) == -1 )
{ t_error( "t_bind failed" );
t_close( nfd[connections] );
return FALSE;
}
if ( t_accept( fd, nfd[connections], &tcall ) == -1 )
{ t_error( "t_accept failed" );
t_close( nfd[connections] );
return FALSE;
}
++connections;
break;
}
if ( t_errno == TLOOK && t_look( fd ) == T_DISCONNECT )
SPXDisconReason( fd, hwnd, connections);
else
{
t_error( "t_listen failed" );
t_close( fd );
Terminate(connections, &fd, &nfd[0]);
EndDialog(hwnd, TRUE);
return TRUE;
}
break;
case WM_CHECK_RECEIVE:
connectionCount = connections;
memset(buf, 0, sizeof(buf));
for(rcvCount = 0; rcvCount < connectionCount; ++ rcvCount)
{
flags = 0; /* initialize for t_rcv call */
while ( t_rcv( nfd[rcvCount], buf, sizeof( buf),&flags ) != -1 /* && (flags & T_MORE)*/ ) // Step 6
{
/*-----------------------------------------------------------------------------------
** Because the connection was opened in non-blocking mode there is a good possibility
** that the complete message has not been received, however, for the purposes of this
** example I'm sending each chunk as I receive it to all connected nodes. Perhaps the
** best way to do this would be to ensure that I have received the entire message
** then send the complete message to each node. In this case the end result is the same.
*/
wsprintf(displayMessage, "%s\r\n", buf);
/*-----------------------------------------------------------------------------------
** Here I jump through some hoops to ensure that the most current received data
** is placed at the top of the edit control.
*/
if(strlen(displayMessage) + strlen(globalMessage) < MAX_MESSAGE_SIZE)
{
strcpy(tempMessage, displayMessage);
strcat(tempMessage, globalMessage);
strcpy(globalMessage, tempMessage);
}
else
{
memset(globalMessage, 0, sizeof(globalMessage));
strcpy(tempMessage, displayMessage);
strcat(tempMessage, globalMessage);
strcpy(globalMessage, tempMessage);
}
SendDlgItemMessage(hwnd, IDC_DISPLAY_DATA, WM_SETTEXT, 0,
(LONG) (LPSTR) globalMessage);
/*-----------------------------------------------------------------------------------
** Here I loop through all connected clients and send the received data to all
** connected clients.
*/
for(cnt = 0; cnt < connections; ++cnt)
{
/*-----------------------------------------------------------------------------------
** Because the connection is in non-blocking mode, you must advance the pointer
** in the send buffer yourself. The following loop demonstates one way you might do this.
*/
nBytes = bytesLeft = strlen(buf);
while (bytesLeft > 0)
{
do
{
bytesSent = t_snd( nfd[cnt], &buf[nBytes-bytesLeft], bytesLeft, 0 );
}while ((bytesSent == -1) && (t_errno == TFLOW));
if (bytesSent == -1 )
{
if (t_errno==TLOOK && t_look(nfd[cnt]) == T_DISCONNECT)
SPXDisconReason(nfd[cnt], hwnd, cnt);
else
{
t_error("t_snd failed\n");
t_close(nfd[cnt]);
for (j=cnt+1; j<connections; ++j)
*(nfd+j-1) = *(nfd+j);
--connections;
break;
}
}
else
bytesLeft -= bytesSent;
} // end - while nBytes > 0
} // end for - loop t_snd to connections
} // end while - t_rcv loop
if ( t_errno == TLOOK && t_look( nfd[rcvCount] ) == T_DISCONNECT )
{
SPXDisconReason( nfd[rcvCount], hwnd, rcvCount );
t_close(nfd[rcvCount]);
for (j=rcvCount+1; j<connections; ++j)
*(nfd+j-1) = *(nfd+j);
--connections;
}
} // end first for-loop connections t_rcv check
break;
case WM_DESTROY :
KillTimer (hwnd, ID_TIMER);
Terminate(connections, &fd, &nfd[0]);
PostQuitMessage(0);
return 0;
case WM_COMMAND:
switch(wparam)
{
case IDC_PUSHBUTTON1:
KillTimer (hwnd, ID_TIMER);
Terminate(connections, &fd, &nfd[0]);
PostQuitMessage(0);
return FALSE;
}
}
return DefWindowProc(hwnd, message, wparam, lparam);
}
BOOL Terminate(int connections, int *fd, int *ndf)
{
int i;
/*-----------------------------------------------------------------------------------
** Close all connection handles.
*/
t_close( *(fd) );
for(i=0; i<connections; ++i)
t_close(ndf[i]);
return TRUE;
}
BOOL SPXDisconReason(int fd, HWND hwnd, int count)
{
struct t_discon discon;
char *msg;
if (t_rcvdis(fd, &discon) == -1)
{
t_error( "t_rcvdis failed" );
return (TRUE);
}
switch( discon.reason )
{
case TLI_SPX_CONNECTION_FAILED:
msg = "Connection failed";
break;
case TLI_SPX_CONNECTION_TERMINATED:
msg = "Connection terminated by client";
break;
case TLI_SPX_MALFORMED_PACKET:
msg = "Internal SPX interface error -- malformed packet";
break;
default:
msg = "Unknown termination reason";
}
memset(displayMessage, 0, sizeof(displayMessage));
wsprintf(displayMessage, "\r\nSPX Connection number %d terminated: \r\n %s\r\n%s", count, msg, globalMessage );
if(strlen(displayMessage) + strlen(globalMessage) < MAX_MESSAGE_SIZE)
{
strcpy(tempMessage, displayMessage);
strcat(tempMessage, globalMessage);
strcpy(globalMessage, tempMessage);
}
else
{
memset(globalMessage, 0, sizeof(globalMessage));
strcpy(tempMessage, displayMessage);
strcat(tempMessage, globalMessage);
strcpy(globalMessage, tempMessage);
}
SendDlgItemMessage(hwnd, IDC_DISPLAY_DATA, WM_SETTEXT, 0,
(LONG) (LPSTR) globalMessage);
return FALSE;
}