connectivity/com.nokia.tcf/native/TCFNative/TCFClient/ClientManager.cpp
changeset 60 9d2210c8eed2
child 505 6de8d9cfdda1
child 916 6743933eec70
equal deleted inserted replaced
59:c892c53c664e 60:9d2210c8eed2
       
     1 /*
       
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of the License "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *
       
    16 */
       
    17 // ClientManager.cpp: implementation of the CClientManager class.
       
    18 //
       
    19 //////////////////////////////////////////////////////////////////////
       
    20 
       
    21 #include "stdafx.h"
       
    22 #include "ClientManager.h"
       
    23 #include "TCErrorConstants.h"
       
    24 #include "resource.h"
       
    25 #include <stdio.h>
       
    26 
       
    27 #ifdef _DEBUG
       
    28 extern BOOL gDoLogging;
       
    29 extern char TCDebugMsg[100];
       
    30 #define TCDEBUGOPEN() if (gDoLogging) m_DebugLog->WaitForAccess();
       
    31 #define TCDEBUGLOGS(s) if (gDoLogging) sprintf(TCDebugMsg,"%s", s); if (gDoLogging) m_DebugLog->log(TCDebugMsg);
       
    32 #define TCDEBUGLOGA1(s, a1) if (gDoLogging) sprintf(TCDebugMsg, s, a1); if (gDoLogging) m_DebugLog->log(TCDebugMsg);
       
    33 #define TCDEBUGLOGA2(s, a1, a2) if (gDoLogging) sprintf(TCDebugMsg, s, a1, a2); if (gDoLogging) m_DebugLog->log(TCDebugMsg);
       
    34 #define TCDEBUGLOGA3(s, a1, a2, a3) if (gDoLogging) sprintf(TCDebugMsg, s, a1, a2, a3); if (gDoLogging) m_DebugLog->log(TCDebugMsg);
       
    35 #define TCDEBUGCLOSE() if (gDoLogging) m_DebugLog->ReleaseAccess();
       
    36 #else
       
    37 #define TCDEBUGOPEN()
       
    38 #define TCDEBUGLOGS(s)
       
    39 #define TCDEBUGLOGA1(s, a1)
       
    40 #define TCDEBUGLOGA2(s, a1, a2)
       
    41 #define TCDEBUGLOGA3(s, a1, a2, a3)
       
    42 #define TCDEBUGCLOSE()
       
    43 #endif
       
    44 
       
    45 #ifdef _DEBUG
       
    46 static char* GetErrorText(DWORD inError);
       
    47 #endif
       
    48 
       
    49 //////////////////////////////////////////////////////////////////////
       
    50 // Construction/Destruction
       
    51 //////////////////////////////////////////////////////////////////////
       
    52 CClientManager::CClientManager()
       
    53 {
       
    54 	m_Server = NULL;
       
    55 	m_StreamList = NULL;
       
    56 	m_ErrorMonitorList = NULL;
       
    57 	m_DebugLog = NULL;
       
    58 	m_DllLocation = NULL;
       
    59 	m_hServer = NULL;
       
    60 	m_hServerThread = NULL;
       
    61 	m_Version[0] = NULL;
       
    62 	m_ServerLockFile = NULL;
       
    63 	m_ServerExeFile = NULL;
       
    64 }
       
    65 CClientManager::CClientManager(HINSTANCE hinstDLL)
       
    66 {
       
    67 #ifdef _DEBUG
       
    68 	if (gDoLogging)
       
    69 		m_DebugLog = new TCDebugLog("TCF_ClientLog", ::GetCurrentProcessId());
       
    70 	else
       
    71 		m_DebugLog = NULL;
       
    72 
       
    73 #else
       
    74 	m_DebugLog = NULL;
       
    75 #endif
       
    76 	TCDEBUGOPEN();
       
    77 	TCDEBUGLOGS("CClientManager::CClientManager\n");
       
    78 
       
    79 	m_Server = new CServerCommand();
       
    80 
       
    81 	// lock server access (it might be running)
       
    82 	m_Server->WaitforServerPipeAccess();
       
    83 
       
    84 	m_StreamList = new InputStreamList();
       
    85 	m_StreamList->clear();
       
    86 
       
    87 	m_ErrorMonitorList = new ErrorMonitorList();
       
    88 	m_ErrorMonitorList->clear();
       
    89 
       
    90 	m_DllLocation = new char[MAX_DLLPATHNAME];
       
    91 	::GetModuleFileName(hinstDLL, m_DllLocation, MAX_DLLPATHNAME);
       
    92 
       
    93 	char exeDirectory[MAX_DLLPATHNAME] = {0};
       
    94 	strncpy(exeDirectory, m_DllLocation, MAX_DLLPATHNAME);
       
    95 	size_t len = strlen(exeDirectory);
       
    96 	// remove file
       
    97 	for (int i = len-1; i > 0; i--)
       
    98 	{
       
    99 		if (exeDirectory[i] == PATH_DELIMITER)
       
   100 			break;
       
   101 	}
       
   102 	exeDirectory[i] = NULL;
       
   103 
       
   104 	m_ServerExeFile = new char[MAX_DLLPATHNAME];
       
   105 	sprintf(m_ServerExeFile, "\"%s%c%s\"", exeDirectory, PATH_DELIMITER, SERVER_PROCESS_NAME);
       
   106 
       
   107 	m_ServerLockFile = new char[MAX_DLLPATHNAME];
       
   108 	sprintf(m_ServerLockFile, "%s%c%s", exeDirectory, PATH_DELIMITER, SERVER_LOCKFILE_NAME);
       
   109 
       
   110 	char name[100];
       
   111 	sprintf(name, "%s%ld", ERRORMONITORLIST_MUTEX_BASENAME, ::GetCurrentProcessId());
       
   112 	m_ErrorMonitorListMutex.Open(name, ERRORMONITORLIST_MUTEX_TIMEOUT);
       
   113 
       
   114 	sprintf(name, "%s%ld", INPUTSTREAMLIST_MUTEX_BASENAME, ::GetCurrentProcessId());
       
   115 	m_StreamListMutex.Open(name, INPUTSTREAMLIST_MUTEX_TIMEOUT);
       
   116 
       
   117 	m_hServer = NULL;
       
   118 	m_hServerThread = NULL;
       
   119 
       
   120 	// release server access
       
   121 	m_Server->ReleaseServerPipeAccess();
       
   122 	int ret = ::LoadString(hinstDLL, IDS_VERSION, m_Version, MAX_VERSION_STRING);
       
   123 
       
   124 	TCDEBUGCLOSE();
       
   125 }
       
   126 
       
   127 CClientManager::~CClientManager()
       
   128 {
       
   129 	TCDEBUGOPEN();
       
   130 	TCDEBUGLOGS("CClientManager::~CClientManager\n");
       
   131 	pServerProcessData pData = m_Server->GetProcessPtr();
       
   132 
       
   133 	if (m_Server)
       
   134 	{
       
   135 		delete m_Server;
       
   136 		m_Server = NULL;
       
   137 	}
       
   138 
       
   139 	WaitForStreamListAccess();
       
   140 	TCDEBUGLOGA1("CClientManager::~CClientManager: erasing stream list size=%d\n", InputStreamListSize());
       
   141 	if (m_StreamList)
       
   142 	{
       
   143 		InputStreamList::iterator iter;
       
   144 		for (iter = m_StreamList->begin(); iter != m_StreamList->end(); iter++)
       
   145 		{
       
   146 			TCDEBUGLOGS("CClientManager::~CClientManager: erasing stream list next 1\n");
       
   147 //			m_StreamList->erase(iter);
       
   148 			delete *iter;
       
   149 //			TCDEBUGLOGS("CClientManager::~CClientManager: erasing stream list next 2\n");
       
   150 		}
       
   151 		m_StreamList->clear();
       
   152 		TCDEBUGLOGS("CClientManager::~CClientManager: erasing stream list done 1\n");
       
   153 		delete m_StreamList;
       
   154 		TCDEBUGLOGS("CClientManager::~CClientManager: erasing stream list done 2\n");
       
   155 	}
       
   156 	ReleaseStreamListAccess();
       
   157 	m_StreamListMutex.Close();
       
   158 
       
   159 	WaitForErrorMonitorListAccess();
       
   160 	TCDEBUGLOGA1("CClientManager::~CClientManager: erasing monitor list size=%d\n", ErrorMonitorListSize());
       
   161 	if (m_ErrorMonitorList)
       
   162 	{
       
   163 		ErrorMonitorList::iterator iter;
       
   164 		for (iter = m_ErrorMonitorList->begin(); iter != m_ErrorMonitorList->end(); iter++)
       
   165 		{
       
   166 			TCDEBUGLOGS("CClientManager::~CClientManager: erasing monitor list next 1\n");
       
   167 //			m_ErrorMonitorList->erase(iter);
       
   168 			delete *iter;
       
   169 //			TCDEBUGLOGS("CClientManager::~CClientManager: erasing monitor list next 1\n");
       
   170 		}
       
   171 		m_ErrorMonitorList->clear();
       
   172 		TCDEBUGLOGS("CClientManager::~CClientManager: erasing monitor list done 1\n");
       
   173 		delete m_ErrorMonitorList;
       
   174 		TCDEBUGLOGS("CClientManager::~CClientManager: erasing monitor list done 2\n");
       
   175 	}
       
   176 	ReleaseErrorMonitorListAccess();
       
   177 	m_ErrorMonitorListMutex.Close();
       
   178 
       
   179 	if (m_DllLocation)
       
   180 	{
       
   181 		delete[] m_DllLocation;
       
   182 		m_DllLocation = NULL;
       
   183 	}
       
   184 
       
   185 	if (m_ServerLockFile)
       
   186 	{
       
   187 		delete[] m_ServerLockFile;
       
   188 		m_ServerLockFile = NULL;
       
   189 	}
       
   190 
       
   191 	if (m_ServerExeFile)
       
   192 	{
       
   193 		delete[] m_ServerExeFile;
       
   194 		m_ServerExeFile = NULL;
       
   195 	}
       
   196 	TCDEBUGLOGS("CClientManager::~CClientManager: closing log\n");
       
   197 	TCDEBUGCLOSE();
       
   198 	if (m_DebugLog)
       
   199 	{
       
   200 		delete m_DebugLog;
       
   201 		m_DebugLog = NULL;
       
   202 	}
       
   203 }
       
   204 CErrorMonitor*
       
   205 CClientManager::FindErrorMonitor(long inClientId)
       
   206 {
       
   207 	CErrorMonitor* errorMonitor = NULL;
       
   208 	ErrorMonitorList::iterator iter;
       
   209 
       
   210 	for (iter = m_ErrorMonitorList->begin(); iter != m_ErrorMonitorList->end(); iter++)
       
   211 	{
       
   212 		if ((*iter)->IsThisClient(inClientId))
       
   213 		{
       
   214 			errorMonitor = *iter;
       
   215 			break;
       
   216 		}
       
   217 	}
       
   218 	return errorMonitor;
       
   219 }
       
   220 long CClientManager::ErrorMonitorListSize()
       
   221 {
       
   222 	long size = m_ErrorMonitorList->size();
       
   223 
       
   224 	return size;
       
   225 }
       
   226 void CClientManager::AddErrorMonitor(CErrorMonitor* monitor)
       
   227 {
       
   228 	m_ErrorMonitorList->push_back(monitor);
       
   229 }
       
   230 void CClientManager::RemoveErrorMonitor(CErrorMonitor* monitor)
       
   231 {
       
   232 	ErrorMonitorList::iterator iter;
       
   233 
       
   234 	for (iter = m_ErrorMonitorList->begin(); iter != m_ErrorMonitorList->end(); iter++)
       
   235 	{
       
   236 		if ((*iter)->IsThisClient(monitor->GetClientId()))
       
   237 		{
       
   238 			m_ErrorMonitorList->erase(iter);
       
   239 			break;
       
   240 		}
       
   241 	}
       
   242 }
       
   243 
       
   244 CInputStream*
       
   245 CClientManager::FindInputStream(long inClientId)
       
   246 {
       
   247 	CInputStream* inputStream = NULL;
       
   248 	InputStreamList::iterator iter;
       
   249 
       
   250 	for (iter = m_StreamList->begin(); iter != m_StreamList->end(); iter++)
       
   251 	{
       
   252 		if ((*iter)->IsThisClient(inClientId))
       
   253 //		if ((*iter).IsThisClient(inClientId))
       
   254 		{
       
   255 			inputStream = *iter;
       
   256 //			inputStream = iter;
       
   257 			break;
       
   258 		}
       
   259 	}
       
   260 	return inputStream;
       
   261 }
       
   262 long CClientManager::InputStreamListSize()
       
   263 {
       
   264 	long size = m_StreamList->size();
       
   265 
       
   266 	return size;
       
   267 }
       
   268 void CClientManager::AddInputStream(CInputStream* stream)
       
   269 {
       
   270 	m_StreamList->push_back(stream);
       
   271 //	m_StreamList->push_back(*stream);
       
   272 
       
   273 }
       
   274 void CClientManager::RemoveInputStream(CInputStream* stream)
       
   275 {
       
   276 	InputStreamList::iterator iter;
       
   277 
       
   278 	for (iter = m_StreamList->begin(); iter != m_StreamList->end(); iter++)
       
   279 	{
       
   280 		if ((*iter)->IsThisClient(stream->GetClientId()))
       
   281 //		if ((*iter).IsThisClient(stream->GetClientId()))
       
   282 		{
       
   283 			m_StreamList->erase(iter);
       
   284 			break;
       
   285 		}
       
   286 	}
       
   287 }
       
   288 
       
   289 BOOL CClientManager::StartServer(pServerProcessData pData)
       
   290 {
       
   291 	TCDEBUGLOGA1("CClientManager::StartServer numRefs = %d\n",pData->numRefs);
       
   292 
       
   293 	BOOL serverStarted = FALSE;
       
   294 	// server is ref counted
       
   295 	// refcount = 0 => server is not running
       
   296 	// refcount > 0 => server already started by some other process
       
   297 	if (pData->numRefs == 0)
       
   298 	{
       
   299 		// server not running
       
   300 		// get exe location
       
   301 		char exeLocation[MAX_DLLPATHNAME] = {0};
       
   302 		strncpy(exeLocation, m_DllLocation, MAX_DLLPATHNAME);
       
   303 		size_t len = strlen(exeLocation);
       
   304 		// remove file
       
   305 		for (int i = len-1; i > 0; i--)
       
   306 		{
       
   307 			if (exeLocation[i] == PATH_DELIMITER)
       
   308 				break;
       
   309 		}
       
   310 		exeLocation[i] = NULL;
       
   311 		char quotedLocation[MAX_DLLPATHNAME] = {0};
       
   312 		sprintf(quotedLocation, "\"%s%c%s\"", exeLocation, PATH_DELIMITER, SERVER_PROCESS_NAME);
       
   313 
       
   314 		TCDEBUGLOGA1("  exeLocation=%s\n", quotedLocation);
       
   315 
       
   316 		// create process
       
   317 		STARTUPINFO si;
       
   318 		memset(&si,0,sizeof(si));
       
   319 		si.cb = sizeof(si);
       
   320 		memset(&pData->serverProcess, 0, sizeof(pData->serverProcess));
       
   321 		pData->serverProcess.hProcess = NULL;
       
   322 		if (!::CreateProcess(
       
   323 			NULL,			// module location
       
   324 			quotedLocation,	// command line
       
   325 			NULL,			// process attributes
       
   326 			NULL,			// thread attributes
       
   327 			FALSE,			// inherit our handles
       
   328 			CREATE_NO_WINDOW,	// no window
       
   329 			NULL,			// use our environment
       
   330 			NULL,			// user our current directory
       
   331 			&si,			// startup info
       
   332 			&pData->serverProcess)) // process info
       
   333 		{
       
   334 			// TODO: error creating process
       
   335 		}
       
   336 		else
       
   337 		{
       
   338 			// we are the creator so save handles for later
       
   339 			m_hServer = pData->serverProcess.hProcess;
       
   340 			m_hServerThread = pData->serverProcess.hThread;
       
   341 			// add a refcount
       
   342 			pData->numRefs++;
       
   343 			serverStarted = TRUE;
       
   344 		}
       
   345 	}
       
   346 	else
       
   347 	{
       
   348 		// already running
       
   349 		// add a refcount and open our process handle to it
       
   350 		pData->numRefs++;
       
   351 		m_hServer = ::OpenProcess(0, FALSE, pData->serverProcess.dwProcessId);
       
   352 		serverStarted = TRUE;
       
   353 	}
       
   354 	TCDEBUGLOGA1("CClientManager::StartServer serverStarted=%d\n", serverStarted);
       
   355 	return serverStarted;
       
   356 }
       
   357 
       
   358 BOOL CClientManager::StopServer(pServerProcessData pData)
       
   359 {
       
   360 	TCDEBUGLOGS("CClientManager::StopServer\n");
       
   361 
       
   362 	BOOL serverStopped = FALSE;
       
   363 
       
   364 	if (pData->serverProcess.hProcess == NULL || pData->numRefs <= 0)
       
   365 	{
       
   366 		serverStopped = TRUE;
       
   367 	}
       
   368 	else
       
   369 	{
       
   370 		TCDEBUGLOGA1(" numRefs = %d\n",pData->numRefs); 
       
   371 
       
   372 		// substract ref count
       
   373 		pData->numRefs--;
       
   374 		// if refcount == 0 then really stop the server process
       
   375 		if (pData->numRefs <= 0)
       
   376 		{
       
   377 			// last client process is closing
       
   378 			// tell server to exit
       
   379 			ServerCommandData cmdrsp;
       
   380 			cmdrsp.command = eCmdExit;
       
   381 		TCDEBUGLOGS(" SendCommand eCmdExit\n");
       
   382 			m_Server->SendCommand(&cmdrsp);
       
   383 		TCDEBUGLOGS(" GetResponse eExit\n");
       
   384 			m_Server->GetResponse(&cmdrsp);
       
   385 			// wait for process to exit
       
   386 		TCDEBUGLOGS(" WaitForSingleObject start\n");
       
   387 			WaitForSingleObject(m_hServer, 10000L /*INFINITE*/);
       
   388 		TCDEBUGLOGS(" WaitForSingleObject found\n");
       
   389 
       
   390 			if (m_hServer != NULL)
       
   391 				CloseHandle(m_hServer);
       
   392 
       
   393 			if (m_hServerThread != NULL)
       
   394 				CloseHandle(m_hServerThread);
       
   395 		}
       
   396 		else
       
   397 		{
       
   398 			// just close our handle to server process
       
   399 			if (m_hServer != NULL)
       
   400 				CloseHandle(m_hServer);
       
   401 
       
   402 			if (m_hServerThread != NULL)
       
   403 				CloseHandle(m_hServerThread);
       
   404 		}
       
   405 	}
       
   406 
       
   407 	TCDEBUGLOGS("CClientManager::StopServer end\n");
       
   408 	return TRUE;
       
   409 }
       
   410 long CClientManager::StartServer()
       
   411 {
       
   412 	long ret = TCAPI_ERR_NONE;
       
   413 	pServerProcessData pData = m_Server->GetProcessPtr();
       
   414 
       
   415 	TCDEBUGLOGA3("CClientManager::StartServer this = %x m_hServer = %x numRefs = %d\n", this, m_hServer, pData->numRefs);
       
   416 //	TCDEBUGLOGA1("  mgrRefs = %d\n", m_MgrServerRef);
       
   417 
       
   418 	BOOL serverStarted = FALSE;
       
   419 	// server is ref counted
       
   420 	// refcount = 0 => server is not running
       
   421 	// refcount > 0 => server already started by some other process
       
   422 
       
   423 	// terminate the TCFServer if it is already running
       
   424 	TerminateServerThroughLockFile(pData);
       
   425 
       
   426 	if (pData->numRefs == 0)
       
   427 	{
       
   428 		// server not running
       
   429 		TCDEBUGLOGA1("  TCFServer exe =%s\n", m_ServerExeFile);
       
   430 		TCDEBUGLOGA1("  TCFServer lock=%s\n", m_ServerLockFile);
       
   431 
       
   432 
       
   433 		// create process
       
   434 		STARTUPINFO si;
       
   435 		memset(&si,0,sizeof(si));
       
   436 		si.cb = sizeof(si);
       
   437 		memset(&pData->serverProcess, 0, sizeof(pData->serverProcess));
       
   438 		pData->serverProcess.hProcess = NULL;
       
   439 		if (!::CreateProcess(
       
   440 			NULL,			// module location
       
   441 			m_ServerExeFile,	// command line
       
   442 			NULL,			// process attributes
       
   443 			NULL,			// thread attributes
       
   444 			FALSE,			// inherit our handles
       
   445 			CREATE_NO_WINDOW,	// no window
       
   446 			NULL,			// use our environment
       
   447 			NULL,			// user our current directory
       
   448 			&si,			// startup info
       
   449 			&pData->serverProcess)) // process info
       
   450 		{
       
   451 			// TODO: error creating process
       
   452 		}
       
   453 		else
       
   454 		{
       
   455 			// we are the creator so save handles for later
       
   456 			m_hServer = pData->serverProcess.hProcess;
       
   457 			m_hServerThread = pData->serverProcess.hThread;
       
   458 			// add a refcount
       
   459 			pData->numRefs++;
       
   460 			serverStarted = TRUE;
       
   461 			TCDEBUGLOGA3("CClientManager::StartServer created m_hServer = %x processId = %d numRefs = %d\n", m_hServer, pData->serverProcess.dwProcessId, pData->numRefs);
       
   462 
       
   463 			// create lock file and save process ID
       
   464 			TCDEBUGLOGS("CClientManager::StartServer CreateLockFile\n");
       
   465 			CreateLockFile(pData->serverProcess.dwProcessId);
       
   466 		}
       
   467 	}
       
   468 	else
       
   469 	{
       
   470 		// already running
       
   471 		// add a refcount and open our process handle to it only if we haven't opened it already
       
   472 		pData->numRefs++;
       
   473 		if (m_hServer == NULL)
       
   474 			m_hServer = ::OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE, FALSE, pData->serverProcess.dwProcessId);
       
   475 		if (m_hServer == 0)
       
   476 		{
       
   477 			TCDEBUGLOGA1("CClientManager::StartServer opened m_hServer null error=%d\n", ::GetLastError());
       
   478 		}
       
   479 		m_hServerThread = NULL;		// only creator gets real thread handle
       
   480 		serverStarted = TRUE;
       
   481 		TCDEBUGLOGA3("CClientManager::StartServer opened m_hServer = %x processId = %d numRefs = %d\n", m_hServer, pData->serverProcess.dwProcessId, pData->numRefs);
       
   482 		// save our process id to lock file
       
   483 		AppendToLockFile(pData->serverProcess.dwProcessId);
       
   484 	}
       
   485 	if (serverStarted)
       
   486 		m_ServerRunning = TRUE;
       
   487 
       
   488 	TCDEBUGLOGA1("CClientManager::StartServer end numRefs = %d\n", pData->numRefs);
       
   489 	return ret;
       
   490 }
       
   491 
       
   492 long CClientManager::StopServer()
       
   493 {
       
   494 	long ret = TCAPI_ERR_NONE;
       
   495 	pServerProcessData pData = m_Server->GetProcessPtr();
       
   496 
       
   497 	TCDEBUGLOGA3("CClientManager::StopServer this = %x m_hServer = %x numRefs = %d\n", this, m_hServer, pData->numRefs);
       
   498 
       
   499 	BOOL serverStopped = FALSE;
       
   500 
       
   501 	if (pData->serverProcess.hProcess == NULL || pData->numRefs <= 0)
       
   502 	{
       
   503 		TCDEBUGLOGS("CClientManager::StopServer hProcess NULL or numRefs <= 0\n");
       
   504 		serverStopped = TRUE;
       
   505 	}
       
   506 #if (0)
       
   507 	else if (m_hServer == NULL)
       
   508 	{
       
   509 		// we've already closed our handle to server
       
   510 		// don't close it again
       
   511 		TCDEBUGLOGS("CClientManager::StopServer m_hServer null\n");
       
   512 	}
       
   513 #endif
       
   514 	else
       
   515 	{
       
   516 		// substract ref count
       
   517 		pData->numRefs--;
       
   518 		if (pData->numRefs < 0) pData->numRefs = 0;
       
   519 		// if refcount == 0 then really stop the server process
       
   520 		if (pData->numRefs == 0)
       
   521 		{
       
   522 			// last client process is closing
       
   523 			// tell server to exit
       
   524 			ServerCommandData cmdrsp;
       
   525 			cmdrsp.command = eCmdExit;
       
   526 			
       
   527 			TCDEBUGLOGS(" SendCommand eCmdExit\n");
       
   528 			m_Server->SendCommand(&cmdrsp);
       
   529 			TCDEBUGLOGS(" GetResponse eExit\n");
       
   530 			m_Server->GetResponse(&cmdrsp);
       
   531 			
       
   532 			// wait for process to exit
       
   533 			TCDEBUGLOGS(" WaitForSingleObject start\n");
       
   534 			DWORD waitErr = ::WaitForSingleObject(m_hServer, 10000L /*INFINITE*/);
       
   535 			TCDEBUGLOGA1("CClientManager::StopServer WaitForSingleObject = %d\n", waitErr);
       
   536 
       
   537 			// now close our handle to server process
       
   538 			if (m_hServer != NULL)
       
   539 			{
       
   540 				CloseHandle(m_hServer);
       
   541 				m_hServer = NULL;
       
   542 			}
       
   543 
       
   544 			if (m_hServerThread != NULL)
       
   545 			{
       
   546 				CloseHandle(m_hServerThread);
       
   547 				m_hServerThread = NULL;
       
   548 			}
       
   549 			serverStopped = TRUE;
       
   550 
       
   551 			// delete lock file
       
   552 			TCDEBUGLOGS("CClientManager::StopServer DeleteLockFile\n");
       
   553 			DeleteLockFile();
       
   554 		}
       
   555 		else
       
   556 		{
       
   557 			// just close our handle to server process
       
   558 
       
   559 			if (m_hServer != NULL)
       
   560 			{
       
   561 				CloseHandle(m_hServer);
       
   562 				m_hServer = NULL;
       
   563 			}
       
   564 
       
   565 			if (m_hServerThread != NULL)
       
   566 			{
       
   567 				CloseHandle(m_hServerThread);
       
   568 				m_hServerThread = NULL;
       
   569 			}
       
   570 			DeleteFromLockFile(pData->serverProcess.dwProcessId);
       
   571 		}
       
   572 	}
       
   573 	if (serverStopped)
       
   574 		m_ServerRunning = FALSE;
       
   575 
       
   576 	TCDEBUGLOGA1("CClientManager::StopServer end numRefs = %d\n", pData->numRefs);
       
   577 	return ret;
       
   578 }
       
   579 
       
   580 BOOL CClientManager::IsServerRunning()
       
   581 {
       
   582 	pServerProcessData pData = m_Server->GetProcessPtr();
       
   583 	if (pData->serverProcess.hProcess != NULL)
       
   584 		return TRUE;
       
   585 	else
       
   586 		return FALSE;
       
   587 
       
   588 }
       
   589 
       
   590 void CClientManager::CreateLockFile(DWORD processId)
       
   591 {
       
   592 	if (m_ServerLockFile != NULL)
       
   593 	{
       
   594 		FILE* f = fopen(m_ServerLockFile, "wt");
       
   595 		TCDEBUGLOGA1("CClientManager::CreateLockFile f=%x\n", f);
       
   596 
       
   597 		if (f)
       
   598 		{
       
   599 			DWORD callingProcessId = ::GetCurrentProcessId();
       
   600 			TCDEBUGLOGA2("CClientManager::CreateLockFile callingProcessId=%d processId=%d\n", callingProcessId, processId);
       
   601 			fprintf(f, "%ld %ld\n", callingProcessId, processId);
       
   602 			fclose(f);
       
   603 		}
       
   604 		else
       
   605 		{
       
   606 			DWORD err = ::GetLastError();
       
   607 			TCDEBUGLOGA2("CClientManager::CreateLockFile fopenErr=%d:%s\n", err, GetErrorText(err));
       
   608 		}
       
   609 	}
       
   610 }
       
   611 void CClientManager::AppendToLockFile(DWORD processId)
       
   612 {
       
   613 	if (m_ServerLockFile != NULL)
       
   614 	{
       
   615 		FILE* f = fopen(m_ServerLockFile, "at");
       
   616 		TCDEBUGLOGA1("CClientManager::AppendToLockFile f=%x\n", f);
       
   617 
       
   618 		if (f)
       
   619 		{
       
   620 			DWORD callingProcessId = ::GetCurrentProcessId();
       
   621 			TCDEBUGLOGA2("CClientManager::AppendToLockFile callingProcessId=%d processId=%d\n", callingProcessId, processId);
       
   622 			fprintf(f, "%ld %ld\n", callingProcessId, processId);
       
   623 			fclose(f);
       
   624 		}
       
   625 		else
       
   626 		{
       
   627 			DWORD err = ::GetLastError();
       
   628 			TCDEBUGLOGA2("CClientManager::AppendToLockFile fopenErr=%d:%s\n", err, GetErrorText(err));
       
   629 		}
       
   630 	}
       
   631 }
       
   632 void CClientManager::DeleteLockFile()
       
   633 {
       
   634 	if (m_ServerLockFile != NULL)
       
   635 	{
       
   636 		TCDEBUGLOGS("CClientManager::DeleteLockFile\n");
       
   637 		::remove(m_ServerLockFile);
       
   638 	}
       
   639 }
       
   640 
       
   641 void CClientManager::DeleteFromLockFile(DWORD serverProcessId)
       
   642 {
       
   643 	DWORD callingId[10];
       
   644 	DWORD serverId[10];
       
   645 	int numIds = 0;
       
   646 
       
   647 	DWORD ourProcessId = ::GetCurrentProcessId();
       
   648 
       
   649 	if (m_ServerLockFile != NULL)
       
   650 	{
       
   651 		DWORD attr = ::GetFileAttributes(m_ServerLockFile);
       
   652 		TCDEBUGLOGA1("CClientManager::DeleteFromLockFile attr=%x\n", attr);
       
   653 
       
   654 		if (attr != 0xffffffff) // error
       
   655 		{
       
   656 			// file exists
       
   657 			// read the process Ids from it 
       
   658 
       
   659 			FILE *f = fopen(m_ServerLockFile, "rt");
       
   660 			TCDEBUGLOGA1("CClientManager::DeleteFromLockFile f=%x\n", f);
       
   661 			if (f)
       
   662 			{
       
   663 				BOOL done = FALSE;
       
   664 				while (!done)
       
   665 				{
       
   666 					DWORD cId = 0xffffffff;
       
   667 					DWORD sId = 0xffffffff;
       
   668 					int n = fscanf(f, "%ld %ld\n", &cId, &sId);
       
   669 					if (n == 2)
       
   670 					{
       
   671 						TCDEBUGLOGA3("CClientManager::DeleteFromLockFile numIds=%d sId=%d pId=%d\n", numIds, cId, sId);
       
   672 						if (cId != ourProcessId || sId != serverProcessId)
       
   673 						{
       
   674 							callingId[numIds] = cId;
       
   675 							serverId[numIds] = sId;
       
   676 							numIds++;
       
   677 							if (numIds > 9)
       
   678 								done = TRUE;
       
   679 						}
       
   680 					}
       
   681 					else
       
   682 					{
       
   683 						done = TRUE;
       
   684 					}
       
   685 				}
       
   686 				fclose(f);
       
   687 			}
       
   688 
       
   689 			// now rewrite lock file without us
       
   690 			::remove(m_ServerLockFile);
       
   691 			if (numIds > 0)
       
   692 			{
       
   693 				f = fopen(m_ServerLockFile, "wt");
       
   694 				if (f)
       
   695 				{
       
   696 					for (int i = 0; i < numIds; i++)
       
   697 					{
       
   698 						fprintf(f, "%ld %ld\n", callingId[i], serverId[i]);
       
   699 					}
       
   700 					fclose(f);
       
   701 				}
       
   702 			}
       
   703 		}
       
   704 	}
       
   705 }
       
   706 
       
   707 // Currently assumes there is only ONE TCFServer, but multiple client processes (that use that server)
       
   708 // we should not have more than a few Carbide processes connecting to the same TCFServer
       
   709 void CClientManager::TerminateServerThroughLockFile(pServerProcessData pData)
       
   710 {
       
   711 	DWORD callingId[10];
       
   712 	DWORD serverId[10];
       
   713 	BOOL liveCaller[10];
       
   714 	int numIds = 0;
       
   715 	if (m_ServerLockFile != NULL)
       
   716 	{
       
   717 		DWORD attr = ::GetFileAttributes(m_ServerLockFile);
       
   718 		TCDEBUGLOGA1("CClientManager::TerminateServerThroughLockFile attr=%x\n", attr);
       
   719 
       
   720 		if (attr != 0xffffffff) // error
       
   721 		{
       
   722 			// file exists
       
   723 			// read the process Ids from it 
       
   724 
       
   725 			FILE *f = fopen(m_ServerLockFile, "rt");
       
   726 			TCDEBUGLOGA1("CClientManager::TerminateServerThroughLockFile f=%x\n", f);
       
   727 			if (f)
       
   728 			{
       
   729 				BOOL done = FALSE;
       
   730 				while (!done)
       
   731 				{
       
   732 					DWORD cId = 0xffffffff;
       
   733 					DWORD sId = 0xffffffff;
       
   734 					int n = fscanf(f, "%ld %ld\n", &cId, &sId);
       
   735 					if (n == 2)
       
   736 					{
       
   737 						TCDEBUGLOGA3("CClientManager::TerminateServerThroughLockFile n=%d sId=%d pId=%d\n", n, cId, sId);
       
   738 						callingId[numIds] = cId;
       
   739 						serverId[numIds] = sId;
       
   740 						numIds++;
       
   741 						if (numIds > 9)
       
   742 							done = TRUE;
       
   743 					}
       
   744 					else
       
   745 					{
       
   746 						done = TRUE;
       
   747 					}
       
   748 				}
       
   749 				fclose(f);
       
   750 
       
   751 				int numDeadCallers = 0;
       
   752 				for (int i = 0; i < numIds; i++)
       
   753 				{
       
   754 					HANDLE h = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, callingId[i]);
       
   755 					if (h)
       
   756 					{
       
   757 						// calling process is still alive
       
   758 						liveCaller[i] = TRUE;
       
   759 						::CloseHandle(h);
       
   760 						TCDEBUGLOGA1("CClientManager::TerminateServerThroughLockFile %d alive\n", callingId[i]);
       
   761 					}
       
   762 					else
       
   763 					{
       
   764 						liveCaller[i] = FALSE;
       
   765 						numDeadCallers++;
       
   766 						DWORD err = ::GetLastError();
       
   767 						TCDEBUGLOGA3("CClientManager::TerminateServerThroughLockFile %d dead err=%d:%s\n", callingId[i], err, GetErrorText(err));
       
   768 					}
       
   769 				}
       
   770 				if (numDeadCallers == numIds)
       
   771 				{
       
   772 					// terminate the TCFServer, and delete lock file
       
   773 					pData->numRefs = 0;
       
   774 					::remove(m_ServerLockFile);
       
   775 					HANDLE h = ::OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE, FALSE, serverId[0]);
       
   776 					if (h)
       
   777 					{
       
   778 						BOOL ret = ::TerminateProcess(h, -1);
       
   779 						if (ret == 0)
       
   780 						{
       
   781 							DWORD err = ::GetLastError();
       
   782 							TCDEBUGLOGA2("CClientManager::TerminateServerThroughLockFile TerminateProcess=%d:%s\n", err, GetErrorText(err));
       
   783 						}
       
   784 						::CloseHandle(h);
       
   785 					}
       
   786 				}
       
   787 				else
       
   788 				{
       
   789 					// leave TCFServer running, recreate lock file and save live callers
       
   790 					::remove(m_ServerLockFile);
       
   791 					f = fopen(m_ServerLockFile, "wt");
       
   792 					if (f)
       
   793 					{
       
   794 						for (int i = 0; i < numIds; i++)
       
   795 						{
       
   796 							if (liveCaller[i])
       
   797 							{
       
   798 								fprintf(f, "%ld %ld\n", callingId[i], serverId[i]);
       
   799 							}
       
   800 						}
       
   801 						fclose(f);
       
   802 					}
       
   803 					pData->numRefs -= numDeadCallers;
       
   804 					if (pData->numRefs < 0) pData->numRefs = 0;
       
   805 				}
       
   806 			}
       
   807 			else
       
   808 			{
       
   809 				// error opening lock file
       
   810 				DWORD err = ::GetLastError();
       
   811 				TCDEBUGLOGA2("CClientManager::TerminateServerThroughLockFile fopenErr=%d:%s\n", err, GetErrorText(err));
       
   812 			}
       
   813 		}
       
   814 	}
       
   815 }
       
   816 #ifdef _DEBUG
       
   817 static char* GetErrorText(DWORD inError)
       
   818 {
       
   819 	static char msg[256];
       
   820 	FormatMessage(
       
   821 		FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
       
   822 		NULL,
       
   823 		inError,
       
   824 		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
       
   825 		(LPTSTR) &msg,
       
   826 		sizeof(msg) - 1,
       
   827 		NULL);
       
   828 
       
   829 	return msg;
       
   830 }
       
   831 #else
       
   832 static char* GetErrorText(DWORD inError)
       
   833 {
       
   834 	return NULL;
       
   835 }
       
   836 #endif