2006-11-13 05:05:01 +01:00
|
|
|
/***********************************************************************
|
|
|
|
*
|
|
|
|
* 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"
|
|
|
|
#include "remoteendpoint.h"
|
|
|
|
#include <assert.h> // Ensure that NDEBUG is defined for release builds!
|
|
|
|
|
|
|
|
//===[ External data ]=====================================================
|
|
|
|
|
|
|
|
//===[ External prototypes ]===============================================
|
|
|
|
|
|
|
|
//===[ Manifest constants ]================================================
|
|
|
|
|
|
|
|
#define REMOTE_ENDPOINT_SIGNATURE 0X50454D52 // RMEP
|
|
|
|
|
|
|
|
//===[ Type definitions ]==================================================
|
|
|
|
|
|
|
|
//===[ Function prototypes ]===============================================
|
|
|
|
|
|
|
|
//===[ Global variables ]==================================================
|
|
|
|
|
|
|
|
//===[ Type definitions ]==================================================
|
|
|
|
|
|
|
|
//===[ Function prototypes ]===============================================
|
|
|
|
|
|
|
|
//===[ Global variables ]==================================================
|
|
|
|
|
|
|
|
//
|
|
|
|
// Object Counters
|
|
|
|
//
|
|
|
|
unsigned long numRemoteEndPointObjects = 0;
|
|
|
|
|
|
|
|
|
|
|
|
//++=======================================================================
|
|
|
|
RemoteEndPoint::RemoteEndPoint(
|
|
|
|
bool multithreaded,
|
|
|
|
int maxRpcRetries,
|
|
|
|
char *pSocketFileName) :
|
|
|
|
|
|
|
|
m_signature (REMOTE_ENDPOINT_SIGNATURE),
|
|
|
|
m_numChannelSubmits (0),
|
|
|
|
m_maxRpcRetries (maxRpcRetries)
|
|
|
|
//
|
|
|
|
// Arguments:
|
|
|
|
//
|
|
|
|
// Returns:
|
|
|
|
//
|
|
|
|
// Abstract:
|
|
|
|
//
|
|
|
|
// Notes:
|
|
|
|
//
|
|
|
|
// L2
|
|
|
|
//=======================================================================--
|
|
|
|
{
|
2006-11-15 07:32:25 +01:00
|
|
|
DbgTrace(1, "RemoteEndPoint::RemoteEndPoint- Start, Obj = %0X\n", this);
|
2006-11-13 05:05:01 +01:00
|
|
|
|
2006-12-08 06:45:03 +01:00
|
|
|
// Verify that the specified path is not too long
|
|
|
|
if (strlen(pSocketFileName) < sizeof(sizeof(m_serverUnAddr.sun_path)))
|
|
|
|
{
|
|
|
|
// Initialize our mutex
|
|
|
|
pthread_mutex_init(&m_mutex, NULL);
|
|
|
|
|
|
|
|
// Set the necessary information in the m_serverUnAddr variable
|
|
|
|
m_serverUnAddr.sun_family = AF_UNIX;
|
|
|
|
strncpy(m_serverUnAddr.sun_path, pSocketFileName, sizeof(m_serverUnAddr.sun_path) - 1);
|
|
|
|
|
|
|
|
// Set the necessary flags to indicate that DOMAIN sockets
|
|
|
|
// should be used for communications.
|
|
|
|
m_Use_PF_UNIX = true;
|
|
|
|
m_Use_AF_INET = false;
|
|
|
|
|
|
|
|
// Setup the number of channels that we may have based on
|
|
|
|
// whether the application is multi-threaded or not.
|
|
|
|
if (multithreaded)
|
|
|
|
m_numCChannels = MAX_CHANNELS_PER_ENDPOINT;
|
|
|
|
else
|
|
|
|
m_numCChannels = 1;
|
|
|
|
|
|
|
|
// Instantiate entries in SmartCChannel vector
|
|
|
|
try {
|
|
|
|
for (int i = 0; i < m_numCChannels; i++)
|
|
|
|
m_cchannelVector.push_back(SmartCChannelPointer());
|
|
|
|
} catch (...) {
|
|
|
|
DbgTrace(0, "RemoteEndPoint::RemoteEndPoint- Exception caught while initializing the cchannelVector\n", 0);
|
|
|
|
pthread_mutex_destroy(&m_mutex);
|
|
|
|
throw bad_alloc();
|
|
|
|
}
|
|
|
|
}
|
2006-11-13 05:05:01 +01:00
|
|
|
else
|
2006-12-08 06:45:03 +01:00
|
|
|
{
|
|
|
|
DbgTrace(0, "RemoteEndPoint::RemoteEndPoint- Socket file path name too long\n", 0);
|
2006-11-13 05:05:01 +01:00
|
|
|
throw bad_alloc();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Increment the object count
|
|
|
|
InterlockedIncrement(&numRemoteEndPointObjects);
|
|
|
|
|
|
|
|
DbgTrace(1, "RemoteEndPoint::RemoteEndPoint- End\n", 0);
|
|
|
|
|
|
|
|
} /*-- RemoteEndPoint::RemoteEndPoint() --*/
|
|
|
|
|
|
|
|
|
|
|
|
//++=======================================================================
|
|
|
|
RemoteEndPoint::RemoteEndPoint(
|
|
|
|
bool multithreaded,
|
|
|
|
int maxRpcRetries,
|
|
|
|
unsigned short int port,
|
|
|
|
uint32_t address) :
|
|
|
|
|
|
|
|
m_signature (REMOTE_ENDPOINT_SIGNATURE),
|
|
|
|
m_numChannelSubmits (0),
|
|
|
|
m_maxRpcRetries (maxRpcRetries)
|
|
|
|
//
|
|
|
|
// Arguments:
|
|
|
|
//
|
|
|
|
// Returns:
|
|
|
|
//
|
|
|
|
// Abstract:
|
|
|
|
//
|
|
|
|
// Notes:
|
|
|
|
//
|
|
|
|
// L2
|
|
|
|
//=======================================================================--
|
|
|
|
{
|
2006-11-15 07:32:25 +01:00
|
|
|
DbgTrace(1, "RemoteEndPoint::RemoteEndPoint- Start, Obj = %0X\n", this);
|
2006-11-13 05:05:01 +01:00
|
|
|
|
|
|
|
// Initialize our mutex
|
|
|
|
pthread_mutex_init(&m_mutex, NULL);
|
|
|
|
|
|
|
|
// Set the necessary information in the serverInAddr variable
|
|
|
|
m_serverInAddr.sin_family = AF_INET;
|
|
|
|
m_serverInAddr.sin_port = htons(port);
|
|
|
|
m_serverInAddr.sin_addr.s_addr = htonl(address);
|
|
|
|
|
|
|
|
// Set the necessary flags to indicate that TCP sockets
|
|
|
|
// should be used for communications.
|
|
|
|
m_Use_AF_INET = true;
|
|
|
|
m_Use_PF_UNIX = false;
|
|
|
|
|
|
|
|
// Setup the number of channels that we may have based on
|
|
|
|
// whether the application is multi-threaded or not.
|
|
|
|
if (multithreaded)
|
|
|
|
m_numCChannels = MAX_CHANNELS_PER_ENDPOINT;
|
|
|
|
else
|
|
|
|
m_numCChannels = 1;
|
|
|
|
|
|
|
|
// Instantiate entries in SmartCChannel vector
|
|
|
|
try {
|
|
|
|
for (int i = 0; i < m_numCChannels; i++)
|
|
|
|
m_cchannelVector.push_back(SmartCChannelPointer());
|
|
|
|
} catch (...) {
|
|
|
|
DbgTrace(0, "RemoteEndPoint::RemoteEndPoint- Exception caught while initializing the cchannelVector\n", 0);
|
2006-12-08 06:45:03 +01:00
|
|
|
pthread_mutex_destroy(&m_mutex);
|
2006-11-13 05:05:01 +01:00
|
|
|
throw bad_alloc();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Increment the object count
|
|
|
|
InterlockedIncrement(&numRemoteEndPointObjects);
|
|
|
|
|
|
|
|
DbgTrace(1, "RemoteEndPoint::RemoteEndPoint- End\n", 0);
|
|
|
|
|
|
|
|
} /*-- RemoteEndPoint::RemoteEndPoint() --*/
|
|
|
|
|
|
|
|
|
|
|
|
//++=======================================================================
|
|
|
|
RemoteEndPoint::~RemoteEndPoint(void)
|
|
|
|
//
|
|
|
|
// Arguments:
|
|
|
|
//
|
|
|
|
// Returns:
|
|
|
|
//
|
|
|
|
// Abstract:
|
|
|
|
//
|
|
|
|
// Notes:
|
|
|
|
//
|
|
|
|
// L2
|
|
|
|
//=======================================================================--
|
|
|
|
{
|
2006-11-15 07:32:25 +01:00
|
|
|
DbgTrace(1, "RemoteEndPoint::~RemoteEndPoint- Start, Obj = %0X\n", this);
|
2006-11-13 05:05:01 +01:00
|
|
|
|
|
|
|
// Clean up all allocated SmartCChannel objects
|
|
|
|
for (int i = 0; i < m_cchannelVector.size(); i++)
|
|
|
|
{
|
|
|
|
if (m_cchannelVector[i].getPointer() != NULL)
|
|
|
|
{
|
|
|
|
CChannel *pCChannel = *(m_cchannelVector[i].getPointer());
|
|
|
|
pCChannel->closeChannel();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_cchannelVector.clear();
|
|
|
|
|
|
|
|
// Decrement the object count
|
|
|
|
InterlockedDecrement(&numRemoteEndPointObjects);
|
|
|
|
|
|
|
|
DbgTrace(1, "RemoteEndPoint::~RemoteEndPoint- End\n", 0);
|
|
|
|
|
|
|
|
} /*-- RemoteEndPoint::~RemoteEndPoint() --*/
|
|
|
|
|
|
|
|
|
|
|
|
//++=======================================================================
|
|
|
|
SmartCChannel*
|
|
|
|
RemoteEndPoint::getCChannel(void)
|
|
|
|
//
|
|
|
|
// Arguments:
|
|
|
|
//
|
|
|
|
// Returns:
|
|
|
|
//
|
|
|
|
// Abstract:
|
|
|
|
//
|
|
|
|
// Notes:
|
|
|
|
//
|
|
|
|
// L2
|
|
|
|
//=======================================================================--
|
|
|
|
{
|
|
|
|
SmartCChannel *pSmartCChannel = NULL;
|
|
|
|
int channelSelector = (m_numChannelSubmits++) % m_numCChannels;
|
|
|
|
|
2006-11-15 07:32:25 +01:00
|
|
|
DbgTrace(1, "RemoteEndPoint::getCChannel- Start, Obj = %0X\n", this);
|
2006-11-13 05:05:01 +01:00
|
|
|
|
|
|
|
#if DEBUG
|
|
|
|
assert(m_signature == REMOTE_ENDPOINT_SIGNATURE);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Obtain our mutex
|
|
|
|
pthread_mutex_lock(&m_mutex);
|
|
|
|
|
|
|
|
// Check if there is an available and usable channel for the client
|
|
|
|
if (m_cchannelVector[channelSelector].getPointer() != NULL
|
|
|
|
&& (*m_cchannelVector[channelSelector].getPointer())->ok())
|
|
|
|
{
|
|
|
|
// Use the available channel
|
|
|
|
pSmartCChannel = new SmartCChannel(*m_cchannelVector[channelSelector].getPointer());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// The channel is either unavailable or unusable, clean up
|
|
|
|
// the channel if it is indeed unusable.
|
|
|
|
if (m_cchannelVector[channelSelector].getPointer() != NULL)
|
|
|
|
{
|
|
|
|
// Clean up the channel
|
|
|
|
CChannel *pCChannel = *m_cchannelVector[channelSelector].getPointer();
|
|
|
|
pCChannel->closeChannel();
|
|
|
|
delete m_cchannelVector[channelSelector].getPointer();
|
|
|
|
m_cchannelVector[channelSelector].setPointer(NULL);
|
|
|
|
}
|
|
|
|
|
2006-12-08 06:45:03 +01:00
|
|
|
CChannel *pCChannel = NULL;
|
2006-11-13 05:05:01 +01:00
|
|
|
try {
|
|
|
|
|
|
|
|
// Use the appropriate server address when instantiating
|
|
|
|
// the CChannel object.
|
|
|
|
if (m_Use_PF_UNIX)
|
|
|
|
{
|
|
|
|
// PF_UNIX
|
|
|
|
pCChannel = new CChannel(&m_serverUnAddr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Assume AF_INET
|
|
|
|
pCChannel = new CChannel(&m_serverInAddr);
|
|
|
|
}
|
|
|
|
|
|
|
|
// CChannel object created, now associate a SmartCChannel
|
|
|
|
// object with it. It is important to do this to keep
|
|
|
|
// the object from being deleted as we initialize it.
|
|
|
|
m_cchannelVector[channelSelector].setPointer(new SmartCChannel(pCChannel));
|
|
|
|
|
|
|
|
// Initialize the CChannel
|
|
|
|
if (pCChannel->init() == 0)
|
|
|
|
{
|
|
|
|
// CChannel initialization succeeded, use it to
|
|
|
|
// satisfy the caller.
|
|
|
|
pSmartCChannel = new SmartCChannel(*m_cchannelVector[channelSelector].getPointer());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// CChannel initialization failed
|
|
|
|
delete m_cchannelVector[channelSelector].getPointer();
|
|
|
|
m_cchannelVector[channelSelector].setPointer(NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (...) {
|
|
|
|
DbgTrace(0, "getCChannel- Exception caught\n", 0);
|
|
|
|
|
|
|
|
// Try to clean things up just in case
|
|
|
|
if (m_cchannelVector[channelSelector].getPointer())
|
|
|
|
{
|
|
|
|
delete m_cchannelVector[channelSelector].getPointer();
|
|
|
|
m_cchannelVector[channelSelector].setPointer(NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (pCChannel != NULL)
|
|
|
|
delete pCChannel;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release client mutex
|
|
|
|
pthread_mutex_unlock(&m_mutex);
|
|
|
|
|
|
|
|
DbgTrace(1, "RemoteEndPoint::getCChannel- End\n", 0);
|
|
|
|
|
|
|
|
return pSmartCChannel;
|
|
|
|
|
|
|
|
} /*-- RemoteEndPoint::getCChannel() --*/
|
|
|
|
|
|
|
|
|
|
|
|
//++=======================================================================
|
|
|
|
int
|
|
|
|
RemoteEndPoint::submitReq(
|
|
|
|
char *pClientData,
|
2006-12-08 06:45:03 +01:00
|
|
|
int32_t clientDataLen,
|
2006-11-13 05:05:01 +01:00
|
|
|
char **ppServerData,
|
2006-12-08 06:45:03 +01:00
|
|
|
int32_t *pServerDataLen)
|
2006-11-13 05:05:01 +01:00
|
|
|
//
|
|
|
|
// Arguments:
|
|
|
|
//
|
|
|
|
// Returns:
|
|
|
|
//
|
|
|
|
// Abstract:
|
|
|
|
//
|
|
|
|
// Notes:
|
|
|
|
//
|
|
|
|
// L2
|
|
|
|
//=======================================================================--
|
|
|
|
{
|
|
|
|
int retStatus = -1;
|
|
|
|
|
2006-11-15 07:32:25 +01:00
|
|
|
DbgTrace(1, "RemoteEndPoint::submitReq- Start, Obj = %0X\n", this);
|
2006-11-13 05:05:01 +01:00
|
|
|
|
|
|
|
try {
|
|
|
|
SmartCChannel *pSmartCChannel;
|
|
|
|
|
|
|
|
// Perform the following in a loop to deal with abnormal connection terminations
|
|
|
|
unsigned long rpcRetryCount = 0;
|
|
|
|
bool okToRetry = true;
|
|
|
|
while (rpcRetryCount < m_maxRpcRetries)
|
|
|
|
{
|
|
|
|
// Get SmartCChannel
|
|
|
|
pSmartCChannel = getCChannel();
|
|
|
|
if (pSmartCChannel != NULL)
|
|
|
|
{
|
|
|
|
// Get pointer to channel object
|
|
|
|
CChannel *pCChannel = *pSmartCChannel;
|
|
|
|
|
|
|
|
// Allocate a requestId
|
|
|
|
uint32_t reqId = pCChannel->allocReqId();
|
|
|
|
|
|
|
|
// Allocate client request object.
|
|
|
|
ClientReq clientReq(reqId);
|
|
|
|
|
|
|
|
// Submit the request via the channel
|
|
|
|
if (pCChannel->submitReq(reqId,
|
|
|
|
clientReq,
|
|
|
|
pClientData,
|
|
|
|
clientDataLen) == 0)
|
|
|
|
{
|
|
|
|
// Request submission over the channel succeeded, now
|
|
|
|
// wait for the completion of the request.
|
|
|
|
if (clientReq.waitForCompletion(ppServerData,
|
|
|
|
pServerDataLen) == 0)
|
|
|
|
{
|
|
|
|
// Now proceed based on the completion status
|
|
|
|
ClientReq::CompletionStatus compStatus = clientReq.completionStatus();
|
|
|
|
if (compStatus == ClientReq::SuccessCompletionStatus)
|
|
|
|
{
|
|
|
|
// Success
|
|
|
|
retStatus = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Received a failure from the server, do not retry.
|
|
|
|
okToRetry = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Error waiting for the completion.
|
|
|
|
okToRetry = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove the request from the channel
|
|
|
|
pCChannel->removeReq(reqId);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DbgTrace(0, "RemoteEndPoint::submitReq- Request submittion over the channel failed\n", 0);
|
|
|
|
|
|
|
|
// Remove the request from the channel
|
|
|
|
pCChannel->removeReq(reqId);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete the SmartCChannel
|
|
|
|
delete pSmartCChannel;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DbgTrace(0, "RemoteEndPoint::submitReq- Channel unavailable\n", 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stop trying if the RPC succeeded or if it is not ok to retry
|
|
|
|
if (retStatus == 0
|
|
|
|
|| !okToRetry)
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Account for this RPC try
|
|
|
|
rpcRetryCount ++;
|
|
|
|
DbgTrace(0, "RemoteEndPoint::submitReq- Will attempt to retry RPC, count = %d\n", rpcRetryCount);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch(...) {
|
|
|
|
|
|
|
|
DbgTrace(0, "RemoteEndPoint::submitReq- Exception caught\n", 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
DbgTrace(1, "RemoteEndPoint::submitReq- End\n", 0);
|
|
|
|
|
|
|
|
return retStatus;
|
|
|
|
|
|
|
|
} /*-- RemoteEndPoint::submitReq() --*/
|
|
|
|
|
|
|
|
|
|
|
|
//=========================================================================
|
|
|
|
//=========================================================================
|
|
|
|
|