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,41 @@
#######################################################################
#
# 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 LINUX
SUBDIRS = $(TARGET_OS)
else
SUBDIRS =
endif
DIST_SUBDIRS = linux
CFILES =
EXTRA_DIST = $(CFILES)
.PHONY: package package-clean package-install package-uninstall
package package-clean package-install package-uninstall:
$(MAKE) -C $(TARGET_OS) $@
maintainer-clean-local:
rm -f Makefile.in

View File

@@ -0,0 +1,103 @@
/***********************************************************************
*
* 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>
*
***********************************************************************/
/***********************************************************************
*
* README for IpcLibs
*
***********************************************************************/
INTRODUCTION
IpcLibs provides an IPC infrastructure that can be linked into client and server
applications.
IpcLibs provides IPC communications over TCP or DOMAIN sockets. It does this in a scalable
and un-serialized manner. The infrastructure can make use of multiple communication channels
between a client and a server and is capabled of concurrently serving multiple requests over
the different channels.
The IpcLib APIs are very simple to utilize and support multi-threaded applications.
SERVER APPLICATION PROGRAMMING NOTES
The IPC API for server applications is defined in casa_s_ipc.h. This API is provided by
libcasa_s_ipc.so.
To utilize the IPC server services, an application must first initialize the infrastructure by
calling IpcServerInit() which is then followed by the desired IpcServerSetXXAddress() call.
After the Ipc server is initialized and the server address is set, then the application calls
IpcServerStart() to start the engine (This causes the engine to start to accept connections and
receive requests from clients).
To start servicing requests, the application executesIpcServerGetRequest(); this calls blocks until
a request is ready to be serviced at which time it returns with an ID which is associated with the
request that needs to be serviced. The returned ID is then used by the application to retrieve the
request data via the IpcServerGetRequestData(), once the application processes the request, it
completes it by executing IpcServerCompleteRequest() with the ID and any data that it may want to
send back to the client.
Note that a server application can call IpcServerGetRequest() from multiple threads to make itself
more scalable.
For an example server application that utilizes the IPC API for servers, see file
linux/server/test/testServer.c.
CLIENT APPLICATION PROGRAMMING NOTES
The IPC API for client applications is defined in casa_c_ipc.h. This API is provided by
libcasa_c_ipc.so.
To utilize the IPC client services, an application must first initialize the infrastructure by
calling IpcClientInit(). Once the IPC client is initialized, then the application needs to open
endpoints for the servers that it wishes to submit requests. Endpoints are opened by calling the
appropriate IpcClientOpenXXRemoteEndPoint() with information about the server listen address.
IpcClientOpenXXRemoteEndpoint() calls return a handles that are associated with the opened
endpoints. This endpoint handles are then utilized by the application to specify the target of
IPC requests.
To submit a request to a particular endpoint, the application executes IpcClientSubmitReq() with
the endpoint handle and the request data. Calls to IpcClientSubmitReq() block until the requests
is processed by the server at which time it returns the reply data.
For an example client application that utilizes the IPC API for clients, see file
linux/client/test/testClient.c.
SECURITY CONSIDERATIONS
IpcLibs does not provide any security features beyond what is provided by the protocol stacks for
tcp/ip and Domain sockets communications.
By leveraging the File System Access Control features, you can scope communications that occur over
Domain sockets to specific or groups of users.

View File

@@ -0,0 +1,14 @@
/***********************************************************************
*
* TODO for IpcLibs
*
***********************************************************************/
INTRODUCTION
This file contains a list of the items still outstanding for IpcLibs.
OUTSTANDING ITEMS
- Add APIs to allow for the senging of fragmented request and reply data.

View File

@@ -0,0 +1,37 @@
#######################################################################
#
# 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>
#
#######################################################################
SUBDIRS = client server
DIST_SUBDIRS = common client server
CFILES =
EXTRA_DIST = $(CFILES)
.PHONY: package package-clean package-install package-uninstall
package package-clean package-install package-uninstall:
$(MAKE) -C $(TARGET_OS) $@
maintainer-clean-local:
rm -f Makefile.in

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() --*/

View File

@@ -0,0 +1,39 @@
#######################################################################
#
# 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>
#
#######################################################################
SUBDIRS =
DIST_SUBDIRS =
CFILES =
CPPFILES = channelproto.cpp
EXTRA_DIST = $(CFILES) $(CPPFILES) *.h
.PHONY: package package-clean package-install package-uninstall
package package-clean package-install package-uninstall:
$(MAKE) -C $(TARGET_OS) $@
maintainer-clean-local:
rm -f Makefile.in

View File

