Created Linux IPC libraries to be used by the AuthToken components.

At this point there is still work to do on them.
This commit is contained in:
Juan Carlos Luciani
2006-08-31 23:05:25 +00:00
parent f80009fec5
commit 4326223276
30 changed files with 7811 additions and 2 deletions

View File

@@ -0,0 +1,122 @@
#######################################################################
#
# Copyright (C) 2006 Novell, Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This program 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
# General Public License for more details.
#
# You should have received a copy of the GNU General Public
# License along with this program; if not, write to the Free
# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# Author: Juan Carlos Luciani <jluciani@novell.com>
#
#######################################################################
if DEBUG
TARGET_CFG = Debug
CFLAGS += -v -w
CPPFLAGS = -g $(CFLAGS)
DEFINES = -DDBG
else
TARGET_CFG = Release
CPPFLAGS = -O2 -w $(CFLAGS)
DEFINES = -DNDEBUG
endif
# Override the link setting for C++
LINK = g++
SUBDIRS =
DIST_SUBDIRS =
ROOT = ../../../..
LIBDIR = $(ROOT)/$(LIB)
# handle Mono secondary dependencies
export MONO_PATH := $(MONO_PATH)
COMMON = ../common
CLIENT = .
MODULE_NAME = libcasa_c_ipc
MODULE_EXT = so
CFILES =
CPPFILES = channelproto.cpp \
cchannel.cpp \
clientreq.cpp \
client.cpp
CSFILES_CSC :=
INCLUDES = -I. -I.. -I../common -I../../../../include
RESOURCES =
DEFINES += -Wno-format-extra-args -fno-strict-aliasing
CFLAGS += $(INCLUDES) $(DEFINES)
CPPFLAGS += $(INCLUDES) $(DEFINES)
LIBS = -lpthread -ldl -lexpat
LDFLAGS = -Bsymbolic -shared -Wl,-soname=$(MODULE_NAME).$(MODULE_EXT)
OBJDIR = ./$(TARGET_CFG)/$(LIB)
OBJS = $(addprefix $(OBJDIR)/, $(CFILES:%.c=%.o)) $(addprefix $(OBJDIR)/, $(CPPFILES:%.cpp=%.o))
EXTRA_DIST = $(CFILES) *.h
CUR_DIR := $(shell pwd)
all: $(OBJDIR)/$(MODULE_NAME).$(MODULE_EXT)
#
# Pattern based rules.
#
vpath %.c $(CLIENT) $(COMMON)
vpath %.cpp $(CLIENT) $(COMMON)
$(OBJDIR)/%.o: %.c
$(CC) -c $(CFLAGS) -o $@ $<
$(OBJDIR)/%.o: %.cpp
$(CC) -c $(CPPFLAGS) -o $@ $<
$(OBJDIR)/$(MODULE_NAME).$(MODULE_EXT): $(OBJDIR) $(OBJS)
@echo [======== Linking $@ ========]
$(LINK) -o $@ $(LDFLAGS) $(OBJS) $(LIBS)
cp -f $(OBJDIR)/$(MODULE_NAME).$(MODULE_EXT) $(LIBDIR)/$(TARGET_CFG)/$(MODULE_NAME).$(MODULE_EXT)
$(OBJDIR):
[ -d $(OBJDIR) ] || mkdir -p $(OBJDIR)
[ -d $(LIBDIR) ] || mkdir -p $(LIBDIR)
[ -d $(LIBDIR)/$(TARGET_CFG) ] || mkdir -p $(LIBDIR)/$(TARGET_CFG)
install-exec-local: $(OBJDIR)/$(MODULE_NAME).$(MODULE_EXT)
$(mkinstalldirs) $(DESTDIR)$(libdir)
$(INSTALL_PROGRAM) $(OBJDIR)/$(MODULE_NAME).$(MODULE_EXT) $(DESTDIR)$(libdir)/
uninstall-local:
cd $(DESTDIR)$(libdir); rm -f $(OBJDIR)/$(MODULE_NAME).$(MODULE_EXT)
rmdir $(DESTDIR)$(libdir)
#installcheck-local: install
# $(mkinstalldirs) $(DESTDIR)$(libdir)
# $(INSTALL_PROGRAM) $(DESTDIR)$(libdir)
# cd $(DESTDIR)$(libdir); $(MONO)
clean-local:
if [ -d $(TARGET_CFG) ]; then rm -rf $(TARGET_CFG); fi
distclean-local:
maintainer-clean-local:
rm -f Makefile.in

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,274 @@
/***********************************************************************
*
* 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>
*
***********************************************************************/
#ifndef _CCHANNEL_
#define _CCHANNEL_
//===[ Include files ]=====================================================
//===[ External data ]=====================================================
//===[ External prototypes ]===============================================
//===[ Manifest constants ]================================================
//===[ Type definitions ]==================================================
//===[ Function prototypes ]===============================================
//===[ Global variables ]==================================================
//===[ Type definitions ]==================================================
// Forward reference
class ClientReq;
//
// CChannel Class Definition
//
class CChannel : public ObjRef
{
// Object State
enum ChannelStates
{
State_Uninitialized = 1,
State_FailedInitialization,
State_Connected,
State_Disconnected,
State_Closed
};
ChannelStates m_state;
// Connection socket
int m_socket;
// Connection addresses
struct sockaddr_in m_remoteAddrIn;
struct sockaddr_un m_remoteAddrUn;
bool m_useTcpSocket;
// ReqId Allocator
uint32_t m_reqIdAllocator;
// Synchronization variables
pthread_mutex_t m_mutex;
//
// Client Request Map - This map contains all of the active ClientReq objects.
// The key used to obtain ClientReq object in the map
// is the Request Id.
//
typedef map<uint32_t, ClientReq*> RCMap;
typedef RCMap::iterator RCMapIter;
typedef pair<RCMapIter, bool> RCIterBoolPair;
RCMap m_rcMap;
//
// Service connection thread procedure
//
// Parameters:
// pSmartCChannel (input) -
// Pointer to SmartPtr<CChannel> object.
//
// Abstract: Thread in charge of servicing channel connection.
//
// Returns: Nothing.
//
static void* connectionThread(SmartPtr<CChannel> *pSmartCChannel);
//
// Open socket routine
//
// Parameters: None.
//
// Abstract: Opens CChannel object socket.
//
// Returns: Nothing.
//
void openSocket(void);
//
// Connect socket routine
//
// Parameters: None.
//
// Abstract: Connects the CChannel object socket.
//
// Returns: Socket connect operation return status.
//
int connectSocket(void);
public:
//
// Constructor
//
// Parameters:
// remoteAddress (input) -
// Reference to sockaddr_in structure containing the remote
// endpoint address.
//
// Abstract: Constructs CChannel object.
//
// Returns: Nothing.
//
CChannel(struct sockaddr_in *remoteAddress);
//
// Constructor
//
// Parameters:
// remoteAddress (input) -
// Reference to sockaddr_un structure containing the remote
// endpoint address.
//
// Abstract: Constructs CChannel object.
//
// Returns: Nothing.
//
CChannel(struct sockaddr_un *remoteAddress);
//
// Destructor
~CChannel(void);
//
// Initialization routine
//
// Parameters: None.
//
// Abstract: Initializes CChannel object.
//
// Returns: 0 if successful.
//
int init(void);
//
// Close channel routine
//
// Parameters: None.
//
// Abstract: Closes the channel.
//
// Returns: Nothing.
//
void closeChannel(void);
//
// Check channel status routine.
//
// Parameters: None.
//
// Abstract: Checks if the channel status is OK
//
// Returns: True if the channel status is OK.
//
bool ok(void);
//
// Allocate Request Id routine
//
// Parameters: None.
//
// Abstract: Closes the channel.
//
// Returns: Allocated Request Id.
//
uint32_t allocReqId(void);
//
// Submit Request routine
//
// Parameters:
// reqId (input) -
// Id of the Request.
//
// clientReq (input) -
// Reference to ClientReq object.
//
// pClientData (input) -
// Pointer to client data that must be sent to
// the server. Buffer is NEVER released by the
// procedure.
//
// clientDataLen (input) -
// Length of the client data.
//
// Abstract: Submits a Request.
//
// Returns: 0 if successful.
//
int submitReq(uint32_t reqId,
ClientReq &clientReq,
char *pClientData,
int clientDataLen);
//
// Remove Request routine
//
// Parameters:
// reqId (input) -
// Id of the Request.
//
// Abstract: Removes a Request from the channel.
//
// Returns: Nothing.
//
void removeReq(uint32_t reqId);
//
// Send Data routine
//
// Parameters:
// reqId (input) -
// Id of the Request.
//
// pClientData (input) -
// Pointer to client data that must be sent to
// the server. Buffer is NEVER released
// by the procedure.
//
// clientDataLen (input) -
// Length of the client data.
//
//
// Abstract: Sends data to the server for a previously
// submitted Request.
//
// Returns: 0 if successful.
//
int sendData(uint32_t reqId,
char *pClientData,
int clientDataLen);
};
typedef SmartPtr<CChannel> SmartCChannel;
//===[ Function prototypes ]===============================================
#endif // _CCHANNEL_
//=========================================================================
//=========================================================================

