/*
  CoreLinux++ 
  Copyright (C) 2000 CoreLinux Consortium
  
   The CoreLinux++ Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.

   The CoreLinux++ Library Library is distributed in the hope that it will 
   be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public
   License along with the GNU C Library; see the file COPYING.LIB.  If not,
   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.  
*/   

/** \example examp21s.cpp

   This example is the server for showing the use of the SemaphoreCommon 
   cross process shared groups.
   
   What it does is start up, initialize the shared memory IPC and wait
   for a client to go live. It then waits on a semaphore for receiving
   input from the client.
   
*/                   

#if   !defined(__EX21_HPP)
#include <ex21.hpp>
#endif

#include <iostream>
#include <exception>

extern "C"
{
   #include <unistd.h>
}

//
// In module function prototypes
//

int   main( int argc, char *argv[] );

//
// General Functions 
//

using namespace corelinux;
using namespace std;

void  handleAssertion( AssertionCref );
void  handleException( ExceptionCref );

//
// Type declarations
//

const Int   POOLSIZE(256);

//
// Main entry point
//


int   main( int argc, char *argv[] )
{

   cout << endl;

   //
   // Practice graceful exception management
   //


   try
   {
      bool                    keepGoing(true);

      MutexSemaphoreGroupPtr  aControlGroup( NULLPTR );
      AbstractSemaphore       *aServerSem( NULLPTR );
      AbstractSemaphore       *aClientSem( NULLPTR );
      MemoryStoragePtr        aTransfer( NULLPTR );
      TransferBlockPtr        aBlock( NULLPTR );

      try
      {
         aControlGroup = new MutexSemaphoreGroup
            (
               2,
               theSemName,
               OWNER_ALL|GROUP_ALL|PUBLIC_ALL,FAIL_IF_EXISTS
            );

         aTransfer = Memory::createStorage
                     (
                        theMemName,
                        POOLSIZE,
                        FAIL_IF_EXISTS,
                        OWNER_ALL | GROUP_ALL | PUBLIC_ALL 
                     );

         aBlock = TransferBlockPtr( *aTransfer );

         aBlock->theTotalSize = POOLSIZE - sizeof(TransferBlock);
         aBlock->theEntrySize = 0;

         aServerSem = aControlGroup->createLockedSemaphore
            (
               theServerSemId,
               FAIL_IF_EXISTS
            );

         aClientSem = aControlGroup->createSemaphore
            (
               theClientSemId,
               FAIL_IF_EXISTS
            );

         cout << "Server process has lock " << endl;
         cout << "Waiting for client to become active." << endl;

         while( aClientSem->isLocked() == false )
         {
            sleep(1);
         }

         cout << "A client has arrived!" << endl;

         aServerSem->release();

         cout << "Waiting for client input" << endl;

         do
         {

            aClientSem->lockWithWait();

            cout  << "Server has control" << endl;

            //
            // Read length, read memory
            //

            if( aBlock->theEntrySize != 0 )
            {
               cout << "Client sent " << aBlock->theData << endl;
               aServerSem->release();
            }
            else
            {
               cout << "Client sent exit request." << endl;
               keepGoing = false;
            }

         } while( keepGoing == true );

         aServerSem->release();
         aControlGroup->destroySemaphore( aServerSem );
         aServerSem = NULLPTR;
         aControlGroup->destroySemaphore( aClientSem );
         aClientSem = NULLPTR;
         Memory::destroyStorage( aTransfer );
         aTransfer = NULLPTR;
      }

      catch( SemaphoreExceptionRef aSemExcp )
      {
         cerr << "Semaphore Exception Received" << endl;
         handleException(aSemExcp);
      }
      catch( AssertionRef aAssert )
      {
         handleAssertion(aAssert);
      }
      catch( ExceptionRef aException )
      {
         handleException(aException);
      }
      catch(...)
      {
         cerr << "Unknown exception received" << endl;
      }

      cout << "Server process exiting." << endl;

      if( aTransfer != NULLPTR )
      {
         Memory::destroyStorage( aTransfer );
         aTransfer = NULLPTR;
      }
      else
      {
         ;  // do nothing
      }

      if( aControlGroup != NULLPTR )
      {
         if( aServerSem != NULLPTR )
         {
            aControlGroup->destroySemaphore( aServerSem );
            aServerSem = NULLPTR;
         }
         else
         {
            ;  // do nothing
         }

         if( aClientSem != NULLPTR )
         {
            aControlGroup->destroySemaphore( aClientSem );
            aClientSem = NULLPTR;
         }
         else
         {
            ;  // do nothing
         }

         delete aControlGroup;
      }
   }

   catch( NullPointerException aException )
   {
      cerr  << "Received NullPointerException!" << endl;
      handleException(aException);
   }
   catch( AssertionRef aAssert )
   {
      handleAssertion(aAssert);
   }
   catch( ExceptionRef aException )
   {
      handleException(aException);
   }
   catch( std::exception & e )
   {
      cerr  << e.what() << endl;
   }
   catch( ... )
   {
      cerr  << "Unknown exception." << endl;
   }

   return 0;               
}

//
// Some utility functions
//

//
// Error handlers
//

void  handleAssertion( AssertionCref aAssert )
{
   cerr << aAssert.getFile() << ":" << aAssert.getLine() << ":" << 
      "Assertion: ";

   if( aAssert.getType() == Assertion::NEVERGETHERE )
   {
      cerr << "NEVER_GET_HERE";
   }
   else
   {
      if( aAssert.getType() == Assertion::REQUIRE )
      {
         cerr  << "REQUIRE";
      }
      else if( aAssert.getType() == Assertion::ENSURE )
      {
         cerr  << "ENSURE";
      }
      else if( aAssert.getType() == Assertion::CHECK )
      {
         cerr  << "CHECK";
      }
      else 
      {
         cerr  << "ASSERT";
      }
      cerr << "( " << aAssert.getWhy() << " )";
   }

   cerr << endl;
}

void  handleException( ExceptionCref aExcp )
{
   cerr << aExcp.getFile() << ":" << aExcp.getLine() << ":" <<
      "Exception: " << aExcp.getWhy() << endl;
}

/*
   Common rcs information do not modify
   $Author: prudhomm $
   $Revision: 1.5 $
   $Date: 2000/08/31 22:49:01 $
   $Locker:  $
*/


