The non-java project is being replaced by a client and a server project

in order to allow for the client component to be consumed by
distributions targeting the desktop. This check-in is for the server
project.
This commit is contained in:
Juan Carlos Luciani
2006-11-13 04:05:01 +00:00
parent 4f53c776c9
commit 2cc21a344c
99 changed files with 21159 additions and 0 deletions

View File

@@ -0,0 +1,126 @@
#######################################################################
#
# 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
DEFINES = -DDBG
else
TARGET_CFG = Release
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 = cchannel.cpp \
clientreq.cpp \
remoteendpoint.cpp \
client.cpp
COMMONCPPFILES = channelproto.cpp
CSFILES_CSC :=
INCLUDES = -I. -I.. -I../common -I../../../../include
RESOURCES =
if LIB64
DEFINES += -D_LIB64
endif
CFLAGS += -Wno-format-extra-args -fno-strict-aliasing -fshort-wchar $(INCLUDES) $(DEFINES)
CPPFLAGS += -Wno-format-extra-args -fno-strict-aliasing -fshort-wchar -fPIC $(INCLUDES) $(DEFINES) $(RPM_OPT_FLAGS)
LIBS = -lpthread
LDFLAGS = -Bsymbolic -shared -Wl,-soname=$(MODULE_NAME).$(MODULE_EXT)
OBJDIR = ./$(TARGET_CFG)/$(LIB)
OBJS = $(addprefix $(OBJDIR)/, $(CFILES:%.c=%.o)) $(addprefix $(OBJDIR)/, $(COMMONCPPFILES:%.cpp=%.o)) $(addprefix $(OBJDIR)/, $(CPPFILES:%.cpp=%.o))
EXTRA_DIST = $(CFILES) $(CPPFILES) *.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

View File