View File

@@ -0,0 +1,630 @@
/***********************************************************************
*
* 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"
//===[ External data ]=====================================================
//===[ External prototypes ]===============================================
//===[ Manifest constants ]================================================
#define MAX_RPC_RETRIES 3
#define MAX_CHANNELS 3
//===[ Type definitions ]==================================================
//
// Class for maintaining SmartCChannel pointers within the daemonVector.
//
class SmartCChannelPointer
{
private:
SmartCChannel *m_pSmartCChannel;
public:
SmartCChannelPointer() : m_pSmartCChannel(NULL) {}
~SmartCChannelPointer() { if (m_pSmartCChannel != NULL) delete m_pSmartCChannel; }
SmartCChannel* getPointer() { return m_pSmartCChannel; }
void setPointer(SmartCChannel *pSmartCChannel) { m_pSmartCChannel = pSmartCChannel; }
};
//===[ Function prototypes ]===============================================
//===[ Global variables ]==================================================
// Debug Level
int DebugLevel = 0;
bool UseSyslog = false;
// Application Name for logging purposes
char unInitialized[] = "Uninitialized";
char *pAppName = unInitialized;
vector<SmartCChannelPointer> cchannelVector;
int numCChannels;
int numChannelSubmits = 0;
// Client mutex
pthread_mutex_t clientMutex;
// Mutex for interlocked operations
pthread_mutex_t interlockedMutex;
// Indications
bool svcInitialized = false;
bool serverAddressSet = false;
// Server address variables
bool use_AF_INET;
bool use_PF_UNIX;
struct sockaddr_in serverInAddr = {0};
struct sockaddr_un serverUnAddr = {0};
//++=======================================================================
void
ReInitializeIpc(void)
//
// Arguments In: None.
//
// Arguments Out: None.
//
// Returns: Nothing.
//
// Abstract: Method to re-initialize the IPC infrastructure for process.
//
// L2
//=======================================================================--
{
CChannel *pCChannel;
DbgTrace(1, "ReInitializeIpc- Start\n", 0);
// Clean up all allocated SmartCChannel objects
for (int i = 0; i < cchannelVector.size(); i++)
{
// Close the channel if present
if (cchannelVector[i].getPointer() != NULL)
{
pCChannel = *(cchannelVector[i].getPointer());
pCChannel->closeChannel();
// Free the SmartCChannel
delete cchannelVector[i].getPointer();
cchannelVector[i].setPointer(NULL);
}
}
DbgTrace(1, "ReInitializeIpc- End\n", 0);
}
//++=======================================================================
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.
//
// L0
//=======================================================================--
{
int retStatus = -1;
DbgTrace(1, "IpcClientInit- Start\n", 0);
// Check input parameters
if (pAppName == NULL)
{
DbgTrace(0, "IpcClientInit- Invalid parameter\n", 0);
goto exit;
}
// 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);
// Save the rest of the debug settings
DebugLevel = debugLevel;
UseSyslog = useSyslog;
// Initialize our mutexes
pthread_mutex_init(&clientMutex, NULL);
pthread_mutex_init(&interlockedMutex, NULL);
// Proceed based on whether or not we have already instantiated
// SmartCChannel vectors.
if (cchannelVector.size() == 0)
{
// SmartCChannel entries have not been instantiated
//
// Setup the number of channels that we may have based on
// whether the application is multi-threaded or not.
if (multithreaded)
numCChannels = MAX_CHANNELS;
else
numCChannels = 1;
// Instantiate entries in SmartCChannel vector
try {
for (int i = 0; i < numCChannels; i++)
cchannelVector.push_back(SmartCChannelPointer());
// Done initializing
svcInitialized = true;
retStatus = 0;
} catch (...) {
DbgTrace(0, "IpcClientInit- Exception caught while initializing the cchannelVector\n", 0);
}
}
else
{
// SmartCChannel vector has already been instantiated
ReInitializeIpc();
retStatus = 0;
}
exit:
DbgTrace(1, "IpcClientInit- End, status = %08X\n", retStatus);
return retStatus;
}
//++=======================================================================
extern "C"
int
IpcClientSetUnAddress(
IN char *pSocketFileName)
//
// Arguments In: pSocketFileName - Pointer to string containing the name
// of the socket file.
//
// Arguments Out: None.
//
// Returns: 0 == Success
// -1 == Failure
//
// Abstract: Method to set the socket file name to utilize for
// communicating with the server via DOMAIN sockets.
//
// Note: The service should have been initialized before calling
// this procedure.
//
// L0
//=======================================================================--
{
int retStatus = -1;
DbgTrace(1, "IpcClientSetUnAddress- Start\n", 0);
// Verify that we have been initialized
if (svcInitialized)
{
// Verify that the address has not already been set
if (serverAddressSet == false)
{
// Set the necessary information in the serverUnAddr variable
serverUnAddr.sun_family = AF_UNIX;
strcpy(serverUnAddr.sun_path, pSocketFileName);
// Set the necessary flags to indicate that DOMAIN sockets
// should be used for communications.
use_PF_UNIX = true;
use_AF_INET = false;
// Success
serverAddressSet = true;
retStatus = 0;
}
else
{
DbgTrace(0, "IpcClientSetUnAddress- Already set\n", 0);
}
}
else
{
DbgTrace(0, "IpcClientSetUnAddress- Not initialized\n", 0);
}
DbgTrace(1, "IpcClientSetUnAddress- End, status = %08X\n", retStatus);
return retStatus;
}
//++=======================================================================
extern "C"
int
IpcClientSetInAddress(
IN unsigned short int serverPort,
IN uint32_t serverAddress)
//
// Arguments In: serverPort - Server's listening port number.
//
// serverAddress - The server's IP Address. Use
// 0x7F000001 if the server is local.
//
// Arguments Out: None.
//
// Returns: 0 == Success
// -1 == Failure
//
// Abstract: Method to set the address to utilize for communicating
// with the server via TCP sockets.
//
// Note: The service should have been initialized before calling
// this procedure.
//
// L0
//=======================================================================--
{
int retStatus = -1;
DbgTrace(1, "IpcClientSetInAddress- Start\n", 0);
// Verify that we have been initialized
if (svcInitialized)
{
// Verify that the address has not already been set
if (serverAddressSet == false)
{
// Set the necessary information in the serverInAddr variable
serverInAddr.sin_family = AF_INET;
serverInAddr.sin_port = htons(serverPort);
serverInAddr.sin_addr.s_addr = htonl(serverAddress);
// Set the necessary flags to indicate that TCP sockets
// should be used for communications.
use_AF_INET = true;
use_PF_UNIX = false;
// Success
serverAddressSet = true;
retStatus = 0;
}
else
{
DbgTrace(0, "IpcClientSetInAddress- Already set\n", 0);
}
}
else
{
DbgTrace(0, "IpcClientSetInAddress- Not initialized\n", 0);
}
DbgTrace(1, "IpcClientSetInAddress- End, status = %08X\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);
ReInitializeIpc();
// Free the AppName string if necessary
if (pAppName != unInitialized)
{
delete[] pAppName;
pAppName = unInitialized;
}
DbgTrace(1, "IpcClientShutdown- End\n", 0);
}
//++=======================================================================
SmartCChannel *
getCChannel(void)
//
// Arguments In: Nothing.
//
// Arguments Out: Nothing.
//
// Returns: Pointer to SmartCChannel object if successful, otherwise
// NULL.
//
// Abstract: Method to get a SmartCChannel for submitting a request.
//
// L2
//=======================================================================--
{
SmartCChannel *pSmartCChannel = NULL;
int channelSelector = (numChannelSubmits++) % numCChannels;
DbgTrace(1, "IPCCLNT -getCChannel- Start\n", 0);
// Just exit if the server address has not been set
if (!serverAddressSet)
{
DbgTrace(0, "IPCCLNT -getCChannel- Server address not set\n", 0);
goto exit;
}
// Obtain client mutex
pthread_mutex_lock(&clientMutex);
// Check if there is an available and usable channel for the client
if (cchannelVector[channelSelector].getPointer() != NULL
&& (*cchannelVector[channelSelector].getPointer())->ok())
{
// Use the available channel
pSmartCChannel = new SmartCChannel(*cchannelVector[channelSelector].getPointer());
}
else
{
// The channel is either unavailable or unusable, clean up
// the channel if it is indeed unusable.
if (cchannelVector[channelSelector].getPointer() != NULL)
{
// Clean up the channel
CChannel *pCChannel = *cchannelVector[channelSelector].getPointer();
pCChannel->closeChannel();
delete cchannelVector[channelSelector].getPointer();
cchannelVector[channelSelector].setPointer(NULL);
}
CChannel *pCChannel;
try {
// Use the appropriate server address when instantiating
// the CChannel object.
if (use_PF_UNIX)
{
// PF_UNIX
pCChannel = new CChannel(&serverUnAddr);
}
else
{
// Assume AF_INET
pCChannel = new CChannel(&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.
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(*cchannelVector[channelSelector].getPointer());
}
else
{
// CChannel initialization failed
delete cchannelVector[channelSelector].getPointer();
cchannelVector[channelSelector].setPointer(NULL);
}
}
catch (...) {
DbgTrace(0, "getCChannel- Exception caught\n", 0);
// Try to clean things up just in case
if (cchannelVector[channelSelector].getPointer())
{
delete cchannelVector[channelSelector].getPointer();
cchannelVector[channelSelector].setPointer(NULL);
}
else
{
if (pCChannel != NULL)
delete pCChannel;
}
}
}
// Release client mutex
pthread_mutex_unlock(&clientMutex);
exit:
DbgTrace(1, "getCChannel- End, Obj = %08X\n", pSmartCChannel);
return pSmartCChannel;
}
//++=======================================================================
extern "C"
int
IpcClientSubmitReq(
IN char *pClientData,
IN int clientDataLen,
INOUT char **ppServerData,
INOUT int *pServerDataLen)
//
// Arguments In: 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.
//
// 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.
//
// Note: The routine blocks until the request completes.
//
// L2
//=======================================================================--
{
int retStatus = -1;
DbgTrace(1, "IpcClientSubmitReq- Start\n", 0);
try {
SmartCChannel *pSmartCChannel;
// Perform the following in a loop to deal with abnormal connection terminations
unsigned long rpcRetryCount = 0;
while (rpcRetryCount < MAX_RPC_RETRIES)
{
// 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.
clientReq.waitForCompletion(ppServerData,
pServerDataLen);
// Remove the request from the channel
pCChannel->removeReq(reqId);
// Now proceed based on the completion status
ClientReq::CompletionStatus compStatus = clientReq.completionStatus();
if (compStatus == ClientReq::SuccessCompletionStatus)
{
// Success
retStatus = 0;
}
}
else
{
DbgTrace(0, "IpcClientSubmitReq- 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, "IpcClientSubmitReq- Channel unavailable\n", 0);
}
// Stop trying if the RPC succeeded
if (retStatus == 0)
break;
// Account for this RPC try
rpcRetryCount ++;
DbgTrace(0, "IpcClientSubmitReq- Will attempt to retry RPC, count = %d\n", rpcRetryCount);
}
}
catch(...) {
DbgTrace(0, "IpcClientSubmitReq-- Exception caught\n", 0);
}
DbgTrace(1, "IpcClientSubmitReq- End, retStatus = %08X\n", retStatus);
return retStatus;
}
//=========================================================================
//=========================================================================

View File

@@ -0,0 +1,353 @@
/***********************************************************************
*
* 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 = %08X\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 = %08X\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,
int serverDataLength)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
DbgTrace(1, "ClientReq::processServerData- Start, Obj = %08X\n", this);
// Acquire exclusive access to the object
pthread_mutex_lock(&m_mutex);
try {
// Save server dataetup the ServerData object
m_pServerData = pServerData;
m_serverDataLen = serverDataLength;
// 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);
}
}
catch(...) {
DbgTrace(0, "ClientReq::processServerData- Exception caught, Obj = %08X\n", this);
// Free the server data buffer
delete[] pServerData;
// 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::processServerData- End\n", 0);
} /*-- ClientReq::processServerData() --*/
//++=======================================================================
void
ClientReq::processError(void)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
DbgTrace(1, "ClientReq::processError- Start, Obj = %08X\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,
int *pResponseDataLength)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
int retStatus;
int oldCancelState;
DbgTrace(1, "ClientReq::waitForCompletion- Start, Obj = %08X\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 = %08X\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 = %08X\n", this);
// Check if we encountered any issues
if (m_internalProblem)
{
compStatus = ErrorCompletionStatus;
}
else
{
compStatus = SuccessCompletionStatus;
}
DbgTrace(1, "ClientReq::completionStatus- End, compStatus = %08X\n", compStatus);
return compStatus;
} /*-- ClientReq::completionStatus() --*/
//=========================================================================
//=========================================================================

