CASA/CASA-auth-token/server/utilities/IpcLibs/linux/client/client.cpp
Juan Carlos Luciani 572284e80f Fixed segmentation fault during ipc_client library un-initialization
caused when the RemoteEndPoint map destructor was executed before the
library destructor.
2008-01-14 20:05:36 +00:00

677 lines
20 KiB
C++

/***********************************************************************
*
* 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"
extern "C" {
#include "casa_c_ipc.h"
}
#include "cchannel.h"
#include "clientreq.h"
#include "remoteendpoint.h"
//===[ External data ]=====================================================
extern
unsigned long numCChannelObjects;
//===[ External prototypes ]===============================================
//===[ Manifest constants ]================================================
#define DEFAULT_MAX_RPC_RETRIES 3
//===[ Type definitions ]==================================================
//===[ Function prototypes ]===============================================
//===[ Global variables ]==================================================
// Debug Level
int DebugLevel = 0;
bool UseSyslog = false;
// Application Name for logging purposes
static char unInitialized[] = "Uninitialized";
char *pAppName = unInitialized;
// Application threaded information
static bool appMultithreaded;
// Client mutex
static pthread_mutex_t clientMutex;
// Mutex for interlocked operations
pthread_mutex_t interlockedMutex;
// Indicators
static bool svcInitialized = false;
// Map of open remote endpoints.
//
// This map contains all of the open remote
// endpoint objects. The key used to obtain
// RemoteEndPoint objects from the map is an
// object handle.
//
typedef map<uint32_t, SmartPtr<RemoteEndPoint>*> REPMap;
typedef REPMap::iterator REPMapIter;
typedef pair<REPMapIter, bool> REPIterBoolPair;
static REPMap *g_pRepMap = NULL;
// RemoteEndPoint handle allocator
static uint32_t remoteEndPointHandleAllocator = 1;
//++=======================================================================
extern "C"
int
IpcClientOpenUnixRemoteEndPoint(
IN char *pSocketFileName,
IN int maxRpcRetries,
INOUT uint32_t *pEndPointHandle)
//
// Arguments In: port - Server's listening port number.
//
// address - The server's IP Address. Use
// 0x7F000001 if the server is local.
//
// maxRpcRetries - Maximum number of Rpc retries that
// should be utilized when submitting
// a request to the endpoint. A value
// of zero requests that the default
// setting be utilized.
//
// Arguments Out: pEndPointHandle - Pointer to variable that will receive
// the endpoint handle.
//
// Returns: 0 == Success
// -1 == Failure
//
// Abstract: Method to open a UNIX (PF_UNIX) remote endpoint.
//
// Note: The service should have been initialized before calling
// this procedure.
//
// L2
//=======================================================================--
{
int retStatus = -1;
DbgTrace(1, "IpcClientOpenUnixRemoteEndPoint- Start\n", 0);
// Verify the input parameters
if (pSocketFileName == NULL
|| pEndPointHandle == NULL)
{
DbgTrace(0, "IpcClientOpenUnixRemoteEndPoint- Invalid parameter\n", 0);
goto exit;
}
// Verify that we have been initialized
if (svcInitialized)
{
// Set the default max rpc retry value if necessary
if (maxRpcRetries == 0)
maxRpcRetries = DEFAULT_MAX_RPC_RETRIES;
// Acquire our mutex
pthread_mutex_lock(&clientMutex);
try {
// Instantiate a RemoteEndPoint object and keep track of it
// with a smart pointer.
SmartRemoteEndPoint *pSmartRemoteEndPoint = new SmartRemoteEndPoint(new RemoteEndPoint(appMultithreaded,
maxRpcRetries,
pSocketFileName));
// Allocate a handle for the endpoint
uint32_t handle = remoteEndPointHandleAllocator + 1;
// Protect against wrap-around
if (handle != 0)
{
// Insert the new RemoteEndPoint into the REP map
REPIterBoolPair insertResult;
insertResult = g_pRepMap->insert(make_pair(handle, pSmartRemoteEndPoint));
if (!insertResult.second)
{
// Insertion failed
DbgTrace(0, "IpcClientOpenUnixRemoteEndPoint- Unable to insert RemoteEndPoint into REP\n", 0);
delete pSmartRemoteEndPoint;
}
else
{
// RemoteEndPoint inserted in the REP map, success.
//
// Consume the allocated handle
remoteEndPointHandleAllocator ++;
*pEndPointHandle = handle;
retStatus = 0;
}
}
else
{
// Handle allocator wrap-around prevented
DbgTrace(0, "IpcClientOpenUnixRemoteEndPoint- Handle allocator wrap-around prevented\n", 0);
delete pSmartRemoteEndPoint;
}
} catch (...) {
DbgTrace(0, "IpcClientOpenUnixRemoteEndPoint- Exception caught\n", 0);
}
pthread_mutex_unlock(&clientMutex);
}
else
{
DbgTrace(0, "IpcClientOpenUnixRemoteEndPoint- Not initialized\n", 0);
}
exit:
DbgTrace(1, "IpcClientOpenUnixRemoteEndPoint- End, status = %0X\n", retStatus);
return retStatus;
}
//++=======================================================================
extern "C"
int
IpcClientOpenInetRemoteEndPoint(
IN unsigned short int port,
IN uint32_t address,
IN int maxRpcRetries,
INOUT uint32_t *pEndPointHandle)
//
// Arguments In: port - Server's listening port number.
//
// address - The server's IP Address. Use
// 0x7F000001 if the server is local.
//
// maxRpcRetries - Maximum number of Rpc retries that
// should be utilized when submitting
// a request to the endpoint. A value
// of zero requests that the default
// setting be utilized.
//
// Arguments Out: pEndPointHandle - Pointer to variable that will receive
// the endpoint handle.
//
// Returns: 0 == Success
// -1 == Failure
//
// Abstract: Method to open a TCP (AF_INET) remote endpoint.
//
// Note: The service should have been initialized before calling
// this procedure.
//
// L2
//=======================================================================--
{
int retStatus = -1;
DbgTrace(1, "IpcClientOpenInetRemoteEndPoint- Start\n", 0);
// Verify the input parameters
if (pEndPointHandle == NULL)
{
DbgTrace(0, "IpcClientOpenInetRemoteEndPoint- Invalid parameter\n", 0);
goto exit;
}
// Verify that we have been initialized
if (svcInitialized)
{
// Set the default max rpc retry value if necessary
if (maxRpcRetries == 0)
maxRpcRetries = DEFAULT_MAX_RPC_RETRIES;
// Acquire our mutex
pthread_mutex_lock(&clientMutex);
try {
// tbd - add code to allow us to share endpoints to the same destination that are already opened
//
// Instantiate a RemoteEndPoint object and keep track of it
// with a smart pointer.
SmartRemoteEndPoint *pSmartRemoteEndPoint = new SmartRemoteEndPoint(new RemoteEndPoint(appMultithreaded,
maxRpcRetries,
port,
address));
// Allocate a handle for the endpoint
uint32_t handle = remoteEndPointHandleAllocator + 1;
// Protect against wrap-around
if (handle != 0)
{
// Insert the new RemoteEndPoint into the REP map
REPIterBoolPair insertResult;
insertResult = g_pRepMap->insert(make_pair(handle, pSmartRemoteEndPoint));
if (!insertResult.second)
{
// Insertion failed
DbgTrace(0, "IpcClientOpenInetRemoteEndPoint- Unable to insert RemoteEndPoint into REP\n", 0);
delete pSmartRemoteEndPoint;
}
else
{
// RemoteEndPoint inserted in the REP map, success.
//
// Consume the allocated handle
remoteEndPointHandleAllocator ++;
*pEndPointHandle = handle;
retStatus = 0;
}
}
else
{
// Handle allocator wrap-around prevented
DbgTrace(0, "IpcClientOpenInetRemoteEndPoint- Handle allocator wrap-around prevented\n", 0);
delete pSmartRemoteEndPoint;
}
} catch (...) {
DbgTrace(0, "IpcClientOpenInetRemoteEndPoint- Exception caught\n", 0);
}
pthread_mutex_unlock(&clientMutex);
}
else
{
DbgTrace(0, "IpcClientOpenInetRemoteEndPoint- Not initialized\n", 0);
}
exit:
DbgTrace(1, "IpcClientOpenInetRemoteEndPoint- End, status = %0X\n", retStatus);
return retStatus;
}
//++=======================================================================
extern "C"
int
IpcClientCloseRemoteEndPoint(
IN uint32_t endPointHandle)
//
// Arguments In: endpointHandle - Handle of the endpoint being closed.
//
//
// Arguments Out: None.
// the endpoint handle.
//
// Returns: 0 == Success
// -1 == Failure
//
// Abstract: Method to close a remote endpoint.
//
// Note: The service should have been initialized before calling
// this procedure.
//
// L2
//=======================================================================--
{
int retStatus = -1;
DbgTrace(1, "IpcClientCloseRemoteEndPoint- Start\n", 0);
// Verify that we have been initialized
if (svcInitialized)
{
// Acquire our mutex
pthread_mutex_lock(&clientMutex);
// Find the appropriate RemoteEndPoint object in the REP Map using
// the handle provided by the caller.
REPMapIter iter = g_pRepMap->find(endPointHandle);
if (iter != g_pRepMap->end())
{
// Object was found in the map, remove it.
SmartRemoteEndPoint *pSmartRemoteEndPoint = iter->second;
g_pRepMap->erase(iter);
// Release our mutex before deleting the endpoint
pthread_mutex_unlock(&clientMutex);
// Close the endpoint
delete pSmartRemoteEndPoint;
// Success
retStatus = 0;
}
else
{
DbgTrace(0, "IpcClientCloseRemoteEndPoint- Invalid handle\n", 0);
// Release our mutex
pthread_mutex_unlock(&clientMutex);
}
}
else
{
DbgTrace(0, "IpcClientCloseRemoteEndPoint- Not initialized\n", 0);
}
DbgTrace(1, "IpcClientCloseRemoteEndPoint- End, status = %0X\n", retStatus);
return retStatus;
}
//++=======================================================================
extern "C"
int
IpcClientSubmitReq(
IN uint32_t endPointHandle,
IN char *pClientData,
IN uint32_t clientDataLen,
INOUT char **ppServerData,
INOUT uint32_t *pServerDataLen)
//
// Arguments In: endPointHandle - Handle of the remote endpoint that will
// be the target of the request.
//
// pClientData - Pointer to client data that must be sent to
// the server. Buffer is NEVER released by the
// procedure.
//
// clientDataLen - Length of the client data.
//
// Arguments Out: ppServerData - Pointer to variable that will receive a
// pointer to the buffer containing the data
// received from the server.
//
// The returned buffer always contains a NULL after the
// data indicated. You may be able to leverage this to
// treat the data as a NULL terminated string in cases
// where the request consists of ASCII characters.
//
// pServerDataLen - Pointer to variable that will receive the
// length of the data received from the server.
//
// Returns: 0 == Request completed gracefully
// -1 == Request did not complete gracefully
//
// Abstract: Method to submit a request.
//
// Notes: The routine blocks until the request completes.
//
// The buffer returned with the server data must be released
// by the calling application by calling free().
//
// L2
//=======================================================================--
{
int retStatus = -1;
DbgTrace(1, "IpcClientSubmitReq- Start\n", 0);
// Verify input parameters
if (pClientData == NULL
|| ppServerData == NULL
|| pServerDataLen == NULL)
{
DbgTrace(0, "IpcClientSubmitReq- Invalid parameter\n", 0);
goto exit;
}
// Verify that we have been initialized
if (svcInitialized)
{
// Acquire our mutex
pthread_mutex_lock(&clientMutex);
// Find the appropriate RemoteEndPoint object in the REP Map using
// the handle provided by the caller.
REPMapIter iter = g_pRepMap->find(endPointHandle);
if (iter != g_pRepMap->end())
{
// Object was found in the map, use it to submit
// the request.
SmartRemoteEndPoint *pSmartRemoteEndPoint = new SmartRemoteEndPoint(*(iter->second));
// Release our mutex before using the remote endpoint
pthread_mutex_unlock(&clientMutex);
// Submit the request
retStatus = (*pSmartRemoteEndPoint)->submitReq(pClientData,
clientDataLen,
ppServerData,
pServerDataLen);
// Get rid of the reference to the remote endpoint
delete pSmartRemoteEndPoint;
}
else
{
DbgTrace(0, "IpcClientSubmitReq- Invalid handle\n", 0);
// Release our mutex
pthread_mutex_unlock(&clientMutex);
}
}
else
{
DbgTrace(0, "IpcClientSubmitReq- Not initialized\n", 0);
}
exit:
DbgTrace(1, "IpcClientSubmitReq- End, retStatus = %0X\n", retStatus);
return retStatus;
}
//++=======================================================================
extern "C"
int
IpcClientInit(
IN char *pName,
IN bool multithreaded,
IN int debugLevel,
IN bool useSyslog)
//
// Arguments In: pName - Pointer to string containing the name that the
// calling application wants associated with the
// debug logs emitted by the library.
//
// multithreaded - Set to TRUE if the process is
// multithreaded.
//
// debugLevel - The level that the library should use for
// determining what information should be logged
// for debugging purposes. 0 being the lowest
// level.
//
// useSyslog - Set to TRUE to log debug statements using Syslog,
// else debugs are log to stderr.
//
// Arguments Out: None.
//
// Returns: 0 == Success
// -1 == Failure
//
// Abstract: Method to initialize the IPC infrastructure for process.
//
// Note: It is necessary to call the appropriate function to
// set the server address before a request can be submitted.
//
// L2
//=======================================================================--
{
int retStatus = -1;
DbgTrace(1, "IpcClientInit- Start\n", 0);
// Check input parameters
if (pName == NULL)
{
DbgTrace(0, "IpcClientInit- Invalid parameter\n", 0);
goto exit;
}
// Verify that we have not been initialized already
if (!svcInitialized)
{
try {
// Save a copy of the application name
pAppName = new char[strlen(pName) + 1];
if (pAppName == NULL)
{
DbgTrace(0, "IpcClientInit- Memory allocation failure\n", 0);
goto exit;
}
strcpy(pAppName, pName);
// Create our Remote Endpoint Map
g_pRepMap = new REPMap();
// Save the app multithreaded information
appMultithreaded = multithreaded;
// Save the rest of the debug settings
DebugLevel = debugLevel;
UseSyslog = useSyslog;
// Initialize our mutexes
pthread_mutex_init(&clientMutex, NULL);
pthread_mutex_init(&interlockedMutex, NULL);
// Success
svcInitialized = true;
retStatus = 0;
} catch (...) {
DbgTrace(0, "IpcClientInit- Exception caught\n", 0);
}
}
else
{
DbgTrace(0, "IpcClientInit- Initialized already\n", 0);
}
exit:
DbgTrace(1, "IpcClientInit- End, status = %0X\n", retStatus);
return retStatus;
}
//++=======================================================================
extern "C"
void
IpcClientShutdown(void)
//
// Arguments In: None.
//
// Arguments Out: None.
//
// Returns: Nothing.
//
// Abstract: Method to shutdown the IPC infrastructure for process.
//
// L2
//=======================================================================--
{
DbgTrace(1, "IpcClientShutdown- Start\n", 0);
// Verify that we have been initialized
if (svcInitialized)
{
// Forget about having been initialized
svcInitialized = false;
// Clean up the REP map
pthread_mutex_lock(&clientMutex);
while (!g_pRepMap->empty())
{
REPMapIter iter = g_pRepMap->begin();
SmartRemoteEndPoint *pSmartRemoteEndPoint = iter->second;
g_pRepMap->erase(iter);
pthread_mutex_unlock(&clientMutex);
delete pSmartRemoteEndPoint;
pthread_mutex_lock(&clientMutex);
}
pthread_mutex_unlock(&clientMutex);
// Free the AppName string if necessary
if (pAppName != unInitialized)
{
delete[] pAppName;
pAppName = unInitialized;
}
// Wait until all of the channels are gone
while (numCChannelObjects)
sleep(0); // Only suffer a time-slice
sleep(0);
// Delete the Remote Endpoint Map
delete(g_pRepMap);
g_pRepMap = NULL;
}
else
{
DbgTrace(0, "IpcClientShutdown- Not initialized\n", 0);
}
DbgTrace(1, "IpcClientShutdown- End\n", 0);
}
//++=======================================================================
static void __attribute__((destructor))
so_fini()
//
// Arguments In: None.
//
// Arguments Out: None.
//
// Returns: Nothing.
//
// Abstract: Library un-initialization routine.
//
// L2
//=======================================================================--
{
DbgTrace(0, "so_fini- Start\n", 0);
IpcClientShutdown();
}
//=========================================================================
//=========================================================================