static char const rcsid[] =
"@(#)$Id: swbsdz.c,v 1.1 2001/05/21 04:09:49 jgibbons Exp $";

/*
**               CONFIDENTIAL & PROPRIETARY INFORMATION
**              Distribution to Authorized Personnel Only
**                 Copyright (c) 2001 Protogate, Inc.
**                        All Rights Reserved
**
** This document contains confidential and proprietary information of
** Protogate, Inc, ("Protogate") and is protected by copyright, trade secret
** and other state and federal laws. The possession or receipt of this
** information does not convey any right to disclose its contents, reproduce
** it, or use, or license the use, for manufacture or sale, the information
** or anything described therein. Any use, disclosure, or reproduction
** without Protogate's prior written permission is strictly prohibited.
**
** Software and Technical Data Rights
**
** Protogate software products and related documentation will be furnished
** hereunder with "Restricted Rights" in accordance with:
**
** A. Subparagraph (c)(1)(ii) of the clause entitled Rights in Technical Data
** and Computer Software (OCT 1988) located at DFARS 252.227-7013; or
**
** B. Subparagraph (c)(2) of the clause entitled Commercial Computer Software -
** Restricted Rights (JUN 1987) located at FAR 52.227.19.
*/

/****************************************************************************
*
*  FILE:         swbsdz.c
*
*  DESCRIPTION:  This file implements an example external program for use
*                with the Message Switch, as configured by the "prog:" keyword
*                in switch.cfg.  This program implements one of 2 behaviors,
*                depending on the value of the first argument: it either
*                compresses all the data it receives from the Message Switch,
*                returning the compressed data to the Message Switch, or it
*                uncompresses all the data it receives from the Message Switch,
*                returning the uncompressed data to the Message Switch.
*                If the first argument is 0 it compresses, else it
*                uncompresses.
*
*                To specify this program as an endpoint for switch
*                specifications in the switch.cfg Message Switch configuration
*                file, the endpoint should have a format like this:
*
*                  prog:swbsdz~0~maxbufsize~idstring     (for compression)
*                  prog:swbsdz~1~maxbufsize~idstring     (for uncompression)
*
*                The real first argument (the file descriptor of the pipe,
*                which is immediately after the swbsdz program name in the
*                call to this program) is not included in the endpoint
*                specification because it is inserted by the Message Switch.
*
*                The second argument is either 0 or not; if it is zero then
*                this program acts as a data compressor, else it acts as a
*                data uncompressor.
*
*                The third argument is taken as the maximum size of the
*                resulting data, in bytes.
*
*                The fourth argument is ignored by this program, but can be
*                used to differentiate between several compression streams,
*                by choosing a different idstring for each stream.  This
*                takes advantage of the fact that the Message Switch assumes
*                that each differing endpoint string should define a
*                different endpoint.
*
*  CALLING SEQUENCE:
*                arg0: swbsdz
*                arg1: the file descriptor of a pipe which connects to the
*                      Message Switch.
*                arg2: 0=compressor, else=decompressor
*                arg3: Maximum resulting buffer size, in bytes
*                arg4: id string (unused)
*
*  REVISION HISTORY:
*
*   Date      Programmer     Description
*  -------   ------------   ---------------
*  21may01   Jeff Gibbons   Original creation.
*
*****************************************************************************/

                                               /* Include files              */
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/time.h>
#include <string.h>
#include <zlib.h>
 
                                               /* Defines                    */
#define OK 0
  
                                               /* Typedefs                   */
                                               /* Global Data                */

                                               /* Local Function Prototypes  */
                                               /* Local Static Data          */
static unsigned char rcv_message[ 16384 ];
static unsigned char snd_message[ 16512 ];
                                               /* Extern Data Declarations   */
                                               /* Extern Function Prototypes */
                                               /* Function Definitions       */

/****************************************************************************
*
*  PROGRAM:      main.c
*
*  DESCRIPTION:  Main entry point for the swbsdz program.
*
*  CALLING SEQUENCE:   described above in file header.
*
*  REVISION HISTORY:
*
*   Date      Programmer     Description
*  -------   ------------   ---------------
*  21may01   Jeff Gibbons   Original creation.
*
*****************************************************************************/

