PIPEC.C

/************************************************************************* 
Copyright Microsoft Corp. 1992-1996
Remote Machine pipe sample

FILE : pipec.c

USAGE : client <local file> <new file> [options]
-s Scramble file
-u Unscramble the file
-n network_address
-p protocol_sequence
-e endpoint
-o options

PURPOSE : Client side of the RPC distributed application pipes.

COMMENTS : This program shows the client side an application that
transfers a file from the client to the server, using
pipes. When the file is received at the server it
"encodes" the data by incrementing all the characters,
and sends the "encoded" file back to the client.

Since this program uses the implicit binding method,
some of the binding handling must be done at the client
side
*************************************************************************/
#include "pipe.h" // Generated by the MIDL compiler
#include "common.h" // Common definitions

#define CLIENT_BUFFER_SIZE 500 // Can send or recieve 500 elements

// Client side global variables
pipe_state in_out_pipe_state; // Pipe state on the client side
_TUCHAR pcClientBuffer[CLIENT_BUFFER_SIZE]; // Buffer used in PipeAlloc


/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* Procedure : void Usage(_TUCHAR *) */
/* Desc : This procedure prints out an error message if the */
/* command line arguments are wrong */
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void Usage(_TUCHAR * pszProgramName)
{
_tprintf(TEXT("USAGE : %s <local_file> <new_file> [-option]\n"),
pszProgramName);
_tprintf(TEXT("Options : -s\tTo encode the file\n"));
_tprintf(TEXT(" -u\tTo Decode the file\n"));
_tprintf(TEXT(" -n\t<Network Address>\n"));
_tprintf(TEXT(" -p\t<Protocol Sequence>\n"));
_tprintf(TEXT(" -e\t<Endpoint>\n"));
_tprintf(TEXT(" -o\t<Options>\n"));
exit(EXECUTION_FAILED);
}


/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* Procedure : PipeAlloc */
/* Desc : This procedure allocates a chunck of memory and */
/* returns a pointer to it. */
/* In this sample the Alloc routine returns a pointer */
/* to the same global allocated memory every time. */
/* This can be done since after each Pull/Push, data */
/* is read/written to file. */
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void PipeAlloc(
char *pcStateInfo, // The state structure
unsigned long nReqSize, // Req. size of buffer in bytes
_TUCHAR **pcAllocatedBuffer,// Pointer to the allocated buffer
unsigned long *pnAllocatedSize) // Size of allocated buf. in bytes
{
// Since the memory is already allocated, just return a pointer to it
if(nReqSize > (CLIENT_BUFFER_SIZE * sizeof(_TUCHAR)))
{
*pnAllocatedSize = CLIENT_BUFFER_SIZE * sizeof(_TUCHAR);
}
else
{
*pnAllocatedSize = nReqSize;
}
*pcAllocatedBuffer = pcClientBuffer;
}


/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* Procedure : PipePull */
/* Desc : This procedure is called by the stub when its ready */
/* to send a chunck of the pipe to the server. */
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void PipePull(
char *pcStateInfo, // The state struct on client side
_TUCHAR *pcBuffer, // Pointer to the buffer
unsigned long nMaxBufferSize, // Size of buffer in elements
unsigned long *pnSizeToSend) // Number of elements put in buffer
{
// Declare a state variable
pipe_state*psState = (pipe_state *) pcStateInfo;

// Open the local file, if it is not already opened
if(psState->hOld == NULL)
{
if(NULL == (psState->hOld =
_tfopen(psState->pszOldName, TEXT("rt"))))
{
_tprintf(TEXT("Could not open the file %s\n"),
psState->pszOldName);
exit(EXECUTION_FAILED);
}
}

// Read max_buffer_size into the buffer
*pnSizeToSend = fread(
pcBuffer,
sizeof(_TUCHAR),
nMaxBufferSize,
psState->hOld);

if(*pnSizeToSend == 0) // When end of the data is reached
{ // cleanup the application
fclose(psState->hOld);
psState->hOld = NULL;
}
}


/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* Procedure : PipePush */
/* Desc : This procedure is called by the stub when a chunck */
/* of data is received from the server. */
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void PipePush(
char *nStateInfo, // State structure on client side
_TUCHAR *pcBuffer, // Ptr to the buffer with the data
unsigned long nNumberOfElements) // Number of elements in the buffer
{
// Declare a state variable
pipe_state*psState = (pipe_state *) nStateInfo;

// Open the New file, if it is not already opened
if(psState->hNew == NULL)
{
if(NULL == (psState->hNew =
_tfopen(psState->pszNewName, TEXT("w"))))
{
_tprintf( TEXT("Unable to create the file %s\n"),
psState->pszNewName);
exit(EXECUTION_FAILED);
}
}


// When number of elements received is 0, this is the end of the pipe
if(nNumberOfElements == 0)
{
// Clean up by closing the opened file
fclose (psState->hNew);
psState->hNew = NULL;
}
else
{
// Write the buffer to the file
fwrite(pcBuffer, sizeof(_TUCHAR), nNumberOfElements, psState->hNew);
}
}


