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