@@ -0,0 +1,949 @@
/***********************************************************************
*
* 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 ]================================================
//
// Socket Mapping definitions
//
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#define LINGER struct linger
#define SOCKADDR_IN struct sockaddr_in
#define closesocket close
//===[ Type definitions ]==================================================
//===[ Function prototypes ]===============================================
//===[ Global variables ]==================================================
//
// Object Counters
//
unsigned long numCChannelObjects = 0;
//===[ Type definitions ]==================================================
//===[ Function prototypes ]===============================================
//===[ Global variables ]==================================================
//++=======================================================================
CChannel::CChannel(
struct sockaddr_in *pRemoteAddress) :
m_state (State_Uninitialized),
m_socket (INVALID_SOCKET),
m_reqIdAllocator (1)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
DbgTrace(1, "CChannel::CChannel(TcpSocket)- Start, Obj = %08X\n", this);
// Use Tcp socket
m_useTcpSocket = true;
// Save a copy of the remote address
memcpy(&m_remoteAddrIn, pRemoteAddress, sizeof(struct sockaddr_in));
// Initialize the mutex
if (pthread_mutex_init(&m_mutex, NULL) != 0)
{
DbgTrace(0, "CChannel::CChannel- Mutex initialization failed\n", 0);
// Throw exception
throw bad_alloc();
}
// Increment the object count
InterlockedIncrement(&numCChannelObjects);
DbgTrace(1, "CChannel::CChannel(TcpSocket)- End\n", 0);
} /*-- CChannel::CChannel(TcpSocket) --*/
//++=======================================================================
CChannel::CChannel(
struct sockaddr_un *pRemoteAddress) :
m_state (State_Uninitialized),
m_socket (INVALID_SOCKET),
m_reqIdAllocator (1)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
DbgTrace(1, "CChannel::CChannel(DomainSocket)- Start, Obj = %08X\n", this);
// Do not use Tcp socket
m_useTcpSocket = false;
// Save a copy of the remote address
memcpy(&m_remoteAddrUn, pRemoteAddress, sizeof(struct sockaddr_un));
// Initialize the mutex
if (pthread_mutex_init(&m_mutex, NULL) != 0)
{
DbgTrace(0, "CChannel::CChannel- Mutex initialization failed\n", 0);
// Throw exception
throw bad_alloc();
}
// Increment the object count
InterlockedIncrement(&numCChannelObjects);
DbgTrace(1, "CChannel::CChannel(DomainSocket)- End\n", 0);
} /*-- CChannel::CChannel(DomainSocket) --*/
//++=======================================================================
CChannel::~CChannel(void)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
DbgTrace(1, "CChannel::~CChannel- Start, Obj = %08X\n", this);
// Cleanup resources allocated for the object
pthread_mutex_destroy(&m_mutex);
// Free connection socket if necessary
if (m_socket != INVALID_SOCKET)
{
shutdown(m_socket, SHUT_RDWR);
struct linger linger_opt = {1, 15};
setsockopt(m_socket, SOL_SOCKET, SO_LINGER, &linger_opt, sizeof(linger_opt));
closesocket(m_socket);
}
// Decrement the object count
InterlockedDecrement(&numCChannelObjects);
DbgTrace(1, "CChannel::~CChannel- End\n", 0);
} /*-- CChannel::~CChannel() --*/
//++=======================================================================
void
CChannel::openSocket(void)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
DbgTrace(1, "CChannel::openSocket- Start\n", 0);
// Open a domain socket if not using Tcp
if (m_useTcpSocket == false)
m_socket = socket(PF_UNIX, SOCK_STREAM, 0);
else
m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
DbgTrace(1, "CChannel::openSocket- End\n", 0);
} /*-- CChannel::openSocket() --*/
//++=======================================================================
int
CChannel::connectSocket(void)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
int retStatus;
DbgTrace(1, "CChannel::connectSocket- Start\n", 0);
// Proceed based on whether or not we need
// to use Tcp sockets.
if (m_useTcpSocket)
{
struct sockaddr_in localAddr = {0};
// Setup the address structure
localAddr.sin_family = AF_INET;
localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
// Perform bind operation
retStatus = bind(m_socket,
(const sockaddr*) &localAddr,
sizeof(struct sockaddr_in));
if (!retStatus)
{
// Perform connect operation
retStatus = connect(m_socket,
(struct sockaddr*) &m_remoteAddrIn,
sizeof(struct sockaddr_in));
if (retStatus == SOCKET_ERROR)
{
DbgTrace(0, "CChannel::connectSocket- Connection creation failed, error = %d\n", errno);
}
}
else
{
DbgTrace(0, "CChannel::connectSocket- Unable to bind socket, error = %d", errno);
}
}
else
{
// Perform connect operation
retStatus = connect(m_socket,
(struct sockaddr*) &m_remoteAddrUn,
sizeof(m_remoteAddrUn.sun_family) + strlen(m_remoteAddrUn.sun_path));
if (retStatus == SOCKET_ERROR)
{
DbgTrace(0, "CChannel::connectSocket- Connection creation failed, error = %d\n", errno);
}
}
DbgTrace(1, "CChannel::connectSocket- End, status = %08X\n", retStatus);
return retStatus;
} /*-- CChannel::connectSocket() --*/
//++=======================================================================
int
CChannel::init(void)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
int retStatus = -1;
SmartCChannel *pSmartCChannel = NULL;
DbgTrace(1, "CChannel::init- Start, Obj = %08X\n", this);
// Verify the state of the object
if (m_state == State_Uninitialized)
{
openSocket();
if (m_socket != INVALID_SOCKET)
{
if (connectSocket() != SOCKET_ERROR)
{
// Advance the object state
m_state = State_Connected;
// Launch a thread to service the channel connection
try {
// Create a SmartCChannel object to make sure that the object
// does not get deleted prematurely.
pSmartCChannel = new SmartCChannel(this);
// Create the channel connection thread
pthread_t thread;
int threadCreateStatus = pthread_create(&thread,
NULL,
(void*(*)(void*))CChannel::connectionThread,
pSmartCChannel);
if (threadCreateStatus == 0)
{
// We succeeded
retStatus = 0;
}
else
{
DbgTrace(0, "CChannel::init- Unable to create channel connection thread, error = %08X\n", threadCreateStatus);
}
}
catch (...) {
DbgTrace(0, "CChannel::init- Exception caught creating smart pointer\n", 0);
}
}
else
{
DbgTrace(0, "CChannel::init- Connection creation failed, error = %d\n", errno);
}
}
else
{
DbgTrace(0, "CChannel::init- Unable to open socket, error = %d\n", errno);
}
}
else
{
DbgTrace(0, "CChannel::init- invalid state, state = %d\n", m_state);
}
// Deal with initialization failures
if (retStatus)
{
// Adjust the object state
m_state = State_FailedInitialization;
// Free SmartCChannel just in case
delete pSmartCChannel;
}
DbgTrace(1, "CChannel::init- End, status = %08X\n", retStatus);
return retStatus;
} /*-- CChannel::init() --*/
//++=======================================================================
void*
CChannel::connectionThread(
SmartPtr<CChannel> *pSmartCChannel)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
CChannel *pCChannel = *pSmartCChannel;
bool doneReceivingData = false;
unsigned long bytesReceived;
uint32_t reqId;
int payloadLength;
unsigned long totalPayloadBytesReceived = 0;
char reqDataPktHdr[ReqDataPktHdrTemplate.length()];
char *pRecvBuff;
RCMapIter iter;
ClientReq *pClientReq;
DbgTrace(1, "CChannel::connectionThread- Start, Obj = %08X\n", pCChannel);
// Set the thread in the detached state so that it is cleaned up when it exits
pthread_detach(pthread_self());
// Check that we are still connected
if (pCChannel->m_state == State_Connected)
{
// Receive and process channel data
while (!doneReceivingData)
{
DbgTrace(2, "CChannel::connectionThread- Receive Loop, Obj = %08X\n", pCChannel);
// Receive the ReqDataPktHdr. Note, if we add other packet types and if the
// packet types have different header lengths, then we will need to modify
// this code to first receive the packet type and then receive the rest
// of the header based on type.
while (1)
{
bytesReceived = recv(pCChannel->m_socket,
reqDataPktHdr,
sizeof(reqDataPktHdr),
MSG_WAITALL);
if (bytesReceived == SOCKET_ERROR
&& errno == EINTR)
{
continue;
}
break;
}
if (bytesReceived != SOCKET_ERROR)
{
// Check if the connection was terminated
if (bytesReceived == sizeof(reqDataPktHdr))
{
// Get the payload length
if (ChannelProto::getReqIdAndPayloadLength(reqDataPktHdr,
sizeof(reqDataPktHdr),
&reqId,
&payloadLength))
{
// Procced based on the packet type
switch (ChannelProto::getPktType(*reqDataPktHdr))
{
case ChannelProto::ReqDataCarrierPacketType:
DbgTrace(2, "CChannel::connectionThread- Processing Request Data Packet, Obj = %08X\n", pCChannel);
// Allocate a buffer big enough to receive the payload. Allow space to NULL terminate.
pRecvBuff = (char*) malloc(payloadLength + 1);
if (pRecvBuff != NULL)
{
pRecvBuff[payloadLength] = '\0';
// Buffer allocated, receive the request payload.
while (1)
{
bytesReceived = recv(pCChannel->m_socket,
pRecvBuff,
payloadLength,
MSG_WAITALL);
if (bytesReceived == SOCKET_ERROR
&& errno == EINTR)
{
continue;
}
break;
}
if (bytesReceived != SOCKET_ERROR)
{
// Verify that we received all of the payload
if (bytesReceived == payloadLength)
{
// Received all of the payload data
totalPayloadBytesReceived += bytesReceived;
// Acquire exclusive access to the CChannel object
pthread_mutex_lock(&pCChannel->m_mutex);
// Find the appropriate ClientReq object in the ClientReqMap using
// the reqId present in the Req Data Packet Header.
iter = pCChannel->m_rcMap.find(reqId);
if (iter != pCChannel->m_rcMap.end())
{
// Object was found in the map, use it to process the
// request payload.
pClientReq = iter->second;
pClientReq->processServerData(pRecvBuff,
bytesReceived);
// Forget about the receive buffer
pRecvBuff = NULL;
}
else
{
DbgTrace(0, "CChannel::connectionThread- Error, did not find object in map, Obj = %08X\n", pCChannel);
}
// Release exclusive access to the CChannel object
pthread_mutex_unlock(&pCChannel->m_mutex);
}
else
{
DbgTrace(1, "CChannel::connectionThread- Connection aborted prematurely, Obj = %08X\n", pCChannel);
//DbgTrace(0, "CChannel::connectionThread- 1Connection aborted prematurely, Obj = %08X\n", pCChannel);
//DbgTrace(0, "CChannel::connectionThread- 1bytesReceived = %d\n", bytesReceived);
//DbgTrace(0, "CChannel::connectionThread- 1payloadLength = %d\n", payloadLength);
//DbgTrace(0, "CChannel::connectionThread- 1errno = %d\n", errno);
//printf("bytesReceived = %d, payloadLength = %d\n", bytesReceived, payloadLength);
//printf("CChannel::connectionThread- 1Connection aborted prematurely, Obj = %08X\n", pCChannel);
doneReceivingData = true;
}
}
else
{
DbgTrace(1, "CChannel::connectionThread- Connection aborted prematurely, Obj = %08X\n", pCChannel);
//DbgTrace(0, "CChannel::connectionThread- 2Connection aborted prematurely, Obj = %08X\n", pCChannel);
//DbgTrace(0, "CChannel::connectionThread- 2errno = %d\n", errno);
//printf("Socket error = %d\n", errno);
//printf("CChannel::connectionThread- 2Connection aborted prematurely, Obj = %08X\n", pCChannel);
doneReceivingData = true;
}
// Free receive buffer if necessary
if (pRecvBuff)
delete[] pRecvBuff;
}
else
{
DbgTrace(0, "CChannel::connectionThread- Unable to allocate receive buffer, Obj = %08X\n", pCChannel);
doneReceivingData = true;
}
break;
case ChannelProto::ReqErrorCarrierPacketType:
DbgTrace(1, "CChannel::connectionThread- Processing Request Error Packet, Obj = %08X\n", pCChannel);
// Acquire exclusive access to the CChannel object
pthread_mutex_lock(&pCChannel->m_mutex);
// Find the appropriate ClientReq object in the ClientReqMap using
// the reqId present in the Req Data Packet Header.
iter = pCChannel->m_rcMap.find(reqId);
if (iter != pCChannel->m_rcMap.end())
{
// Object was found in the map, use it to process the Request Error.
pClientReq = iter->second;
pClientReq->processError();
}
else
{
DbgTrace(0, "CChannel::connectionThread- Error, did not find object in map, Obj = %08X\n", pCChannel);
}
// Release exclusive access to the CChannel object
pthread_mutex_unlock(&pCChannel->m_mutex);
break;
default:
DbgTrace(0, "CChannel::connectionThread- Unknown Packet Type, Obj = %08X\n", pCChannel);
doneReceivingData = true;
break;
}
}
else
{
DbgTrace(1, "CChannel::connectionThread- Unable to obtain payload length, Obj = %08X\n", pCChannel);
doneReceivingData = true;
}
}
else
{
DbgTrace(1, "CChannel::connectionThread- The channel connection was terminated, Obj = %08X\n", pCChannel);
//DbgTrace(0, "CChannel::connectionThread- 3The channel connection was terminated, Obj = %08X\n", pCChannel);
//DbgTrace(0, "CChannel::connectionThread- 3bytesReceived = %d\n", bytesReceived);
//DbgTrace(0, "CChannel::connectionThread- 3expected = %d\n", ReqDataPktHdrTemplate.length());
//DbgTrace(0, "CChannel::connectionThread- 3errno = %d\n", errno);
//printf("bytesReceived = %d, expected = %d\n", bytesReceived, ReqDataPktHdrTemplate.length());
//printf("CChannel::connectionThread- 3The channel connection was terminated, Obj = %08X\n", pCChannel);
doneReceivingData = true;
}
}
else
{
DbgTrace(1, "CChannel::connectionThread- The channel connection was aborted, Obj = %08X\n", pCChannel);
//DbgTrace(0, "CChannel::connectionThread- 4The channel connection was aborted, Obj = %08X\n", pCChannel);
//DbgTrace(0, "CChannel::connectionThread- 4errno = %d\n", errno);
//printf("Socket error = %d\n", errno);
//printf("CChannel::connectionThread- 4The channel connection was aborted, Obj = %08X\n", pCChannel);
doneReceivingData = true;
}
}
}
// Acquire exclusive access to the CChannel object
pthread_mutex_lock(&pCChannel->m_mutex);
// Try to change the CChannel state to disconnected
if (pCChannel->m_state == State_Connected)
pCChannel->m_state = State_Disconnected;
// Deliver error notifications to all of the ClientReqs
// still associated with the CChannel.
if (!pCChannel->m_rcMap.empty())
{
iter = pCChannel->m_rcMap.begin();
while (iter != pCChannel->m_rcMap.end())
{
// Object was found in the map, deliver error notification
// to it.
pClientReq = iter->second;
pClientReq->processError();
// Move on to the next element in the map
iter ++;
}
}
// Release exclusive access to the CChannel object
pthread_mutex_unlock(&pCChannel->m_mutex);
// Free SmartCChannel
delete pSmartCChannel;
DbgTrace(0, "CChannel::connectionThread- End\n", 0);
// Exit
pthread_exit(NULL);
return 0; // never-reached!
} /*-- CChannel::connectionThread() --*/
//++=======================================================================
void
CChannel::closeChannel(void)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
DbgTrace(1, "CChannel::closeChannel- Start, Obj = %08X\n", this);
// Acquire CChannel mutex
pthread_mutex_lock(&m_mutex);
// Switch the socket state to closed
m_state = State_Closed;
// Check if we must close the socket
if (m_socket != INVALID_SOCKET)
{
// Socket needs to be closed, this will
// release the channel connection thread
// if it is active.
shutdown(m_socket, SHUT_RDWR);
struct linger linger_opt = {1, 15};
setsockopt(m_socket, SOL_SOCKET, SO_LINGER, &linger_opt, sizeof(linger_opt));
closesocket(m_socket);
m_socket = INVALID_SOCKET;
}
// Release CChannel mutex
pthread_mutex_unlock(&m_mutex);
DbgTrace(1, "CChannel::closeChannel- End\n", 0);
} /*-- CChannel::closeChannel() --*/
//++=======================================================================
bool
CChannel::ok(void)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
bool retStatus;
DbgTrace(1, "CChannel::ok- Start, Obj = %08X\n", this);
// Return true if connected
if (m_state == State_Connected)
retStatus = true;
else
retStatus = false;
DbgTrace(1, "CChannel::ok- End, retStatus = %08X\n", retStatus);
return retStatus;
} /*-- CChannel::ok() --*/
//++=======================================================================
uint32_t
CChannel::allocReqId(void)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
uint32_t allocatedId;
DbgTrace(1, "CChannel::allocReqId- Start, Obj = %08X\n", this);
// Perform atomic operation
allocatedId = InterlockedIncrement(&m_reqIdAllocator);
DbgTrace(1, "CChannel::allocReqId- End, allocatedId = %08X\n", allocatedId);
return allocatedId;
} /*-- CChannel::allocReqId() --*/
//++=======================================================================
int
CChannel::submitReq(
uint32_t reqId,
ClientReq &clientReq,
char *pClientData,
int clientDataLen)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
int retStatus = -1;
char reqDataPktHdr[ReqDataPktHdrTemplate.length()];
struct msghdr sendmsgHdr = {0};
struct iovec ioVectors[2];
unsigned long bytesSent;
unsigned long totalBytesSent = 0;
unsigned long bytesToSend = sizeof(reqDataPktHdr) + clientDataLen;
DbgTrace(1, "CChannel::submitReq- Start, Obj = %08X\n", this);
// Acquire exclusive access to the channel object
pthread_mutex_lock(&m_mutex);
// Verify that the channel is connected
if (m_state == State_Connected)
{
// Insert the specified ClientReq into the ClientReqMap and forward the client
// data to the server.
RCIterBoolPair insertResult;
insertResult = m_rcMap.insert(make_pair(reqId, &clientReq));
if (!insertResult.second)
{
// Insertion failed
DbgTrace(0, "CChannel::submitReq- Unable to insert ClientReq into ClientReqMap, Obj = %08X\n", this);
}
else
{
// Insertion succeded, now send the request to the server.
//
// Build ReqDataHeader
if (ChannelProto::buildReqDataPktHdr(reqId,
clientDataLen,
reqDataPktHdr) == 0)
{
// Packet header was built, now sent it along with the client data to
// the server.
ioVectors[0].iov_base = reqDataPktHdr;
ioVectors[0].iov_len = sizeof(reqDataPktHdr);
ioVectors[1].iov_base = (char*) pClientData;
ioVectors[1].iov_len = clientDataLen;
sendmsgHdr.msg_iov = ioVectors;
sendmsgHdr.msg_iovlen = 2;
while (1)
{
bytesSent = sendmsg(m_socket,
&sendmsgHdr,
MSG_NOSIGNAL);
if (bytesSent == SOCKET_ERROR)
{
// Check if we were interrupted during the transfer
if (errno == EINTR)
{
// Just try again
continue;
}
// An unrecoverable error was encountered during the send operation,
// assume there was a communication failure. Close the socket to make
// sure that the connectionThread cleans up.
DbgTrace(0, "CChannel::submitReq- sendmsg error, errno = %d\n", errno);
m_state = State_Disconnected;
shutdown(m_socket, SHUT_RDWR);
struct linger linger_opt = {1, 15};
setsockopt(m_socket, SOL_SOCKET, SO_LINGER, &linger_opt, sizeof(linger_opt));
closesocket(m_socket);
m_socket = INVALID_SOCKET;
break;
}
else
{
// Account for the bytes sent
totalBytesSent += bytesSent;
// Check if we are done sending all of the data
if (totalBytesSent >= bytesToSend)
{
// We are done
break;
}
else
{
// Adjust the ioVector structure to send data not yet sent
if (totalBytesSent >= sizeof(reqDataPktHdr))
{
// The packet header was sent, use only one ioVector.
int clientDataAlreadySent = totalBytesSent - sizeof(reqDataPktHdr);
ioVectors[0].iov_base = (char*) pClientData + clientDataAlreadySent;
ioVectors[0].iov_len = clientDataLen - clientDataAlreadySent;
sendmsgHdr.msg_iov = ioVectors;
sendmsgHdr.msg_iovlen = 1;
}
else
{
// Not all of the packet header was sent, use two ioVectors.
ioVectors[0].iov_base = (char*) reqDataPktHdr + totalBytesSent;
ioVectors[0].iov_len = sizeof(reqDataPktHdr) - totalBytesSent;
ioVectors[1].iov_base = (char*) pClientData;
ioVectors[1].iov_len = clientDataLen;
sendmsgHdr.msg_iov = ioVectors;
sendmsgHdr.msg_iovlen = 2;
}
}
}
}
// Return success even if the send failed to allow things to be cleaned up
// by the connectionThread routine.
retStatus = 0;
}
else
{
DbgTrace(0, "CChannel::submitReq- Error building Req Data Pkt Header, Obj = %08X\n", this);
// Remove ClientReq from the ClientReqMap
RCMapIter iter = m_rcMap.find(reqId);
if (iter != m_rcMap.end())
{
// Object was found in the map, remove it.
m_rcMap.erase(iter);
}
else
{
DbgTrace(0, "CChannel::submitReq- Error, did not find object in map to remove\n", 0);
}
}
}
}
else
{
DbgTrace(1, "CChannel::submitReq- Channel not connected, state = %08X\n", m_state);
}
// Release exclusive access to the channel object
pthread_mutex_unlock(&m_mutex);
DbgTrace(1, "CChannel::submitReq- End, retStatus = %08X\n", retStatus);
return retStatus;
} /*-- CChannel::submitReq() --*/
//++=======================================================================
void
CChannel::removeReq(
uint32_t reqId)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
DbgTrace(1, "CChannel::removeReq- Start, Obj = %08X\n", this);
// Acquire exclusive access to the channel object
pthread_mutex_lock(&m_mutex);
// Try to find the ClientReq in the ClientReqMap using the reqId
RCMapIter iter = m_rcMap.find(reqId);
if (iter != m_rcMap.end())
{
// Object was found in the map, remove it.
m_rcMap.erase(iter);
}
else
{
DbgTrace(0, "CChannel::removeReq- Error, did not find object in map\n", 0);
}
// Release exclusive access to the channel object
pthread_mutex_unlock(&m_mutex);
DbgTrace(1, "CChannel::removeReq- End\n", 0);
} /*-- CChannel::removeReq() --*/
//=========================================================================
//=========================================================================

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,628 @@
/***********************************************************************
*
* 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
char unInitialized[] = "Uninitialized";
char *pAppName = unInitialized;
// Application threaded information
bool appMultithreaded;
// Client mutex
pthread_mutex_t clientMutex;
// Mutex for interlocked operations
pthread_mutex_t interlockedMutex;
// Indicators
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;
REPMap repMap;
// RemoteEndPoint handle allocator
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 ++;
// Insert the new RemoteEndPoint into the REP map
REPIterBoolPair insertResult;
insertResult = repMap.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.
*pEndPointHandle = handle;
retStatus = 0;
}
} 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 = %08X\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 ++;
// Insert the new RemoteEndPoint into the REP map
REPIterBoolPair insertResult;
insertResult = repMap.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.
*pEndPointHandle = handle;
retStatus = 0;
}
} 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 = %08X\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 = repMap.find(endPointHandle);
if (iter != repMap.end())
{
// Object was found in the map, remove it.
SmartRemoteEndPoint *pSmartRemoteEndPoint = iter->second;
repMap.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);
}
exit:
DbgTrace(1, "IpcClientCloseRemoteEndPoint- End, status = %08X\n", retStatus);
return retStatus;
}
//++=======================================================================
extern "C"
int
IpcClientSubmitReq(
IN uint32_t endPointHandle,
IN char *pClientData,
IN int clientDataLen,
INOUT char **ppServerData,
INOUT int *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 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 = repMap.find(endPointHandle);
if (iter != repMap.end())
{
// Object was found in the map, use it to submit
// the request.
SmartRemoteEndPoint *pSmartRemoteEndPoint = new SmartRemoteEndPoint(*(iter->second));
// Release our mutex before deleting the 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);
}
DbgTrace(1, "IpcClientSubmitReq- End, retStatus = %08X\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 (pAppName == NULL)
{
DbgTrace(0, "IpcClientInit- Invalid parameter\n", 0);
goto exit;
}
// Verify that we have not been initialized already
if (!svcInitialized)
{
// 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 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;
}
else
{
DbgTrace(0, "IpcClientInit- Initialized already\n", 0);
}
exit:
DbgTrace(1, "IpcClientInit- 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);
// 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 (!repMap.empty())
{
REPMapIter iter = repMap.begin();
SmartRemoteEndPoint *pSmartRemoteEndPoint = iter->second;
repMap.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);
}
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();
}
//=========================================================================
//=========================================================================

View File

@@ -0,0 +1,332 @@
/***********************************************************************
*
* 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);
// 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 = %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,441 @@
/***********************************************************************
*
* 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
//=======================================================================--
{
DbgTrace(1, "RemoteEndPoint::RemoteEndPoint- Start, Obj = %08X\n", this);
// Initialize our mutex
pthread_mutex_init(&m_mutex, NULL);
// Set the necessary information in the m_serverUnAddr variable
m_serverUnAddr.sun_family = AF_UNIX;
strcpy(m_serverUnAddr.sun_path, pSocketFileName);
// 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);
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
//=======================================================================--
{
DbgTrace(1, "RemoteEndPoint::RemoteEndPoint- Start, Obj = %08X\n", this);
// 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);
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
//=======================================================================--
{
DbgTrace(1, "RemoteEndPoint::~RemoteEndPoint- Start, Obj = %08X\n", this);
// 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;
DbgTrace(1, "RemoteEndPoint::getCChannel- Start, Obj = %08X\n", this);
#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);
}
CChannel *pCChannel;
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,
int clientDataLen,
char **ppServerData,
int *pServerDataLen)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
int retStatus = -1;
DbgTrace(1, "RemoteEndPoint::submitReq- Start, Obj = %08X\n", this);
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() --*/
//=========================================================================
//=========================================================================

