home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Network Support Encyclopedia 96-1
/
novell-nsepro-1996-1-cd2.iso
/
download
/
netware
/
xsap1a.exe
/
SERVER.C
< prev
next >
Wrap
Text File
|
1994-08-24
|
17KB
|
693 lines
/****************************************************************************
** File: SERVER.C
**
** Desc:
**
** Example of SAPing server process. It listens on it's dynamic
** socket for requests and services them.
**
** 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: None.
**
** Programmers:
**
** Ini Who Firm
** -----------------------------------------------------------------------
** ABJ Adam B. Jerome Novell Developer Support.
**
** History:
**
** When Who What
** -----------------------------------------------------------------------
** 08-19-94 ABJ First code.
*/
/****************************************************************************
** Include headers, macros, function prototypes, etc.
*/
/*------------------------------------------------------------------------
** ANSI
*/
#include <stdlib.h> /* exit() */
#include <stdio.h> /* printf() */
#include <string.h> /* strlen() */
#include <conio.h> /* CreateScreen(), DestroyScreen() */
#include <process.h> /* GetNLMHandle() */
#include <errno.h> /* errno */
#include <signal.h> /* signal(), SIGTERM, SIGINT */
/*------------------------------------------------------------------------
** NetWare
*/
#include <advanced.h> /* AllocatResourceTag() */
#include <nwsnut.h> /* NWSRestoreNut(), NWSPushList(), ...*/
#include <nwipxspx.h> /* IPXOpenSocket() */
#include <niterror.h> /* NetWareErrno */
#include <sap.h> /* AdvertiseService(), ShutDownAdvertising() */
#include <nwsemaph.h> /* OpenLocalSemaphore(), CloseLocalSemaphore() */
#include <nwmisc.h> /* IntSwap() */
/*------------------------------------------------------------------------
** SERVER
*/
#include "common.h"
#define NLM_MIN_ECBS 10 /* Initial number of ECBs */
typedef struct ECB_NODE
{
struct ECB_NODE *prior;
struct ECB_NODE *next;
IPX_ECB ecb;
} ECB_NODE;
/****************************************************************************
** Global storage
*/
unsigned short NLM_serviceSocket = 0x0000; /* zero value causes NetWare to allocate a socket dynamicly */
int NLM_exiting = 0;
int NLM_threadCnt = 0;
LONG NLM_sapHandle = (-1);
IPX_ECB *NLM_queueHead = NULL;
long NLM_semHandle = 0;
char *NLM_serverName;
/****************************************************************************
** Signal handler.
**
** Parameters:
**
** int event Signal event which occured.
*/
void NLM_SignalHandler(int event)
{
switch(event)
{
case SIGTERM:
NLM_exiting = (-1);
while(NLM_threadCnt) ThreadSwitch();
delay(1000);
break;
case SIGINT:
signal(SIGINT, NLM_SignalHandler);
break;
}
return;
}
/****************************************************************************
** Allocate (or free) ECB nodes.
**
** Parameters:
**
** int buffers Number of communication buffers to allocate;
** or (0) zero to free all allocated buffers.
*/
void NLM_AllocCommBuffers(int buffers)
{
static ECB_NODE *head = NULL;
static ECB_NODE *tail = NULL;
ECB_NODE *node;
int cCode;
int cnt;
/*------------------------------------------------------------------------
** Free nodes.
*/
if(buffers == 0)
{
/*---------------------------------------------------------------------
** Cancel events.
*/
node=head;
while(node != NULL)
{
if(node->ecb.status > 0)
{
cCode=IpxCancelEvent(&node->ecb);
switch(cCode)
{
case ESUCCESS:
break;
case ERR_ECB_CANNOT_BE_CANCELLED:
printf("ERROR: ECB cannot be canceled.\n");
break;
default:
printf("ERROR: IpxCancelEvent() returned unknown error %d.\n", cCode);
break;
}
}
node=node->next;
}
/*---------------------------------------------------------------------
** Free nodes.
*/
while(head != NULL)
{
node=head;
head=head->next;
if(node->ecb.fragList[0].fragAddress != NULL)
free(node->ecb.fragList[0].fragAddress);
if(node->ecb.fragList[1].fragAddress != NULL)
free(node->ecb.fragList[1].fragAddress);
free(node);
}
goto END;
}
/*------------------------------------------------------------------------
** Allocate new nodes.
*/
for(cnt=0; cnt<buffers; ++cnt)
{
/*---------------------------------------------------------------------
** Allocate an ECB_NODE.
*/
node=(ECB_NODE *)malloc(sizeof(ECB_NODE));
if(node == NULL)
{
printf("ERROR: Cannot allocate ECB_NODE.\n");
goto END_ERROR;
}
memset(node, 0x00, sizeof(ECB_NODE));
/*---------------------------------------------------------------------
** Initialize ECB.
*/
node->ecb.queueHead = &NLM_queueHead;
node->ecb.semHandle = NLM_semHandle;
node->ecb.fragCount = 2;
node->ecb.fragList[0].fragSize = sizeof(IPX_HEADER);
node->ecb.fragList[0].fragAddress = malloc(sizeof(IPX_HEADER));
if(node->ecb.fragList[0].fragAddress == NULL) goto END_ERROR;
node->ecb.fragList[1].fragSize = COM_MAX_DATA_SIZE;
node->ecb.fragList[1].fragAddress = malloc(COM_MAX_DATA_SIZE);
if(node->ecb.fragList[1].fragAddress == NULL) goto END_ERROR;
/*---------------------------------------------------------------------
** Link node into node list.
*/
if(head == NULL) /* Add node to empty list */
{
node->prior = NULL;
node->next = NULL;
head = node;
tail = node;
}
else /* Add node to end of list */
{
node->prior = tail;
node->next = NULL;
tail->next = node;
tail = node;
}
/*---------------------------------------------------------------------
** Post the ECB.
*/
cCode=IpxReceive(NLM_serviceSocket, &node->ecb);
switch(cCode)
{
case ESUCCESS:
break;
case ERR_SOCKET_NOT_OPEN:
printf("ERROR: Socket not open.\n");
goto END_ERROR;
case ERR_REQUEST_CANCELLED:
printf("ERROR: Request cancelled.\n");
goto END_ERROR;
case ERR_PACKET_OVERFLOW:
printf("ERROR: Packet overflow.\n");
goto END_ERROR;
case ERR_TIMEOUT_FAILURE: /* ERROR_BAD_PACKET has same value. */
printf("ERROR: Timeout failure, or bad packet.\n");
goto END_ERROR;
default:
printf("ERROR: IpxRecieve() returned unknown error %d.\n", cCode);
goto END_ERROR;
}
}
goto END;
END_ERROR:
if(node != NULL)
{
if(node->ecb.fragList[0].fragAddress != NULL)
free(node->ecb.fragList[0].fragAddress);
if(node->ecb.fragList[1].fragAddress != NULL)
free(node->ecb.fragList[1].fragAddress);
free(node);
}
END:
return;
}
/****************************************************************************
** Program shut down.
*/
void NLM_Uninit(void)
{
int cCode;
NLM_exiting = (-1);
/*------------------------------------------------------------------------
** Shut down server SAP advertising.
*/
if(NLM_sapHandle != (-1))
{
cCode=ShutdownAdvertising(NLM_sapHandle);
switch(cCode)
{
case 0:
break;
default:
printf("ERROR: ShutDownAdvertising() returned error code %d\n", cCode);
}
}
/*------------------------------------------------------------------------
** Free up list of ECBs.
*/
NLM_AllocCommBuffers(0);
/*------------------------------------------------------------------------
** Give our semaphore back to NetWare.
*/
if(NLM_semHandle)
{
cCode=CloseLocalSemaphore(NLM_semHandle);
switch(cCode)
{
case ESUCCESS:
break;
default:
printf("ERROR: CloseLocalSemaphore() returned unknown error: %d\n", cCode);
}
}
/*------------------------------------------------------------------------
** Give our socket back to NetWare.
*/
if(NLM_serviceSocket != 0x0000)
{
cCode=IpxCloseSocket(NLM_serviceSocket);
switch(cCode)
{
case ESUCCESS:
break;
default:
printf("ERROR: IpxCloseSocket() returned an unknown error: %d\n", cCode);
break;
}
}
return;
}
/****************************************************************************
** Handle a client Request.
*/
void NLM_HandleRequest(void *vp)
{
COM_DATA_PACKET *p = (COM_DATA_PACKET *)vp;
switch(p->type)
{
case COM_REQ_PING:
strcpy(p->data, "PONG");
p->status = COM_SUCCESS;
break;
default:
p->status = COM_ERR_UNKNOWN_TYPE;
break;
}
return;
}
/****************************************************************************
** Handle a client packet.
*/
void NLM_HandlePacket(void *vArg)
{
IPX_ECB *ecb = (IPX_ECB *)vArg;
IPX_HEADER *ipxHdr = (IPX_HEADER *)ecb->fragList[0].fragAddress;
IPX_HEADER hdr;
int cCode;
/*------------------------------------------------------------------------
** Service the client's request.
*/
NLM_HandleRequest(ecb->fragList[1].fragAddress);
/*------------------------------------------------------------------------
** Swap IPX header's source & destination.
*/
memcpy(&hdr, &ipxHdr->destNet, sizeof(InternetAddress));
memcpy(&ipxHdr->destNet, &ipxHdr->sourceNet, sizeof(InternetAddress));
memcpy(&ipxHdr->sourceNet, &hdr, sizeof(InternetAddress));
/*------------------------------------------------------------------------
** Send the packet back to client.
*/
cCode=IpxSend(0, ecb);
switch(cCode)
{
case ESUCCESS:
break;
case ERR_NO_KNOWN_ROUTE_TO_DESTINATION:
printf("ERROR: No known route to destination.\n");
NLM_exiting = (-1);
break;
case ERR_REQUEST_CANCELLED:
printf("ERROR: Request canceled.\n");
NLM_exiting = (-1);
break;
case ERR_BAD_PACKET:
printf("ERROR: Bad packet received.\n");
NLM_exiting = (-1);
break;
case HARDWARE_FAILURE:
printf("ERROR: Hardware failure.\n");
NLM_exiting = (-1);
break;
default:
printf("ERROR: IpxSendPacket() returned an unknown error: %d.\n", cCode);
NLM_exiting = (-1);
break;
}
/*------------------------------------------------------------------------
** Re-post the ECB.
*/
ecb->semHandle = NLM_semHandle;
cCode=IpxReceive(NLM_serviceSocket, ecb);
switch(cCode)
{
case ESUCCESS:
break;
case ERR_SOCKET_NOT_OPEN:
printf("ERROR: Socket not open.\n");
NLM_exiting = (-1);
break;
case ERR_REQUEST_CANCELLED:
printf("ERROR: Request cancelled.\n");
NLM_exiting = (-1);
break;
case ERR_PACKET_OVERFLOW:
printf("ERROR: Packet overflow.\n");
NLM_exiting = (-1);
break;
case ERR_TIMEOUT_FAILURE: /* ERROR_BAD_PACKET has same value. */
printf("ERROR: Timeout failure, or bad packet.\n");
break;
default:
printf("ERROR: IpxRecieve() returned unknown error %d.\n", cCode);
NLM_exiting = (-1);
break;
}
return;
}
/****************************************************************************
** Watch for incomming client requests.
*/
void NLM_PollForPackets(void *v)
{
int cCode;
IPX_ECB *head = NULL;
IPX_ECB *node;
int threadID;
v=v;
while(!NLM_exiting)
{
/*---------------------------------------------------------------------
** Wait for an ECB event.
*/
cCode=WaitOnLocalSemaphore(NLM_semHandle);
switch(cCode)
{
case 0:
break;
default:
printf("ERROR: WaitOnLocalSemaphore() returned unknown error: %d.\n", cCode);
NLM_exiting = (-1);
break;
}
/*---------------------------------------------------------------------
** Get list of incomming ECBs.
*/
if((head=IpxGetAndClearQ(&NLM_queueHead)) == NULL) continue;
while(head != NULL)
{
node=head;
head=head->next;
threadID=BeginThread(NLM_HandlePacket, NULL, 0, node);
if(threadID == EFAILURE)
{
switch(errno)
{
case ENOMEM:
printf("ERROR: Not enough memory to begin event handler thread.\n");
break;
case EINVAL:
printf("ERROR: Invalid argument was passed into BeginThread().\n");
break;
default:
printf("ERROR: BeginThread() returned unknown error: %d.\n", errno);
break;
}
NLM_exiting = (-1);
break;
}
}
ThreadSwitch();
}
return;
}
/****************************************************************************
** Program core process.
*/
void NLM_Proc(void)
{
printf("<Press a key to unload>\n");
while(!NLM_exiting)
{
/*---------------------------------------------------------------------
** Alternate unload method.
*/
if(kbhit())
{
if(!getch()) getch();
NLM_exiting = (-1);
}
ThreadSwitch();
}
return;
}
/****************************************************************************
** Program initialization.
*/
void NLM_Init(int argC, char *argV[])
{
LONG cCode;
int threadID;
/*------------------------------------------------------------------------
** Check and parse command-line args.
*/
if(argC != 2)
{
printf("USAGE: SERVER {NLM_serverName}\n");
cCode = (-1);
goto END;
}
NLM_serverName=argV[1];
if(strlen(NLM_serverName) > 47)
{
printf("ERROR: Server name is too long.\n");
cCode = (-1);
goto END;
}
/*------------------------------------------------------------------------
** Register functions with NetWare.
*/
signal(SIGINT, NLM_SignalHandler);
signal(SIGTERM, NLM_SignalHandler);
/*------------------------------------------------------------------------
** Get NetWare to assign us a dynamic socket number.
*/
cCode=IpxOpenSocket(&NLM_serviceSocket);
switch(cCode)
{
case ESUCCESS:
break;
case ERR_IPX_NOT_INSTALLED:
printf("ERROR: IPX is not installed.\n");
goto END;
case ERR_SOCKET_ALREADY_OPEN:
printf("ERROR: IPX socket 0x%04hX is already in use on this node.\n", NLM_serviceSocket);
goto END;
case ERR_SOCKET_TABLE_FULL:
printf("ERROR: IPX socket table is full on this node.\n");
goto END;
default:
printf("ERROR: IpxOpenSocket() returned an unknown error: %d\n", cCode);
goto END;
}
/*------------------------------------------------------------------------
** Open a local semaphore handle for receiving IPX packets.
*/
NLM_semHandle=OpenLocalSemaphore(0);
/*------------------------------------------------------------------------
** Begin listening on socket for requests.
*/
NLM_AllocCommBuffers(NLM_MIN_ECBS);
/*------------------------------------------------------------------------
** Begin advertising.
*/
NLM_sapHandle=(int)AdvertiseService(
/* serverType */ COM_SERVER_TYPE,
/* NLM_serverName */ NLM_serverName,
/* NLM_serviceSocket */ NLM_serviceSocket
);
if(NLM_sapHandle == (-1)) switch(NetWareErrno)
{
default:
printf("ERROR: AdvertiseService() returned error code %d.\n", NetWareErrno);
goto END;
}
/*------------------------------------------------------------------------
** Begin listening for requests.
*/
threadID=BeginThread(NLM_PollForPackets, NULL, 0, NULL);
if(threadID == EFAILURE)
{
switch(errno)
{
case ENOMEM:
printf("ERROR: Not enough memory to begin polling thread.\n");
break;
case EINVAL:
printf("ERROR: Invalid argument was passed into BeginThread().\n");
break;
default:
printf("ERROR: BeginThread() returned unknown error: %d.\n", errno);
break;
}
NLM_exiting = (-1);
goto END;
}
END:
if(cCode) NLM_exiting=(-1);
return;
}
/****************************************************************************
** Program start.
*/
void main(int argC, char *argV[])
{
NLM_threadCnt++;
NLM_Init(argC, argV);
NLM_Proc();
NLM_Uninit();
NLM_threadCnt--;
exit(0);
}