/*  File: dceserverlib.c
 *  Author: Richard Bruskiewich (rbrusk@octogene.medgen.ubc.ca)
 *  Copyright (C) J Thierry-Mieg and R Durbin, 1992
 *-------------------------------------------------------------------
 * This file is part of the ACEDB genome database package, written by
 * 	Richard Durbin (MRC LMB, UK) rd@mrc-lmb.cam.ac.uk, and
 *	Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.cnrs-mop.fr
 *
 * Description:
 * Distributed Computing Environment (DCE) RPC - server side
 * Adapted from Microsoft sample and  rpcace_sp.c code (version 1.13 7/31/96) 
 * 
 * Exported functions:
 *	 ace_server()
 *
 * HISTORY:
 * Last edited: Feb 18 04:32 1997 (rbrusk): converted to "use all protocols"
 * * Jan 23 14:45 1997 (rbrusk)
 * * Jan 10 05:30 1997 (rbrusk)
 * Created: Jan 10 05:30 1997 (rbrusk)
 ******************************************
 * rpcace_sp.c HISTORY:
 *    from a first version by Peter Kocab
 *    edited by Bigwood & Co
 * Last edited: Jan 10 16:13 1996 (mieg)
 * Created: Fri Nov 18 16:42:20 1994 (mieg)
 *-------------------------------------------------------------------
 */

/* %W% %G%	 */

#include "acedb.h"
#include <errno.h>
#include <ctype.h>
#include "rpcace.h"
#include "dceprot.c"
#include "my_dce.h"
  
static RPC_BINDING_VECTOR *pBindingVector = 0 ;

void wait_for_client (u_long port, BOOL isDaemon /* UNIX legacy - ignored for now */)
{
	RPC_STATUS status;
    unsigned int    cMinCalls           = 1;
    unsigned int    cMaxCalls           = 20;
    unsigned int    fDontWait           = FALSE;
	int i ;

	/*
		psz* parameters set in "dceprot.c";
		host and isDaemon values are currently ignored
	*/
	status = RpcServerUseAllProtseqs( cMaxCalls, pszSecurity ); 
 
    if (status) {
        exit(status);
    }
	status = RpcServerInqBindings( &pBindingVector );
 
    if (status) {
        exit(status);
    }

	status = RpcEpRegister( RPC_ACE_v1_0_s_ifspec,
							pBindingVector,
							NULL,
							NULL);
    if (status) {
        exit(status);
    }

	/* Clear the dynamic endpoints from binding vector */
	for (i = 0 ; i < pBindingVector->Count ; ++i)
    {
		RpcBindingReset( pBindingVector->BindingH[i] );
    }

	/*
		Implemention notes (TTD):

	   1.	This call SHOULD be conditional based upon
			whether or not the AceServer name has previously been exported,
			just in case the Digital Cell Directory name service is used
			(i.e. too much redundant net traffic could be generated by this call?
	
		2.	The pszAceServerEntryName should be user configurable
			(upon AceServer installation)?
	*/
	status = RpcNsBindingExport(RPC_C_NS_SYNTAX_DCE, 	
								pszDefaultEntryName, 	
								RPC_ACE_v1_0_s_ifspec, 	
								pBindingVector,
								NULL );
    if (status) {
        exit(status);
    }

	status = RpcServerRegisterIf( RPC_ACE_v1_0_s_ifspec, NULL, NULL ) ;
	
    if (status) {
        exit(status);

    }

	status = RpcServerListen(cMinCalls,
                             cMaxCalls,
                             fDontWait);
    if (status) {
        exit(status);
    }
}
	
void stopDCEServer(void)
{
    RPC_STATUS status;
  
    status = RpcMgmtStopServerListening(NULL);
 
    if (status) {
       exit(status);
    }
 
    status = RpcServerUnregisterIf( RPC_ACE_v1_0_s_ifspec,
									NULL, FALSE);
    if (status) {
       exit(status);
    }

	status = RpcEpUnregister( RPC_ACE_v1_0_s_ifspec,
							  pBindingVector, 	
							  NULL );
    if (status) {
       exit(status);
    }

	status = RpcBindingVectorFree( &pBindingVector ) ;

    if (status) {
        exit(status);
    }

/* This call should only be used for permanently removing the 
   service from the DCE/RPC Name Service database?

	status = RpcNsBindingUnexport(	RPC_C_NS_SYNTAX_DEFAULT, 	
									pszAceServerEntryName, 	
									RPC_ACE_v1_0_s_ifspec, 
									NULL );
    if (status) {
        exit(status);
    }
*/

} //end stopDCEServer()


/*
** Remote version for DCE "ace_server"
*/

extern Stack processQueries (int *ip, int *magicp, char *cp, int maxBytes, int *enc) ; 

// ace_reponse *ace_server_1 (ace_data *question, struct svc_req *rqstp)

void ace_server( handle_t IDL_handle, LP_ACE_DATA ace_data,
                 error_status_t	*ace_rpc_status ) 
{
	Stack s ;
	unsigned char *cp ;
	long nn ;
	RPC_STATUS status ;
	int clientId = ace_data->clientId ;
	int magic = ace_data->magic ;
	int encore ;
	int maxBytes = (int)(ace_data->kBytes * 1024);

	/* Assume success at start */
	*ace_rpc_status = 0 /* error_status_ok/ESUCCESS (?) */ ;
	encore = - ace_data->encore ;  /* sign is inverted to allow overloading */

	s = processQueries (&clientId, &magic, ace_data->question, maxBytes, &encore) ; 

	nn = s && stackMark(s) ? stackMark(s) : 100 ;
	/* stackMrk == 0 happens if we write to a file and are in the encore case */

	cp = (unsigned char *)RpcSmAllocate( sizeof(unsigned char)*(nn + 1), &status ) ;	
	if (status == RPC_S_OK)
	{
		*(cp + nn) = 0 ;
		if (s &&  stackMark(s))
			memcpy (cp, stackText(s,0), nn) ;
		else 
		{ 
			if (!s)
			{
				strcpy(cp,"// Sorry, broken connection, possibly due to client time out") ;
			}
			else 
				strcpy(cp,"// ") ;
		}
	}
	else
	{
		cp = (unsigned char *)RpcSmAllocate( sizeof(unsigned char)*300, &status ) ;	
		if (status == RPC_S_OK)
		{
			sprintf(cp, "%s%d%s\n%s\n",
			   "//! Sorry, the answer is too long (",stackMark (s)," kilobytes),",
			   "//! I can\'t mallocate a sufficient buffer." ) ;
			*ace_rpc_status = ENOMEM ; /* signal an "out of memory" error? */ ;
		}
		else
		{
			cp = NULL ; /* a real memory allocation problem!!! */
		}
	}

	ace_data->reponse = cp ;
	ace_data->clientId = clientId ;
	ace_data->magic = magic ;
	ace_data->encore = encore; /* let client know if you have more */
}

/********* end of file ********/