View File

@@ -0,0 +1,203 @@
/***********************************************************************
*
* 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 _REMOTEENDPOINT_
#define _REMOTEENDPOINT_
//===[ Include files ]=====================================================
//===[ External data ]=====================================================
//===[ External prototypes ]===============================================
//===[ Manifest constants ]================================================
#define MAX_CHANNELS_PER_ENDPOINT 3
//===[ Type definitions ]==================================================
//===[ Function prototypes ]===============================================
//===[ Global variables ]==================================================
//===[ Type definitions ]==================================================
//
// Server Thread Class
//
class RemoteEndPoint : public ObjRef
{
//
// 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; }
};
// Signature
unsigned long m_signature;
// End-point address
bool m_Use_AF_INET;
bool m_Use_PF_UNIX;
struct sockaddr_in m_serverInAddr;
struct sockaddr_un m_serverUnAddr;
// SmartCChannelPointers vector
vector<SmartCChannelPointer> m_cchannelVector;
int m_numCChannels;
// Endpoint mutex
pthread_mutex_t m_mutex;
// Number of submits made to the endpoint
int m_numChannelSubmits;
// Max number of Rpc retries
int m_maxRpcRetries;
public:
//
// Destructor
~RemoteEndPoint(void);
//
// Constructor
//
// Parameters:
// multithreaded (input) -
// Set to TRUE if the process is
// multithreaded.
//
// maxRpcRetries (input) -
// Max Rpc retries.
//
// pSocketFileName (input) -
// Pointer to string containing the name
// of the socket file.
//
// Abstract: Constructs RemoteEndPoint object and initializes it using
// a domain socket file name.
//
// Returns: Nothing.
//
RemoteEndPoint(bool multiThreaded,
int maxRpcRetries,
char *pSocketFileName);
//
// Constructor
//
// Parameters:
// multithreaded (input) -
// Set to TRUE if the process is
// multithreaded.
//
// maxRpcRetries (input) -
// Max Rpc retries.
//
// port (input) -
// Server's listening port number.
//
// address (input) -
// The server's IP Address. Use
// 0x7F000001 if the endpoint is local.
//
// Abstract: Constructs RemoteEndPoint object and initializes it using
// a tcp socket address.
//
// Returns: Nothing.
//
RemoteEndPoint(bool multiThreaded,
int maxRpcRetries,
unsigned short int port,
uint32_t address);
//
// Get a SmartCChannel.
//
// Parameters: None.
//
// Abstract: Gets a SmartCChannel for submitting requests to the
// remote endpoint.
//
// Returns: Pointer to SmartCChannel object if successful, otherwise
// NULL.
//
SmartCChannel *getCChannel(void);
//
// Submit a request to the endpoint,
//
// Parameters:
// 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.
//
// ppServerData (input/output) -
// Pointer to variable that will receive a
// pointer to the buffer containing the data
// received from the server.
//
// pServerDataLen (input/output) -
// Pointer to variable that will receive the
// length of the data received from the server.
//
// Abstract: Method to submit a request.
//
// Returns: 0 == Request completed gracefully
// -1 == Request did not complete gracefully
//
// Note: The routine blocks until the request completes.
//
int submitReq(char *pClientData,
int clientDataLen,
char **ppServerData,
int *pServerDataLen);
};
typedef SmartPtr<RemoteEndPoint> SmartRemoteEndPoint;
//===[ Function prototypes ]===============================================
#endif // _REMOTEENDPOINT_
//=========================================================================
//=========================================================================

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,301 @@
/***********************************************************************
*
* 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(
uint32_t remoteEndPointHandle)
//
// 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(remoteEndPointHandle,
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;
uint32_t endPointHandle;
DbgTrace(1, "ExecuteTests- Start\n", 0);
// Initialize the Client Ipc Subsystem
if (IpcClientInit("TestClient",
true,
DebugLevel,
false) == 0)
{
// Set the server listen address
if (IpcClientOpenInetRemoteEndPoint(5000,
0x7F000001,
0,
&endPointHandle) == 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*)endPointHandle);
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
&& !errorDetected)
sleep(1);
sleep(1);
}
// Close the remote endpoint
if (IpcClientCloseRemoteEndPoint(endPointHandle) != 0)
{
DbgTrace(0, "ExecuteTests- Error closing remote endpoint\n", 0);
}
}
else
{
DbgTrace(0, "ExecuteTests- Error opening remote endpoint\n", 0);
}
IpcClientShutdown();
sleep(1);
}
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;
int initialCount;
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);
initialCount = submitReqCount;
ExecuteTests();
printf("Submits issued = %d\n", initialCount - submitReqCount);
}
else
{
// Invalid option detected
printf(usage, argv[0]);
}
return 0;
} /*-- main() --*/