@@ -0,0 +1,388 @@
/***********************************************************************
*
* 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"
//===[ External data ]=====================================================
//===[ External prototypes ]===============================================
//===[ Manifest constants ]================================================
//===[ Type definitions ]==================================================
//===[ Function prototypes ]===============================================
//===[ Global variables ]==================================================
// Channel Packet Types
string DataCarrierTypeTemplate = "TypeXX";
string ReqDataCarrierType = "Type01";
string ReqErrorCarrierType = "Type02";
// Channel Packet Headers
string ReqIdHdr = "ReqIdHdr =";
string PayloadLengthHdr = "PayloadLength =";
// Req Data Pkt Hdr Template
string ReqDataPktHdrTemplate = "Type01\r\nReqIdHdr =XXXXXXXX\r\nPayloadLength =XXXXXXXX\r\n\r\n";
// Req Error Pkt Hdr Template
string ReqErrorPktHdrTemplate = "Type02\r\nReqIdHdr =XXXXXXXX\r\nPayloadLength =XXXXXXXX\r\n\r\n";
//++=======================================================================
int
ChannelProto::buildReqDataPktHdr(
uint32_t reqId,
int32_t payloadLength,
char *pPktHdr)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
int retStatus = -1;
DbgTrace(1, "ChannelProto::buildReqDataPktHdr- Start\n", 0);
try {
// - Req Data Packet Header Format -
//
// ReqDataCarrierType
// ReqIdHdr value (value format=%08X)
// PayloadLengthHdr value (value format=%08X)
//
// Setup the necessary value strings
char wrkBuffer[10];
sprintf(wrkBuffer, "%08X", reqId);
string reqIdValue = wrkBuffer;
sprintf(wrkBuffer, "%08X", payloadLength);
string payloadLengthValue = wrkBuffer;
// Format the header.
char* pCurr = pPktHdr;
memcpy(pCurr, ReqDataCarrierType.c_str(), ReqDataCarrierType.length());
pCurr += ReqDataCarrierType.length();
memcpy(pCurr, "\r\n", 2);
pCurr += 2;
memcpy(pCurr, ReqIdHdr.c_str(), ReqIdHdr.length());
pCurr += ReqIdHdr.length();
memcpy(pCurr, reqIdValue.c_str(), reqIdValue.length());
pCurr += reqIdValue.length();
memcpy(pCurr, "\r\n", 2);
pCurr += 2;
memcpy(pCurr, PayloadLengthHdr.c_str(), PayloadLengthHdr.length());
pCurr += PayloadLengthHdr.length();
memcpy(pCurr, payloadLengthValue.c_str(), payloadLengthValue.length());
pCurr += payloadLengthValue.length();
memcpy(pCurr, "\r\n\r\n", 4);
// Success
retStatus = 0;
}
catch (...) {
DbgTrace(0, "ChannelProto::buildReqDataPktHdr- Exception caught while creating header\n", 0);
}
DbgTrace(1, "ChannelProto::buildReqDataPktHdr- End, retStatus = %08X\n", retStatus);
return retStatus;
} /*-- ChannelProto::buildReqDataPktHdr() --*/
//++=======================================================================
int
ChannelProto::buildReqErrorPktHdr(
uint32_t reqId,
int32_t payloadLength,
char *pPktHdr)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
int retStatus = -1;
DbgTrace(1, "ChannelProto::buildReqErrorPktHdr- Start\n", 0);
try {
// - Req Error Packet Header Format -
//
// ReqErrorCarrierType
// ReqIdHdr value (value format=%08X)
// PayloadLengthHdr value (value format=%08X)
//
// Setup the necessary value strings
char wrkBuffer[10];
sprintf(wrkBuffer, "%08X", reqId);
string reqIdValue = wrkBuffer;
sprintf(wrkBuffer, "%08X", payloadLength);
string payloadLengthValue = wrkBuffer;
// Format the header.
char* pCurr = pPktHdr;
memcpy(pCurr, ReqErrorCarrierType.c_str(), ReqErrorCarrierType.length());
pCurr += ReqErrorCarrierType.length();
memcpy(pCurr, "\r\n", 2);
pCurr += 2;
memcpy(pCurr, ReqIdHdr.c_str(), ReqIdHdr.length());
pCurr += ReqIdHdr.length();
memcpy(pCurr, reqIdValue.c_str(), reqIdValue.length());
pCurr += reqIdValue.length();
memcpy(pCurr, "\r\n", 2);
pCurr += 2;
memcpy(pCurr, PayloadLengthHdr.c_str(), PayloadLengthHdr.length());
pCurr += PayloadLengthHdr.length();
memcpy(pCurr, payloadLengthValue.c_str(), payloadLengthValue.length());
pCurr += payloadLengthValue.length();
memcpy(pCurr, "\r\n\r\n", 4);
// Success
retStatus = 0;
}
catch (...) {
DbgTrace(0, "ChannelProto::buildReqErrorPktHdr- Exception caught while creating header\n", 0);
}
DbgTrace(1, "ChannelProto::buildReqErrorPktHdr- End, retStatus = %08X\n", retStatus);
return retStatus;
} /*-- ChannelProto::buildReqErrorPktHdr() --*/
//++=======================================================================
ChannelProto::PacketTypes
ChannelProto::getPktType(
char &buff)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
PacketTypes packetType = UnknownPacketType;
DbgTrace(1, "ChannelProto::getPktType- Start\n", 0);
// Find the end of the Channel Packet Type
char *pCurr = &buff;
while (*pCurr != '\r')
pCurr ++;
// Found the end of the Channel Packet Type, now
// calculate its length.
int channelPktTypeLength = pCurr - &buff;
// Now start comparing
if (channelPktTypeLength == ReqDataCarrierType.length()
&& !memcmp(&buff, ReqDataCarrierType.c_str(), channelPktTypeLength))
{
// The type is Channel Req Data Carrier
packetType = ReqDataCarrierPacketType;
}
else if (channelPktTypeLength == ReqErrorCarrierType.length()
&& !memcmp(&buff, ReqErrorCarrierType.c_str(), channelPktTypeLength))
{
// The type is Channel Req Error Carrier
packetType = ReqErrorCarrierPacketType;
}
else
{
DbgTrace(0, "ChannelProto::getPktType- No match found\n", 0);
}
DbgTrace(1, "ChannelProto::getPktType- End, type = %d\n", packetType);
return packetType;
} /*-- ChannelProto::getPktType() --*/
//++=======================================================================
bool
ChannelProto::getReqIdAndPayloadLength(
char *pBuff,
int hdrLength,
uint32_t *pReqId,
int32_t *pPayloadLength)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
bool reqIdObtained = false;
bool payloadLengthObtained = false;
DbgTrace(1, "ChannelProto::getReqIdAndPayloadLength- Start\n", 0);
char *pCurr = pBuff;
char *pChannelHdr = NULL;
int bytesLeft = hdrLength;
// Skip the Channel Packet Type
while (bytesLeft >= 2)
{
if (*pCurr == '\r'
&& *(pCurr+1) == '\n')
{
// Found the end of the channel packet type
pCurr += 2;
bytesLeft -= 2;
break;
}
else
{
pCurr ++;
bytesLeft --;
}
}
// Start processing Channel Packet Headers
pChannelHdr = pCurr;
while (bytesLeft >= 2
&& (!reqIdObtained || !payloadLengthObtained))
{
if (*pCurr == '\r'
&& *(pCurr+1) == '\n')
{
// Found the end of the current channel header
pCurr += 2;
bytesLeft -= 2;
// Check if the line is empty or if it contained a
// channel header.
if ((pCurr - pChannelHdr) == 2)
{
// This was an empty line, which means that
// we reached the end of the channel packet header.
break;
}
else
{
// Check if the header is the Req Id Hdr
if (!reqIdObtained && (pCurr - pChannelHdr) > ReqIdHdr.length()
&& !memcmp(pChannelHdr, ReqIdHdr.c_str(), ReqIdHdr.length()))
{
// We found the Req Id Hdr, get the value.
char *pValue = pChannelHdr + ReqIdHdr.length();
// Temporarily NULL terminate the value
*(pCurr-2) = '\0';
// Convert the value to hex
*pReqId = strtoul(pValue, NULL, 16);
// Undo the damage that we did
*(pCurr-2) = '\r';
// Remember that the Req Id was obtained
reqIdObtained = true;
}
// Check if the header is the Payload Length Hdr
else if ((pCurr - pChannelHdr) > PayloadLengthHdr.length()
&& !memcmp(pChannelHdr, PayloadLengthHdr.c_str(), PayloadLengthHdr.length()))
{
// We found the Payload Length Hdr, get the value.
char *pValue = pChannelHdr + PayloadLengthHdr.length();
// Temporarily NULL terminate the value
*(pCurr-2) = '\0';
// Convert the value to hex
*pPayloadLength = strtoul(pValue, NULL, 16);
// Undo the damage that we did
*(pCurr-2) = '\r';
// Remember that the Payload Lenght was obtained
payloadLengthObtained = true;
}
// Get set to process the next header
pChannelHdr = pCurr;
}
}
else
{
pCurr ++;
bytesLeft --;
}
}
DbgTrace(1,
"ChannelProto::getReqIdAndPayloadLength- End, retStatus = %08X\n",
reqIdObtained && payloadLengthObtained);
return reqIdObtained && payloadLengthObtained;
} /*-- ChannelProto::getReqIdAndPayloadLength() --*/
//=========================================================================
//=========================================================================