int
main( int argc, char **argv )
{
   int       iFd;
   int       iBehavior;
   int       iMaxSize;
   #define RCV_MAXSIZE   (iMaxSize + 128)
   #define SND_MAXSIZE   (iMaxSize + 256)
   uLong     uRcvLen;
   uLong     uSndLen;
   int       iResult;
   fd_set    sReadFds;

   Bytef *rcv_message;
   Bytef *snd_message;

   static const char* myVersion = ZLIB_VERSION;

   if ( argc < 4 )
   {
      printf( "swbsdz: called incorrectly: calling sequence should be:\n" );
      printf( "    swbsdz \"filedescriptor\"  \"0 or 1\" "
                          " \"max result size\"  \"ident string\"\n" );
      exit( 1 );
   }
#ifdef DEBUG
   else
   {
      int  ii;
      printf( "swbsdz debug: Initializing with these arguments:\n" );
      for ( ii = 0; ii < argc; ii++ )
         printf( "  arg%d: %s.\n", ii, argv[ii] );
      printf( "\n" );
   }
#endif

   if (zlibVersion()[0] != myVersion[0])          /* major number difference */
   {
      printf( "swbsdz: ERROR: incompatible zlib version.\n" );
      printf( "swbsdz: ERROR: compiled with %s, using %s.\n",
              ZLIB_VERSION, zlibVersion() );
      exit(1);
   }
   else if ( strcmp(zlibVersion(), ZLIB_VERSION) != 0 )      /* minor # diff */
   {
      printf( "swbsdz: WARNING: different zlib version.\n" );
      printf( "swbsdz: WARNING: compiled with %s, using %s.\n",
              ZLIB_VERSION, zlibVersion() );
   }


   iFd = atoi( argv[ 1 ] );
   iBehavior = atoi( argv[ 2 ] );
   iMaxSize = atoi( argv[ 3 ] );

   if ( 65536 < iMaxSize )
   {
      printf( "swbsdz: WARNING: maxsize is too large; limiting to 65535.\n" );
      iMaxSize = 65535;
   }
   rcv_message = (Bytef *)malloc( iMaxSize + 128 );
   if ( ( NULL == ( rcv_message = (Bytef *)malloc( RCV_MAXSIZE ) ) ) ||
        ( NULL == ( snd_message = (Bytef *)malloc( SND_MAXSIZE ) ) )    )
   {
      printf( "swbsdz: ERROR: malloc failure.\n" );
      close(iFd);
      exit(1);
   }
   
   FD_ZERO( &sReadFds );

   while ( 1 )
   {
      uSndLen = iMaxSize;

      FD_SET( iFd, &sReadFds );
      select( iFd + 1, &sReadFds, NULL, NULL, NULL );

      if ( 0 > ( uRcvLen = read( iFd, rcv_message, RCV_MAXSIZE ) ))
      {
         perror( "\nERROR: swbsdz failed reading pipe: " );
         printf( "swbsdz: ERROR: failed reading pipe, errno %d.\n", errno );
         printf( "swbsdz: ERROR:   (behavior=%s size=%s id=%s err=%d).\n",
                 argv[2], argv[3], argv[4], iResult );
      }
                                  /* if arg2==0 (compressing was requested) */
      else if ( ( 0 == iBehavior ) &&
                ( Z_OK > ( iResult = compress(   snd_message,
                                                 &uSndLen,
                                                 (const Bytef *)rcv_message,
                                                 uRcvLen ) ) )              ||
                ( 0 != iBehavior ) &&
                ( Z_OK > ( iResult = uncompress( snd_message,
                                                 &uSndLen,
                                                 (const Bytef *)rcv_message,
                                                 uRcvLen ) ) )                )
      {
         printf(
          "swbsdz: ERROR: comp/uncomp failed (bhv=%s size=%s id=%s err=%d).\n",
                 argv[2], argv[3], argv[4], iResult );
                 /* compression or uncompression failed; send unaltered data */
         if ( iMaxSize < uRcvLen )
         {
            uRcvLen = iMaxSize;
         }
         if ( uRcvLen != write( iFd, rcv_message, (int)uRcvLen ) )
         {
            perror( "\nERROR: swbsdz failed writing pipe: " );
            printf( "swbsdz: ERROR: failed writing pipe, errno %d.\n",
                    errno );
            printf( "swbsdz: ERROR:  (behavior=%s size=%s id=%s err=%d).\n",
                    argv[2], argv[3], argv[4], iResult );
         }
      }
      else if ( uSndLen != write( iFd, snd_message, (int)uSndLen ) )
      {
         perror( "\nERROR: swbsdz failed writing pipe: " );
         printf( "swbsdz: ERROR: failed writing pipe, errno %d.\n", errno );
         printf( "swbsdz: ERROR:   (behavior=%s size=%s id=%s err=%d).\n",
                 argv[2], argv[3], argv[4], iResult );
      }
   }

   close(iFd);
   exit(0);
}