/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* Client side main program */
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int _CRTAPI1 main(int argc, char *argv[])
{
RPC_STATUS nStatus; // Status returned from RPC-calls
CHAR_PIPE_TYPE in_out_pipe; // Pipe structure used for the pipe
TCHAR
*pszOldFileName, // Name of the input file
*pszNewFileName; // Name of the output file
unsigned long
nAction = SCRAMBLE, // Scramble / Unscramble file
nIdx, // Counter in loops
nNumArgs; // The number of args from the command line

// These variables are used for the implicit binding
_TUCHAR*pszUuid= NULL;
_TUCHAR*pszProtocolSequence= PROTOCOL_SEQUENCE;
_TUCHAR*pszNetworkAddress= NULL;
_TUCHAR*pszEndpoint= END_POINT;
_TUCHAR*pszOptions= NULL;
_TUCHAR*pszStringBinding= NULL;


// Get a common handle on the command line arguments for both
// UNICODE and ASCII
#ifdef _UNICODE
LPWSTR*szArglist= CommandLineToArgvW(GetCommandLine(), &nNumArgs);
if (NULL == szArglist)
{
_tprintf(TEXT("SERVER.C : CommandLineToArgW failed"));
exit(EXECUTION_FAILED);
}
#else
char **szArglist= argv;
nNumArgs = argc;
#endif

// Check to see that the call was correct
if (nNumArgs < 3)
{
Usage(szArglist[0]);
}

// Allow the user to override settings with commandline switches
for (nIdx = 3; nIdx < nNumArgs; nIdx++)
{
if ((_tcscmp(szArglist[nIdx], TEXT("-n")) == 0) ||
(_tcscmp(szArglist[nIdx], TEXT("-N")) == 0))
{
pszNetworkAddress = szArglist[++nIdx];
}
else if((_tcscmp(szArglist[nIdx], TEXT("-p")) == 0) ||
(_tcscmp(szArglist[nIdx], TEXT("-P")) == 0))
{
pszProtocolSequence = szArglist[++nIdx];
}
else if((_tcscmp(szArglist[nIdx], TEXT("-e")) == 0) ||
(_tcscmp(szArglist[nIdx], TEXT("-e")) == 0))
{
pszEndpoint = szArglist[++nIdx];
}
else if((_tcscmp(szArglist[nIdx], TEXT("-o")) == 0) ||
(_tcscmp(szArglist[nIdx], TEXT("-O")) == 0))
{
pszOptions = szArglist[++nIdx];
}
else if((_tcscmp(szArglist[nIdx], TEXT("-s")) == 0) ||
(_tcscmp(szArglist[nIdx], TEXT("-S")) == 0))
{
nAction = SCRAMBLE;
}
else if((_tcscmp(szArglist[nIdx], TEXT("-u")) == 0) ||
(_tcscmp(szArglist[nIdx], TEXT("-U")) == 0))
{
nAction = UNSCRAMBLE;
}
else
{
Usage(szArglist[0]);
}
}

// Allocate space for the filenames
if(NULL == (pszOldFileName= (TCHAR *) midl_user_allocate(
sizeof(TCHAR) * (_tcsclen(szArglist[1]) + 1))))
{
_tprintf(TEXT("Memory allocation error\n"));
exit(EXECUTION_FAILED);
}
if(NULL == (pszNewFileName= (TCHAR *) midl_user_allocate(
sizeof(TCHAR) * (_tcsclen(szArglist[2]) + 1))))
{
_tprintf(TEXT("Memory allocation error\n"));
exit(EXECUTION_FAILED);
}

// Initialize the state variables for the in pipe
_tcscpy(pszOldFileName, szArglist[1]);
_tcscpy(pszNewFileName, szArglist[2]);

// Since we are doing implicit binding, we need to initialize the
// global varaible global_pipe_sample_handle from the client.
// Use a function to concatenate the elements of the string
// binding into the proper sequence
nStatus = RpcStringBindingCompose(
pszUuid,
pszProtocolSequence,
pszNetworkAddress,
pszEndpoint,
pszOptions,
&pszStringBinding);
EXIT_IF_FAIL(nStatus, "RpcStringBindingCompose");

// Set the binding handle that will be used to bind to the server
nStatus = RpcBindingFromStringBinding(
pszStringBinding,
&global_pipe_sample_handle); // The global handle
EXIT_IF_FAIL(nStatus, "RpcBindingFromStringBinding");


/* Initialize pipestructure */
in_out_pipe_state.hOld = NULL;
in_out_pipe_state.hNew = NULL;
in_out_pipe_state.pszOldName = pszOldFileName;
in_out_pipe_state.pszNewName = pszNewFileName;

in_out_pipe.state= (char *) &in_out_pipe_state;
in_out_pipe.alloc= PipeAlloc;
in_out_pipe.pull= PipePull;
in_out_pipe.push= PipePush;

RpcTryExcept
{
// Call the remote procedure to send the file to remote machine
_tprintf(TEXT("Calling the remote procedure ScrambleFile()\n"));
ScrambleFile(nAction, &in_out_pipe);
_tprintf(TEXT("Call to ScrambleFile() returned\n"));
}
RpcExcept(DO_EXCEPTION)
{
_tprintf(TEXT("Run-time exception %08X = %d in %s\n"),
RpcExceptionCode(), RpcExceptionCode(), TEXT(__FILE__));
exit(EXECUTION_FAILED);
}
RpcEndExcept


// Deallocate the memory used for the names in the state variable
midl_user_free(pszOldFileName);
midl_user_free(pszNewFileName);

// Deallocate the memory used for the ARGLIST if using UNICODE
#ifdef _UNICODE
if (NULL != szArglist)
free(szArglist);
#endif

// Shut down the server
ShutDown();

return (EXECUTION_OK);
}


/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* Procedure : midl_user_allocate() and midl_user_free() */
/* Desc. : These procedure are declared in the header file */
/* generated by the midl compiler. These procedures */
/* should be used for all memory allocation and */
/* deallocation. */
/* These procedures are also called by the stub code to*/
/* allocate and free memory. */
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void __RPC_FAR * __RPC_API midl_user_allocate(size_t nLen)
{
return (malloc(nLen));
}

void __RPC_API midl_user_free(void __RPC_FAR * lpvPointer)
{
if(NULL == lpvPointer)
{
free (lpvPointer);
}
}