/****************************************************************************
                   Microsoft RPC Version 2.0
           Copyright Microsoft Corp. 1992, 1993, 1994
                       nhello Example

    FILE:       nsserv.c
    
    USAGE:      nsserv
                         -m maxcalls
                         -n mincalls
                         -f flag for RpcServerListen wait
                         -a nhello_sample_nsi_entry_name
                         -t name_syntax_type
    
    PURPOSE:    Server side of RPC distributed application nhello
    
    FUNCTIONS:  main() - registers server as RPC server
    
    COMMENTS:   

****************************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <tchar.h>
#include "nhello.h"   // header file generated by MIDL compiler
#include "service.h"


VOID ServiceStart (DWORD dwArgc, LPTSTR *lpszArgv)
{
    RPC_STATUS status;
    RPC_STATUS temp_status;
    RPC_BINDING_VECTOR * pBindingVector = NULL;
    unsigned char * pszEntryName    = "/.:/nhello_sample";
    unsigned char * pszSecurity     = NULL;
    unsigned int    cMinCalls       = 1;
    unsigned int    cMaxCalls       = 20;
    unsigned int    fDontWait       = 0;
    unsigned int    fNameSyntaxType = RPC_C_NS_SYNTAX_DEFAULT;
    BOOL bRegistered = FALSE;
    BOOL bEndpoint = FALSE;
    BOOL bExported = FALSE;
    BOOL bProto = FALSE;
    DWORD i;


    /* allow the user to override settings with command line switches */
    for (i = 1; i < dwArgc; i++) {
        if ((*(lpszArgv[i]) == '-') || (*(lpszArgv[i]) == '/')) {
            switch (tolower(*((lpszArgv[i])+1))) {
            case 'm':
                cMaxCalls = (unsigned int) atoi(lpszArgv[++i]);
                break;
            case 'n':
                cMinCalls = (unsigned int) atoi(lpszArgv[++i]);
                break;
            case 'f':
                fDontWait = (unsigned int) atoi(lpszArgv[++i]);
                break;
            case 'a':
                pszEntryName = lpszArgv[++i];
                break;
            case 't':
                fNameSyntaxType = (unsigned int) atoi(lpszArgv[++i]);
                break;
            }
        }
    }

    // Prepare to Use All Protseqs
    if (!ReportStatusToSCMgr(
        SERVICE_START_PENDING, // service state
        NO_ERROR,              // exit code
        30000))                // wait hint  - UseAll can take quite a while
        goto cleanup;

    printf("CallingRpcServerUseAllProtseqs...\n");

    status = RpcServerUseAllProtseqs( cMaxCalls, pszSecurity );
    printf("RpcServerUseAllProtseqs returned 0x%x\n", status);
    if (status)
        goto cleanup;

    // Prepare to Register Interface
    if (!ReportStatusToSCMgr(
        SERVICE_START_PENDING, // service state
        NO_ERROR,              // exit code
        30000))                 // wait hint
        goto cleanup;

    status = RpcServerRegisterIf(nhello_v1_0_s_ifspec, // interface to register
                                 NULL,   // MgrTypeUuid
                                 NULL);  // MgrEpv; null means use default
    printf( TEXT("RpcServerRegisterIf returned 0x%x\n"), status);
    if (status)
        goto cleanup;
    else
        bRegistered = TRUE;


    // Prepare to Inquire Bindings
    if (!ReportStatusToSCMgr(
        SERVICE_START_PENDING, // service state
        NO_ERROR,              // exit code
        30000))                // wait hint  - Inq can take quite a while
        goto cleanup;

    status = RpcServerInqBindings(&pBindingVector);
    printf( TEXT("RpcServerInqBindings returned 0x%x\n"), status);
    if (status)
        goto cleanup;


    // Prepare to Register Endpoint
    if (!ReportStatusToSCMgr(
        SERVICE_START_PENDING, // service state
        NO_ERROR,              // exit code
        45000))                // wait hint  - Inq can take quite a while
        goto cleanup;

    status = RpcEpRegister(nhello_v1_0_s_ifspec,
                           pBindingVector,
                           NULL,
                           NULL);
    printf( TEXT("RpcEpRegister returned 0x%x\n"), status);
    if (status)
        goto cleanup;
    else 
        bEndpoint = TRUE;


    // Prepare to Export to NameService
    if (!ReportStatusToSCMgr(
        SERVICE_START_PENDING, // service state
        NO_ERROR,              // exit code
        45000))                // wait hint
        goto cleanup;

    status = RpcNsBindingExport(fNameSyntaxType,  // name syntax type
                                pszEntryName,     // nsi entry name
                                nhello_v1_0_s_ifspec,
                                pBindingVector,   // set in previous call
                                NULL);            // UUID vector 
    printf( TEXT("RpcNsBindingExport returned 0x%x\n"), status);
    if (status)
        goto cleanup;
    else 
        bExported = TRUE;


    // Prepare to start listening.  At this point the service is initialized
    if (!ReportStatusToSCMgr(
        SERVICE_RUNNING, // service state
        NO_ERROR,        // exit code
        0))              // wait hint
        goto cleanup;

    printf( TEXT("Calling RpcServerListen\n"));
    status = RpcServerListen(cMinCalls,
                             cMaxCalls,
                             fDontWait );  // wait flag
    printf( TEXT("RpcServerListen returned: 0x%x\n"), status);
    if (status) {
        goto cleanup;
    }

    if (fDontWait) {
        printf("Calling RpcMgmtWaitServerListen\n");
        status = RpcMgmtWaitServerListen();  //  wait operation
        printf("RpcMgmtWaitServerListen returned: 0x%x\n", status);
    }


  cleanup:

    if ( bExported )
    {
        ReportStatusToSCMgr(
            SERVICE_STOP_PENDING,  // service state
            NO_ERROR,              // exit code
            3000);                 // wait hint  

        temp_status = RpcNsBindingUnexport(RPC_C_NS_SYNTAX_DEFAULT,  // name syntax type
                                           pszEntryName,     // nsi entry name
                                           nhello_v1_0_s_ifspec,
                                           NULL);            // UUID vector 
        printf( TEXT("RpcNsBindingUnexport returned 0x%x\n"), temp_status);
    }


    if ( bEndpoint )
    {
        ReportStatusToSCMgr(
            SERVICE_STOP_PENDING,  // service state
            NO_ERROR,              // exit code
            3000);                 // wait hint  

        temp_status = RpcEpUnregister(nhello_v1_0_s_ifspec,
                                      pBindingVector,
                                      NULL);
        printf( TEXT("RpcEpUnregister returned 0x%x\n"), temp_status);
    }

    if ( pBindingVector )
    {
        ReportStatusToSCMgr(
            SERVICE_STOP_PENDING,  // service state
            NO_ERROR,              // exit code
            3000);                 // wait hint  

        temp_status = RpcBindingVectorFree(&pBindingVector);
        printf( TEXT("RpcBindingVectorFree returned 0x%x\n"), temp_status);
    }
    
    if ( bRegistered )
    {
        ReportStatusToSCMgr(
            SERVICE_STOP_PENDING,  // service state
            NO_ERROR,              // exit code
            3000);                 // wait hint  

        temp_status = RpcServerUnregisterIf(nhello_v1_0_s_ifspec, // interface to register
                                     NULL,   // MgrTypeUuid
                                     1);     // wait for outstanding calls
        printf( TEXT("RpcServerUnregisterIf returned 0x%x\n"), temp_status);
    }

    ReportStatusToSCMgr(
        SERVICE_STOP_PENDING,  // service state
        NO_ERROR,              // exit code
        3000);                 // wait hint  


}


void ServiceStop( )
{
    RPC_STATUS status;

    ReportStatusToSCMgr(
        SERVICE_STOP_PENDING,  // service state
        NO_ERROR,              // exit code
        3000);                 // wait hint

    status = RpcMgmtIsServerListening( NULL );
    printf( TEXT("RpcMgmtIsServerListening returned 0x%x\n"), status);

    if ( status == RPC_S_OK )
        RpcMgmtStopServerListening( NULL );
        
}

/*********************************************************************/
/*                 MIDL allocate and free                            */
/*********************************************************************/

void __RPC_FAR * __RPC_USER midl_user_allocate(size_t len)
{
    return(malloc(len));
}

void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
{
    free(ptr);
}

/* end file nsserv.c */
