diff -r c892c53c664e -r 9d2210c8eed2 connectivity/com.nokia.tcf/native/TCFNative/TCFClient/ClientManager.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/connectivity/com.nokia.tcf/native/TCFNative/TCFClient/ClientManager.cpp Mon Apr 06 15:18:48 2009 -0500 @@ -0,0 +1,836 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ +// ClientManager.cpp: implementation of the CClientManager class. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "ClientManager.h" +#include "TCErrorConstants.h" +#include "resource.h" +#include + +#ifdef _DEBUG +extern BOOL gDoLogging; +extern char TCDebugMsg[100]; +#define TCDEBUGOPEN() if (gDoLogging) m_DebugLog->WaitForAccess(); +#define TCDEBUGLOGS(s) if (gDoLogging) sprintf(TCDebugMsg,"%s", s); if (gDoLogging) m_DebugLog->log(TCDebugMsg); +#define TCDEBUGLOGA1(s, a1) if (gDoLogging) sprintf(TCDebugMsg, s, a1); if (gDoLogging) m_DebugLog->log(TCDebugMsg); +#define TCDEBUGLOGA2(s, a1, a2) if (gDoLogging) sprintf(TCDebugMsg, s, a1, a2); if (gDoLogging) m_DebugLog->log(TCDebugMsg); +#define TCDEBUGLOGA3(s, a1, a2, a3) if (gDoLogging) sprintf(TCDebugMsg, s, a1, a2, a3); if (gDoLogging) m_DebugLog->log(TCDebugMsg); +#define TCDEBUGCLOSE() if (gDoLogging) m_DebugLog->ReleaseAccess(); +#else +#define TCDEBUGOPEN() +#define TCDEBUGLOGS(s) +#define TCDEBUGLOGA1(s, a1) +#define TCDEBUGLOGA2(s, a1, a2) +#define TCDEBUGLOGA3(s, a1, a2, a3) +#define TCDEBUGCLOSE() +#endif + +#ifdef _DEBUG +static char* GetErrorText(DWORD inError); +#endif + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// +CClientManager::CClientManager() +{ + m_Server = NULL; + m_StreamList = NULL; + m_ErrorMonitorList = NULL; + m_DebugLog = NULL; + m_DllLocation = NULL; + m_hServer = NULL; + m_hServerThread = NULL; + m_Version[0] = NULL; + m_ServerLockFile = NULL; + m_ServerExeFile = NULL; +} +CClientManager::CClientManager(HINSTANCE hinstDLL) +{ +#ifdef _DEBUG + if (gDoLogging) + m_DebugLog = new TCDebugLog("TCF_ClientLog", ::GetCurrentProcessId()); + else + m_DebugLog = NULL; + +#else + m_DebugLog = NULL; +#endif + TCDEBUGOPEN(); + TCDEBUGLOGS("CClientManager::CClientManager\n"); + + m_Server = new CServerCommand(); + + // lock server access (it might be running) + m_Server->WaitforServerPipeAccess(); + + m_StreamList = new InputStreamList(); + m_StreamList->clear(); + + m_ErrorMonitorList = new ErrorMonitorList(); + m_ErrorMonitorList->clear(); + + m_DllLocation = new char[MAX_DLLPATHNAME]; + ::GetModuleFileName(hinstDLL, m_DllLocation, MAX_DLLPATHNAME); + + char exeDirectory[MAX_DLLPATHNAME] = {0}; + strncpy(exeDirectory, m_DllLocation, MAX_DLLPATHNAME); + size_t len = strlen(exeDirectory); + // remove file + for (int i = len-1; i > 0; i--) + { + if (exeDirectory[i] == PATH_DELIMITER) + break; + } + exeDirectory[i] = NULL; + + m_ServerExeFile = new char[MAX_DLLPATHNAME]; + sprintf(m_ServerExeFile, "\"%s%c%s\"", exeDirectory, PATH_DELIMITER, SERVER_PROCESS_NAME); + + m_ServerLockFile = new char[MAX_DLLPATHNAME]; + sprintf(m_ServerLockFile, "%s%c%s", exeDirectory, PATH_DELIMITER, SERVER_LOCKFILE_NAME); + + char name[100]; + sprintf(name, "%s%ld", ERRORMONITORLIST_MUTEX_BASENAME, ::GetCurrentProcessId()); + m_ErrorMonitorListMutex.Open(name, ERRORMONITORLIST_MUTEX_TIMEOUT); + + sprintf(name, "%s%ld", INPUTSTREAMLIST_MUTEX_BASENAME, ::GetCurrentProcessId()); + m_StreamListMutex.Open(name, INPUTSTREAMLIST_MUTEX_TIMEOUT); + + m_hServer = NULL; + m_hServerThread = NULL; + + // release server access + m_Server->ReleaseServerPipeAccess(); + int ret = ::LoadString(hinstDLL, IDS_VERSION, m_Version, MAX_VERSION_STRING); + + TCDEBUGCLOSE(); +} + +CClientManager::~CClientManager() +{ + TCDEBUGOPEN(); + TCDEBUGLOGS("CClientManager::~CClientManager\n"); + pServerProcessData pData = m_Server->GetProcessPtr(); + + if (m_Server) + { + delete m_Server; + m_Server = NULL; + } + + WaitForStreamListAccess(); + TCDEBUGLOGA1("CClientManager::~CClientManager: erasing stream list size=%d\n", InputStreamListSize()); + if (m_StreamList) + { + InputStreamList::iterator iter; + for (iter = m_StreamList->begin(); iter != m_StreamList->end(); iter++) + { + TCDEBUGLOGS("CClientManager::~CClientManager: erasing stream list next 1\n"); +// m_StreamList->erase(iter); + delete *iter; +// TCDEBUGLOGS("CClientManager::~CClientManager: erasing stream list next 2\n"); + } + m_StreamList->clear(); + TCDEBUGLOGS("CClientManager::~CClientManager: erasing stream list done 1\n"); + delete m_StreamList; + TCDEBUGLOGS("CClientManager::~CClientManager: erasing stream list done 2\n"); + } + ReleaseStreamListAccess(); + m_StreamListMutex.Close(); + + WaitForErrorMonitorListAccess(); + TCDEBUGLOGA1("CClientManager::~CClientManager: erasing monitor list size=%d\n", ErrorMonitorListSize()); + if (m_ErrorMonitorList) + { + ErrorMonitorList::iterator iter; + for (iter = m_ErrorMonitorList->begin(); iter != m_ErrorMonitorList->end(); iter++) + { + TCDEBUGLOGS("CClientManager::~CClientManager: erasing monitor list next 1\n"); +// m_ErrorMonitorList->erase(iter); + delete *iter; +// TCDEBUGLOGS("CClientManager::~CClientManager: erasing monitor list next 1\n"); + } + m_ErrorMonitorList->clear(); + TCDEBUGLOGS("CClientManager::~CClientManager: erasing monitor list done 1\n"); + delete m_ErrorMonitorList; + TCDEBUGLOGS("CClientManager::~CClientManager: erasing monitor list done 2\n"); + } + ReleaseErrorMonitorListAccess(); + m_ErrorMonitorListMutex.Close(); + + if (m_DllLocation) + { + delete[] m_DllLocation; + m_DllLocation = NULL; + } + + if (m_ServerLockFile) + { + delete[] m_ServerLockFile; + m_ServerLockFile = NULL; + } + + if (m_ServerExeFile) + { + delete[] m_ServerExeFile; + m_ServerExeFile = NULL; + } + TCDEBUGLOGS("CClientManager::~CClientManager: closing log\n"); + TCDEBUGCLOSE(); + if (m_DebugLog) + { + delete m_DebugLog; + m_DebugLog = NULL; + } +} +CErrorMonitor* +CClientManager::FindErrorMonitor(long inClientId) +{ + CErrorMonitor* errorMonitor = NULL; + ErrorMonitorList::iterator iter; + + for (iter = m_ErrorMonitorList->begin(); iter != m_ErrorMonitorList->end(); iter++) + { + if ((*iter)->IsThisClient(inClientId)) + { + errorMonitor = *iter; + break; + } + } + return errorMonitor; +} +long CClientManager::ErrorMonitorListSize() +{ + long size = m_ErrorMonitorList->size(); + + return size; +} +void CClientManager::AddErrorMonitor(CErrorMonitor* monitor) +{ + m_ErrorMonitorList->push_back(monitor); +} +void CClientManager::RemoveErrorMonitor(CErrorMonitor* monitor) +{ + ErrorMonitorList::iterator iter; + + for (iter = m_ErrorMonitorList->begin(); iter != m_ErrorMonitorList->end(); iter++) + { + if ((*iter)->IsThisClient(monitor->GetClientId())) + { + m_ErrorMonitorList->erase(iter); + break; + } + } +} + +CInputStream* +CClientManager::FindInputStream(long inClientId) +{ + CInputStream* inputStream = NULL; + InputStreamList::iterator iter; + + for (iter = m_StreamList->begin(); iter != m_StreamList->end(); iter++) + { + if ((*iter)->IsThisClient(inClientId)) +// if ((*iter).IsThisClient(inClientId)) + { + inputStream = *iter; +// inputStream = iter; + break; + } + } + return inputStream; +} +long CClientManager::InputStreamListSize() +{ + long size = m_StreamList->size(); + + return size; +} +void CClientManager::AddInputStream(CInputStream* stream) +{ + m_StreamList->push_back(stream); +// m_StreamList->push_back(*stream); + +} +void CClientManager::RemoveInputStream(CInputStream* stream) +{ + InputStreamList::iterator iter; + + for (iter = m_StreamList->begin(); iter != m_StreamList->end(); iter++) + { + if ((*iter)->IsThisClient(stream->GetClientId())) +// if ((*iter).IsThisClient(stream->GetClientId())) + { + m_StreamList->erase(iter); + break; + } + } +} + +BOOL CClientManager::StartServer(pServerProcessData pData) +{ + TCDEBUGLOGA1("CClientManager::StartServer numRefs = %d\n",pData->numRefs); + + BOOL serverStarted = FALSE; + // server is ref counted + // refcount = 0 => server is not running + // refcount > 0 => server already started by some other process + if (pData->numRefs == 0) + { + // server not running + // get exe location + char exeLocation[MAX_DLLPATHNAME] = {0}; + strncpy(exeLocation, m_DllLocation, MAX_DLLPATHNAME); + size_t len = strlen(exeLocation); + // remove file + for (int i = len-1; i > 0; i--) + { + if (exeLocation[i] == PATH_DELIMITER) + break; + } + exeLocation[i] = NULL; + char quotedLocation[MAX_DLLPATHNAME] = {0}; + sprintf(quotedLocation, "\"%s%c%s\"", exeLocation, PATH_DELIMITER, SERVER_PROCESS_NAME); + + TCDEBUGLOGA1(" exeLocation=%s\n", quotedLocation); + + // create process + STARTUPINFO si; + memset(&si,0,sizeof(si)); + si.cb = sizeof(si); + memset(&pData->serverProcess, 0, sizeof(pData->serverProcess)); + pData->serverProcess.hProcess = NULL; + if (!::CreateProcess( + NULL, // module location + quotedLocation, // command line + NULL, // process attributes + NULL, // thread attributes + FALSE, // inherit our handles + CREATE_NO_WINDOW, // no window + NULL, // use our environment + NULL, // user our current directory + &si, // startup info + &pData->serverProcess)) // process info + { + // TODO: error creating process + } + else + { + // we are the creator so save handles for later + m_hServer = pData->serverProcess.hProcess; + m_hServerThread = pData->serverProcess.hThread; + // add a refcount + pData->numRefs++; + serverStarted = TRUE; + } + } + else + { + // already running + // add a refcount and open our process handle to it + pData->numRefs++; + m_hServer = ::OpenProcess(0, FALSE, pData->serverProcess.dwProcessId); + serverStarted = TRUE; + } + TCDEBUGLOGA1("CClientManager::StartServer serverStarted=%d\n", serverStarted); + return serverStarted; +} + +BOOL CClientManager::StopServer(pServerProcessData pData) +{ + TCDEBUGLOGS("CClientManager::StopServer\n"); + + BOOL serverStopped = FALSE; + + if (pData->serverProcess.hProcess == NULL || pData->numRefs <= 0) + { + serverStopped = TRUE; + } + else + { + TCDEBUGLOGA1(" numRefs = %d\n",pData->numRefs); + + // substract ref count + pData->numRefs--; + // if refcount == 0 then really stop the server process + if (pData->numRefs <= 0) + { + // last client process is closing + // tell server to exit + ServerCommandData cmdrsp; + cmdrsp.command = eCmdExit; + TCDEBUGLOGS(" SendCommand eCmdExit\n"); + m_Server->SendCommand(&cmdrsp); + TCDEBUGLOGS(" GetResponse eExit\n"); + m_Server->GetResponse(&cmdrsp); + // wait for process to exit + TCDEBUGLOGS(" WaitForSingleObject start\n"); + WaitForSingleObject(m_hServer, 10000L /*INFINITE*/); + TCDEBUGLOGS(" WaitForSingleObject found\n"); + + if (m_hServer != NULL) + CloseHandle(m_hServer); + + if (m_hServerThread != NULL) + CloseHandle(m_hServerThread); + } + else + { + // just close our handle to server process + if (m_hServer != NULL) + CloseHandle(m_hServer); + + if (m_hServerThread != NULL) + CloseHandle(m_hServerThread); + } + } + + TCDEBUGLOGS("CClientManager::StopServer end\n"); + return TRUE; +} +long CClientManager::StartServer() +{ + long ret = TCAPI_ERR_NONE; + pServerProcessData pData = m_Server->GetProcessPtr(); + + TCDEBUGLOGA3("CClientManager::StartServer this = %x m_hServer = %x numRefs = %d\n", this, m_hServer, pData->numRefs); +// TCDEBUGLOGA1(" mgrRefs = %d\n", m_MgrServerRef); + + BOOL serverStarted = FALSE; + // server is ref counted + // refcount = 0 => server is not running + // refcount > 0 => server already started by some other process + + // terminate the TCFServer if it is already running + TerminateServerThroughLockFile(pData); + + if (pData->numRefs == 0) + { + // server not running + TCDEBUGLOGA1(" TCFServer exe =%s\n", m_ServerExeFile); + TCDEBUGLOGA1(" TCFServer lock=%s\n", m_ServerLockFile); + + + // create process + STARTUPINFO si; + memset(&si,0,sizeof(si)); + si.cb = sizeof(si); + memset(&pData->serverProcess, 0, sizeof(pData->serverProcess)); + pData->serverProcess.hProcess = NULL; + if (!::CreateProcess( + NULL, // module location + m_ServerExeFile, // command line + NULL, // process attributes + NULL, // thread attributes + FALSE, // inherit our handles + CREATE_NO_WINDOW, // no window + NULL, // use our environment + NULL, // user our current directory + &si, // startup info + &pData->serverProcess)) // process info + { + // TODO: error creating process + } + else + { + // we are the creator so save handles for later + m_hServer = pData->serverProcess.hProcess; + m_hServerThread = pData->serverProcess.hThread; + // add a refcount + pData->numRefs++; + serverStarted = TRUE; + TCDEBUGLOGA3("CClientManager::StartServer created m_hServer = %x processId = %d numRefs = %d\n", m_hServer, pData->serverProcess.dwProcessId, pData->numRefs); + + // create lock file and save process ID + TCDEBUGLOGS("CClientManager::StartServer CreateLockFile\n"); + CreateLockFile(pData->serverProcess.dwProcessId); + } + } + else + { + // already running + // add a refcount and open our process handle to it only if we haven't opened it already + pData->numRefs++; + if (m_hServer == NULL) + m_hServer = ::OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE, FALSE, pData->serverProcess.dwProcessId); + if (m_hServer == 0) + { + TCDEBUGLOGA1("CClientManager::StartServer opened m_hServer null error=%d\n", ::GetLastError()); + } + m_hServerThread = NULL; // only creator gets real thread handle + serverStarted = TRUE; + TCDEBUGLOGA3("CClientManager::StartServer opened m_hServer = %x processId = %d numRefs = %d\n", m_hServer, pData->serverProcess.dwProcessId, pData->numRefs); + // save our process id to lock file + AppendToLockFile(pData->serverProcess.dwProcessId); + } + if (serverStarted) + m_ServerRunning = TRUE; + + TCDEBUGLOGA1("CClientManager::StartServer end numRefs = %d\n", pData->numRefs); + return ret; +} + +long CClientManager::StopServer() +{ + long ret = TCAPI_ERR_NONE; + pServerProcessData pData = m_Server->GetProcessPtr(); + + TCDEBUGLOGA3("CClientManager::StopServer this = %x m_hServer = %x numRefs = %d\n", this, m_hServer, pData->numRefs); + + BOOL serverStopped = FALSE; + + if (pData->serverProcess.hProcess == NULL || pData->numRefs <= 0) + { + TCDEBUGLOGS("CClientManager::StopServer hProcess NULL or numRefs <= 0\n"); + serverStopped = TRUE; + } +#if (0) + else if (m_hServer == NULL) + { + // we've already closed our handle to server + // don't close it again + TCDEBUGLOGS("CClientManager::StopServer m_hServer null\n"); + } +#endif + else + { + // substract ref count + pData->numRefs--; + if (pData->numRefs < 0) pData->numRefs = 0; + // if refcount == 0 then really stop the server process + if (pData->numRefs == 0) + { + // last client process is closing + // tell server to exit + ServerCommandData cmdrsp; + cmdrsp.command = eCmdExit; + + TCDEBUGLOGS(" SendCommand eCmdExit\n"); + m_Server->SendCommand(&cmdrsp); + TCDEBUGLOGS(" GetResponse eExit\n"); + m_Server->GetResponse(&cmdrsp); + + // wait for process to exit + TCDEBUGLOGS(" WaitForSingleObject start\n"); + DWORD waitErr = ::WaitForSingleObject(m_hServer, 10000L /*INFINITE*/); + TCDEBUGLOGA1("CClientManager::StopServer WaitForSingleObject = %d\n", waitErr); + + // now close our handle to server process + if (m_hServer != NULL) + { + CloseHandle(m_hServer); + m_hServer = NULL; + } + + if (m_hServerThread != NULL) + { + CloseHandle(m_hServerThread); + m_hServerThread = NULL; + } + serverStopped = TRUE; + + // delete lock file + TCDEBUGLOGS("CClientManager::StopServer DeleteLockFile\n"); + DeleteLockFile(); + } + else + { + // just close our handle to server process + + if (m_hServer != NULL) + { + CloseHandle(m_hServer); + m_hServer = NULL; + } + + if (m_hServerThread != NULL) + { + CloseHandle(m_hServerThread); + m_hServerThread = NULL; + } + DeleteFromLockFile(pData->serverProcess.dwProcessId); + } + } + if (serverStopped) + m_ServerRunning = FALSE; + + TCDEBUGLOGA1("CClientManager::StopServer end numRefs = %d\n", pData->numRefs); + return ret; +} + +BOOL CClientManager::IsServerRunning() +{ + pServerProcessData pData = m_Server->GetProcessPtr(); + if (pData->serverProcess.hProcess != NULL) + return TRUE; + else + return FALSE; + +} + +void CClientManager::CreateLockFile(DWORD processId) +{ + if (m_ServerLockFile != NULL) + { + FILE* f = fopen(m_ServerLockFile, "wt"); + TCDEBUGLOGA1("CClientManager::CreateLockFile f=%x\n", f); + + if (f) + { + DWORD callingProcessId = ::GetCurrentProcessId(); + TCDEBUGLOGA2("CClientManager::CreateLockFile callingProcessId=%d processId=%d\n", callingProcessId, processId); + fprintf(f, "%ld %ld\n", callingProcessId, processId); + fclose(f); + } + else + { + DWORD err = ::GetLastError(); + TCDEBUGLOGA2("CClientManager::CreateLockFile fopenErr=%d:%s\n", err, GetErrorText(err)); + } + } +} +void CClientManager::AppendToLockFile(DWORD processId) +{ + if (m_ServerLockFile != NULL) + { + FILE* f = fopen(m_ServerLockFile, "at"); + TCDEBUGLOGA1("CClientManager::AppendToLockFile f=%x\n", f); + + if (f) + { + DWORD callingProcessId = ::GetCurrentProcessId(); + TCDEBUGLOGA2("CClientManager::AppendToLockFile callingProcessId=%d processId=%d\n", callingProcessId, processId); + fprintf(f, "%ld %ld\n", callingProcessId, processId); + fclose(f); + } + else + { + DWORD err = ::GetLastError(); + TCDEBUGLOGA2("CClientManager::AppendToLockFile fopenErr=%d:%s\n", err, GetErrorText(err)); + } + } +} +void CClientManager::DeleteLockFile() +{ + if (m_ServerLockFile != NULL) + { + TCDEBUGLOGS("CClientManager::DeleteLockFile\n"); + ::remove(m_ServerLockFile); + } +} + +void CClientManager::DeleteFromLockFile(DWORD serverProcessId) +{ + DWORD callingId[10]; + DWORD serverId[10]; + int numIds = 0; + + DWORD ourProcessId = ::GetCurrentProcessId(); + + if (m_ServerLockFile != NULL) + { + DWORD attr = ::GetFileAttributes(m_ServerLockFile); + TCDEBUGLOGA1("CClientManager::DeleteFromLockFile attr=%x\n", attr); + + if (attr != 0xffffffff) // error + { + // file exists + // read the process Ids from it + + FILE *f = fopen(m_ServerLockFile, "rt"); + TCDEBUGLOGA1("CClientManager::DeleteFromLockFile f=%x\n", f); + if (f) + { + BOOL done = FALSE; + while (!done) + { + DWORD cId = 0xffffffff; + DWORD sId = 0xffffffff; + int n = fscanf(f, "%ld %ld\n", &cId, &sId); + if (n == 2) + { + TCDEBUGLOGA3("CClientManager::DeleteFromLockFile numIds=%d sId=%d pId=%d\n", numIds, cId, sId); + if (cId != ourProcessId || sId != serverProcessId) + { + callingId[numIds] = cId; + serverId[numIds] = sId; + numIds++; + if (numIds > 9) + done = TRUE; + } + } + else + { + done = TRUE; + } + } + fclose(f); + } + + // now rewrite lock file without us + ::remove(m_ServerLockFile); + if (numIds > 0) + { + f = fopen(m_ServerLockFile, "wt"); + if (f) + { + for (int i = 0; i < numIds; i++) + { + fprintf(f, "%ld %ld\n", callingId[i], serverId[i]); + } + fclose(f); + } + } + } + } +} + +// Currently assumes there is only ONE TCFServer, but multiple client processes (that use that server) +// we should not have more than a few Carbide processes connecting to the same TCFServer +void CClientManager::TerminateServerThroughLockFile(pServerProcessData pData) +{ + DWORD callingId[10]; + DWORD serverId[10]; + BOOL liveCaller[10]; + int numIds = 0; + if (m_ServerLockFile != NULL) + { + DWORD attr = ::GetFileAttributes(m_ServerLockFile); + TCDEBUGLOGA1("CClientManager::TerminateServerThroughLockFile attr=%x\n", attr); + + if (attr != 0xffffffff) // error + { + // file exists + // read the process Ids from it + + FILE *f = fopen(m_ServerLockFile, "rt"); + TCDEBUGLOGA1("CClientManager::TerminateServerThroughLockFile f=%x\n", f); + if (f) + { + BOOL done = FALSE; + while (!done) + { + DWORD cId = 0xffffffff; + DWORD sId = 0xffffffff; + int n = fscanf(f, "%ld %ld\n", &cId, &sId); + if (n == 2) + { + TCDEBUGLOGA3("CClientManager::TerminateServerThroughLockFile n=%d sId=%d pId=%d\n", n, cId, sId); + callingId[numIds] = cId; + serverId[numIds] = sId; + numIds++; + if (numIds > 9) + done = TRUE; + } + else + { + done = TRUE; + } + } + fclose(f); + + int numDeadCallers = 0; + for (int i = 0; i < numIds; i++) + { + HANDLE h = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, callingId[i]); + if (h) + { + // calling process is still alive + liveCaller[i] = TRUE; + ::CloseHandle(h); + TCDEBUGLOGA1("CClientManager::TerminateServerThroughLockFile %d alive\n", callingId[i]); + } + else + { + liveCaller[i] = FALSE; + numDeadCallers++; + DWORD err = ::GetLastError(); + TCDEBUGLOGA3("CClientManager::TerminateServerThroughLockFile %d dead err=%d:%s\n", callingId[i], err, GetErrorText(err)); + } + } + if (numDeadCallers == numIds) + { + // terminate the TCFServer, and delete lock file + pData->numRefs = 0; + ::remove(m_ServerLockFile); + HANDLE h = ::OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE, FALSE, serverId[0]); + if (h) + { + BOOL ret = ::TerminateProcess(h, -1); + if (ret == 0) + { + DWORD err = ::GetLastError(); + TCDEBUGLOGA2("CClientManager::TerminateServerThroughLockFile TerminateProcess=%d:%s\n", err, GetErrorText(err)); + } + ::CloseHandle(h); + } + } + else + { + // leave TCFServer running, recreate lock file and save live callers + ::remove(m_ServerLockFile); + f = fopen(m_ServerLockFile, "wt"); + if (f) + { + for (int i = 0; i < numIds; i++) + { + if (liveCaller[i]) + { + fprintf(f, "%ld %ld\n", callingId[i], serverId[i]); + } + } + fclose(f); + } + pData->numRefs -= numDeadCallers; + if (pData->numRefs < 0) pData->numRefs = 0; + } + } + else + { + // error opening lock file + DWORD err = ::GetLastError(); + TCDEBUGLOGA2("CClientManager::TerminateServerThroughLockFile fopenErr=%d:%s\n", err, GetErrorText(err)); + } + } + } +} +#ifdef _DEBUG +static char* GetErrorText(DWORD inError) +{ + static char msg[256]; + FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + inError, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &msg, + sizeof(msg) - 1, + NULL); + + return msg; +} +#else +static char* GetErrorText(DWORD inError) +{ + return NULL; +} +#endif