home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Network Support Encyclopedia 96-1
/
novell-nsepro-1996-1-cd2.iso
/
download
/
netware
/
xtli1.exe
/
FILETX.C
< prev
next >
Wrap
Text File
|
1994-09-13
|
21KB
|
808 lines
/****************************************************************************
** File: FILETX.C
**
** Description:
**
** Sample TLI server application for NLM environment. Program will send
** a specified file to client TLI endpoints. Companion product is FILERX
** (FILERX.C and FILERX.EXE).
**
** 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.
**
** QMK386 options used:
**
** /it - TLI symbols
**
** Programmers:
**
** Ini Who Firm
** -----------------------------------------------------------------------
** ABJ Adam B. Jerome Novell Developer Support
**
** History:
**
** When Who What
** -----------------------------------------------------------------------
** 07-01-94 ABJ First code.
**
*/
/****************************************************************************
** Include headers, macros, structures, typedefs, etc.
*/
/*------------------------------------------------------------------------
** ANSI
*/
#include <stdio.h> /* FILE, size_t, fopen(), gets(), printf(), sprintf(), fread(), feof(), fclose */
#include <malloc.h> /* malloc(), free() */
#include <string.h> /* strupr() */
#include <conio.h> /* getch(), kbhit() */
#include <process.h> /* delay(), exit(), atexit(), ThreadSwitch(), BeginThread() */
#include <sys/types.h> /* fd_set */
#include <fcntl.h> /* O_RDWR */
/*------------------------------------------------------------------------
** NetWare.
*/
#include <niterror.h> /* NetWareErrno */
#include <sap.h> /* AdvertiseService(), ShutdownAdvertising() */
#include <tiuser.h> /* T_BIND, T_CALL, T_MORE, T_LOOK, T_DISCONNECT,... */
/*------------------------------------------------------------------------
** Filetx
*/
#define SERVER_TYPE 0x0275 /* Novell Developer Support test server type */
/****************************************************************************
** Global storage.
*/
struct t_call *tCall = NULL;
struct t_bind *tBind = NULL;
int exitingNLM = FALSE;
int threadCnt = 0;
LONG sapHandle = 0;
int fh = (-1);
int bound = (-1);
char *sendFile = NULL;
/****************************************************************************
** Program shut-down (graceful).
*/
void Uninit(void)
{
/*------------------------------------------------------------------------
** Function sign-in.
*/
printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< SHUT DOWN >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
exitingNLM=TRUE;
/*------------------------------------------------------------------------
** Kill the SAP.
*/
if(sapHandle != 0)
{
printf("Stopping SAP Advertising...");
ShutdownAdvertising(sapHandle);
printf("Stopped.\n");
}
/*------------------------------------------------------------------------
** Free TLI allocations.
*/
printf("Freeing TLI allocations...");
if(tBind != NULL) t_free((char *)tBind, T_BIND);
if(tCall != NULL) t_free((char *)tCall, T_CALL);
printf("Freed.\n");
/*------------------------------------------------------------------------
** Unbind TLI protocol address.
*/
if(bound != (-1))
{
printf("Unbinding TLI address...");
t_unbind(fh);
printf("Unbound.\n");
}
/*------------------------------------------------------------------------
** Closing TLI device handle.
*/
if(bound != (-1))
{
printf("Closing TLI handle...");
t_close(fh);
printf("Closed.\n");
}
--threadCnt; /* See Init() for the ++threadCnt. */
exit(0);
}
/****************************************************************************
** Convert an IPX address to a string.
*/
char *IPXaddr2str(char *szStr, void *addr)
{
char *a;
a=(char *)addr;
sprintf(szStr,
"%02X%02X%02X%02X:%02X%02X%02X%02X%02X%02X:%02X%02X",
(0x00FF & a[ 0]),
(0x00FF & a[ 1]),
(0x00FF & a[ 2]),
(0x00FF & a[ 3]),
(0x00FF & a[ 4]),
(0x00FF & a[ 5]),
(0x00FF & a[ 6]),
(0x00FF & a[ 7]),
(0x00FF & a[ 8]),
(0x00FF & a[ 9]),
(0x00FF & a[10]),
(0x00FF & a[11])
);
return(szStr);
}
/****************************************************************************
** ATEXIT registered function.
*/
void TerminateNLM(void)
{
exitingNLM = TRUE; /* Signal all threads to die. */
while(threadCnt) ThreadSwitch(); /* Wait for all threads to die. */
delay(5); /* Give some time for things to calm. */
return;
}
/****************************************************************************
** Handle connection. (child process)
**
** This is where communication really happens.
*/
void ChildProcess(int *newFh)
{
int cCode;
char buf[48];
int exitingProcess=FALSE;
FILE *fp;
size_t bytes;
++threadCnt;
/*------------------------------------------------------------------------
** Send client a text file.
*/
fp=fopen(sendFile, "r");
if(fp != NULL)
{
while((bytes=fread(buf, 1, sizeof(buf), fp)))
{
/*---------------------------------------------------------------------
** Echo (send) packet back to the client.
*/
cCode = t_snd(
/* I- fd */ *newFh,
/* I- buf */ buf,
/* I- nbytes */ bytes,
/* I- flags */ feof(fp) ? 0 : T_MORE
);
if(cCode == (-1))
{
/*------------------------------------------------------------------
** I don't care what happened, we are shutting down this process.
*/
exitingProcess=TRUE;
/*------------------------------------------------------------------
** Now, what happened?
*/
switch(t_errno)
{
/*---------------------------------------------------------------
** An asynchronous event has occured on the transport endpoint
** specified by fd.
*/
case TLOOK:
/*---------------------------------------------------------------------
** Ok, What's this all important event?
*/
cCode=t_look(*newFh);
switch(cCode)
{
/*---------------------------------------------------------------------
** Other endpoint wants to disconnect?
*/
case T_DISCONNECT:
break;
/*---------------------------------------------------------------------
** t_look blew up?
*/
case (-1):
switch(t_errno)
{
case TBADF:
case TSYSERR:
default:
t_error("[CHILD]t_look");
break;
}
break;
/*---------------------------------------------------------------------
** We expect that it is not one of these.
*/
case 0: /* No event has occured. */
case T_LISTEN: /* Connect indication recieved. */
case T_CONNECT: /* Connection confirmation received. */
case T_DATA: /* Normal data received. */
case T_EXDATA: /* Expedited data received. */
case T_UDERR: /* Datagram error indication. */
case T_ORDREL: /* Orderly release indication. */
case T_GODATA: /* Flow control restrictions on normal data flow have been lifted. */
case T_GOEXDATA: /* Flow control restrictions on expedited data flow have been lifted. */
default: /* Undocumented elephant trap. */
printf("[CHILD]t_look:{%d}\n", cCode);
break;
}
break;
/*---------------------------------------------------------------
** We expect that it is not one of these.
*/
case TBADDATA:
case TBADF:
case TBADFLAG:
case TFLOW:
case TNOTSUPPORT:
case TOUTSTATE:
case TSYSERR:
default:
t_error("[CHILD]t_snd");
break;
}
}
}
fclose(fp);
}
/*------------------------------------------------------------------------
** Lets tell the other endpoint that we would like to go away now.
*/
cCode=t_snddis(
/* I- fd */ *newFh,
/* I- call */ NULL
);
if(cCode == (-1)) switch(t_errno)
{
/*---------------------------------------------------------------------
** We expect none of these.
*/
case TBADF:
case TOUTSTATE:
case TBADDATA:
case TBADSEQ:
case TNOTSUPPORT:
case TSYSERR:
default:
t_error("[CHILD]t_snddis");
break;
}
/*------------------------------------------------------------------------
** Wait for disconnect message.
*/
do {
ThreadSwitch();
cCode=t_rcvdis(
/* I- fd */ *newFh,
/* -O discon */ NULL
);
if(cCode == -1) switch(t_errno)
{
case TNODIS:
break;
/*------------------------------------------------------------------
** We expect none of these.
*/
case TBADF:
case TBUFOVFLW:
case TNOTSUPPORT:
case TOUTSTATE:
case TSYSERR:
default:
t_error("[CHILD]t_rcvdis");
break;
}
} while(cCode == TNODIS);
/*------------------------------------------------------------------------
** Unbinding the new TLI endpoint.
*/
cCode=t_unbind(*newFh);
if(cCode) switch(t_errno)
{
/*---------------------------------------------------------------------
** We expect none of these.
*/
case TBADF:
case TOUTSTATE:
case TLOOK:
case TSYSERR:
default:
t_error("[CHILD]t_unbind");
break;
}
/*------------------------------------------------------------------------
** Closing the new TLI endpoint.
*/
cCode=t_close(*newFh);
if(cCode == -1) switch(t_errno)
{
case TBADF:
default:
t_error("[CHILD]t_close");
break;
}
/*------------------------------------------------------------------------
** Free the allocated handle.
*/
if(newFh != NULL) free(newFh);
--threadCnt;
/*------------------------------------------------------------------------
** End of thread.
*/
return;
}
/****************************************************************************
** Progam core proccess loop; Service connection requests. Spawn new threads
** to handle connections.
*/
void CoreProc(void)
{
int *newFh;
char szTemp[256];
int cCode;
int newBindFlag = -1;
/*------------------------------------------------------------------------
** Function sign-in.
*/
printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CORE PROCESS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
/*------------------------------------------------------------------------
** Answer the phone loop.
*/
while(!exitingNLM)
{
/*------------------------------------------------------------------------
** Check for user exit request.
*/
ThreadSwitch();
if(kbhit())
{
/*------------------------------------------------------------------
** Flush the keyboard buffer.
*/
while(kbhit()) if(!getch()) getch();
do {
printf("Exit? (Y/N): ");
gets(szTemp);
strupr(szTemp);
} while((szTemp[0] != 'N') && (szTemp[0] != 'Y'));
if(szTemp[0] == 'Y')
{
exitingNLM=TRUE;
break;
}
}
/*---------------------------------------------------------------------
** Wait for the phone to ring...
*/
printf("Listening...");
cCode=t_listen(
/* I- fd */ fh,
/* -O call */ tCall
);
if(cCode == (-1))
{
switch(t_errno)
{
/*------------------------------------------------------------------
** We opened in polling mode. As we poll, and nobody is there, we
** will get this case. Ignore it and go on, but do not attempt to
** connect.
*/
case TNODATA:
printf("\r");
continue;
/*------------------------------------------------------------------
** We don't want any of these to happen.
*/
case TBADF:
case TBADQLEN:
case TBUFOVFLW:
case TLOOK:
case TNOTSUPPORT:
case TOUTSTATE:
case TSYSERR:
default:
t_error("ERROR");
exitingNLM=TRUE;
continue;
}
}
/*---------------------------------------------------------------------
** "Ring..."
*/
printf("RING!!!\n");
/*------------------------------------------------------------------
** Malloc memory for newFh. (Being that we cannot pass objects from
** our stack to a child process). Child process will free this
** memory (if we are successful).
*/
printf("Allocating new file handle...");
newFh=(int *)malloc(sizeof(int));
if(newFh == NULL)
{
printf("ERROR: Out of memory.\n");
goto CONNECT_ERR;
}
printf("Allocated.\n");
/*------------------------------------------------------------------------
** Open a new endpoint to service connection.
*/
printf("Opening new endpoint...");
*newFh = t_open(
/* I- path */ "/dev/nspx",
/* I- oflag */ O_RDWR,
/* -O info */ NULL
);
if(*newFh == (-1))
{
switch(t_errno)
{
case TSYSERR:
case TBADFLAG:
case TBADNAME:
default:
t_error("ERROR");
break;
}
goto CONNECT_ERR;
}
printf("Open.\n");
/*------------------------------------------------------------------------
** Bind it as appropriate (Transport provider will provide an address).
*/
printf("Binding new endpoint...");
newBindFlag=t_bind(
/* I- fd */ *newFh,
/* I- req */ NULL,
/* -O ret */ NULL
);
if(newBindFlag == -1)
{
t_error("ERROR");
goto CONNECT_ERR;
}
printf("Bound.\n");
/*------------------------------------------------------------------------
** Accept the call from a client to the alloced fileHandle.
*/
printf("Accepting call...");
if(t_accept(fh, *newFh, tCall) == -1)
{
t_error("ERROR");
goto CONNECT_ERR;
}
printf("Accepted.\n");
/*------------------------------------------------------------------------
** Check for disconnect request. (Client may have changed his mind).
*/
ThreadSwitch();
printf("Checking for a disconnect request...");
cCode=t_look(*newFh);
if(cCode == T_DISCONNECT)
{
printf("ERROR: Disconnect request encountered.\n");
/*---------------------------------------------------------------
** Recieve the disconnect request.
*/
printf("Recieving disconnect...");
cCode=t_rcvdis(
/* fd */ *newFh,
/* discon */ NULL
);
if(cCode < 0)
t_error("ERROR");
else
printf("Recieved.\n");
goto CONNECT_ERR;
}
printf("Not encountered.\n");
/*------------------------------------------------------------------------
** Spawn child process to handle it from here.
*/
printf("Spawning child process...");
cCode=BeginThread(ChildProcess, NULL, NULL, newFh);
if(cCode == (-1))
{
printf("ERROR: Failed.\n");
goto CONNECT_ERR;
}
else
{
printf("Child process is ON-LINE.\n");
continue;
}
CONNECT_ERR:
exitingNLM=TRUE;
/*------------------------------------------------------------------------
** Unbinding the new TLI endpoint.
*/
if(newBindFlag != (-1))
{
printf("Unbinding new endpoint...");
if(t_unbind(*newFh))
t_error("t_unbind");
else
printf("Unbound.\n");
}
/*------------------------------------------------------------------------
** Closing the new TLI endpoint.
*/
if(*newFh != (-1))
{
printf("Closing new endpoint...");
if(t_close(*newFh))
t_error("t_close");
else
printf("Closed.\n");
}
/*------------------------------------------------------------------------
** Freeing new handle.
*/
if(newFh != NULL)
{
printf("Freeing new handle...");
free(newFh);
printf("Freed.\n");
}
}
return;
}
/****************************************************************************
** Program initialization.
*/
void Init(int argc, char *argv[])
{
struct t_info tInfo;
char szTemp[256];
FILE *fp;
++threadCnt; /* See Uninit() for the --threadswitch. */
/*------------------------------------------------------------------------
** Function sign-in.
*/
printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< INITIALIZATION >>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
/*------------------------------------------------------------------------
** Check command line args.
*/
if(argc != 3)
{
printf("Usage: LOAD %s <server's name> <filename>\n", argv[0]);
printf("\n");
printf(" <server's name> Name that this NLM will be known as\n");
printf(" on the network.\n");
printf("\n");
printf(" <filename> Name of file (including path) that will\n");
printf(" be sent to requesting client endpoints\n");
printf("\n");
Uninit();
}
/*------------------------------------------------------------------------
** Get (and verify existance of) specified file.
*/
sendFile=argv[2];
fp=fopen(sendFile, "r");
if(fp != NULL) fclose(fp);
else
{
printf("ERROR: Cannot open file: %s\n", sendFile);
exitingNLM = TRUE;
Uninit();
}
/*------------------------------------------------------------------------
** Register exit procedure.
*/
if(atexit(TerminateNLM) != NULL)
{
printf("ERROR: atexit failed.\n");
Uninit();
}
/*------------------------------------------------------------------------
** Initialize a TLI endpoint to listen for connection requests.
*/
printf("Opening TLI endpoint...");
fh=t_open(
/* I- path */ "/dev/nspx",
/* I- oflag */ O_RDWR|O_NDELAY,
/* -O info */ &tInfo
);
if(fh == -1)
{
switch(t_errno)
{
case TBADFLAG: /* Invalid flag was specified. */
case TBADNAME: /* Invalid transport provider name was specified. */
case TSYSERR: /* System error occured. */
default:
t_error("ERROR");
break;
}
Uninit();
}
printf("Opened.\n");
/*------------------------------------------------------------------------
** Allocate and initialize TLI structures.
*/
printf("Allocating...");
tBind = (struct t_bind *)t_alloc(
/* I- fd */ fh,
/* I- struct_type */ T_BIND,
/* I- fields */ T_ALL
);
if(tBind == NULL)
{
switch(t_errno)
{
case TBADF:
case TSYSERR:
case TNOTSUPPORT:
case TNOSTRUCTYPE:
default:
t_error("ERROR:");
}
Uninit();
}
tCall = (struct t_call *)t_alloc(
/* I- fd */ fh,
/* I- struct_type */ T_CALL,
/* I- fields */ T_ADDR
);
if(tCall == NULL)
{
switch(t_errno)
{
case TBADF:
case TSYSERR:
case TNOTSUPPORT:
case TNOSTRUCTYPE:
default:
t_error("ERROR:");
}
Uninit();
}
printf("Allocated.\n");
/*------------------------------------------------------------------------
** Associate specified protocol address with the TLI endpoint
** Fill out tBind structure, requesting address (dynamic IPX socket
** number) be assigned.
*/
printf("Binding...");
tBind->qlen = 1;
tBind->addr.len = 0;
bound=t_bind(
/* I- fd */ fh,
/* I- req */ tBind,
/* -O ret */ tBind
);
if(bound == (-1))
{
switch(t_errno)
{
case TBADF:
case TOUTSTATE:
case TBADADDR:
case TBUFOVFLW:
case TSYSERR:
case TADDRBUSY:
default:
t_error("ERROR: t_bind");
}
Uninit();
}
printf("Bound. [%s]\n", IPXaddr2str(szTemp, tBind->addr.buf));
/*-------------------------------------------------------------------------
** Use the above (dynamically assigned) IPX socket number to begin SAPping.
*/
printf("Begin SAPping...");
sapHandle=AdvertiseService(
/* I- serverType */ SERVER_TYPE,
/* I- serverName */ argv[1],
/* I- serviceSocket */ *(WORD *)(((IPX_ADDR *)tBind->addr.buf)->ipxa_socket)
);
if(sapHandle == -1)
{
printf("ERROR: #%d.\n", NetWareErrno);
Uninit();
}
printf("Initiated.\n");
return;
}
/****************************************************************************
** Program start.
*/
void main(int argc, char *argv[])
{
Init(argc, argv);
CoreProc();
Uninit();
}