View File

@@ -0,0 +1,173 @@
/***********************************************************************
*
* 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>
*
***********************************************************************/
#ifndef _CLIENTREQ_
#define _CLIENTREQ_
//===[ Include files ]=====================================================
//===[ External data ]=====================================================
//===[ External prototypes ]===============================================
//===[ Manifest constants ]================================================
//===[ Type definitions ]==================================================
//===[ Function prototypes ]===============================================
//===[ Global variables ]==================================================
//===[ Type definitions ]==================================================
//
// Client Request Class
//
class ClientReq
{
// Req Id
uint32_t m_reqId;
// Server Data
char *m_pServerData;
int m_serverDataLen;
// Flag indicating the state of the submitting
// thread.
bool m_submitThreadActive;
// Flag indicating that the Request has completed.
bool m_completed;
// Flag indicating that a problem was encountered
// while processing the Request.
bool m_internalProblem;
// Synchronization variables
pthread_mutex_t m_mutex;
pthread_cond_t m_condition;
public:
// Completion Statuses
enum CompletionStatus
{
SuccessCompletionStatus = 1,
ErrorCompletionStatus
};
//
// Constructor
//
// Parameters:
// reqId (input) -
// Id of the Request.
//
// clientHandler (input) -
// Pointer to Client Handler routine.
//
// Abstract: Constructs ClientReq object.
//
// Returns: Nothing.
//
ClientReq(uint32_t reqId);
//
// Destructor
~ClientReq(void);
//
// Process Server Data routine
//
// Parameters:
// pServerData (input) -
// Pointer to buffer containing the server data.
// Buffer is released by call to the routine.
//
// serverDataLength (input) -
// Length of the server data.
//
// Abstract: Processes server data.
//
// Returns: Nothing.
//
void processServerData(char *pServerData,
int serverDataLength);
//
// Process Error routine
//
// Parameters: None.
//
// Abstract: Processes channel and server error
// indication.
//
// Returns: Nothing.
//
void processError(void);
//
// Wait For Completion routine
//
// Parameters:
// ppResponseData (input/output) -
// Pointer to variable that will receive pointer to
// buffer containing the data sent by the server.
//
// pResponseDataLength (input/output) -
// Pointer to variable that will receive the length
// of the data sent by the server.
//
//
// Abstract: Waits for the Request completion.
//
// Returns: 0 == Request completed gracefully
// -1 == Request did not complete gracefully
//
int waitForCompletion(char **ppResponseData,
int *pResponseDataLength);
//
// Completion status
//
// Parameters: None.
//
// Abstract: Obtains the request completion status.
//
// Returns: Request completion status.
// status in order to find out.
//
ClientReq::CompletionStatus completionStatus(void);
};
//===[ Function prototypes ]===============================================
#endif // _CLIENTREQ_
//=========================================================================
//=========================================================================