View File

@@ -0,0 +1,157 @@
/***********************************************************************
*
* 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 _CHANNELPROTO_
#define _CHANNELPROTO_
//===[ Include files ]=====================================================
//===[ External data ]=====================================================
extern string ReqDataPktHdrTemplate;
extern string ReqErrorPktHdrTemplate;
//===[ External prototypes ]===============================================
//===[ Manifest constants ]================================================
//===[ Type definitions ]==================================================
//===[ Function prototypes ]===============================================
//===[ Global variables ]==================================================
//===[ Type definitions ]==================================================
//
// ChannelProto Class Definition
//
class ChannelProto
{
public:
// Packet Types
enum PacketTypes
{
ReqDataCarrierPacketType = 1,
ReqErrorCarrierPacketType,
UnknownPacketType
};
//
// Build Req Data Packet Header routine
//
// Parameters:
// reqId (input) -
// Req id.
//
// payloadLength (input) -
// Length of the payload being carried by the packet.
//
// pPktHdt (input/output) -
// Pointer to buffer that will receive the header.
// Note, this buffer needs to be big eneough to
// contain the ReqDataPktHdrTemplate string.
//
// Abstract: Returns Req Data Pkt Hdr for the specified
// parameters.
//
// Returns: 0 if successful.
//
static int buildReqDataPktHdr(uint32_t reqId,
int32_t payloadLength,
char *pPktHdr);
//
// Build Req Error Packet Header routine
//
// Parameters:
// reqId (input) -
// Req id.
//
// payloadLength (input) -
// Length of the payload being carried by the packet.
//
// pPktHdt (input/output) -
// Pointer to buffer that will receive the header.
// Note, this buffer needs to be big eneough to
// contain the ReqErrorPktHdrTemplate string.
//
// Abstract: Returns Req Error Pkt Hdr for the specified
// parameters.
//
// Returns: 0 if successful.
//
static int buildReqErrorPktHdr(uint32_t reqId,
int32_t payloadLength,
char *pPktHdr);
//
// Get Channel Packet Type routine
//
// Parameters:
// buff (input) -
// Reference to buffer containing the packet data.
//
// Abstract: Returns the type of the specified channel packet.
//
// Returns: Channel packet type.
//
static PacketTypes getPktType(char &buff);
//
// Get Req Id and Payload Length Values routine
//
// Parameters:
// buff (input) -
// Reference to buffer containing the packet data.
//
// hdrLength (input) -
// Length of the channel header.
//
// pReqId (input/output) -
// Pointer to variable that will receive the req id.
//
// pPayloadLength (input/output) -
// Pointer to variable that will receive the payload length.
//
// Abstract: Returns the values of the ReqId and PayloadLength headers
// present in the channel packet header.
//
// Returns: True if successful.
//
static bool getReqIdAndPayloadLength(char *pBuff,
int hdrLength,
uint32_t *pReqId,
int32_t *pPayloadLength);
};
//===[ Function prototypes ]===============================================
#endif // _CHANNELPROTO_
//=========================================================================
//=========================================================================

View File

@@ -0,0 +1,152 @@
/**********************\*************************************************
*
* 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 _IPCINT_
#define _IPCINT_
//===[ Include files ]=====================================================
#include <iostream>
#include <string>
#include <list>
#include <map>
#include <vector>
using namespace std;
extern "C" {
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <syslog.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <assert.h> // Ensure that NDEBUG is defined for release builds!
#include <sys/ipc.h>
}
//===[ External data ]=====================================================
extern int DebugLevel;
extern bool UseSyslog;
extern char *pAppName;
extern pthread_mutex_t interlockedMutex;
//===[ Macro definitions ]=================================================
//
// DbgTrace macro define
//
#define MAX_FORMAT_STRING_LEN 1024
#define DbgTrace(LEVEL, X, Y) { \
if (LEVEL == 0 || DebugLevel >= LEVEL) { \
if (UseSyslog) \
syslog(LOG_USER | LOG_INFO, X, Y); \
else { \
char *pFormatString = new char[MAX_FORMAT_STRING_LEN]; \
if (pFormatString) { \
snprintf(pFormatString, MAX_FORMAT_STRING_LEN, X, Y); \
fprintf(stderr, "%s -%s", pAppName, pFormatString); \
delete[] pFormatString; \
} \
} \
} \
}
//
// Interlocked Increment and Decrement macros
//
// Well, kind of interlocked :-).
//
__inline static unsigned long
InterlockedIncrement(unsigned long *pValue)
{
unsigned long retVal;
pthread_mutex_lock(&interlockedMutex);
(*pValue) ++;
retVal = *pValue;
pthread_mutex_unlock(&interlockedMutex);
return retVal;
}
__inline static unsigned long
InterlockedDecrement(unsigned long *pValue)
{
unsigned long retVal;
pthread_mutex_lock(&interlockedMutex);
(*pValue) --;
retVal = *pValue;
pthread_mutex_unlock(&interlockedMutex);
return retVal;
}
__inline static uint32_t
InterlockedIncrement(uint32_t *pValue)
{
uint32_t retVal;
pthread_mutex_lock(&interlockedMutex);
(*pValue) ++;
retVal = *pValue;
pthread_mutex_unlock(&interlockedMutex);
return retVal;
}
__inline static uint32_t
InterlockedDecrement(uint32_t *pValue)
{
uint32_t retVal;
pthread_mutex_lock(&interlockedMutex);
(*pValue) --;
retVal = *pValue;
pthread_mutex_unlock(&interlockedMutex);
return retVal;
}
//===[ Include files ]=====================================================
#include "smartptr.h"
#include "channelproto.h"
//===[ External prototypes ]===============================================
//===[ Manifest constants ]================================================
//===[ Type definitions ]==================================================
//===[ Function prototypes ]===============================================
#endif // _IPCINT_
//=========================================================================
//=========================================================================

View File

@@ -0,0 +1,275 @@
/***********************************************************************
*
* 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.
*
***********************************************************************/
#ifndef SMARTPTR_H
#define SMARTPTR_H
/*******************************************************************************
* Include Files
*******************************************************************************/
/*******************************************************************************
* Definitions
*******************************************************************************/
/*******************************************************************************
* Types and Classes
*******************************************************************************/
//------------------------------------------------------------------------------
// Reference Object
//
// In order to use the SmartPtr<> class, the object type used to instantiate
// the SmartPtr template must inheirit from the ObjRef class.
//
//------------------------------------------------------------------------------
class ObjRef
{
//---------------------------------------------------------------------------
// Public interface
//
public:
ObjRef() : m_Count(0) {}
void IncRefCount(void)
{
InterlockedIncrement(&m_Count);
}
bool DecRefCount(void)
{
if ((m_Count > 0) && (InterlockedDecrement(&m_Count) == 0))
{
return true;
}
else
{
return false;
}
}
unsigned int GetRefCount(void) const
{
return m_Count;
}
//---------------------------------------------------------------------------
// Private data
//
private:
mutable unsigned long m_Count;
};
//------------------------------------------------------------------------------
// SmartPtr Object
//
//------------------------------------------------------------------------------
template<class T>
class SmartPtr
{
//---------------------------------------------------------------------------
// Public interface
//
public:
SmartPtr();
SmartPtr(T* ptr);
SmartPtr(const SmartPtr<T>& ref);
virtual ~SmartPtr();
operator bool (void) const;
bool operator! (void) const;
bool operator== (SmartPtr<T>& ref) const;
bool operator!= (SmartPtr<T>& ref) const;
SmartPtr<T>& operator= (const SmartPtr<T>& ref);
SmartPtr<T>& operator= (T* ptr);
T& operator* (void) const;
T* operator-> (void) const;
operator T* (void) const;
//---------------------------------------------------------------------------
// Private interface
//
private:
void deleteObject(void);
void resetPtr(T* newPtr);
//---------------------------------------------------------------------------
// Private data
//
private:
T* m_Ptr;
};
template<class T>
inline SmartPtr<T>::SmartPtr() :
m_Ptr(0)
{
} // End of SmartPtr::SmartPtr()
template<class T>
inline SmartPtr<T>::SmartPtr(T* ptr) :
m_Ptr(0)
{
resetPtr(ptr);
} // End of SmartPtr::SmartPtr()
template<class T>
inline SmartPtr<T>::SmartPtr(const SmartPtr<T>& ref) :
m_Ptr(0)
{
resetPtr(ref.m_Ptr);
} // End of SmartPtr::SmartPtr()
template<class T>
inline SmartPtr<T>::~SmartPtr()
{
deleteObject();
} // End of SmartPtr::~SmartPtr()
template<class T>
inline SmartPtr<T>::operator bool (void) const
{
return m_Ptr != 0;
} // End of SmartPtr::operator bool()
template<class T>
inline bool SmartPtr<T>::operator! (void) const
{
return m_Ptr == 0;
} // End of SmartPtr::operator!()
template<class T>
inline bool SmartPtr<T>::operator== (SmartPtr<T>& ref) const
{
return m_Ptr == ref.m_Ptr;
} // End of SmartPtr::operator==()
template<class T>
inline bool SmartPtr<T>::operator!= (SmartPtr<T>& ref) const
{
return m_Ptr != ref.m_Ptr;
} // End of SmartPtr::operator==()
template<class T>
inline SmartPtr<T>& SmartPtr<T>::operator= (const SmartPtr<T>& ref)
{
resetPtr(ref.m_Ptr);
return *this;
} // End of SmartPtr::operator=()
template<class T>
inline SmartPtr<T>& SmartPtr<T>::operator= (T* ptr)
{
resetPtr(ptr);
return *this;
} // End of SmartPtr::operator=()
template<class T>
inline T& SmartPtr<T>::operator* (void) const
{
return *m_Ptr;
} // End of SmartPtr::operator*()
template<class T>
inline T* SmartPtr<T>::operator-> (void) const
{
return m_Ptr;
} // End of SmartPtr::operator->()
template<class T>
inline SmartPtr<T>::operator T* (void) const
{
return m_Ptr;
} // End of SmartPtr::operator T*()
template<class T>
inline void SmartPtr<T>::deleteObject(void)
{
if (m_Ptr && m_Ptr->DecRefCount())
{
delete m_Ptr;
m_Ptr = 0;
}
} // End of SmartPtr::deleteObject()
template<class T>
inline void SmartPtr<T>::resetPtr(T* newPtr)
{
if (m_Ptr != newPtr)
{
deleteObject();
m_Ptr = newPtr;
if (m_Ptr)
{
// New object reference.
m_Ptr->IncRefCount();
}
}
} // End of SmartPtr::resetPtr()
#endif // SMARTPTR_H
/******************************************************************************/
/******************************************************************************/

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
SERVER = .
MODULE_NAME = libcasa_s_ipc
MODULE_EXT = so
CFILES =
CPPFILES = schannel.cpp \
serverreq.cpp \
serverthread.cpp \
server.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 $(SERVER) $(COMMON)
vpath %.cpp $(SERVER) $(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,776 @@
/***********************************************************************
*
* 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 "schannel.h"
#include "serverreq.h"
//===[ External data ]=====================================================
//===[ External prototypes ]===============================================
extern int
ServiceRequest(
ServerReq *pServerReq);
extern void
RemoveFromSChannelList(
SChannel *pSChannel);
//===[ 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 numSChannelObjects = 0;
//===[ Type definitions ]==================================================
//===[ Function prototypes ]===============================================
//===[ Global variables ]==================================================
//++=======================================================================
SChannel::SChannel(
int connSocket) :
m_state (State_Connected),
m_socket (connSocket)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
DbgTrace(1, "SChannel::SChannel- Start, Obj = %08X\n", this);
// Initialize the mutex
if (pthread_mutex_init(&m_mutex, NULL) != 0)
{
DbgTrace(0, "SChannel::SChannel- Mutex initialization failed\n", 0);
// Throw exception
throw bad_alloc();
}
// Increment the object count
InterlockedIncrement(&numSChannelObjects);
DbgTrace(1, "SChannel::SChannel- End\n", 0);
} /*-- SChannel::SChannel() --*/
//++=======================================================================
SChannel::~SChannel(void)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
DbgTrace(1, "SChannel::~SChannel- 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(&numSChannelObjects);
DbgTrace(1, "SChannel::~SChannel- End\n", 0);
} /*-- SChannel::~SChannel() --*/
//++=======================================================================
int
SChannel::init(void)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
int retStatus = -1;
SmartSChannel *pSmartSChannel = NULL;
DbgTrace(1, "SChannel::init- Start, Obj = %08X\n", this);
// Verify the state of the object
if (m_state == State_Connected)
{
// Launch a thread to service the channel connection
try {
// Create a SmartSChannel object to make sure that the object
// does not get deleted prematurely.
pSmartSChannel = new SmartSChannel(this);
// Create the channel connection thread
pthread_t thread;
int threadCreateStatus = pthread_create(&thread,
NULL,
(void*(*)(void*))SChannel::connectionThread,
pSmartSChannel);
if (threadCreateStatus == 0)
{
// We succeeded
retStatus = 0;
}
else
{
DbgTrace(0, "SChannel::init- Unable to create channel connection thread, error = %08X\n", threadCreateStatus);
}
}
catch (...) {
DbgTrace(0, "SChannel::init- Exception caught creating smart pointer\n", 0);
}
}
else
{
DbgTrace(0, "SChannel::init- invalid state, state = %d\n", m_state);
}
// Deal with initialization failures
if (retStatus)
{
// Adjust the object state
m_state = State_FailedInitialization;
// Free SmartSChannel just in case
delete pSmartSChannel;
}
DbgTrace(1, "SChannel::init- End, status = %08X\n", retStatus);
return retStatus;
} /*-- SChannel::init() --*/
//++=======================================================================
void*
SChannel::connectionThread(
SmartPtr<SChannel> *pSmartSChannel)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
SChannel *pSChannel = *pSmartSChannel;
bool doneReceivingData = false;
unsigned long bytesReceived;
unsigned long bytesSent;
uint32_t reqId;
int payloadLength;
unsigned long totalPayloadBytesReceived = 0;
char reqDataPktHdr[ReqDataPktHdrTemplate.length()];
char reqErrorPktHdr[ReqErrorPktHdrTemplate.length()];
char *pRecvBuff;
ServerReq *pServerReq;
DbgTrace(1, "SChannel::connectionThread- Start, Obj = %08X\n", pSChannel);
// 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 (pSChannel->m_state == State_Connected)
{
// Receive and process channel data
while (!doneReceivingData)
{
DbgTrace(2, "SChannel::connectionThread- Receive Loop, Obj = %08X\n", pSChannel);
// 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(pSChannel->m_socket,
reqDataPktHdr,
ReqDataPktHdrTemplate.length(),
MSG_WAITALL);
if (bytesReceived != SOCKET_ERROR
|| errno != EINTR)
{
break;
}
}
if (bytesReceived != SOCKET_ERROR)
{
// Check if the connection was terminated
if (bytesReceived == ReqDataPktHdrTemplate.length())
{
// Get the reqId and 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, "SChannel::connectionThread- Processing Request Data Packet, Obj = %08X\n", pSChannel);
// Allocate a buffer big enough to receive the payload. Allow space to NULL terminate.
pRecvBuff = new char[payloadLength + 1];
if (pRecvBuff != NULL)
{
pRecvBuff[payloadLength] = '\0';
// Buffer allocated, receive the Req payload.
while (1)
{
bytesReceived = recv(pSChannel->m_socket,
pRecvBuff,
payloadLength,
MSG_WAITALL);
if (bytesReceived != SOCKET_ERROR
|| errno != EINTR)
{
break;
}
}
if (bytesReceived != SOCKET_ERROR)
{
// Verify that we received all of the payload
if (bytesReceived == payloadLength)
{
// Received all of the payload data
totalPayloadBytesReceived += bytesReceived;
// Instantiate ServerReq object
bool reqProcessingStartedSuccessfully = false;
try {
pServerReq = new ServerReq(pSChannel,
reqId,
pRecvBuff,
bytesReceived);
}
catch (...) {
DbgTrace(0, "SChannel::connectionThread- Exception caught creating ServerReq obj\n", 0);
}
// Acquire exclusive access to the SChannel object
pthread_mutex_lock(&pSChannel->m_mutex);
if (pServerReq)
{
// Forget about the receive buffer
pRecvBuff = NULL;
// Start processing the Request
if (ServiceRequest(pServerReq) != 0)
{
// Failed to start processing of the Request, delete the ServerReq object.
DbgTrace(0, "SChannel::connectionThread- StartRequest failed, Obj = %08X\n", pSChannel);
delete pServerReq;
}
else
{
reqProcessingStartedSuccessfully = true;
}
}
else
{
//DbgTrace(1, "SChannel::connectionThread- Failed to obtain idle ServerReq, Obj = %08X\n", pSChannel);
DbgTrace(0, "SChannel::connectionThread- Failed to obtain idle ServerReq, Obj = %08X\n", pSChannel);
}
// Check if we must send an Request Error packet back to the client
if (reqProcessingStartedSuccessfully == false)
{
// Build ReqErrorHeader
if (ChannelProto::buildReqErrorPktHdr(reqId,
0,
reqErrorPktHdr) == 0)
{
// Packet header was built, now sent it to the client.
bytesSent = send(pSChannel->m_socket,
reqErrorPktHdr,
sizeof(reqErrorPktHdr),
MSG_NOSIGNAL);
if (bytesSent != sizeof(reqErrorPktHdr))
{
DbgTrace(1, "SChannel::connectionThread- Connection aborted prematurely, Obj = %08X\n", pSChannel);
//printf("SChannel::connectionThread- 1Connection aborted prematurely, Obj = %08X\n", pSChannel);
doneReceivingData = true;
}
}
else
{
DbgTrace(0, "SChannel::connectionThread- Error building Req End Pkt Header, Obj = %08X\n", pSChannel);
}
}
// Release exclusive access to the SChannel object
pthread_mutex_unlock(&pSChannel->m_mutex);
}
else
{
DbgTrace(1, "SChannel::connectionThread- Connection aborted prematurely, Obj = %08X\n", pSChannel);
//printf("bytesReceived = %d, payloadLength = %d\n", bytesReceived, payloadLength);
//printf("SChannel::connectionThread- 2Connection aborted prematurely, Obj = %08X\n", pSChannel);
doneReceivingData = true;
}
}
else
{
DbgTrace(1, "SChannel::connectionThread- Connection aborted prematurely, Obj = %08X\n", pSChannel);
//printf("Socket error = %d\n", errno);
//printf("SChannel::connectionThread- 3Connection aborted prematurely, Obj = %08X\n", pSChannel);
doneReceivingData = true;
}
// Free receive buffer if necessary
if (pRecvBuff)
delete[] pRecvBuff;
}
else
{
DbgTrace(0, "SChannel::connectionThread- Unable to allocate receive buffer, Obj = %08X\n", pSChannel);
doneReceivingData = true;
}
break;
default:
DbgTrace(0, "SChannel::connectionThread- Unknown Packet Type, Obj = %08X\n", pSChannel);
doneReceivingData = true;
break;
}
}
else
{
DbgTrace(1, "SChannel::connectionThread- Unable to obtain payload length, Obj = %08X\n", pSChannel);
doneReceivingData = true;
}
}
else
{
DbgTrace(1, "SChannel::connectionThread- The channel connection was terminated, Obj = %08X\n", pSChannel);
//printf("bytesReceived = %d, expected = %d\n", bytesReceived, ReqDataPktHdrTemplate.length());
//printf("SChannel::connectionThread- 4The channel connection was terminated, Obj = %08X\n", pSChannel);
doneReceivingData = true;
}
}
else
{
DbgTrace(1, "SChannel::connectionThread- The channel connection was aborted, Obj = %08X\n", pSChannel);
//printf("Socket error = %d\n", errno);
//printf("SChannel::connectionThread- 5The channel connection was aborted, Obj = %08X\n", pSChannel);
doneReceivingData = true;
}
}
}
// Acquire exclusive access to the SChannel object
pthread_mutex_lock(&pSChannel->m_mutex);
// Try to change the SChannel state to disconnected
if (pSChannel->m_state == State_Connected)
pSChannel->m_state = State_Disconnected;
// Release exclusive access to the SChannel object
pthread_mutex_unlock(&pSChannel->m_mutex);
// Remove ourselves from the SChannel list
RemoveFromSChannelList(pSChannel);
// Free SmartSChannel
delete pSmartSChannel;
DbgTrace(1, "SChannel::connectionThread- End\n", 0);
// Exit
pthread_exit(NULL);
return 0; // never-reached!
} /*-- SChannel::connectionThread() --*/
//++=======================================================================
void
SChannel::closeChannel(void)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
DbgTrace(1, "SChannel::closeChannel- Start, Obj = %08X\n", this);
// Acquire SChannel 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 SChannel mutex
pthread_mutex_unlock(&m_mutex);
DbgTrace(1, "SChannel::closeChannel- End\n", 0);
} /*-- SChannel::closeChannel() --*/
//++=======================================================================
int
SChannel::sendReplyData(
uint32_t reqId,
char *pServerData,
int32_t serverDataLen)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// Environment:
//
// 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) + serverDataLen;
DbgTrace(1, "SChannel::sendReplyData- 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)
{
// Build ReqDataHeader
if (ChannelProto::buildReqDataPktHdr(reqId,
serverDataLen,
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*) pServerData;
ioVectors[1].iov_len = serverDataLen;
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.
//printf("SChannel::sendReplyData- sendmsgn error, totalBytesSent = %d, bytesToSend = %d, errno = %d\n", totalBytesSent, bytesToSend, errno);
DbgTrace(0, "SChannel::sendReplyData- sendmsgn 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 serverDataAlreadySent = totalBytesSent - sizeof(reqDataPktHdr);
ioVectors[0].iov_base = (char*) pServerData + serverDataAlreadySent;
ioVectors[0].iov_len = serverDataLen - serverDataAlreadySent;
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*) pServerData;
ioVectors[1].iov_len = serverDataLen;
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, "SChannel::sendReplyData- Error building Req Data Pkt Header, Obj = %08X\n", this);
}
}
else
{
DbgTrace(1, "SChannel::sendReplyData- Channel not connected, state = %08X\n", m_state);
}
// Release exclusive access to the channel object
pthread_mutex_unlock(&m_mutex);
DbgTrace(1, "SChannel::sendReplyData- End, retStatus = %08X\n", retStatus);
return retStatus;
} /*-- SChannel::sendReplyData() --*/
//++=======================================================================
int
SChannel::sendReplyError(
uint32_t reqId)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// Environment:
//
// L2
//=======================================================================--
{
int retStatus = -1;
char reqErrorPktHdr[ReqErrorPktHdrTemplate.length()];
struct msghdr sendmsgHdr = {0};
struct iovec ioVectors[1];
unsigned long bytesSent;
unsigned long totalBytesSent = 0;
unsigned long bytesToSend = sizeof(reqErrorPktHdr);
DbgTrace(1, "SChannel::sendReplyError- 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)
{
// Build ReqErrorHeader
if (ChannelProto::buildReqErrorPktHdr(reqId,
0,
reqErrorPktHdr) == 0)
{
// Packet header was built, now sent it along with the client data to
// the server.
ioVectors[0].iov_base = reqErrorPktHdr;
ioVectors[0].iov_len = sizeof(reqErrorPktHdr);
sendmsgHdr.msg_iov = ioVectors;
sendmsgHdr.msg_iovlen = 1;
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.
//printf("SChannel::sendReplyError- sendmsgn error, totalBytesSent = %d, bytesToSend = %d, errno = %d\n", totalBytesSent, bytesToSend, errno);
DbgTrace(0, "SChannel::sendReplyError- sendmsgn 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
ioVectors[0].iov_base = (char*) reqErrorPktHdr + totalBytesSent;
ioVectors[0].iov_len = sizeof(reqErrorPktHdr) - totalBytesSent;
sendmsgHdr.msg_iov = ioVectors;
sendmsgHdr.msg_iovlen = 1;
}
}
}
// Return success even if the send failed to allow things to be cleaned up
// by the connectionThread routine.
retStatus = 0;
}
else
{
DbgTrace(0, "SChannel::sendReplyError- Error building Req Data Pkt Header, Obj = %08X\n", this);
}
}
else
{
DbgTrace(1, "SChannel::sendReplyError- Channel not connected, state = %08X\n", m_state);
}
// Release exclusive access to the channel object
pthread_mutex_unlock(&m_mutex);
DbgTrace(1, "SChannel::sendReplyError- End, retStatus = %08X\n", retStatus);
return retStatus;
} /*-- SChannel::sendReplyError() --*/
//=========================================================================
//=========================================================================

