/***********************************************************************
 * 
 *  Copyright (C) 2006 Novell, Inc. All Rights Reserved.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; version 2.1
 *  of the License.
 *
 *  This 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 Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, Novell, Inc.
 * 
 *  To contact Novell about this file by physical or electronic mail, 
 *  you may find current contact information at www.novell.com.
 * 
 *  Author: Juan Carlos Luciani <jluciani@novell.com>
 *
 ***********************************************************************/


//===[ Include files ]=====================================================

#include "ipcint.h"
#include "cchannel.h"
#include "clientreq.h"


//===[ External data ]=====================================================

//===[ External prototypes ]===============================================

//===[ Manifest constants ]================================================

//===[ Type definitions ]==================================================

//===[ Function prototypes ]===============================================

//===[ Global variables ]==================================================

//===[ Type definitions ]==================================================

//===[ Function prototypes ]===============================================

//===[ Global variables ]==================================================

//
// Object Counters
//
unsigned long  numClientReqObjects = 0;


//++=======================================================================
ClientReq::ClientReq(
   uint32_t reqId) :

   m_reqId (reqId),
   m_pServerData (NULL),
   m_submitThreadActive (true),
   m_completed (false),
   m_internalProblem (false)
//
//  Arguments: 
//
//  Returns:   
//
//  Abstract:  
//
//  Notes:
//
// L2
//=======================================================================--
{
   DbgTrace(1, "ClientReq::ClientReq- Start, Obj = %0X\n", this);

   // Initialize the mutex
   if (pthread_mutex_init(&m_mutex, NULL) != 0)
   {
      DbgTrace(0, "ClientReq::ClientReq- Mutex initialization failed\n", 0);

      // Throw exception
      throw bad_alloc();
   }

   // Initialize the condition
   if (pthread_cond_init(&m_condition, NULL) != 0)
   {
      DbgTrace(0, "ClientReq::ClientReq- Condition initialization failed\n", 0);

      // Destroy the allocated mutex
      pthread_mutex_destroy(&m_mutex);

      // Throw exception
      throw bad_alloc();
   }

   // Increment the object count
   InterlockedIncrement(&numClientReqObjects);

   DbgTrace(1, "ClientReq::ClientReq- End\n", 0);

}  /*-- ClientReq::ClientReq() --*/


//++=======================================================================
ClientReq::~ClientReq(void)
//
//  Arguments: 
//
//  Returns:   
//
//  Abstract:  
//
//  Notes:
//
// L2
//=======================================================================--
{
   DbgTrace(1, "ClientReq::~ClientReq- Start, Obj = %0X\n", this);

   // Cleanup resources allocated for the object
   pthread_mutex_destroy(&m_mutex);
   pthread_cond_destroy(&m_condition);

   // Release any server data that we may have
   if (m_pServerData != NULL)
      free(m_pServerData);

   // Decrement the object count
   InterlockedDecrement(&numClientReqObjects);

   DbgTrace(1, "ClientReq::~ClientReq- End\n", 0);

}  /*-- ClientReq::~ClientReq() --*/


//++=======================================================================
void
ClientReq::processServerData(
   char *pServerData,
   uint32_t serverDataLength)
//
//  Arguments: 
//
//  Returns:   
//
//  Abstract:  
//
//  Notes:
//
// L2
//=======================================================================--
{
   DbgTrace(1, "ClientReq::processServerData- Start, Obj = %0X\n", this);

   // Acquire exclusive access to the object
   pthread_mutex_lock(&m_mutex);

   // Save server dataetup the ServerData object
   m_pServerData = pServerData;
   m_serverDataLen = serverDataLength;

   // Mark the request as completed
   m_completed = true;

   // Check if we must awaken the thread that submitted the request
   // so that it can service the server data.
   if (!m_submitThreadActive)
   {
      // The submit thread is not active, awaken it.
      m_submitThreadActive = true;
      pthread_cond_signal(&m_condition);
   }

   // Release exclusive access to the object
   pthread_mutex_unlock(&m_mutex);

   DbgTrace(1, "ClientReq::processServerData- End\n", 0);

}  /*-- ClientReq::processServerData() --*/


//++=======================================================================
void
ClientReq::processError(void)
//
//  Arguments: 
//
//  Returns:   
//
//  Abstract:  
//
//  Notes:
//
// L2
//=======================================================================--
{
   DbgTrace(1, "ClientReq::processError- Start, Obj = %0X\n", this);

   // Acquire exclusive access to the object
   pthread_mutex_lock(&m_mutex);

   // Record that we suffered an internal problem and mark the
   // request as completed.
   m_internalProblem = true;
   m_completed = true;

   // Check if we must awaken the thread that submitted the request
   // so that it can deal with the problem.
   if (!m_submitThreadActive)
   {
      // The submit thread is not active, awaken it.
      m_submitThreadActive = true;
      pthread_cond_signal(&m_condition);
   }

   // Release exclusive access to the object
   pthread_mutex_unlock(&m_mutex);

   DbgTrace(1, "ClientReq::processError- End\n", 0);

}  /*-- ClientReq::processError() --*/


//++=======================================================================
int
ClientReq::waitForCompletion(
   char **ppResponseData,
   uint32_t *pResponseDataLength)
//
//  Arguments: 
//
//  Returns:   
//
//  Abstract:  
//
//  Notes:
//
// L2
//=======================================================================--
{
   int                           retStatus;
   int                           oldCancelState;

   DbgTrace(1, "ClientReq::waitForCompletion- Start, Obj = %0X\n", this);

   // Make sure that the thread can not be cancelled while executing
   // in this routine.
   pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldCancelState);

   // Acquire exclusive access to the object
   pthread_mutex_lock(&m_mutex);

   // Continue until the request completes
   while (!m_completed)
   {
      // Wait to be awaken
      //
      // Indicate that we are no longer active
      m_submitThreadActive = false;
      pthread_cond_wait(&m_condition, &m_mutex);
   }

   // Release exclusive access to the object
   pthread_mutex_unlock(&m_mutex);

   // Determine the parameters that should be returned
   if (!m_internalProblem)
   {
      retStatus = 0;
      *ppResponseData = m_pServerData;
      *pResponseDataLength = m_serverDataLen;

      // Forget about the server data buffer
      m_pServerData = NULL;
   }
   else
      retStatus = -1;

   DbgTrace(1, "ClientReq::waitForCompletion- End, retStatus = %0X\n", retStatus);

   // Restore the threads cancel state
   pthread_setcancelstate(oldCancelState, NULL);

   return retStatus;

}  /*-- ClientReq::waitForCompletion() --*/


//++=======================================================================
ClientReq::CompletionStatus
ClientReq::completionStatus(void)
//
//  Arguments: 
//
//  Returns:   
//
//  Abstract:  
//
//  Notes:
//
// L2
//=======================================================================--
{
   CompletionStatus  compStatus;

   DbgTrace(1, "ClientReq::completionStatus- Start, Obj = %0X\n", this);

   // Check if we encountered any issues
   if (m_internalProblem)
   {
      compStatus = ErrorCompletionStatus;
   }
   else
   {
      compStatus = SuccessCompletionStatus;
   }

   DbgTrace(1, "ClientReq::completionStatus- End, compStatus = %0X\n", compStatus);

   return compStatus;

}  /*-- ClientReq::completionStatus() --*/


//=========================================================================
//=========================================================================