/*********************************************************************** * * 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_s_ipc.h" } #include "schannel.h" #include "serverthread.h" #include "serverreq.h" //===[ Type definitions ]================================================== #define MAX_FILE_PATH_LEN 1024 // // Socket Mapping definitions // #define INVALID_SOCKET -1 #define SOCKET_ERROR -1 #define LINGER struct linger #define SOCKADDR_IN struct sockaddr_in #define closesocket close //===[ Function prototypes ]=============================================== extern unsigned long numServerReqObjects; extern unsigned long numSChannelObjects; //===[ Global variables ]================================================== // Debug variables int DebugLevel = 0; bool UseSyslog = false; // Application Name for logging purposes char unInitialized[] = "Uninitialized"; char *pAppName = unInitialized; // Indicators bool svcInitialized = false; bool svcStarted = false; bool serverAddressSet = false; // Listen Port Number bool use_AF_INET; bool use_PF_UNIX; unsigned short int listenPortNumber = 0; char listenSocketFile[MAX_FILE_PATH_LEN]; // Listening Socket int listenSocket = INVALID_SOCKET; // Operating parameters bool acceptingConnections = true; bool terminating = false; // SChannel list list sChannelList; pthread_mutex_t serverMutex; // Mutex for interlocked operations pthread_mutex_t interlockedMutex; // // Active 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. Note, this id is associated with // a request when ProcessRequest() is called and it does // not have anything to do with the requests rpc id. // typedef map RSMap; typedef RSMap::iterator RSMapIter; typedef pair RSIterBoolPair; RSMap rsMap; int numActiveRequests = 0; // // Next request id (Can not be zero) // int32_t nextReqId = 1; // // Pending ServerRequests List and count - Server requests are staged on this lists until // they become active. // list pendingServerReqList; int numPendingRequests = 0; // ServerThreads operating parameters list waitingServerThreadList; int waitingServerThreads = 0; //++======================================================================= int ServiceRequest( ServerReq *pServerReq) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { int retStatus = -1; DbgTrace(1, "ServiceRequest- Start\n", 0); // Obtain server mutex pthread_mutex_lock(&serverMutex); // Do not process if trying to terminate if (!terminating) { try { // Insert the request into the pending server request list pendingServerReqList.push_back(pServerReq); numPendingRequests ++; // Check if there is a thread that can be awaken to process the request if (waitingServerThreads) { // There are waiting ServerThreads, remove one from the list // and reduce the waitingServerThreads count. list::iterator iter = waitingServerThreadList.begin(); ServerThread *pServerThread = *iter; waitingServerThreadList.erase(iter); waitingServerThreads --; // Wake up the server thread pServerThread->awaken(); } // Success retStatus = 0; } catch (...) { DbgTrace(0, "ServiceRequest- Exception caught\n", 0); } } // Release server mutex pthread_mutex_unlock(&serverMutex); DbgTrace(1, "ServiceRequest- End, retStatus = %08X\n", retStatus); return retStatus; } /*-- ServiceRequest() --*/ //++======================================================================= void AbortPendingRequests(void) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { DbgTrace(1, "AbortPendingRequests- Start\n", 0); // Obtain server mutex pthread_mutex_lock(&serverMutex); // Abort and delete all of the ServerReq in the pendingServerReqList while (numPendingRequests) { list::iterator iter = pendingServerReqList.begin(); ServerReq *pServerReq = *iter; pendingServerReqList.erase(iter); numPendingRequests --; pServerReq->abort(); delete pServerReq; } // Release server mutex pthread_mutex_unlock(&serverMutex); DbgTrace(1, "AbortPendingRequests- End\n", 0); } /*-- AbortPendingRequests() --*/ //++======================================================================= void AwakenSuspendedServerThreads(void) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { DbgTrace(1, "AwakenSuspendedServerThreads- Start\n", 0); // Obtain server mutex pthread_mutex_lock(&serverMutex); // Awaken all of the ServerThreads in the waitingServerThreadsList while (waitingServerThreads) { list::iterator iter = waitingServerThreadList.begin(); ServerThread *pServerThread = *iter; waitingServerThreadList.erase(iter); waitingServerThreads --; // Wake up the server thread pServerThread->awaken(); } // Release server mutex pthread_mutex_unlock(&serverMutex); DbgTrace(1, "AwakenSuspendedServerThreads- End\n", 0); } /*-- AwakenSuspendedServerThreads() --*/ //++======================================================================= void RemoveFromSChannelList( SChannel *pSChannel) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { list::iterator iter; bool objectRemoved = false; DbgTrace(1, "RemoveFromSChannelList- Start, Obj = %08X\n", pSChannel); // Obtain server mutex pthread_mutex_lock(&serverMutex); // Find the object in the list if (!sChannelList.empty()) { iter = sChannelList.begin(); while (iter != sChannelList.end()) { if (*iter == pSChannel) { // Object found, remove it from the list. sChannelList.erase(iter); // Remember that we removed the object objectRemoved = true; break; } // Proceed to the next item iter ++; } } // Release server mutex pthread_mutex_unlock(&serverMutex); // Check if the object was removed if (objectRemoved == false) { DbgTrace(0, "RemoveFromSChannelList- Error, did not find object in list\n", 0); } DbgTrace(1, "RemoveFromSChannelList- End\n", 0); } /*-- RemoveFromSChannelList() --*/ //++======================================================================= void ShutdownSChannels(void) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { list::iterator iter; SChannel *pSChannel; struct timespec waitTime = {0}; DbgTrace(1, "ShutdownSChannels- Start\n", 0); // Obtain server mutex pthread_mutex_lock(&serverMutex); // Close all of the SChannels in the SChannelList if (!sChannelList.empty()) { iter = sChannelList.begin(); while (iter != sChannelList.end()) { // Found SChannel in the idle list, close it. (*iter)->closeChannel(); // Move on to the next item in the list iter ++; } } // Release server mutex pthread_mutex_unlock(&serverMutex); // Loop until all SChannels are gone while (numSChannelObjects != 0) { // Wait for sometime waitTime.tv_sec = 1; // One second nanosleep(&waitTime, NULL); } DbgTrace(1, "ShutdownSChannels- End\n", 0); } /*-- ShutdownSChannels() --*/ //++======================================================================= int OpenSocket(void) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { int openedSocket; // Open a domain socket if a listen port number has not // been configured else open a Tcp socket. if (use_PF_UNIX) openedSocket = socket(PF_UNIX, SOCK_STREAM, 0); else openedSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); return openedSocket; } /*-- OpenSocket() --*/ //++======================================================================= int BindSocket(int socketToBind) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { int retStatus; // Bind domain socket if a listen port number has not // been configured else open a Tcp socket. if (use_PF_UNIX) { struct sockaddr_un listenAddr; // Set the file creation mask to 000 mode_t prevMask = umask(000); // Remove pre-existing socket unlink(listenSocketFile); // Setup the address that the daemon will use to listen // for connections. listenAddr.sun_family = AF_UNIX; strcpy(listenAddr.sun_path, listenSocketFile); // Perform the bind operation retStatus = bind(socketToBind, (const sockaddr*) &listenAddr, sizeof(listenAddr.sun_family) + strlen(listenAddr.sun_path)); // Return the file creation mask to its previous value umask(prevMask); } else { struct sockaddr_in listenAddr = {0}; int on = 1; // Setup the address that the daemon will use to listen // for connections. listenAddr.sin_family = AF_INET; listenAddr.sin_addr.s_addr = htonl(INADDR_ANY); listenAddr.sin_port = htons(listenPortNumber); // Set the SO_REUSEADDR option on the socket to avoid // problems in case of a re-start. setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); // Perform the bind operation retStatus = bind(socketToBind, (const sockaddr*) &listenAddr, sizeof(struct sockaddr_in)); } return retStatus; } /*-- BindSocket() --*/ //++======================================================================= int AcceptConnection(int acceptPendingSocket) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { int connectionSocket; socklen_t remoteAddrLen; // Use the appropriate address structure when Accepting connection if (use_PF_UNIX) { struct sockaddr_un remoteAddr; remoteAddrLen = sizeof(remoteAddr); // Perform the accept operation connectionSocket = accept(acceptPendingSocket, (struct sockaddr*) &remoteAddr, &remoteAddrLen); } else { struct sockaddr_in remoteAddr; remoteAddrLen = sizeof(remoteAddr); // Perform the accept operation connectionSocket = accept(acceptPendingSocket, (struct sockaddr*) &remoteAddr, &remoteAddrLen); } return connectionSocket; } /*-- AcceptConnection() --*/ //++======================================================================= void ServiceConnections(void) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { int connSocket; SChannel *pSChannel; bool sChannelAddedToList = false; DbgTrace(1, "ServiceConnections- Start\n", 0); // Open listening Tcp socket listenSocket = OpenSocket(); if (listenSocket != INVALID_SOCKET) { // Bind the socket if (!BindSocket(listenSocket)) { // Socket has been bound to our listen address, now set // the socket in listen mode. if (listen(listenSocket, SOMAXCONN) != SOCKET_ERROR) { // The socket is now in listen mode, start accepting connections. while (acceptingConnections) { pSChannel = NULL; connSocket = AcceptConnection(listenSocket); if (connSocket != INVALID_SOCKET) { // We received a new connection // // Obtain server mutex pthread_mutex_lock(&serverMutex); // Create a SChannel object to service the connection try { pSChannel = new SChannel(connSocket); // Associate a smart pointer with the channel to make sure // that it does not go away prematurely while we execute // SChannel::init(), also, this will allow the object to // get cleaned up if its initialization fails. SmartSChannel smartSChannel = pSChannel; // SChannel created, insert it into the SChannel list. sChannelList.push_back(pSChannel); sChannelAddedToList = true; // Initialize the SChannel if (pSChannel->init()) { DbgTrace(0, "ServiceConnections- SChannel intialization failed\n", 0); // Remove the SChannel object from the SChannel list sChannelList.pop_back(); sChannelAddedToList = false; } } catch (...) { DbgTrace(0, "ServiceConnections- Exception caught\n", 0); // Free necessary resources if (pSChannel) { if (sChannelAddedToList) sChannelList.pop_back(); delete pSChannel; } else closesocket(connSocket); } // Release server mutex pthread_mutex_unlock(&serverMutex); } else { // Check if accept failed because we got interrupted if (errno == EINTR) { // We got interrupted during the accept, try again. continue; } else { // This could be because the listen socket got closed. DbgTrace(1, "ServiceConnections- Accept failed, error = %d\n", errno); // Break out of the accept loop if the socket indeed got closed if (listenSocket == INVALID_SOCKET) break; } } } } else { DbgTrace(0, "ServiceConnections- Listen failed, error = %d\n", errno); } } else { DbgTrace(0, "ServiceConnections- Unable to bind socket, error = %d\n", errno); } // Close listening socket if necessary if (listenSocket != INVALID_SOCKET) closesocket(listenSocket); } else { DbgTrace(0, "ServiceConnections- Unable to open socket, error = %d\n", errno); } DbgTrace(1, "ServiceConnections- End\n", 0); } /*-- ServiceConnections() --*/ //++======================================================================= void* ServiceConnectionsThread(void) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { DbgTrace(1, "ServiceConnectionsThread- Start\n", 0); // Set the thread in the detached state so that it is cleaned up when it exits pthread_detach(pthread_self()); // Service connections until no longer necessary ServiceConnections(); // Clean up ShutdownSChannels(); DbgTrace(1, "ServiceConnectionsThread- End\n", 0); // Exit pthread_exit(NULL); return 0; // never-reached! } /*-- ServiceConnectionsThread() --*/ //++======================================================================= extern "C" int32_t IpcServerGetRequest(void) // // Arguments In: None. // // Arguments Out: None. // // Returns: The id of the pending request. // 0 == Not able to wait for request. // // Abstract: A server thread invokes this method to be informed when // a request is received that needs to be acted upon. // // Notes: The routine blocks until a request becomes available or // until the IpcServer is shutdown. // // An application can execute this method from multiple // threads to allow requests to be process concurrently. // // L2 //=======================================================================-- { int32_t requestId = 0; DbgTrace(1, "IpcServerGetRequest- Start\n", 0); // Make sure that the service has been started if (!svcStarted) { DbgTrace(0, "IpcServerGetRequest- Service has not been started\n", 0); goto exit; } try { // Instantiate ServerThread object ServerThread serverThread; // Obtain server mutex pthread_mutex_lock(&serverMutex); // Try to find a request to process while (!terminating) { // Make sure that this is initialized to zero requestId = 0; // Check if there is a request for us to process if (numPendingRequests) { // Obtain pending request and place it in the active map list::iterator iter = pendingServerReqList.begin(); ServerReq *pServerReq = *iter; pendingServerReqList.erase(iter); numPendingRequests --; // Assign an id to this request and increment // the nextReqId. // // Protect against zero since it is not valid. if (nextReqId != 0) { requestId = nextReqId; nextReqId ++; } else { requestId = 1; nextReqId = 2; } // Place the request in the active request map RSIterBoolPair insertResult = rsMap.insert(make_pair(requestId, pServerReq)); if (!insertResult.second) { // Insertion failed DbgTrace(0, "IpcServerGetRequest- Unable to insert ServerReq into map\n", 0); // Abort and free the request pServerReq->abort(); delete pServerReq; // Try again continue; } else { // Increment the number of active requests numActiveRequests ++; // Exit to allow the calling thread to process the request break; } } else { // There is not a request for us to process, place us on the waiting // server thread list and wait to be awaken. waitingServerThreadList.push_back(&serverThread); waitingServerThreads ++; serverThread.suspend(&serverMutex); } } // Release server mutex pthread_mutex_unlock(&serverMutex); } catch (...) { DbgTrace(1, "IpcServerGetRequest- Exception caught\n", 0); } exit: DbgTrace(1, "IpcServerGetRequest- End, requestId = %08X\n", requestId); return requestId; } /*-- IpcServerGetRequest() --*/ //++======================================================================= extern "C" int32_t IpcServerGetRequestData( IN int32_t requestId, INOUT char **ppReqData) // // Arguments In: requestId - The id of the request being processed. // // Arguments Out: ppReqData - Pointer to variable that will receive a // pointer to the buffer containing the request // data the client. // // Returns: The length of the request data returned. // // Abstract: Method to obtain the data associated with a particular // request. // // Notes: The returned buffer SHOULD NOT be released by the calling // application. // // 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. // L2 //=======================================================================-- { int32_t reqDataLen = 0; DbgTrace(1, "IpcServerGetRequestData- Start, requestId = %08X\n", requestId); // Make sure that the service has been started if (svcStarted) { // Obtain server mutex pthread_mutex_lock(&serverMutex); // Find request in the active map RSMapIter iter = rsMap.find(requestId); if (iter != rsMap.end()) { // Request was found in the map, obtain a reference to it. ServerReq *pServerReq = iter->second; // Release server mutex pthread_mutex_unlock(&serverMutex); // Obtain the request data associated with the request reqDataLen = pServerReq->getReqData(ppReqData); } else { DbgTrace(0, "IpcServerGetRequestData- Request not found in map\n", 0); // Release server mutex pthread_mutex_unlock(&serverMutex); } } else { DbgTrace(0, "IpcServerGetRequestData- Service has not been started\n", 0); } DbgTrace(1, "IpcServerGetRequestData- End, reqDataLen = %08X\n", reqDataLen); return reqDataLen; } /*-- IpcServerGetRequestData() --*/ //++======================================================================= extern "C" void IpcServerCompleteRequest( IN int32_t requestId, IN char *pReplyData) // // Arguments In: requestId - The id of the request being completed. // // pReplyData - Pointer to reply data that must be sent to // the client for this request. // // Arguments Out: None. // // Returns: Nothing. // // Abstract: Method to complete a request being processed. // // Notes: The returned buffer will not NOT be released by the method. // // L2 //=======================================================================-- { DbgTrace(1, "IpcServerCompleteRequest- Start, requestId = %08X\n", requestId); // Make sure that the service has been started if (svcStarted) { // Obtain server mutex pthread_mutex_lock(&serverMutex); // Find request in the active map RSMapIter iter = rsMap.find(requestId); if (iter != rsMap.end()) { // Request was found in the map, get a reference to it and // remove it from the map> ServerReq *pServerReq = iter->second; rsMap.erase(iter); numActiveRequests --; // Release server mutex pthread_mutex_unlock(&serverMutex); // Coomplete the request and delete it. pServerReq->complete(pReplyData); delete pServerReq; } else { DbgTrace(0, "IpcServerCompleteRequest- Request not found in map\n", 0); // Release server mutex pthread_mutex_unlock(&serverMutex); } } else { DbgTrace(0, "IpcServerCompleteRequest- Service has not been started\n", 0); } DbgTrace(1, "IpcServerCompleteRequest- End\n", 0); } /*-- IpcServerCompleteRequest() --*/ //++======================================================================= extern "C" void IpcServerAbortRequest( IN int32_t requestId) // // Arguments In: requestId - The id of the request being aborted. // // Arguments Out: None. // // Returns: Nothing. // // Abstract: Method to abort a request being processed. // // Notes: // // L2 //=======================================================================-- { DbgTrace(1, "IpcServerAbortRequest- Start, requestId = %08X\n", requestId); // Make sure that the service has been started if (svcStarted) { // Obtain server mutex pthread_mutex_lock(&serverMutex); // Find request in the active map RSMapIter iter = rsMap.find(requestId); if (iter != rsMap.end()) { // Request was found in the map, get a reference to it and // remove it from the map> ServerReq *pServerReq = iter->second; rsMap.erase(iter); numActiveRequests --; // Release server mutex pthread_mutex_unlock(&serverMutex); // Coomplete the request and delete it. pServerReq->abort(); delete pServerReq; } else { DbgTrace(0, "IpcServerAbortRequest- Request not found in map\n", 0); // Release server mutex pthread_mutex_unlock(&serverMutex); } } else { DbgTrace(0, "IpcServerAbortRequest- Service has not been started\n", 0); } DbgTrace(1, "IpcServerAbortRequest- End\n", 0); } /*-- IpcServerAbortRequest() --*/ //++======================================================================= extern "C" int IpcServerStart(void) // // Arguments In: None. // // Arguments Out: None. // // Returns: 0 == Success // -1 == Failure // // Abstract: Method to enable the reception of server requests. // // Note: The service needs to be initialized and the listen address // needs to be set before calling this procedure. // // L2 //=======================================================================-- { int retStatus = -1; DbgTrace(1, "IpcServerStart- Start\n", 0); // Make sure that the listen address has been set if (serverAddressSet) { // Do not do anything if we have already been started if (!svcStarted) { // Create a threat to service connections pthread_t thread; int threadCreateStatus; threadCreateStatus = pthread_create(&thread, NULL, (void*(*)(void*))ServiceConnectionsThread, (void*)NULL); if (threadCreateStatus != 0) { DbgTrace(0, "IpcServerStart- Unable to create service connections thread, error = %08X\n", threadCreateStatus); retStatus = -1; } else { // Success svcStarted = true; retStatus = 0; } } } else { DbgTrace(0, "IpcServerStart- Either not initialized or the address has not been set\n", 0); } DbgTrace(1, "IpcServerStart- End, retStatus = %08X\n", retStatus); return retStatus; } /*-- IpcServerStart() --*/ //++======================================================================= extern "C" int IpcServerSetUnAddress( IN char *pSocketFileName) // // Arguments In: pSocketFileName - Pointer to string containing the name // of the socket file to listen on. // // Arguments Out: None. // // Returns: 0 == Success // -1 == Failure // // Abstract: Method to set the socket file name to utilize for // communicating with the server via DOMAIN sockets. // // Note: The service needs to be initialized before calling this procedure. // // L2 //=======================================================================-- { int retStatus = -1; DbgTrace(1, "IpcServerSetUnAddress- Start\n", 0); // Verify the input parameters if (pSocketFileName == NULL || strlen(pSocketFileName) >= sizeof(listenSocketFile)) { DbgTrace(0, "IpcServerSetUnAddress- Invalid input parameter\n", 0); goto exit; } // Make sure that we have been initialized if (svcInitialized) { // Make sure that the address has not already been set. if (serverAddressSet == false) { // Save a copy of the socket file name strcpy(listenSocketFile, pSocketFileName); // Remember this serverAddressSet = true; use_AF_INET = false; use_PF_UNIX = true; // Success retStatus = 0; } else { DbgTrace(0, "IpcServerSetUnAddress- Already set\n", 0); } } else { DbgTrace(0, "IpcServerSetUnAddress- Service not yet initialized\n", 0); } exit: DbgTrace(1, "IpcServerSetUnAddress- End, retStatus = %08X\n", retStatus); return retStatus; } /*-- IpcServerSetUnAddress() --*/ //++======================================================================= extern "C" int IpcServerSetInAddress( IN unsigned short int listenPort) // // Arguments In: serverPort - Server's listening port number. // // Arguments Out: None. // // Returns: 0 == Success // -1 == Failure // // Abstract: Method to set the address to utilize for communicating // with the server via TCP sockets. // // Note: The service needs to be initialized before calling this procedure. // // L2 //=======================================================================-- { int retStatus = -1; DbgTrace(1, "IpcServerSetInAddress- Start\n", 0); // Verify the input parameters if (listenPort == 0) { DbgTrace(0, "IpcServerSetInAddress- Invalid input parameter\n", 0); goto exit; } // Make sure that we have been initialized if (svcInitialized) { // Make sure that the address has not already been set. if (serverAddressSet == false) { // Save the listen port number listenPortNumber = listenPort; // Remember this serverAddressSet = true; use_AF_INET = true; use_PF_UNIX = false; // Success retStatus = 0; } else { DbgTrace(0, "IpcServerSetInAddress- Already set\n", 0); } } else { DbgTrace(0, "IpcServerSetInAddress- Service not yet initialized\n", 0); } exit: DbgTrace(1, "IpcServerSetInAddress- End, retStatus = %08X\n", retStatus); return retStatus; } /*-- IpcServerSetInAddress() --*/ //++======================================================================= extern "C" int IpcServerInit( IN char *pName, 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. // // 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 start procedure to start // servicing requests. // // L2 //=======================================================================-- { int retStatus = -1; DbgTrace(1, "IpcServerInit- Start\n", 0); // Check input parameters if (pAppName == NULL) { DbgTrace(0, "IpcServerInit- Invalid parameter\n", 0); goto exit; } // Save a copy of the application name pAppName = new char[strlen(pName) + 1]; if (pAppName == NULL) { DbgTrace(0, "IpcServerInit- Memory allocation failure\n", 0); goto exit; } strcpy(pAppName, pName); // Save the rest of the debug settings DebugLevel = debugLevel; UseSyslog = useSyslog; // Set to ignore SIGPIPE signals signal(SIGPIPE, SIG_IGN); // Initialize our mutexes pthread_mutex_init(&serverMutex, NULL); pthread_mutex_init(&interlockedMutex, NULL); // Success svcInitialized = true; retStatus = 0; exit: DbgTrace(1, "IpcServerInit- End, retStatus = %08X\n", retStatus); return retStatus; } /*-- IpcServerInit() --*/ //++======================================================================= extern "C" void IpcServerShutdown(void) // // Arguments In: None. // // Arguments Out: None. // // Returns: Nothing. // // Abstract: Method to shutdown the IPC service. // // Note: // // L2 //=======================================================================-- { DbgTrace(1, "IpcServerShutdown- Start\n", 0); // Verify that we have been initialized if (svcInitialized) { // We are being asked to terminate terminating = true; // Abort all pending requests AbortPendingRequests(); // Awaken any suspended server threads AwakenSuspendedServerThreads(); // Wait for all of the active requests to complete while (numActiveRequests) sleep(1); // Close the listen socket if not already closed. This will // cause the ServiceConnectionsThread to clean things up and // shutdown. if (listenSocket != INVALID_SOCKET) { // Close the socket closesocket(listenSocket); listenSocket = INVALID_SOCKET; } // Forget about having being initialized svcInitialized = false; } // Free the AppName string if necessary if (pAppName != unInitialized) { delete[] pAppName; pAppName = unInitialized; } // Forget about some things serverAddressSet = false; svcInitialized = false; DbgTrace(1, "IpcServerShutdown- End\n", 0); } /*-- IpcServerShutdown() --*/ //========================================================================= //=========================================================================