View File

@@ -0,0 +1,3 @@
#!/bin/bash
gcc -o TestClient testClient.c -g -I../../../../../include -L../../../../../lib/Release -lpthread -lcasa_c_ipc -Xlinker -rpath -Xlinker ../../../../../lib/Release

View File

@@ -0,0 +1,286 @@
/***********************************************************************
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <getopt.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <pthread.h>
#include <unistd.h>
#include <stdint.h>
#include "casa_s_ipc.h"
//===[ Type definitions ]==================================================
//
// DbgTrace macro define
//
#define DbgTrace(LEVEL, X, Y) { \
if (LEVEL == 0) \
printf(X, Y); \
else if (DebugLevel >= LEVEL) \
printf(X, Y); \
}
//===[ Function prototypes ]===============================================
//===[ Global variables ]==================================================
// Usage string
char usage[] = "\nTest: usage: [-c requestCount] [-t submitThreadCount] [-D DebugLevel]\n";
int DebugLevel = 3;
// Request count
int submitReqCount = 100;
// Submit thread count
int submitThreadCount = 1;
// Synch mutex
pthread_mutex_t testMutex;
bool errorDetected = false;
//++=======================================================================
void* SubmitThread()
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// Environment:
//
//=======================================================================--
{
char reqData[] = "This is the request data";
char *pReplyData;
int replyDataLen;
DbgTrace(1, "SubmitThread- Start\n", 0);
pthread_mutex_lock(&testMutex);
while (submitReqCount != 0
&& !errorDetected)
{
submitReqCount --;
pthread_mutex_unlock(&testMutex);
// Submit request to the server
if (IpcClientSubmitReq(reqData,
strlen(reqData),
&pReplyData,
&replyDataLen) != 0)
{
DbgTrace(0, "SubmitThread- Req submit error\n", 0);
errorDetected = true;
}
else
{
// Free the reply data buffer
free(pReplyData);
}
pthread_mutex_lock(&testMutex);
}
DbgTrace(1, "SubmitThread- End\n", 0);
// Exit
pthread_exit(NULL);
return 0; // never-reached!
}
//++=======================================================================
void
ExecuteTests(void)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// Environment:
//
//=======================================================================--
{
pthread_t thread;
int threadCreateStatus;
int threadCreatedCount = 0;
int i;
DbgTrace(1, "ExecuteTests- Start\n", 0);
// Initialize the Client Ipc Subsystem
if (IpcClientInit("TestClient",
true,
3,
false) == 0)
{
// Set the server listen address
if (IpcClientSetInAddress(5000,
0x7F000001) == 0)
{
// Start the configured number of threads to submit requests to
// the server.
for (i = 0; i < submitThreadCount; i++)
{
threadCreateStatus = pthread_create(&thread,
NULL,
(void*(*)(void*))SubmitThread,
(void*)NULL);
if (threadCreateStatus == 0)
threadCreatedCount ++;
else
{
DbgTrace(0, "ExecuteTests- Error creating submit thread, error = %08X\n", threadCreateStatus);
}
}
// Wait for the requests to be submitted
if (threadCreatedCount != 0)
{
while (submitReqCount
&& !errorDatected)
sleep(1);
sleep(1);
}
}
else
{
DbgTrace(0, "ExecuteTests- Error setting server address\n", 0);
}
IpcClientShutdown();
}
else
{
DbgTrace(0, "ExecuteTests- Ipc subsystem initialization failed\n", 0);
}
DbgTrace(1, "ExecuteTests- End\n", 0);
}
//++=======================================================================
int
main(
int argc,
char* argv[])
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
int optionsSpecified = 0;
bool doneScanning = false;
bool invalidOption = false;
int option;
printf("**** Ipc Client test ****\n");
// Scan through the options specified
while (!doneScanning)
{
opterr = 0;
option = getopt(argc, argv, "c:t:D:");
// Proceed based on the result
switch (option)
{
case 'D':
// Set the debug level
printf("DebugLevel = %s\n", optarg);
DebugLevel = atoi(optarg);
optionsSpecified++;
break;
case 'c':
// Set the submit request count
submitReqCount = atoi(optarg);
optionsSpecified++;
break;
case 't':
// Set the submit thread count
submitThreadCount = atoi(optarg);
optionsSpecified++;
break;
case '?':
// Invalid option detected
doneScanning = true;
invalidOption = true;
break;
default:
// Done scanning
doneScanning = true;
break;
}
}
// Do some sanity checking
if (!invalidOption)
{
printf("submitReqCount = %d\n", submitReqCount);
printf("submitThreadCount = %d\n", submitThreadCount);
ExecuteTests();
}
else
{
// Invalid option detected
printf(usage, argv[0]);
}
return 0;
} /*-- main() --*/