View File

@@ -0,0 +1,178 @@
/***********************************************************************
*
* 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 _SCHANNEL_
#define _SCHANNEL_
//===[ Include files ]=====================================================
//===[ External data ]=====================================================
//===[ External prototypes ]===============================================
//===[ Manifest constants ]================================================
//===[ Type definitions ]==================================================
//===[ Function prototypes ]===============================================
//===[ Global variables ]==================================================
//===[ Type definitions ]==================================================
// Forward reference
class ServerReq;
//
// SChannel Class Definition
//
class SChannel : public ObjRef
{
// Object State
enum ChannelStates
{
State_FailedInitialization = 1,
State_Connected,
State_Disconnected,
State_Closed
};
ChannelStates m_state;
// Connection socket
int m_socket;
// Synchronization variables
pthread_mutex_t m_mutex;
//
// Server Request Map - This map contains all of the active ServerReq objects.
// The key used to obtain ServerReq object in the map
// is the Request Id.
//
typedef map<uint32_t, ServerReq*> RSMap;
typedef RSMap::iterator RSMapIter;
typedef pair<RSMapIter, bool> RSIterBoolPair;
RSMap m_rsMap;
//
// Service connection thread procedure
//
// Parameters:
// pSmartSChannel (input) -
// Pointer to SmartPtr<SChannel> object.
//
// Abstract: Thread in charge of servicing channel connection.
//
// Returns: Nothing.
//
static void* connectionThread(SmartPtr<SChannel> *pSmartSChannel);
public:
//
// Constructor
//
// Parameters:
// connSocket (input) -
// Socket for channel connection.
//
// Abstract: Constructs SChannel object.
//
// Returns: Nothing.
//
SChannel(int connSocket);
//
// Destructor
~SChannel(void);
//
// Initialization routine
//
// Parameters: None.
//
// Abstract: Initializes SChannel object.
//
// Returns: 0 if successful.
//
int init(void);
//
// Close channel routine
//
// Parameters: None.
//
// Abstract: Closes the channel.
//
// Returns: Nothing.
//
void closeChannel(void);
//
// Send Reply Data routine
//
// Parameters:
// reqId (input) -
// Request Id.
//
// pServerData (input) -
// Pointer to server data that must be sent to
// the client. Buffer is NOT released by the
// procedure.
//
// serverDataLen (input) -
// Length of the server data.
//
// Abstract: Sends data to the client for active Request.
//
// Returns: 0 if successful.
//
int sendReplyData(uint32_t reqId,
char *pServerData,
int32_t serverDataLen);
//
// Send Reply Error routine
//
// Parameters:
// reqId (input) -
// Request Id.
//
// Abstract: Indicates to the client that the request was
// not processed successfully..
//
// Returns: 0 if successful.
//
int sendReplyError(uint32_t reqId);
};
typedef SmartPtr<SChannel> SmartSChannel;
//===[ Function prototypes ]===============================================
#endif // _SCHANNEL_
//=========================================================================
//=========================================================================

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,225 @@
/***********************************************************************
*
* 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 "schannel.h"
#include "serverreq.h"
#include <assert.h> // Ensure that NDEBUG is defined for release builds!
//===[ External data ]=====================================================
//===[ External prototypes ]===============================================
//===[ Manifest constants ]================================================
#define SERVER_REQ_SIGNATURE 0x52525653 // SVRR
//===[ Type definitions ]==================================================
//===[ Function prototypes ]===============================================
//===[ Global variables ]==================================================
//===[ Type definitions ]==================================================
//===[ Function prototypes ]===============================================
//===[ Global variables ]==================================================
//
// Object Counters
//
unsigned long numServerReqObjects = 0;
//++=======================================================================
ServerReq::ServerReq(
SChannel *pSChannel,
uint32_t reqId,
char *pClientData,
int32_t clientDataLength) :
m_signature (SERVER_REQ_SIGNATURE),
m_reqId (reqId),
m_pClientData (pClientData),
m_clientDataLength (clientDataLength)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
DbgTrace(1, "ServerReq::ServerReq- Start, Obj = %08X\n", this);
// Create a SmartSChannel object to keep the SChannel object from
// going away while we process the request.
m_pSmartSChannel = new SmartSChannel(pSChannel);
// Increment the object count
InterlockedIncrement(&numServerReqObjects);
DbgTrace(1, "ServerReq::ServerReq- End\n", 0);
} /*-- ServerReq::ServerReq() --*/
//++=======================================================================
ServerReq::~ServerReq(void)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
DbgTrace(1, "ServerReq::~ServerReq- Start, Obj = %08X\n", this);
// Free any client data that may be hanging around
if (m_pClientData)
free(m_pClientData);
// Delete the SmartSChannel
delete m_pSmartSChannel;
// Decrement the object count
InterlockedDecrement(&numServerReqObjects);
DbgTrace(1, "ServerReq::~ServerReq- End\n", 0);
} /*-- ServerReq::~ServerReq() --*/
//++=======================================================================
int
ServerReq::getReqData(
char **ppClientData)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
DbgTrace(1, "ServerReq::getReqData- Start, Obj = %08X\n", this);
#if DEBUG
assert(m_signature == SERVER_REQ_SIGNATURE);
#endif
// Return pointer to the client data
*ppClientData = m_pClientData;
DbgTrace(1, "ServerReq::getReqData- End, reqDataLen = %08X\n", m_clientDataLength);
return m_clientDataLength;
}
//++=======================================================================
void
ServerReq::complete(
char *pServerData)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
SChannel *pSChannel = *m_pSmartSChannel;
DbgTrace(1, "ServerReq::complete- Start, Obj = %08X\n", this);
#if DEBUG
assert(m_signature == SERVER_REQ_SIGNATURE);
#endif
// Send data to the client
pSChannel->sendReplyData(m_reqId,
pServerData,
strlen(pServerData));
DbgTrace(1, "ServerReq::complete- End\n", 0);
} /*-- ServerReq::complete() --*/
//++=======================================================================
void
ServerReq::abort(void)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
SChannel *pSChannel = *m_pSmartSChannel;
DbgTrace(1, "ServerReq::abort- Start, Obj = %08X\n", this);
#if DEBUG
assert(m_signature == SERVER_REQ_SIGNATURE);
#endif
// Send an error to the client
pSChannel->sendReplyError(m_reqId);
DbgTrace(1, "ServerReq::abort- End\n", 0);
} /*-- ServerReq::abort() --*/
//=========================================================================
//=========================================================================

