home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Network Support Encyclopedia 96-1
/
novell-nsepro-1996-1-cd2.iso
/
download
/
netware
/
spxex1.exe
/
SPXCHAT.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-31
|
20KB
|
681 lines
/****************************************************************************
** File: SPXCHAT.CPP
**
** Description:
**
** Sample OS/2 application that demonstrates sending and receiving
** SPX packets in OS/2. Note the inclusion of dos16.h, which
** is where the 16 bit semaphore calls are prototyped.
**
** This program uses the following command-line syntax.
** Usage: SPXCHAT [SERVER]|[CLIENT <Address>]
** Address = Net/Node (in hex, leading zero's required)
** Example: SPXCHAT SERVER -or- SPXCHAT CLIENT 00001234/00001b02362
**
**
**
** Disclaimer:
**
** Novell, Inc. makes no representations or warranties with respect to
** any NetWare software, and specifically disclaims any express or
** implied warranties of merchantability, title, or fitness for a
** particular purpose.
**
** Distribution of any NetWare software is forbidden without the
** express written consent of Novell, Inc. Further, Novell reserves
** the right to discontinue distribution of any NetWare software.
**
** Novell is not responsible for lost profits or revenue, loss of use
** of the software, loss of data, costs of re-creating lost data, the
** cost of any substitute equipment or program, or claims by any party
** other than you. Novell strongly recommends a backup be made before
** any software is installed. Technical support for this software
** may be provided at the discretion of Novell.
**
** Programmers:
**
** Ini Who Firm
** -------------------------------------------------------------------
** VLS VL Smith
** DRS Dan Stratton Novell Developer Support
**
** History:
**
** When Who What
** -------------------------------------------------------------------
** 11-12-93 VLS First Code
** 07-01-94 DRS Modified for 1.0e SDK and 32 bit compilers
** 03-30-95 DRS Modified into SPX Chat for OS/2
*/
#define INCL_BASE
#define INCL_DOS
#define INCL_VIO
#define INCL_DOSPROCESS
#include <os2.h>
#include <stdio.h>
#include <string.h>
#include <conio.h>
#include <process.h>
#include <errno.h>
#include <ctype.h>
#define SEMCALLSET Dos16SemSet
#define SEMCALLWAIT Dos16SemWait
#define MAX_MESSAGE_SIZE 254
#define ERROR_COMPLETION 0xA000
#define MY_SOCKET 0x4445
#define IS32BIT
#define NWOS2
/* for now, just allow to run with either Borland or IBM */
#if defined (__BORLANDC__)
#define BCPP
void Send(void *sendInfo);
void Rec(void *recInfo);
#elif (defined (__IBMC__) || defined(__IBMCPP__))
#define CSET2
#pragma stack16(2048)
void _Export _Optlink Send(void *sendInfo);
void _Export _Optlink Rec(void *recInfo);
#endif
extern "C"{
#include <nwcalls.h>
#include <spxcalls.h>
#include <spxerror.h>
#include "dos16.h"
}
typedef struct IPXAddress
{
BYTE network[4]; /* high-low */
BYTE node[6]; /* high-low */
BYTE socket[2]; /* high-low */
}IPXAddress;
typedef struct SPXInfoStruct
{
USHORT connectionNumber;
BYTE spxBuffer[MAX_MESSAGE_SIZE];
void NWPTR semaph;
SPX_HEADER spxHeader;
SPX_ECB spxEcb;
}SPXInfoStruct;
int CheckForCompletion( SPX_ECB * ) ;
void GetWorkStationAddress(char *, char *) ;
void killConn(SPX_ECB *spxEcb, void NWPTR sem, USHORT connectionNumber, USHORT spxSocket);
int ParseAddress( char *address, IPXAddress *destination );
int PutAddress( char *string, char *buf, int hexBytes );
int clientProc(IPXAddress *tempAddress, USHORT *connectionNumber, void NWPTR *semaphore, SPX_ECB *spxEcb, SPX_HEADER *spxHeader,USHORT *spxSocket);
int serverProc(USHORT *connectionNumber,void NWPTR *semaphore, SPX_ECB *spxEcb, SPX_HEADER *spxHeader,USHORT *spxSocket);
BOOL terminateConnection = FALSE; /* set in most error conditions */
BOOL wasKilled = FALSE; /* Tells us if the other guy killed the connection */
/* --------------------------------------------------------------------
ParseAddress and PutAddress build an internetwork address from an
input address from the user. This address is then inserted into a
IPX_ADDR structure for use later in the program.
-------------------------------------------------------------------- */
int ParseAddress( char *addr, IPXAddress *destination )
{
if ( strlen( addr ) == 21 && addr[ 8 ] == '/' )
if ( PutAddress( (char *)addr, (char *)destination->network, 4 ) )
if ( PutAddress( (char *)&addr[ 9 ],(char *)destination->node, 6 ) )
return 1;
return 0;
} /* ParseAddress */
int PutAddress( char *string, char *buf, int hexBytes )
{
int i, j, value;
char c;
for ( i = 0; i < hexBytes; i++ )
{
value = 0; /* build a byte from two nibbles */
for ( j = 0; j < 2; j++ )
{
value <<= 4;
if ( ( c = toupper( *string ) ) >= '0' && c <= '9')
value += c - '0';
else if ( c >= 'A' && c <= 'F' )
value += c - 'A' + 10;
else
return 0;
string++;
}
*buf++ = value;
}
return 1;
} /* PutAddress */
/* ---------------------------------------------------------------
Usage prints the correct command-line usage of this
sample application.
--------------------------------------------------------------- */
void usage(void)
{
printf( "Usage:\tSPXCHAT [SERVER]|[CLIENT <Address>]\n" );
printf( "\tAddress = Net/Node (in hex, leading zero's required)\n" );
printf( "\tExample:\"SPXCHAT SERVER\n" );
printf( "\tOR \"SPXCHAT CLIENT 00001234/00001b02362e\"\n" );
}
/* -----------------------------------------------------------
Generic send data function for both Server and
Client sides. It prompts the user for data and
and sends it. Packet length is limited to 254
bytes of data right now, simply because gets,
cgets, etc. only accepts that much data at a
time.
----------------------------------------------------------- */
void Send(void *sendInfo)
{
WORD ccode = 0;
#if defined(BCPP)
char tempspxBuffer[MAX_MESSAGE_SIZE+2];
#endif
((SPXInfoStruct *)sendInfo)->semaph = 0L ;
((SPXInfoStruct *)sendInfo)->spxEcb.hsem = &(((SPXInfoStruct *)sendInfo)->semaph);
((SPXInfoStruct *)sendInfo)->spxEcb.fragCount = 2;
((SPXInfoStruct *)sendInfo)->spxEcb.fragList[0].fragAddress = &(((SPXInfoStruct *)sendInfo)->spxHeader);
((SPXInfoStruct *)sendInfo)->spxEcb.fragList[0].fragSize = sizeof(SPX_HEADER);
((SPXInfoStruct *)sendInfo)->spxEcb.fragList[1].fragAddress = ((SPXInfoStruct *)sendInfo)->spxBuffer ;
((SPXInfoStruct *)sendInfo)->spxEcb.fragList[1].fragSize = MAX_MESSAGE_SIZE;
do
{
printf("\nEnter Message ( .QUIT to quit)\n>> ");
fflush(stdout);
/* We do the following ifdef because a Borland compiled
program returns semaphore locking errors if you kill
the thread with a pending gets(), and IBM CSET traps
the entire session if you do a cgets from within a
thread. Besides, you're going to put a real interface
on this anyway, right? */
#if defined(CSET2)
gets((char *)(((SPXInfoStruct *)sendInfo)->spxBuffer));
#else
tempspxBuffer[0] = MAX_MESSAGE_SIZE;
tempspxBuffer[1] = 0;
cgets(tempspxBuffer);
strcpy((char *)(((SPXInfoStruct *)sendInfo)->spxBuffer), &tempspxBuffer[2]);
#endif
if(stricmp((const char *)(((SPXInfoStruct *)sendInfo)->spxBuffer), ".QUIT")==0)
{
terminateConnection = TRUE;
_endthread();
}
ccode = SEMCALLSET( &(((SPXInfoStruct *)sendInfo)->semaph) );
if(ccode != 0)
{
printf( "Error: SEMCALLSET returned 0x%04X - %d in clientSend\n", ccode,ccode );
terminateConnection = TRUE;
_endthread();
}
ccode = SpxSendSequencedPacket(((SPXInfoStruct *)sendInfo)->connectionNumber, &(((SPXInfoStruct *)sendInfo)->spxEcb));
if(ccode != 0)
{
printf( "Error: SpxSendSequencedPacket returned 0x%04X\n", ccode );
terminateConnection = TRUE;
_endthread();
}
ccode = CheckForCompletion(&(((SPXInfoStruct *)sendInfo)->spxEcb));
if(ccode)
{
terminateConnection = TRUE;
_endthread();
}
}while(!terminateConnection);
_endthread();
}
/* --------------------------------------------------------------
Generic SPX receive thread that both client and server
sides use. It's pretty basic right now, it just gets
the data and prints it out.
-------------------------------------------------------------- */
void Rec(void *recInfo)
{
WORD ccode = 0;
((SPXInfoStruct *)recInfo)->semaph = 0L;
((SPXInfoStruct *)recInfo)->spxEcb.hsem = &(((SPXInfoStruct *)recInfo)->semaph);
((SPXInfoStruct *)recInfo)->spxEcb.fragCount = 2;
((SPXInfoStruct *)recInfo)->spxEcb.fragList[0].fragAddress = &((SPXInfoStruct *)recInfo)->spxHeader;
((SPXInfoStruct *)recInfo)->spxEcb.fragList[0].fragSize = sizeof(SPX_HEADER);
((SPXInfoStruct *)recInfo)->spxEcb.fragList[1].fragAddress = ((SPXInfoStruct *)recInfo)->spxBuffer;
((SPXInfoStruct *)recInfo)->spxEcb.fragList[1].fragSize = MAX_MESSAGE_SIZE;
do
{
ccode = SEMCALLSET( &((SPXInfoStruct *)recInfo)->semaph );
if(ccode != 0)
{
printf( "Error: SEMCALLSET returned 0x%04X - %d in clientRec\n", ccode,ccode );
terminateConnection = TRUE;
_endthread();
}
ccode = SpxListenForConnectionPacket( ((SPXInfoStruct *)recInfo)->connectionNumber,&((SPXInfoStruct *)recInfo)->spxEcb);
if(ccode != 0)
{
printf( "Error: SpxListenForConnectionPacket returned 0x%04X\n", ccode );
terminateConnection = TRUE;
_endthread();
}
ccode = CheckForCompletion(&((SPXInfoStruct *)recInfo)->spxEcb);
if(ccode)
{
terminateConnection = TRUE;
_endthread();
} printf( "Data Received <%s>\n>>", ((SPXInfoStruct *)recInfo)->spxBuffer );
fflush(stdout);
}while(!terminateConnection);
_endthread();
}
/* ------------------------------------------------------------
This is the client portion of the test code. It
calls SpxEstablishConnection, which relies on the
server side doing an SpxListenForConnection.
------------------------------------------------------------ */
int clientProc(IPXAddress *tempAddress, USHORT *connectionNumber, void NWPTR *semaphore, SPX_ECB *spxEcb, SPX_HEADER *spxHeader,USHORT *spxSocket)
{
WORD ccode ;
memset(spxHeader, 0, sizeof(spxHeader));
memset(spxEcb, 0, sizeof(spxEcb));
memcpy((void *)&(spxHeader->destNet), (const void *)tempAddress,10);
spxHeader->destSocket = NWWordSwap(MY_SOCKET);
spxHeader->dataStreamType = 0 ;
*semaphore = 0L ;
spxEcb->hsem = semaphore ;
spxEcb->fragCount = 1;
spxEcb->fragList[0].fragAddress = spxHeader ;
spxEcb->fragList[0].fragSize = sizeof(SPX_HEADER);
*spxSocket = 0 ;
ccode = SpxOpenSocket( spxSocket ) ;
if(ccode)
{
printf( "Error: SpxOpenSocket returned 0x%04X\n", ccode );
return(1);
}
else printf( "Opened socket 0x%04X\n", *spxSocket );
ccode = SpxECBErrorCheck(ECB_ERROR_CHECK_ON);
if(ccode)
{
printf( "Error: SpxECBErrorCheck returned 0x%04X\n", ccode );
return(1);
}
ccode = SEMCALLSET( semaphore );
if(ccode)
{
printf( "Error: SEMCALLSET returned 0x%04X - %d before establishConnection\n", ccode,ccode );
return(1);
}
ccode = SpxEstablishConnection(*spxSocket,spxEcb, 0, WATCHDOG_CONNECTION, connectionNumber ) ; if(ccode)
{
printf( "Error: SpxExtablishConnection returned 0x%04X\n", ccode );
return(1);
}
printf("Establishing Connection.....\n");
ccode = CheckForCompletion(spxEcb);
if(ccode)
{
terminateConnection = TRUE;
return(1);
}
printf( "CONNECTION ESATBLISHED\n") ;
return 0;
} // end of sendThread
/* ------------------------------------------------------------
This is the server portion of the test code. It
calls SpxListenForConnection, which responds when the
client does a SpxEstablishConnection.
------------------------------------------------------------ */
int serverProc(USHORT *connectionNumber,void NWPTR *semaphore, SPX_ECB *spxEcb, SPX_HEADER *spxHeader,USHORT *spxSocket)
{
WORD ccode ;
*semaphore = 0L ;
spxEcb->hsem = semaphore ;
spxEcb->fragCount = 1;
spxEcb->fragList[0].fragAddress = spxHeader ;
spxEcb->fragList[0].fragSize = sizeof(SPX_HEADER);
ccode = SpxECBErrorCheck(ECB_ERROR_CHECK_ON);
if( ccode != 0 )
{
printf( "\nError: SpxECBErrorCheck returned 0x%04X", ccode );
return(1);
}
*spxSocket = NWWordSwap(MY_SOCKET);
ccode = SpxOpenSocket( spxSocket ) ;
if( ccode != 0 )
{
printf( "\nError: SpxOpenSocket returned 0x%04X", ccode );
return(1);
}
else printf("Socket 0x%04X opened\n", NWWordSwap(*spxSocket));
ccode = SEMCALLSET( semaphore );
if( ccode != 0 )
{
printf( "\nError: SEMCALLSET returned 0x%04X", ccode );
return(1);
}
ccode = SpxListenForConnection(*spxSocket, spxEcb, 0, WATCHDOG_CONNECTION, connectionNumber ) ;
if( ccode != 0 )
{
printf( "\nError: SpxListenForConnection returned 0x%04X", ccode );
return(1);
}
else printf("Listening for Connection.....\n");
ccode = CheckForCompletion(spxEcb);
if(ccode)
{
terminateConnection = TRUE;
return(1);
} printf( "CONNECTION ESTABLISHED\n") ;
return 0;
}
/* --------------------------------------------------------
Terminate connection in an error condition
-------------------------------------------------------- */
void killConn(SPX_ECB *spxEcb, void NWPTR sem, USHORT connectionNumber, USHORT spxSocket)
{
WORD ccode=0;
//spxEcb->fragCount = 1;
if(!wasKilled)
{
ccode = SEMCALLSET(&sem);
if( ccode != 0 )
{
printf( "Error: SEMCALLSET returned %d in killConn\n",ccode );
ccode = SpxCloseSocket(spxSocket);
return;
}
ccode = SpxTerminateConnection( connectionNumber, (SPX_ECB NWPTR)spxEcb );
if( ccode != 0 )
{
printf( "Error: SpxTerminateConnection returned 0x%04X\n", ccode );
ccode = SpxCloseSocket(spxSocket);
return;
}
ccode = CheckForCompletion(spxEcb);
if(ccode)
{
terminateConnection = TRUE;
ccode = SpxCloseSocket(spxSocket);
return;
}
}
ccode = SpxCloseSocket(spxSocket);
return;
}
/* ----------------------------------------------------------------------
CheckForCompletion - this function checks the completion status of the
ECB. It uses a semaph to loop on the status field until the ECB
has completed. It then checks if that status is an error.
---------------------------------------------------------------------- */
int CheckForCompletion( SPX_ECB *endpoint )
{
WORD ccode = 0 ;
/* If we have already completed, return */
if( endpoint->status == SPX_SUCCESSFUL )
return(0);
/* Check to see if we completed but have an error */
if(endpoint->status >= ERROR_COMPLETION )
{
switch(endpoint->status)
{
case 0xA3EC: printf("Connection Was Terminated\n");
wasKilled = TRUE;
break;
case 0xA3ED: printf("Connection Was Aborted\n");
wasKilled = TRUE;
break;
case 0xA2EE: printf("Connection Not Found\n");
break;
case 0xA2FC: printf("Packet Was Canceled\n");
break; default: printf( "\nError: ECB Status returned 0x%04X", endpoint->status );
break;
}
return(1);
}
if((ccode = SEMCALLWAIT( endpoint->hsem, SEM_INDEFINITE_WAIT )) != 0)
{
printf( "\nError: SEMCALLWAIT returned %d in CheckForCompletion",ccode );
return(1);
}
/* Check to see if we have an error */
if(endpoint->status >= ERROR_COMPLETION )
{
switch(endpoint->status)
{
case 0xA3EC: printf("Connection Was Terminated\n");
wasKilled = TRUE;
break;
case 0xA3ED: printf("Connection Was Aborted\n");
wasKilled = TRUE;
break;
case 0xA2EE: printf("Connection Not Found\n");
break;
case 0xA2FC: printf("Packet Was Canceled\n");
break;
default: printf("\nError: Second ECB Status returned 0x%04X", endpoint->status ); break;
}
return(1);
}
return(0);
}
void main(USHORT argc, BYTE *argv[])
{
int ccode=0;
int i;
IPXAddress tempAddress;
TID tempThreadId, sendThreadId, recThreadId;
APIRET rcode;
USHORT connectionNumber ;
void NWPTR semaphore;
SPX_ECB spxEcb;
SPX_HEADER spxHeader;
USHORT spxSocket ;
SPXInfoStruct sendInfo;
SPXInfoStruct recInfo;
memset((void *)&sendInfo,0,sizeof(SPXInfoStruct));
memset((void *)&recInfo,0,sizeof(SPXInfoStruct));
if ( argc < 2)
{
usage();
exit( 1 );
}
if( stricmp((const char *)argv[1],"CLIENT")==0)
{
if(argc < 3 || ! ParseAddress((char *)argv[ 2 ], &tempAddress ))
{
usage();
exit( 1 );
}
ccode=clientProc(&tempAddress,&connectionNumber,&semaphore, &spxEcb, &spxHeader,&spxSocket);
if(ccode)
{
exit(1);
}
}
else if(strcmpi((const char *)argv[1],"SERVER")==0)
{
ccode=serverProc(&connectionNumber,&semaphore, &spxEcb, &spxHeader,&spxSocket);
if(ccode)
{
exit(1);
}
}
else
{
usage();
exit( 1 );
}
recInfo.connectionNumber = connectionNumber;
sendInfo.connectionNumber = connectionNumber;
#if (defined(CSET2))
if ((sendThreadId=_beginthread(Send, NULL, 4096,(void *)&sendInfo)) < 0)
#else
if ((sendThreadId=_beginthread(Send, 4096, (void *)&sendInfo)) < 0)
#endif
{
printf("Unable to create Send thread, errno = %d\n",errno);
exit(1);
}
#if (defined(CSET2))
if ((recThreadId=_beginthread(Rec, NULL, 4096,(void *)&recInfo)) < 0)
#else
if ((recThreadId=_beginthread(Rec, 4096, (void *)&recInfo)) < 0)
#endif
{
printf("Unable to create Receive thread, errno = %d\n",errno);
exit(1);
}
tempThreadId = 0;
rcode = DosWaitThread(&tempThreadId, DCWW_WAIT);
if(rcode)
{
printf( "Error: DosWaitThread returned %d\n", rcode );
exit(1);
}
printf("\nTerminating this session...\n");
/* The following code gets around a little problem.
The receive thread probably has an SpxListenForConnectionPacket
posted. If it does, we can't simply kill the thread, SPX
would be left in an unstable state. If we simply terminate
the connection, we may have to wait a number of seconds for
the SPX watchdog to time out. So, we terminate the session,
then cancel any waiting ECB's. That let's the app terminate
quickly and safely, and also notifies the other side we are
shutting down. */
killConn(&spxEcb, semaphore, connectionNumber, spxSocket);
if(tempThreadId == sendThreadId)
{
ccode=SpxCancelPacket(&(recInfo.spxEcb));
if(ccode)
{
printf( "Error: SpxCancelPacket returned %d\n", ccode );
}
rcode=DosWaitThread(&recThreadId,DCWW_WAIT);
if(rcode)
{
printf( "Error: DosWaitThread returned %d\n", rcode );
exit(1);
}
}
else
{
/* We're able to just kill the Send thread since it's almost always
sitting at the gets or cgets command. */
rcode=DosKillThread(sendThreadId);
if(rcode)
{
printf( "Error: DosKillThread returned %d\n", rcode );
exit(1);
}
}
}