View File

@@ -0,0 +1,145 @@
/***********************************************************************
*
* 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 _SERVERREQ_
#define _SERVERREQ_
//===[ Include files ]=====================================================
//===[ External data ]=====================================================
//===[ External prototypes ]===============================================
//===[ Manifest constants ]================================================
//===[ Type definitions ]==================================================
//===[ Function prototypes ]===============================================
//===[ Global variables ]==================================================
//===[ Type definitions ]==================================================
//
// Server Request Class
//
class ServerReq
{
// Signature
unsigned long m_signature;
// Id of request being processed
uint32_t m_reqId;
// SmartSChannel object pointer for request being processed.
SmartSChannel *m_pSmartSChannel;
// Request Client Data
char *m_pClientData;
int32_t m_clientDataLength;
public:
//
// Destructor
~ServerReq(void);
//
// Constructor
//
// Parameters:
// pSChannel (input) -
// Pointer to SChannel object.
//
// reqId (input) -
// Request Id.
//
// pClientData (input) -
// Pointer to buffer containing the client data.
// Buffer is released when the object is destroyed.
//
// clientDataLength (input) -
// Length of the client data.
//
// Abstract: Constructs ServerReq object.
//
// Returns: Nothing.
//
ServerReq(SChannel *pSChannel,
uint32_t reqId,
char *pClientData,
int32_t clientDataLength);
//
// Get request Data routine
//
// Parameters:
// ppClientData (input/output) -
// Pointer to variable that will receive pointer to
// data sent by the client. Buffer should NOT released by
// caller.
//
// Abstract: Sends the requests reply data to the client.
//
// Returns: The length of the client request data. 0 if not successful.
//
int getReqData(char **ppClientData);
//
// Complete Request routine
//
// Parameters:
// pServerData (input) -
// Pointer to server data that must be sent to
// the client. Buffer is NOT released by the
// procedure.
//
// Abstract: Completes the request.
//
// Returns: Nothing.
//
void complete(char *pServerData);
//
// Abort Request routine
//
// Parameters: None.
//
// Abstract: Aborts the request.
//
// Returns: Nothing.
//
void abort(void);
};
//===[ Function prototypes ]===============================================
#endif // _SERVERREQ_
//=========================================================================
//=========================================================================

View File

@@ -0,0 +1,181 @@
/***********************************************************************
*
* 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 "serverthread.h"
#include <assert.h> // Ensure that NDEBUG is defined for release builds!
//===[ External data ]=====================================================
//===[ External prototypes ]===============================================
//===[ Manifest constants ]================================================
#define SERVER_THREAD_SIGNATURE 0x54525653 // SVRT
//===[ Type definitions ]==================================================
//===[ Function prototypes ]===============================================
//===[ Global variables ]==================================================
//===[ Type definitions ]==================================================
//===[ Function prototypes ]===============================================
//===[ Global variables ]==================================================
//
// Object Counters
//
unsigned long numServerThreadObjects = 0;
//++=======================================================================
ServerThread::ServerThread(void) :
m_signature (SERVER_THREAD_SIGNATURE)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
DbgTrace(1, "ServerThread::ServerThread- Start, Obj = %08X\n", this);
// Initialize the condition
if (pthread_cond_init(&m_condition, NULL) != 0)
{
DbgTrace(0, "ServerThread::ServerThread- Condition initialization failed\n", 0);
// Throw exception
throw bad_alloc();
}
// Increment the object count
InterlockedIncrement(&numServerThreadObjects);
DbgTrace(1, "ServerThread::ServerThread- End\n", 0);
} /*-- ServerThread::ServerThread() --*/
//++=======================================================================
ServerThread::~ServerThread(void)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
DbgTrace(1, "ServerThread::~ServerThread- Start, Obj = %08X\n", this);
// Cleanup resources allocated for the object
pthread_cond_destroy(&m_condition);
// Decrement the object count
InterlockedDecrement(&numServerThreadObjects);
DbgTrace(1, "ServerThread::~ServerThread- End\n", 0);
} /*-- ServerThread::~ServerThread() --*/
//++=======================================================================
void
ServerThread::awaken(void)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
DbgTrace(1, "ServerThread::awaken- Start, Obj = %08X\n", this);
#if DEBUG
assert(m_signature == SERVER_THREAD_SIGNATURE);
#endif
// Signal ourselves to wake up
pthread_cond_signal(&m_condition);
DbgTrace(1, "ServerThread::awaken- End\n", 0);
} /*-- ServerThread::awaken() --*/
//++=======================================================================
void
ServerThread::suspend(
pthread_mutex_t *pMutex)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
DbgTrace(1, "ServerThread::suspend- Start, Obj = %08X\n", this);
#if DEBUG
assert(m_signature == SERVER_THREAD_SIGNATURE);
#endif
// Wait until signaled to awaken
pthread_cond_wait(&m_condition, pMutex);
DbgTrace(1, "ServerThread::suspend- End\n", 0);
} /*-- ServerThread::suspend() --*/
//=========================================================================
//=========================================================================

View File

@@ -0,0 +1,107 @@
/***********************************************************************
*
* 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 _SERVERTHREAD_
#define _SERVERTHREAD_
//===[ Include files ]=====================================================
//===[ External data ]=====================================================
//===[ External prototypes ]===============================================
//===[ Manifest constants ]================================================
//===[ Type definitions ]==================================================
//===[ Function prototypes ]===============================================
//===[ Global variables ]==================================================
//===[ Type definitions ]==================================================
//
// Server Thread Class
//
class ServerThread
{
// Signature
unsigned long m_signature;
// Synchronization variable
pthread_cond_t m_condition;
public:
//
// Destructor
~ServerThread(void);
//
// Constructor
//
// Parameters: None.
//
// Abstract: Constructs ServerThread object.
//
// Returns: Nothing.
//
ServerThread(void);
//
// Awaken ServerThread routine
//
// Parameters: None.
//
// Abstract: Awakens a ServerThread.
//
// Returns: Nothing.
//
void awaken(void);
//
// Suspend ServerThread routine
//
// Parameters:
// pMutex (input) -
// Pointer to mutex to associate with
// condition used for waiting..
//
// Abstract: Suspends a ServerThread.
//
// Returns: Nothing.
//
void suspend(pthread_mutex_t *pMutex);
};
//===[ Function prototypes ]===============================================
#endif // _SERVERTHREAD_
//=========================================================================
//=========================================================================

View File

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

View File

@@ -0,0 +1,311 @@
/***********************************************************************
*
* 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: -l lifetime [-D DebugLevel]\n";
int DebugLevel = 3;
// Test lifetime
int testLifetime = 60; // Seconds
bool processingRequests = true;
//++=======================================================================
void* UnInitThread()
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// Environment:
//
//=======================================================================--
{
DbgTrace(1, "UnInitThread- Start\n", 0);
// Sleep for the configured amount
sleep(testLifetime);
// Stop processing Rpc Requests
processingRequests = false;
// Un-init the Svc Rpc Service Subsystem
IpcServerShutdown();
DbgTrace(1, "UnInitThread- End\n", 0);
// Exit
pthread_exit(NULL);
return 0; // never-reached!
}
//++=======================================================================
void* ProcessRequestThread(int32_t requestId)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// Environment:
//
//=======================================================================--
{
char *pReqData = NULL;
DbgTrace(1, "ProcessRequestThread- Start\n", 0);
// Get the rpc data
int dataLen = IpcServerGetRequestData(requestId, &pReqData);
if (dataLen != 0)
{
// Just echo the data back as the reply
IpcServerCompleteRequest(requestId,pReqData);
}
else
{
DbgTrace(0, "ProcessRequestThread- Error obtaining Request data\n", 0);
IpcServerAbortRequest(requestId);
}
DbgTrace(1, "ProcessRequestThread- End\n", 0);
// Exit
pthread_exit(NULL);
return 0; // never-reached!
}
//++=======================================================================
void
ExecuteTests(void)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// Environment:
//
//=======================================================================--
{
pthread_t thread;
int threadCreateStatus;
DbgTrace(1, "ExecuteTests- Start\n", 0);
// Initialize the Svc Ipc Subsystem
if (IpcServerInit("TestServer",
DebugLevel,
false) == 0)
{
// Set the server listen address
if (IpcServerSetInAddress(5000) == 0)
{
// Now start servicing requests.
if (IpcServerStart() == 0)
{
// The Ipc subsystem was started, now create a thread for
// un-initializing the Ipc subsystem after a while.
threadCreateStatus = pthread_create(&thread,
NULL,
(void*(*)(void*))UnInitThread,
(void*)NULL);
if (threadCreateStatus != 0)
{
DbgTrace(0, "ExecuteTests- Unable to create un-initialization thread, error = %08X\n", threadCreateStatus);
IpcServerShutdown();
}
else
{
// Process Incoming Requests
while (processingRequests)
{
int32_t requestId = IpcServerGetRequest();
if (requestId != 0)
{
// Create a thread to handle the request
threadCreateStatus = pthread_create(&thread,
NULL,
(void*(*)(void*))ProcessRequestThread,
(void*)requestId);
if (threadCreateStatus != 0)
{
DbgTrace(0, "ExecuteTests- Unable to create process request thread, error = %08X\n", threadCreateStatus);
IpcServerAbortRequest(requestId);
}
}
else
{
// No need to service requests any longer
break;
}
}
}
}
else
{
DbgTrace(0, "ExecuteTests- Error starting the Ipc subsystem\n", 0);
IpcServerShutdown();
}
}
else
{
DbgTrace(0, "ExecuteTests- Error setting server address\n", 0);
IpcServerShutdown();
}
}
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 Server test ****\n");
// Scan through the options specified
while (!doneScanning)
{
opterr = 0;
option = getopt(argc, argv, "l: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 'l':
// Set the test lifetime
printf("Lifetime = %s\n", optarg);
testLifetime = 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)
{
ExecuteTests();
}
else
{
// Invalid option detected
printf(usage, argv[0]);
}
return 0;
} /*-- main() --*/

View File

@@ -0,0 +1,37 @@
#######################################################################
#
# 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>
#
#######################################################################
SUBDIRS = IpcLibs
DIST_SUBDIRS = IpcLibs
CFILES =
EXTRA_DIST = $(CFILES)
.PHONY: package package-clean package-install package-uninstall
package package-clean package-install package-uninstall:
$(MAKE) -C $(TARGET_OS) $@
maintainer-clean-local:
rm -f Makefile.in