Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

11944 lines
302 KiB

  1. /*++ BUILD Version: 0000 // Increment this if a change has global effects
  2. Copyright (c) 1995-1998 Microsoft Corporation
  3. Module Name:
  4. server.c
  5. Abstract:
  6. Src module for tapi server
  7. Author:
  8. Dan Knudson (DanKn) 01-Apr-1995
  9. Revision History:
  10. --*/
  11. #include "windows.h"
  12. #include "stdio.h"
  13. #include "stdlib.h"
  14. #include "tchar.h"
  15. #include "assert.h"
  16. #include "process.h"
  17. #include "winsvcp.h"
  18. #include "tapi.h"
  19. #include "tspi.h"
  20. #include "utils.h"
  21. #include "client.h"
  22. #include "server.h"
  23. #define INIT_FUNCTABLE
  24. #include "private.h"
  25. #undef INIT_FUNCTABLE
  26. #include "tapsrv.h"
  27. #include "tapiperf.h"
  28. #include "winnetwk.h"
  29. #include "buffer.h"
  30. #include "line.h"
  31. #include "tapihndl.h"
  32. #include <tchar.h>
  33. #include "loc_comn.h"
  34. #include "tapimmc.h"
  35. #include "resource.h"
  36. //
  37. // Bit flags to tell ServiceShutdown how much of the service has been initialized
  38. //
  39. #define SERVICE_INIT_TRACELOG 0x00000001
  40. #define SERVICE_INIT_SCM_REGISTERED 0x00000002
  41. #define SERVICE_INIT_LOCKTABLE 0x00000004
  42. #define SERVICE_INIT_CRITSEC_SAFEMUTEX 0x00000008
  43. #define SERVICE_INIT_CRITSEC_REMOTECLI 0x00000010
  44. #define SERVICE_INIT_CRITSEC_PRILIST 0x00000020
  45. #define SERVICE_INIT_CRITSEC_MGMTDLLS 0x00000040
  46. #define SERVICE_INIT_CRITSEC_DLLLIST 0x00000080
  47. #define SERVICE_INIT_CRITSEC_CLIENTHND 0x00000100
  48. #define SERVICE_INIT_CRITSEC_CNCLIENTMSG 0x00000200
  49. #define SERVICE_INIT_CRITSEC_DGCLIENTMSG 0x00000400
  50. #define SERVICE_INIT_CRITSEC_GLOB_CRITSEC 0x00000800
  51. #define SERVICE_INIT_CRITSEC_GLOB_REMOTESP 0x00001000
  52. #define SERVICE_INIT_CRITSEC_MGMT 0x00002000
  53. #define SERVICE_INIT_SPEVENT_HANDLER 0x00004000
  54. #define SERVICE_INIT_MANAGEMENT_DLL 0x00008000
  55. #define SERVICE_INIT_EVENT_NOTIFICATION 0x00010000
  56. #define SERVICE_INIT_RPC 0x00020000
  57. #if DBG
  58. BOOL gbBreakOnLeak = FALSE;
  59. BOOL gfBreakOnSeriousProblems = FALSE;
  60. void
  61. DumpHandleList();
  62. #endif
  63. extern const DWORD TapiPrimes[];
  64. const TCHAR gszRegTapisrvSCPGuid[] = TEXT("TAPISRVSCPGUID");
  65. // PERF
  66. PERFBLOCK PerfBlock;
  67. BOOL InitPerf();
  68. TAPIGLOBALS TapiGlobals;
  69. HANDLE ghTapisrvHeap, ghHandleTable;
  70. HANDLE ghEventService;
  71. HANDLE ghSCMAutostartEvent = NULL;
  72. BOOL gbPriorityListsInitialized;
  73. BOOL gbQueueSPEvents;
  74. BOOL gfWeHadAtLeastOneClient;
  75. BOOL gbSPEventHandlerThreadExit;
  76. BOOL gbNTServer;
  77. BOOL gbServerInited;
  78. BOOL gbAutostartDone = FALSE;
  79. HINSTANCE ghInstance;
  80. CRITICAL_SECTION gSafeMutexCritSec,
  81. gRemoteCliEventBufCritSec,
  82. gPriorityListCritSec,
  83. gManagementDllsCritSec,
  84. gDllListCritSec,
  85. gClientHandleCritSec,
  86. gCnClientMsgPendingCritSec,
  87. gDgClientMsgPendingCritSec,
  88. gLockTableCritSecs[2];
  89. #define MIN_WAIT_HINT 60000
  90. DWORD gdwServiceState = SERVICE_START_PENDING,
  91. gdwWaitHint = MIN_WAIT_HINT,
  92. gdwCheckPoint = 0,
  93. gdwDllIDs = 0,
  94. gdwRpcTimeout = 30000,
  95. gdwRpcRetryCount = 5,
  96. gdwTotalAsyncThreads = 0,
  97. gdwThreadsPerProcessor = 4,
  98. guiAlignmentFaultEnabled = FALSE,
  99. gdwTapiSCPTTL = 60 * 24;
  100. gdwServiceInitFlags = 0;
  101. DWORD gdwPointerToLockTableIndexBits;
  102. CRITICAL_SECTION *gLockTable;
  103. DWORD gdwNumLockTableEntries;
  104. BOOL (WINAPI * pfnInitializeCriticalSectionAndSpinCount)
  105. (LPCRITICAL_SECTION, DWORD);
  106. LIST_ENTRY CnClientMsgPendingListHead;
  107. LIST_ENTRY DgClientMsgPendingListHead;
  108. SPEVENTHANDLERTHREADINFO gSPEventHandlerThreadInfo;
  109. PSPEVENTHANDLERTHREADINFO aSPEventHandlerThreadInfo;
  110. DWORD gdwNumSPEventHandlerThreads;
  111. LONG glNumActiveSPEventHandlerThreads;
  112. #if DBG
  113. const TCHAR gszTapisrvDebugLevel[] = TEXT("TapiSrvDebugLevel");
  114. const TCHAR gszBreakOnLeak[] = TEXT("BreakOnLeak");
  115. #endif
  116. const TCHAR gszProvider[] = TEXT("Provider");
  117. const TCHAR gszNumLines[] = TEXT("NumLines");
  118. const TCHAR gszUIDllName[] = TEXT("UIDllName");
  119. const TCHAR gszNumPhones[] = TEXT("NumPhones");
  120. const TCHAR gszSyncLevel[] = TEXT("SyncLevel");
  121. const TCHAR gszProductType[] = TEXT("ProductType");
  122. const TCHAR gszProductTypeServer[] = TEXT("ServerNT");
  123. const TCHAR gszProductTypeLanmanNt[] = TEXT("LANMANNT");
  124. const TCHAR gszProviderID[] = TEXT("ProviderID");
  125. const TCHAR gszNumProviders[] = TEXT("NumProviders");
  126. const TCHAR gszNextProviderID[] = TEXT("NextProviderID");
  127. const TCHAR gszRequestMakeCallW[] = TEXT("RequestMakeCall");
  128. const TCHAR gszRequestMediaCallW[] = TEXT("RequestMediaCall");
  129. const TCHAR gszProviderFilename[] = TEXT("ProviderFilename");
  130. const WCHAR gszMapperDll[] = L"MapperDll";
  131. const WCHAR gszManagementDlls[] = L"ManagementDlls";
  132. const TCHAR gszDomainName[] = TEXT("DomainName");
  133. const TCHAR gszRegKeyHandoffPriorities[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Telephony\\HandoffPriorities");
  134. const TCHAR gszRegKeyHandoffPrioritiesMediaModes[] = TEXT("MediaModes");
  135. const TCHAR gszRegKeyTelephony[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Telephony");
  136. const TCHAR gszRegKeyProviders[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Telephony\\Providers");
  137. const TCHAR gszRegKeyServer[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Telephony\\Server");
  138. const TCHAR gszRegKeyNTServer[] = TEXT("System\\CurrentControlSet\\Control\\ProductOptions");
  139. const TCHAR
  140. *gaszMediaModes[] =
  141. {
  142. TEXT(""),
  143. TEXT("unknown"),
  144. TEXT("interactivevoice"),
  145. TEXT("automatedvoice"),
  146. TEXT("datamodem"),
  147. TEXT("g3fax"),
  148. TEXT("tdd"),
  149. TEXT("g4fax"),
  150. TEXT("digitaldata"),
  151. TEXT("teletex"),
  152. TEXT("videotex"),
  153. TEXT("telex"),
  154. TEXT("mixed"),
  155. TEXT("adsi"),
  156. TEXT("voiceview"),
  157. TEXT("video"),
  158. NULL
  159. };
  160. // used for GetProcAddress calls, remain as ANSI
  161. const char *gaszTSPIFuncNames[] =
  162. {
  163. "TSPI_lineAccept",
  164. "TSPI_lineAddToConference",
  165. "TSPI_lineAgentSpecific",
  166. "TSPI_lineAnswer",
  167. "TSPI_lineBlindTransfer",
  168. "TSPI_lineClose",
  169. "TSPI_lineCloseCall",
  170. "TSPI_lineCompleteCall",
  171. "TSPI_lineCompleteTransfer",
  172. "TSPI_lineConditionalMediaDetection",
  173. "TSPI_lineDevSpecific",
  174. "TSPI_lineDevSpecificFeature",
  175. "TSPI_lineDial",
  176. "TSPI_lineDrop",
  177. "TSPI_lineForward",
  178. "TSPI_lineGatherDigits",
  179. "TSPI_lineGenerateDigits",
  180. "TSPI_lineGenerateTone",
  181. "TSPI_lineGetAddressCaps",
  182. "TSPI_lineGetAddressID",
  183. "TSPI_lineGetAddressStatus",
  184. "TSPI_lineGetAgentActivityList",
  185. "TSPI_lineGetAgentCaps",
  186. "TSPI_lineGetAgentGroupList",
  187. "TSPI_lineGetAgentStatus",
  188. "TSPI_lineGetCallAddressID",
  189. "TSPI_lineGetCallInfo",
  190. "TSPI_lineGetCallStatus",
  191. "TSPI_lineGetDevCaps",
  192. "TSPI_lineGetDevConfig",
  193. "TSPI_lineGetExtensionID",
  194. "TSPI_lineGetIcon",
  195. "TSPI_lineGetID",
  196. "TSPI_lineGetLineDevStatus",
  197. "TSPI_lineGetNumAddressIDs",
  198. "TSPI_lineHold",
  199. "TSPI_lineMakeCall",
  200. "TSPI_lineMonitorDigits",
  201. "TSPI_lineMonitorMedia",
  202. "TSPI_lineMonitorTones",
  203. "TSPI_lineNegotiateExtVersion",
  204. "TSPI_lineNegotiateTSPIVersion",
  205. "TSPI_lineOpen",
  206. "TSPI_linePark",
  207. "TSPI_linePickup",
  208. "TSPI_linePrepareAddToConference",
  209. "TSPI_lineRedirect",
  210. "TSPI_lineReleaseUserUserInfo",
  211. "TSPI_lineRemoveFromConference",
  212. "TSPI_lineSecureCall",
  213. "TSPI_lineSelectExtVersion",
  214. "TSPI_lineSendUserUserInfo",
  215. "TSPI_lineSetAgentActivity",
  216. "TSPI_lineSetAgentGroup",
  217. "TSPI_lineSetAgentState",
  218. "TSPI_lineSetAppSpecific",
  219. "TSPI_lineSetCallData",
  220. "TSPI_lineSetCallParams",
  221. "TSPI_lineSetCallQualityOfService",
  222. "TSPI_lineSetCallTreatment",
  223. "TSPI_lineSetCurrentLocation",
  224. "TSPI_lineSetDefaultMediaDetection",
  225. "TSPI_lineSetDevConfig",
  226. "TSPI_lineSetLineDevStatus",
  227. "TSPI_lineSetMediaControl",
  228. "TSPI_lineSetMediaMode",
  229. "TSPI_lineSetStatusMessages",
  230. "TSPI_lineSetTerminal",
  231. "TSPI_lineSetupConference",
  232. "TSPI_lineSetupTransfer",
  233. "TSPI_lineSwapHold",
  234. "TSPI_lineUncompleteCall",
  235. "TSPI_lineUnhold",
  236. "TSPI_lineUnpark",
  237. "TSPI_phoneClose",
  238. "TSPI_phoneDevSpecific",
  239. "TSPI_phoneGetButtonInfo",
  240. "TSPI_phoneGetData",
  241. "TSPI_phoneGetDevCaps",
  242. "TSPI_phoneGetDisplay",
  243. "TSPI_phoneGetExtensionID",
  244. "TSPI_phoneGetGain",
  245. "TSPI_phoneGetHookSwitch",
  246. "TSPI_phoneGetIcon",
  247. "TSPI_phoneGetID",
  248. "TSPI_phoneGetLamp",
  249. "TSPI_phoneGetRing",
  250. "TSPI_phoneGetStatus",
  251. "TSPI_phoneGetVolume",
  252. "TSPI_phoneNegotiateExtVersion",
  253. "TSPI_phoneNegotiateTSPIVersion",
  254. "TSPI_phoneOpen",
  255. "TSPI_phoneSelectExtVersion",
  256. "TSPI_phoneSetButtonInfo",
  257. "TSPI_phoneSetData",
  258. "TSPI_phoneSetDisplay",
  259. "TSPI_phoneSetGain",
  260. "TSPI_phoneSetHookSwitch",
  261. "TSPI_phoneSetLamp",
  262. "TSPI_phoneSetRing",
  263. "TSPI_phoneSetStatusMessages",
  264. "TSPI_phoneSetVolume",
  265. "TSPI_providerCreateLineDevice",
  266. "TSPI_providerCreatePhoneDevice",
  267. "TSPI_providerEnumDevices",
  268. "TSPI_providerFreeDialogInstance",
  269. "TSPI_providerGenericDialogData",
  270. "TSPI_providerInit",
  271. "TSPI_providerShutdown",
  272. "TSPI_providerUIIdentify",
  273. "TSPI_lineMSPIdentify",
  274. "TSPI_lineReceiveMSPData",
  275. "TSPI_providerCheckForNewUser",
  276. "TSPI_lineGetCallIDs",
  277. "TSPI_lineGetCallHubTracking",
  278. "TSPI_lineSetCallHubTracking",
  279. "TSPI_providerPrivateFactoryIdentify",
  280. "TSPI_lineDevSpecificEx",
  281. "TSPI_lineCreateAgent",
  282. "TSPI_lineCreateAgentSession",
  283. "TSPI_lineGetAgentInfo",
  284. "TSPI_lineGetAgentSessionInfo",
  285. "TSPI_lineGetAgentSessionList",
  286. "TSPI_lineGetQueueInfo",
  287. "TSPI_lineGetGroupList",
  288. "TSPI_lineGetQueueList",
  289. "TSPI_lineSetAgentMeasurementPeriod",
  290. "TSPI_lineSetAgentSessionState",
  291. "TSPI_lineSetQueueMeasurementPeriod",
  292. "TSPI_lineSetAgentStateEx",
  293. "TSPI_lineGetProxyStatus",
  294. "TSPI_lineCreateMSPInstance",
  295. "TSPI_lineCloseMSPInstance",
  296. NULL
  297. };
  298. // used for GetProcAddress calls, remain as ANSI
  299. const char *gaszTCFuncNames[] =
  300. {
  301. "TAPICLIENT_Load",
  302. "TAPICLIENT_Free",
  303. "TAPICLIENT_ClientInitialize",
  304. "TAPICLIENT_ClientShutdown",
  305. "TAPICLIENT_GetDeviceAccess",
  306. "TAPICLIENT_LineAddToConference",
  307. "TAPICLIENT_LineBlindTransfer",
  308. "TAPICLIENT_LineConfigDialog",
  309. "TAPICLIENT_LineDial",
  310. "TAPICLIENT_LineForward",
  311. "TAPICLIENT_LineGenerateDigits",
  312. "TAPICLIENT_LineMakeCall",
  313. "TAPICLIENT_LineOpen",
  314. "TAPICLIENT_LineRedirect",
  315. "TAPICLIENT_LineSetCallData",
  316. "TAPICLIENT_LineSetCallParams",
  317. "TAPICLIENT_LineSetCallPrivilege",
  318. "TAPICLIENT_LineSetCallTreatment",
  319. "TAPICLIENT_LineSetCurrentLocation",
  320. "TAPICLIENT_LineSetDevConfig",
  321. "TAPICLIENT_LineSetLineDevStatus",
  322. "TAPICLIENT_LineSetMediaControl",
  323. "TAPICLIENT_LineSetMediaMode",
  324. "TAPICLIENT_LineSetTerminal",
  325. "TAPICLIENT_LineSetTollList",
  326. "TAPICLIENT_PhoneConfigDialog",
  327. "TAPICLIENT_PhoneOpen",
  328. NULL
  329. };
  330. PTPROVIDER pRemoteSP;
  331. extern WCHAR gszTapiAdministrators[];
  332. extern WCHAR gszFileName[];
  333. extern WCHAR gszLines[];
  334. extern WCHAR gszPhones[];
  335. extern WCHAR gszEmptyString[];
  336. extern LPLINECOUNTRYLIST gpCountryList;
  337. extern LPDEVICEINFOLIST gpLineInfoList;
  338. extern LPDEVICEINFOLIST gpPhoneInfoList;
  339. extern LPDWORD gpLineDevFlags;
  340. extern DWORD gdwNumFlags;
  341. extern FILETIME gftLineLastWrite;
  342. extern FILETIME gftPhoneLastWrite;
  343. extern CRITICAL_SECTION gMgmtCritSec;
  344. extern BOOL gbLockMMCWrite;
  345. #define POINTERTOTABLEINDEX(p) \
  346. ((((ULONG_PTR) p) >> 4) & gdwPointerToLockTableIndexBits)
  347. #define LOCKTCLIENT(p) \
  348. EnterCriticalSection(&gLockTable[POINTERTOTABLEINDEX(p)])
  349. #define UNLOCKTCLIENT(p) \
  350. LeaveCriticalSection(&gLockTable[POINTERTOTABLEINDEX(p)])
  351. #if DBG
  352. DWORD gdwDebugLevel;
  353. DWORD gdwQueueDebugLevel = 0;
  354. #endif
  355. typedef struct
  356. {
  357. DWORD dwTickCount;
  358. PTCLIENT ptClient;
  359. } WATCHDOGSTRUCT, *PWATCHDOGSTRUCT;
  360. struct
  361. {
  362. PHANDLE phThreads;
  363. DWORD dwNumThreads;
  364. PWATCHDOGSTRUCT pWatchDogStruct;
  365. HANDLE hEvent;
  366. BOOL bExit;
  367. } gEventNotificationThreadParams;
  368. struct
  369. {
  370. LONG lCookie;
  371. LONG lNumRundowns;
  372. BOOL bIgnoreRundowns;
  373. } gRundownLock;
  374. BOOL VerifyDomainName (HKEY hKey);
  375. void
  376. EventNotificationThread(
  377. LPVOID pParams
  378. );
  379. #if MEMPHIS
  380. VOID
  381. ServiceMain(
  382. DWORD dwArgc,
  383. LPTSTR *lpszArgv
  384. );
  385. #else
  386. VOID
  387. WINAPI
  388. ServiceMain (
  389. DWORD dwArgc,
  390. PWSTR* lpszArgv
  391. );
  392. #endif
  393. void
  394. PASCAL
  395. LineEventProc(
  396. HTAPILINE htLine,
  397. HTAPICALL htCall,
  398. DWORD dwMsg,
  399. ULONG_PTR Param1,
  400. ULONG_PTR Param2,
  401. ULONG_PTR Param3
  402. );
  403. void
  404. CALLBACK
  405. LineEventProcSP(
  406. HTAPILINE htLine,
  407. HTAPICALL htCall,
  408. DWORD dwMsg,
  409. ULONG_PTR Param1,
  410. ULONG_PTR Param2,
  411. ULONG_PTR Param3
  412. );
  413. void
  414. PASCAL
  415. PhoneEventProc(
  416. HTAPIPHONE htPhone,
  417. DWORD dwMsg,
  418. ULONG_PTR Param1,
  419. ULONG_PTR Param2,
  420. ULONG_PTR Param3
  421. );
  422. void
  423. CALLBACK
  424. PhoneEventProcSP(
  425. HTAPIPHONE htPhone,
  426. DWORD dwMsg,
  427. ULONG_PTR Param1,
  428. ULONG_PTR Param2,
  429. ULONG_PTR Param3
  430. );
  431. PTLINELOOKUPENTRY
  432. GetLineLookupEntry(
  433. DWORD dwDeviceID
  434. );
  435. PTPHONELOOKUPENTRY
  436. GetPhoneLookupEntry(
  437. DWORD dwDeviceID
  438. );
  439. char *
  440. PASCAL
  441. MapResultCodeToText(
  442. LONG lResult,
  443. char *pszResult
  444. );
  445. DWORD
  446. InitSecurityDescriptor(
  447. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  448. PSID * ppSid,
  449. PACL * ppDacl
  450. );
  451. void
  452. PASCAL
  453. GetMediaModesPriorityLists(
  454. HKEY hKeyHandoffPriorities,
  455. PRILISTSTRUCT ** ppList
  456. );
  457. void
  458. PASCAL
  459. GetPriorityList(
  460. HKEY hKeyHandoffPriorities,
  461. const TCHAR *pszListName,
  462. WCHAR **ppszPriorityList
  463. );
  464. void
  465. PASCAL
  466. SetMediaModesPriorityList(
  467. HKEY hKeyPri,
  468. PRILISTSTRUCT * pPriListStruct
  469. );
  470. void
  471. PASCAL
  472. SetPriorityList(
  473. HKEY hKeyHandoffPriorities,
  474. const TCHAR *pszListName,
  475. WCHAR *pszPriorityList
  476. );
  477. void
  478. SPEventHandlerThread(
  479. PSPEVENTHANDLERTHREADINFO pInfo
  480. );
  481. PTCLIENT
  482. PASCAL
  483. WaitForExclusiveClientAccess(
  484. PTCLIENT ptClient
  485. );
  486. BOOL
  487. IsNTServer(
  488. void
  489. );
  490. void
  491. CleanUpManagementMemory(
  492. );
  493. #if TELE_SERVER
  494. void
  495. ReadAndInitMapper();
  496. void
  497. ReadAndInitManagementDlls();
  498. void
  499. ManagementProc(
  500. LONG l
  501. );
  502. void
  503. GetManageDllListPointer(
  504. PTMANAGEDLLLISTHEADER * ppDllList
  505. );
  506. void
  507. FreeManageDllListPointer(
  508. PTMANAGEDLLLISTHEADER pDllList
  509. );
  510. BOOL
  511. GetTCClient(
  512. PTMANAGEDLLINFO pDll,
  513. PTCLIENT ptClient,
  514. DWORD dwAPI,
  515. HMANAGEMENTCLIENT *phClient
  516. );
  517. #endif
  518. LRESULT
  519. UpdateLastWriteTime (
  520. BOOL bLine
  521. );
  522. LRESULT
  523. BuildDeviceInfoList(
  524. BOOL bLine
  525. );
  526. BOOL
  527. CleanUpClient(
  528. PTCLIENT ptClient,
  529. BOOL bRundown
  530. );
  531. void
  532. PASCAL
  533. SendReinitMsgToAllXxxApps(
  534. void
  535. );
  536. LONG
  537. AppendNewDeviceInfo (
  538. BOOL bLine,
  539. DWORD dwDeviceID
  540. );
  541. DWORD
  542. PASCAL
  543. MyInitializeCriticalSection(
  544. LPCRITICAL_SECTION pCriticalSection,
  545. DWORD dwSpinCount
  546. )
  547. {
  548. DWORD dwRet = 0;
  549. __try
  550. {
  551. if (pfnInitializeCriticalSectionAndSpinCount)
  552. {
  553. (*pfnInitializeCriticalSectionAndSpinCount)(
  554. pCriticalSection,
  555. dwSpinCount
  556. );
  557. }
  558. else
  559. {
  560. InitializeCriticalSection (pCriticalSection);
  561. }
  562. }
  563. __except (EXCEPTION_EXECUTE_HANDLER)
  564. {
  565. dwRet = GetExceptionCode();
  566. }
  567. return dwRet;
  568. }
  569. #if MEMPHIS
  570. VOID
  571. __cdecl
  572. main(
  573. void
  574. )
  575. {
  576. //
  577. // On retail Memphis, don't show TAPISRV one the ALT-CTL-DEL task list
  578. //
  579. #if DBG
  580. #else
  581. RegisterServiceProcess( 0, RSP_SIMPLE_SERVICE );
  582. #endif
  583. LOG((TL_TRACE, "main: Calling ServiceMain (Win95)..."));
  584. ServiceMain (0, NULL);
  585. Sleep(0);
  586. Sleep(0);
  587. Sleep(0);
  588. // ExitThread(0);
  589. ExitProcess(0);
  590. }
  591. #else
  592. BOOL
  593. WINAPI
  594. DllMain (
  595. HINSTANCE hinst,
  596. DWORD dwReason,
  597. LPVOID pvReserved)
  598. {
  599. switch (dwReason) {
  600. case DLL_PROCESS_ATTACH:
  601. {
  602. ghInstance = hinst;
  603. DisableThreadLibraryCalls (hinst);
  604. break;
  605. }
  606. case DLL_PROCESS_DETACH:
  607. {
  608. break;
  609. }
  610. }
  611. return TRUE;
  612. }
  613. #endif
  614. #if 0
  615. void
  616. PASCAL
  617. SendAMsgToAllClients(
  618. DWORD dwWantVersion,
  619. ULONG_PTR Msg,
  620. ULONG_PTR Param1,
  621. ULONG_PTR Param2,
  622. ULONG_PTR Param3
  623. )
  624. {
  625. ASYNCEVENTMSG msg;
  626. PTCLIENT ptClient = TapiGlobals.ptClients;
  627. ZeroMemory (&msg, sizeof (ASYNCEVENTMSG));
  628. msg.TotalSize = sizeof (ASYNCEVENTMSG);
  629. msg.Msg = Msg;
  630. msg.Param1 = Param1;
  631. msg.Param2 = Param2;
  632. msg.Param3 = Param3;
  633. while (ptClient)
  634. {
  635. WriteEventBuffer(ptClient, &msg);
  636. ptClient = ptClient->pNext;
  637. }
  638. }
  639. #endif
  640. BOOL
  641. ReportStatusToSCMgr(
  642. DWORD dwCurrentState,
  643. DWORD dwWin32ExitCode,
  644. DWORD dwCheckPoint,
  645. DWORD dwWaitHint
  646. )
  647. {
  648. SERVICE_STATUS ssStatus;
  649. if (!TapiGlobals.sshStatusHandle)
  650. {
  651. LOG((TL_ERROR, "sshStatusHandle is NULL in ReportStatusToSCMgr"));
  652. return FALSE;
  653. }
  654. ssStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
  655. ssStatus.dwCurrentState = dwCurrentState;
  656. ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
  657. SERVICE_ACCEPT_PAUSE_CONTINUE;
  658. ssStatus.dwWin32ExitCode = dwWin32ExitCode;
  659. ssStatus.dwServiceSpecificExitCode = 0;
  660. ssStatus.dwCheckPoint = dwCheckPoint;
  661. ssStatus.dwWaitHint = dwWaitHint;
  662. SetServiceStatus (TapiGlobals.sshStatusHandle, &ssStatus);
  663. return TRUE;
  664. }
  665. VOID
  666. ServiceControl(
  667. DWORD dwCtrlCode
  668. )
  669. {
  670. LOG((TL_INFO, "Service control code=%ld", dwCtrlCode ));
  671. if ( SERVICE_CONTROL_STOP == dwCtrlCode ||
  672. SERVICE_CONTROL_SHUTDOWN == dwCtrlCode )
  673. {
  674. //
  675. // This service was stopped - alert any active apps, allowing
  676. // a little extra time for msg processing
  677. //
  678. LOG((TL_TRACE, "Somebody did a 'NET STOP TAPISRV'... exiting..."));
  679. SendReinitMsgToAllXxxApps();
  680. ReportStatusToSCMgr(
  681. gdwServiceState = SERVICE_STOP_PENDING,
  682. NO_ERROR,
  683. (gdwCheckPoint = 0),
  684. 4000
  685. );
  686. Sleep (4000);
  687. RpcServerUnregisterIf (tapsrv_ServerIfHandle, NULL, TRUE);
  688. if (ghEventService)
  689. {
  690. SetEvent (ghEventService);
  691. }
  692. return;
  693. }
  694. if ( SERVICE_CONTROL_PAUSE == dwCtrlCode )
  695. {
  696. LOG((TL_TRACE,
  697. "Somebody did a 'NET PAUSE TAPISRV'... not allowing new clients..."
  698. ));
  699. TapiGlobals.dwFlags |= TAPIGLOBALS_PAUSED;
  700. ReportStatusToSCMgr(
  701. gdwServiceState = SERVICE_PAUSED,
  702. NO_ERROR,
  703. (gdwCheckPoint = 0),
  704. 0
  705. );
  706. return;
  707. }
  708. if ( SERVICE_CONTROL_CONTINUE == dwCtrlCode )
  709. {
  710. LOG((TL_TRACE,
  711. "Somebody did a 'NET CONTINUE TAPISRV'... allowing new clients..."
  712. ));
  713. TapiGlobals.dwFlags &= ~(TAPIGLOBALS_PAUSED);
  714. ReportStatusToSCMgr(
  715. gdwServiceState = SERVICE_RUNNING,
  716. NO_ERROR,
  717. (gdwCheckPoint = 0),
  718. 0
  719. );
  720. return;
  721. }
  722. switch (gdwServiceState)
  723. {
  724. case SERVICE_START_PENDING:
  725. case SERVICE_STOP_PENDING:
  726. ReportStatusToSCMgr(
  727. gdwServiceState,
  728. NO_ERROR,
  729. ++gdwCheckPoint,
  730. gdwWaitHint
  731. );
  732. break;
  733. default:
  734. ReportStatusToSCMgr(
  735. gdwServiceState,
  736. NO_ERROR,
  737. 0,
  738. 0
  739. );
  740. break;
  741. }
  742. }
  743. VOID
  744. CALLBACK
  745. FreeContextCallback(
  746. LPVOID Context,
  747. LPVOID Context2
  748. )
  749. {
  750. if (Context2)
  751. {
  752. //
  753. // Special case: Context is a "fast" ptCallClient, that is
  754. // a TCALLCLIENT embedded within a TCALL structure, so don't
  755. // free it
  756. //
  757. }
  758. else
  759. {
  760. //
  761. // The general case, Context is the pointer to free
  762. //
  763. ServerFree (Context);
  764. }
  765. }
  766. #if MEMPHIS
  767. #define DEFAULTRPCMINCALLS 1
  768. #define DEFAULTRPCMAXCALLS 20
  769. #define RPCMAXMAX 2000
  770. #define RPCMINMAX 100
  771. #else
  772. #define DEFAULTRPCMINCALLS 1
  773. #define DEFAULTRPCMAXCALLS 500
  774. #define RPCMAXMAX 20000
  775. #define RPCMINMAX 1000
  776. #endif
  777. typedef struct _SERVICE_SHUTDOWN_PARAMS {
  778. HANDLE hThreadMgmt;
  779. PSID psid;
  780. PACL pdacl;
  781. } SERVICE_SHUTDOWN_PARAMS;
  782. VOID CALLBACK ServiceShutdown (
  783. PVOID lpParam,
  784. BOOLEAN fTimeOut
  785. );
  786. #if MEMPHIS
  787. VOID
  788. ServiceMain(
  789. DWORD dwArgc,
  790. LPTSTR *lpszArgv
  791. )
  792. #else
  793. VOID
  794. WINAPI
  795. ServiceMain (
  796. DWORD dwArgc,
  797. PWSTR* lpszArgv
  798. )
  799. #endif
  800. {
  801. DWORD dwMinCalls, dwMaxCalls, i;
  802. #if MEMPHIS
  803. HANDLE hEvent = NULL;
  804. #endif
  805. HANDLE hThreadMgmt;
  806. BOOL bFatalError = FALSE;
  807. assert(gdwServiceInitFlags == 0);
  808. gdwServiceInitFlags = 0;
  809. TRACELOGREGISTER(_T("tapisrv"));
  810. gdwServiceInitFlags |= SERVICE_INIT_TRACELOG ;
  811. //
  812. // Initialize globals
  813. //
  814. ZeroMemory (&TapiGlobals, sizeof (TAPIGLOBALS));
  815. TapiGlobals.ulPermMasks = EM_ALL;
  816. TapiGlobals.hProcess = GetCurrentProcess();
  817. TapiGlobals.hLineIcon = LoadIcon (ghInstance, MAKEINTRESOURCE(IDI_LINE_ICON));
  818. TapiGlobals.hPhoneIcon = LoadIcon (ghInstance, MAKEINTRESOURCE(IDI_PHONE_ICON));
  819. gbPriorityListsInitialized = FALSE;
  820. gbQueueSPEvents = FALSE;
  821. gfWeHadAtLeastOneClient = FALSE;
  822. CnClientMsgPendingListHead.Flink =
  823. CnClientMsgPendingListHead.Blink = &CnClientMsgPendingListHead;
  824. DgClientMsgPendingListHead.Flink =
  825. DgClientMsgPendingListHead.Blink = &DgClientMsgPendingListHead;
  826. gdwNumSPEventHandlerThreads = 0;
  827. glNumActiveSPEventHandlerThreads = 0;
  828. pRemoteSP = (PTPROVIDER) NULL;
  829. gbSPEventHandlerThreadExit = FALSE;
  830. gRundownLock.lCookie = 0;
  831. gRundownLock.lNumRundowns = 0;
  832. gLockTable = NULL;
  833. gdwNumLockTableEntries = 0;
  834. gpCountryList = NULL;
  835. gpLineInfoList = NULL;
  836. gpPhoneInfoList = NULL;
  837. gpLineDevFlags = NULL;
  838. gdwNumFlags = 0;
  839. gbLockMMCWrite = FALSE;
  840. gdwServiceState = SERVICE_START_PENDING,
  841. gdwWaitHint = MIN_WAIT_HINT,
  842. gdwCheckPoint = 0,
  843. gdwDllIDs = 0,
  844. gdwRpcRetryCount = 5,
  845. gdwTotalAsyncThreads = 0,
  846. gdwThreadsPerProcessor = 4;
  847. gbNTServer = IsNTServer();
  848. ghEventService = CreateEvent(NULL, TRUE, FALSE, NULL);
  849. gbAutostartDone = FALSE;
  850. #if defined(_ALPHA_)
  851. guiAlignmentFaultEnabled = SetErrorMode(0);
  852. SetErrorMode(guiAlignmentFaultEnabled);
  853. guiAlignmentFaultEnabled = !(guiAlignmentFaultEnabled
  854. & SEM_NOALIGNMENTFAULTEXCEPT);
  855. #else
  856. guiAlignmentFaultEnabled = 0;
  857. #endif
  858. #if MEMPHIS
  859. {
  860. #else
  861. //
  862. // Register the service control handler & report status to sc mgr
  863. //
  864. TapiGlobals.sshStatusHandle = RegisterServiceCtrlHandler(
  865. TEXT("tapisrv"),
  866. ServiceControl
  867. );
  868. if (NULL == TapiGlobals.sshStatusHandle)
  869. {
  870. LOG((TL_TRACE, "ServiceMain: RegisterServiceCtrlHandler failed, error x%x",
  871. GetLastError() ));
  872. bFatalError = TRUE;
  873. }
  874. else
  875. {
  876. gdwServiceInitFlags |= SERVICE_INIT_SCM_REGISTERED;
  877. }
  878. if (!bFatalError)
  879. {
  880. ReportStatusToSCMgr(
  881. (gdwServiceState = SERVICE_START_PENDING),
  882. // service state
  883. NO_ERROR, // exit code
  884. (gdwCheckPoint = 0), // checkpoint
  885. gdwWaitHint // wait hint
  886. );
  887. #endif
  888. if (!(ghTapisrvHeap = HeapCreate (0, 0x10000, 0)))
  889. {
  890. ghTapisrvHeap = GetProcessHeap();
  891. }
  892. ghHandleTable = CreateHandleTable(
  893. ghTapisrvHeap,
  894. FreeContextCallback,
  895. 0x10000,
  896. 0x7fffffff
  897. );
  898. #if MEMPHIS
  899. #else
  900. InitPerf();
  901. #endif
  902. (FARPROC) pfnInitializeCriticalSectionAndSpinCount = GetProcAddress(
  903. GetModuleHandle (TEXT("kernel32.dll")),
  904. "InitializeCriticalSectionAndSpinCount"
  905. );
  906. ghSCMAutostartEvent = OpenEvent(
  907. SYNCHRONIZE,
  908. FALSE,
  909. SC_AUTOSTART_EVENT_NAME
  910. );
  911. if (NULL == ghSCMAutostartEvent)
  912. {
  913. LOG((TL_ERROR,
  914. "OpenEvent ('%s') failed, err=%d",
  915. SC_AUTOSTART_EVENT_NAME,
  916. GetLastError()
  917. ));
  918. }
  919. }
  920. //
  921. // Grab relevent values from the registry
  922. //
  923. if (!bFatalError)
  924. {
  925. HKEY hKey;
  926. const TCHAR szRPCMinCalls[] = TEXT("Min");
  927. const TCHAR szRPCMaxCalls[] = TEXT("Max");
  928. const TCHAR szTapisrvWaitHint[] = TEXT("TapisrvWaitHint");
  929. const TCHAR szRPCTimeout[] = TEXT("RPCTimeout");
  930. #if DBG
  931. gdwDebugLevel = 0;
  932. #endif
  933. if (RegOpenKeyEx(
  934. HKEY_LOCAL_MACHINE,
  935. gszRegKeyTelephony,
  936. 0,
  937. KEY_QUERY_VALUE | KEY_SET_VALUE,
  938. &hKey
  939. ) == ERROR_SUCCESS)
  940. {
  941. DWORD dwDataSize = sizeof (DWORD), dwDataType;
  942. #if DBG
  943. RegQueryValueEx(
  944. hKey,
  945. gszTapisrvDebugLevel,
  946. 0,
  947. &dwDataType,
  948. (LPBYTE) &gdwDebugLevel,
  949. &dwDataSize
  950. );
  951. dwDataSize = sizeof (DWORD);
  952. RegQueryValueEx(
  953. hKey,
  954. gszBreakOnLeak,
  955. 0,
  956. &dwDataType,
  957. (LPBYTE)&gbBreakOnLeak,
  958. &dwDataSize
  959. );
  960. dwDataSize = sizeof (DWORD);
  961. RegQueryValueEx(
  962. hKey,
  963. TEXT("BreakOnSeriousProblems"),
  964. 0,
  965. &dwDataType,
  966. (LPBYTE) &gfBreakOnSeriousProblems,
  967. &dwDataSize
  968. );
  969. dwDataSize = sizeof(DWORD);
  970. #endif
  971. RegQueryValueEx(
  972. hKey,
  973. szTapisrvWaitHint,
  974. 0,
  975. &dwDataType,
  976. (LPBYTE) &gdwWaitHint,
  977. &dwDataSize
  978. );
  979. gdwWaitHint = (gdwWaitHint < MIN_WAIT_HINT ?
  980. MIN_WAIT_HINT : gdwWaitHint);
  981. dwDataSize = sizeof (DWORD);
  982. if (RegQueryValueEx(
  983. hKey,
  984. szRPCMinCalls,
  985. NULL,
  986. &dwDataType,
  987. (LPBYTE) &dwMinCalls,
  988. &dwDataSize
  989. ) != ERROR_SUCCESS)
  990. {
  991. dwMinCalls = DEFAULTRPCMINCALLS;
  992. }
  993. dwDataSize = sizeof (DWORD);
  994. if (RegQueryValueEx(
  995. hKey,
  996. TEXT("TapiScpTTL"),
  997. NULL,
  998. &dwDataType,
  999. (LPBYTE) &gdwTapiSCPTTL,
  1000. &dwDataSize
  1001. ) != ERROR_SUCCESS)
  1002. {
  1003. gdwTapiSCPTTL = 60 * 24; // default to 24 hours
  1004. }
  1005. if (gdwTapiSCPTTL < 60)
  1006. {
  1007. gdwTapiSCPTTL = 60; // 60 minute TTL as the minimum
  1008. }
  1009. dwDataSize = sizeof (DWORD);
  1010. if (RegQueryValueEx(
  1011. hKey,
  1012. szRPCMaxCalls,
  1013. NULL,
  1014. &dwDataType,
  1015. (LPBYTE) &dwMaxCalls,
  1016. &dwDataSize
  1017. ) != ERROR_SUCCESS)
  1018. {
  1019. dwMaxCalls = DEFAULTRPCMAXCALLS;
  1020. }
  1021. LOG((TL_INFO,
  1022. "RPC min calls %lu RPC max calls %lu",
  1023. dwMinCalls,
  1024. dwMaxCalls
  1025. ));
  1026. // check values
  1027. if (dwMaxCalls == 0)
  1028. {
  1029. LOG((TL_INFO,
  1030. "RPC max at 0. Changed to %lu",
  1031. DEFAULTRPCMAXCALLS
  1032. ));
  1033. dwMaxCalls = DEFAULTRPCMAXCALLS;
  1034. }
  1035. if (dwMinCalls == 0)
  1036. {
  1037. LOG((TL_INFO,
  1038. "RPC min at 0. Changed to %lu",
  1039. DEFAULTRPCMINCALLS
  1040. ));
  1041. dwMinCalls = DEFAULTRPCMINCALLS;
  1042. }
  1043. if (dwMaxCalls > RPCMAXMAX)
  1044. {
  1045. LOG((TL_INFO,
  1046. "RPC max too high at %lu. Changed to %lu",
  1047. dwMaxCalls,
  1048. RPCMAXMAX
  1049. ));
  1050. dwMaxCalls = RPCMAXMAX;
  1051. }
  1052. if (dwMinCalls > dwMaxCalls)
  1053. {
  1054. LOG((TL_INFO,
  1055. "RPC min greater than RPC max. Changed to %lu",
  1056. dwMaxCalls
  1057. ));
  1058. dwMinCalls = dwMaxCalls;
  1059. }
  1060. if (dwMinCalls > RPCMINMAX)
  1061. {
  1062. LOG((TL_INFO,
  1063. "RPC min greater than allowed at %lu. Changed to %lu",
  1064. dwMinCalls, RPCMINMAX
  1065. ));
  1066. dwMinCalls = RPCMINMAX;
  1067. }
  1068. dwDataSize = sizeof (DWORD);
  1069. if (RegQueryValueEx(
  1070. hKey,
  1071. szRPCTimeout,
  1072. NULL,
  1073. &dwDataType,
  1074. (LPBYTE) &gdwRpcTimeout,
  1075. &dwDataSize
  1076. ) != ERROR_SUCCESS)
  1077. {
  1078. gdwRpcTimeout = 30000;
  1079. }
  1080. VerifyDomainName (hKey);
  1081. RegCloseKey (hKey);
  1082. }
  1083. }
  1084. LOG((TL_TRACE, "ServiceMain: enter"));
  1085. //
  1086. // More server-only reg stuff
  1087. //
  1088. #if TELE_SERVER
  1089. if (!bFatalError)
  1090. {
  1091. HKEY hKey;
  1092. DWORD dwDataSize;
  1093. DWORD dwDataType;
  1094. DWORD dwTemp;
  1095. TCHAR szProductType[64];
  1096. //
  1097. // Get the "Server" reg settings
  1098. //
  1099. // It would have made more sense if this reg value were named
  1100. // "EnableSharing", but we have to support what's out there
  1101. // already...
  1102. //
  1103. if (RegOpenKeyEx(
  1104. HKEY_LOCAL_MACHINE,
  1105. gszRegKeyServer,
  1106. 0,
  1107. KEY_QUERY_VALUE,
  1108. &hKey
  1109. ) == ERROR_SUCCESS)
  1110. {
  1111. dwDataSize = sizeof (dwTemp);
  1112. dwTemp = 1; // default is sharing == disabled
  1113. if (RegQueryValueEx(
  1114. hKey,
  1115. TEXT("DisableSharing"),
  1116. 0,
  1117. &dwDataType,
  1118. (LPBYTE) &dwTemp,
  1119. &dwDataSize
  1120. ) == ERROR_SUCCESS)
  1121. {
  1122. if (dwTemp == 0)
  1123. {
  1124. TapiGlobals.dwFlags |= TAPIGLOBALS_SERVER;
  1125. }
  1126. }
  1127. gdwTotalAsyncThreads = 0;
  1128. dwDataSize = sizeof (DWORD);
  1129. RegQueryValueEx(
  1130. hKey,
  1131. TEXT("TotalAsyncThreads"),
  1132. 0,
  1133. &dwDataType,
  1134. (LPBYTE) &gdwTotalAsyncThreads,
  1135. &dwDataSize
  1136. );
  1137. if (gdwTotalAsyncThreads)
  1138. {
  1139. LOG((TL_INFO,
  1140. "Setting total async threads to %d", gdwTotalAsyncThreads
  1141. ));
  1142. }
  1143. gdwThreadsPerProcessor = 4;
  1144. dwDataSize = sizeof (DWORD);
  1145. RegQueryValueEx(
  1146. hKey,
  1147. TEXT("ThreadsPerProcessor"),
  1148. 0,
  1149. &dwDataType,
  1150. (LPBYTE) &gdwThreadsPerProcessor,
  1151. &dwDataSize
  1152. );
  1153. LOG((TL_INFO, "Threads per processor is %d", gdwThreadsPerProcessor));
  1154. RegCloseKey( hKey );
  1155. }
  1156. //
  1157. // Now check to see if this is really running on NT Server.
  1158. // If not, then, turn off the SERVER bit in dwFlags.
  1159. //
  1160. if (!gbNTServer)
  1161. {
  1162. TapiGlobals.dwFlags &= ~(TAPIGLOBALS_SERVER);
  1163. }
  1164. }
  1165. #endif
  1166. //
  1167. // Init the lock table
  1168. //
  1169. if (!bFatalError)
  1170. {
  1171. HKEY hKey;
  1172. DWORD i,
  1173. dwLockTableNumEntries,
  1174. dwDataSize = sizeof(DWORD),
  1175. dwDataType,
  1176. dwBitMask;
  1177. BOOL bException = FALSE;
  1178. #define MIN_HANDLE_BUCKETS 8
  1179. #define MAX_HANDLE_BUCKETS 128
  1180. dwLockTableNumEntries = (TapiGlobals.dwFlags & TAPIGLOBALS_SERVER ?
  1181. 32 : MIN_HANDLE_BUCKETS);
  1182. //
  1183. // Retrieve registry override settings, if any
  1184. //
  1185. if (RegOpenKeyEx(
  1186. HKEY_LOCAL_MACHINE,
  1187. gszRegKeyTelephony,
  1188. 0,
  1189. KEY_QUERY_VALUE,
  1190. &hKey
  1191. ) == ERROR_SUCCESS)
  1192. {
  1193. RegQueryValueExW(
  1194. hKey,
  1195. L"TapisrvNumHandleBuckets",
  1196. 0,
  1197. &dwDataType,
  1198. (LPBYTE) &dwLockTableNumEntries,
  1199. &dwDataSize
  1200. );
  1201. //RegQueryValueExW(
  1202. // hKey,
  1203. // L"TapisrvSpinCount",
  1204. // 0,
  1205. // &dwDataType,
  1206. // (LPBYTE) &gdwSpinCount,
  1207. // &dwDataSize
  1208. // );
  1209. RegCloseKey (hKey);
  1210. }
  1211. //
  1212. // Determine a reasonable number of lock table entries, which
  1213. // is some number == 2**N within min/max possible values
  1214. //
  1215. if (dwLockTableNumEntries > MAX_HANDLE_BUCKETS)
  1216. {
  1217. dwLockTableNumEntries = MAX_HANDLE_BUCKETS;
  1218. }
  1219. else if (dwLockTableNumEntries < MIN_HANDLE_BUCKETS)
  1220. {
  1221. dwLockTableNumEntries = MIN_HANDLE_BUCKETS;
  1222. }
  1223. for(
  1224. dwBitMask = MAX_HANDLE_BUCKETS;
  1225. (dwBitMask & dwLockTableNumEntries) == 0;
  1226. dwBitMask >>= 1
  1227. );
  1228. dwLockTableNumEntries = dwBitMask;
  1229. //
  1230. // Calculate pointer-to-lock-table-index conversion value
  1231. // (significant bits)
  1232. //
  1233. gdwPointerToLockTableIndexBits = dwLockTableNumEntries - 1;
  1234. //gdwSpinCount = ( gdwSpinCount > MAX_SPIN_COUNT ?
  1235. // MAX_SPIN_COUNT : gdwSpinCount );
  1236. //
  1237. // Alloc & init the lock table
  1238. //
  1239. if (!(gLockTable = ServerAlloc(
  1240. dwLockTableNumEntries * sizeof (CRITICAL_SECTION)
  1241. )))
  1242. {
  1243. gLockTable = gLockTableCritSecs;
  1244. dwLockTableNumEntries = sizeof(gLockTableCritSecs)
  1245. / sizeof(CRITICAL_SECTION);
  1246. gdwPointerToLockTableIndexBits = dwLockTableNumEntries - 1;
  1247. }
  1248. for (i = 0; i < dwLockTableNumEntries; i++)
  1249. {
  1250. if ( NO_ERROR != MyInitializeCriticalSection (&gLockTable[i], 1000) )
  1251. {
  1252. bException = TRUE;
  1253. break;
  1254. }
  1255. }
  1256. if (bException)
  1257. {
  1258. bFatalError = TRUE;
  1259. LOG((TL_ERROR, "Exception in InitializeCriticalSection" ));
  1260. for (; i > 0; i--)
  1261. {
  1262. DeleteCriticalSection (&gLockTable[i-1]);
  1263. }
  1264. if (gLockTable != gLockTableCritSecs)
  1265. {
  1266. ServerFree (gLockTable);
  1267. }
  1268. gLockTable = NULL;
  1269. }
  1270. else
  1271. {
  1272. gdwNumLockTableEntries = dwLockTableNumEntries;
  1273. gdwServiceInitFlags |= SERVICE_INIT_LOCKTABLE;
  1274. }
  1275. }
  1276. bFatalError = bFatalError || MyInitializeCriticalSection (&gSafeMutexCritSec, 200);
  1277. if(!bFatalError)
  1278. gdwServiceInitFlags |= SERVICE_INIT_CRITSEC_SAFEMUTEX;
  1279. bFatalError = bFatalError || MyInitializeCriticalSection (&gRemoteCliEventBufCritSec, 200);
  1280. if(!bFatalError)
  1281. gdwServiceInitFlags |= SERVICE_INIT_CRITSEC_REMOTECLI;
  1282. bFatalError = bFatalError || MyInitializeCriticalSection (&gPriorityListCritSec, 200);
  1283. if(!bFatalError)
  1284. gdwServiceInitFlags |= SERVICE_INIT_CRITSEC_PRILIST;
  1285. bFatalError = bFatalError || MyInitializeCriticalSection (&gManagementDllsCritSec, 200);
  1286. if(!bFatalError)
  1287. gdwServiceInitFlags |= SERVICE_INIT_CRITSEC_MGMTDLLS;
  1288. bFatalError = bFatalError || MyInitializeCriticalSection (&gDllListCritSec, 200);
  1289. if(!bFatalError)
  1290. gdwServiceInitFlags |= SERVICE_INIT_CRITSEC_DLLLIST;
  1291. bFatalError = bFatalError || MyInitializeCriticalSection (&gClientHandleCritSec, 200);
  1292. if(!bFatalError)
  1293. gdwServiceInitFlags |= SERVICE_INIT_CRITSEC_CLIENTHND;
  1294. bFatalError = bFatalError || MyInitializeCriticalSection (&gCnClientMsgPendingCritSec, 200);
  1295. if(!bFatalError)
  1296. gdwServiceInitFlags |= SERVICE_INIT_CRITSEC_CNCLIENTMSG;
  1297. bFatalError = bFatalError || MyInitializeCriticalSection (&gDgClientMsgPendingCritSec, 200);
  1298. if(!bFatalError)
  1299. gdwServiceInitFlags |= SERVICE_INIT_CRITSEC_DGCLIENTMSG;
  1300. bFatalError = bFatalError || TapiMyInitializeCriticalSection (&TapiGlobals.CritSec, 200);
  1301. if(!bFatalError)
  1302. gdwServiceInitFlags |= SERVICE_INIT_CRITSEC_GLOB_CRITSEC;
  1303. bFatalError = bFatalError || MyInitializeCriticalSection (&TapiGlobals.RemoteSPCritSec, 200);
  1304. if(!bFatalError)
  1305. gdwServiceInitFlags |= SERVICE_INIT_CRITSEC_GLOB_REMOTESP;
  1306. bFatalError = bFatalError || MyInitializeCriticalSection (&gMgmtCritSec, 200);
  1307. if(!bFatalError)
  1308. gdwServiceInitFlags |= SERVICE_INIT_CRITSEC_MGMT;
  1309. if (!bFatalError)
  1310. {
  1311. DWORD dwTID, i;
  1312. HANDLE hThread;
  1313. SYSTEM_INFO SystemInfo;
  1314. BOOL bError = FALSE;
  1315. //
  1316. // Start a thread for as many processors there are
  1317. //
  1318. SystemInfo.dwNumberOfProcessors = 1;
  1319. GetSystemInfo( &SystemInfo );
  1320. aSPEventHandlerThreadInfo = ServerAlloc(
  1321. SystemInfo.dwNumberOfProcessors * sizeof (SPEVENTHANDLERTHREADINFO)
  1322. );
  1323. if (!aSPEventHandlerThreadInfo)
  1324. {
  1325. aSPEventHandlerThreadInfo = &gSPEventHandlerThreadInfo;
  1326. SystemInfo.dwNumberOfProcessors = 1;
  1327. }
  1328. for (i = 0; i < SystemInfo.dwNumberOfProcessors; i++)
  1329. {
  1330. if ( NO_ERROR != MyInitializeCriticalSection(
  1331. &aSPEventHandlerThreadInfo[i].CritSec,
  1332. 1000
  1333. )
  1334. )
  1335. {
  1336. bError = TRUE;
  1337. LOG((TL_ERROR, "Exception in InitializeCriticalSection"));
  1338. break;
  1339. }
  1340. InitializeListHead (&aSPEventHandlerThreadInfo[i].ListHead);
  1341. aSPEventHandlerThreadInfo[i].hEvent = CreateEvent(
  1342. (LPSECURITY_ATTRIBUTES) NULL,
  1343. TRUE, // manual reset
  1344. FALSE, // non-signaled
  1345. NULL // unnamed
  1346. );
  1347. if (aSPEventHandlerThreadInfo[i].hEvent == NULL)
  1348. {
  1349. bError = TRUE;
  1350. LOG((TL_ERROR,
  1351. "CreateEvent('SPEventHandlerThread') " \
  1352. "(Proc%d)failed, err=%d",
  1353. SystemInfo.dwNumberOfProcessors,
  1354. GetLastError()
  1355. ));
  1356. DeleteCriticalSection(&aSPEventHandlerThreadInfo[i].CritSec);
  1357. break;
  1358. }
  1359. if ((hThread = CreateThread(
  1360. (LPSECURITY_ATTRIBUTES) NULL,
  1361. 0,
  1362. (LPTHREAD_START_ROUTINE) SPEventHandlerThread,
  1363. (LPVOID) (aSPEventHandlerThreadInfo +
  1364. gdwNumSPEventHandlerThreads),
  1365. 0,
  1366. &dwTID
  1367. )))
  1368. {
  1369. gdwNumSPEventHandlerThreads++;
  1370. CloseHandle (hThread);
  1371. }
  1372. else
  1373. {
  1374. LOG((TL_ERROR,
  1375. "CreateThread('SPEventHandlerThread') " \
  1376. "(Proc%d)failed, err=%d",
  1377. SystemInfo.dwNumberOfProcessors,
  1378. GetLastError()
  1379. ));
  1380. }
  1381. }
  1382. if (bError && i == 0)
  1383. {
  1384. bFatalError = TRUE;
  1385. }
  1386. else
  1387. {
  1388. glNumActiveSPEventHandlerThreads = (LONG) gdwNumSPEventHandlerThreads;
  1389. gdwServiceInitFlags |= SERVICE_INIT_SPEVENT_HANDLER;
  1390. }
  1391. }
  1392. //
  1393. // Init some globals
  1394. //
  1395. #if TELE_SERVER
  1396. TapiGlobals.pIDArrays = NULL;
  1397. #endif
  1398. if (!bFatalError)
  1399. {
  1400. DWORD dwSize = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
  1401. TapiGlobals.pszComputerName = ServerAlloc (dwSize);
  1402. if (TapiGlobals.pszComputerName)
  1403. {
  1404. #ifdef PARTIAL_UNICODE
  1405. {
  1406. CHAR buf[MAX_COMPUTERNAME_LENGTH + 1];
  1407. GetComputerName (buf, &dwSize);
  1408. MultiByteToWideChar(
  1409. GetACP(),
  1410. MB_PRECOMPOSED,
  1411. buf,
  1412. dwSize,
  1413. TapiGlobals.pszComputerName,
  1414. dwSize
  1415. );
  1416. }
  1417. #else
  1418. GetComputerNameW(TapiGlobals.pszComputerName, &dwSize);
  1419. #endif
  1420. TapiGlobals.dwComputerNameSize = (1 +
  1421. lstrlenW(TapiGlobals.pszComputerName)) * sizeof(WCHAR);
  1422. }
  1423. }
  1424. #if TELE_SERVER
  1425. if (!bFatalError)
  1426. {
  1427. ReadAndInitMapper();
  1428. ReadAndInitManagementDlls();
  1429. gdwServiceInitFlags |= SERVICE_INIT_MANAGEMENT_DLL;
  1430. }
  1431. //
  1432. // Alloc the EventNotificationThread resources and start the thread
  1433. //
  1434. if ( !bFatalError && (TapiGlobals.dwFlags & TAPIGLOBALS_SERVER))
  1435. {
  1436. DWORD dwID;
  1437. // now start a thread to wait for changes to the managementdll key
  1438. hThreadMgmt = CreateThread(
  1439. NULL,
  1440. 0,
  1441. (LPTHREAD_START_ROUTINE)ManagementProc,
  1442. 0,
  1443. 0,
  1444. &dwID
  1445. );
  1446. if (!(gEventNotificationThreadParams.hEvent = CreateEvent(
  1447. (LPSECURITY_ATTRIBUTES) NULL, // no security attrs
  1448. TRUE, // manual reset
  1449. FALSE, // initially non-signaled
  1450. NULL // unnamed
  1451. )))
  1452. {
  1453. }
  1454. gEventNotificationThreadParams.bExit = FALSE;
  1455. {
  1456. DWORD dwTID, dwCount;
  1457. SYSTEM_INFO SystemInfo;
  1458. //
  1459. // Start a thread for as many processors there are
  1460. //
  1461. GetSystemInfo( &SystemInfo );
  1462. if (gdwTotalAsyncThreads)
  1463. {
  1464. dwCount = gdwTotalAsyncThreads;
  1465. }
  1466. else
  1467. {
  1468. dwCount = SystemInfo.dwNumberOfProcessors *
  1469. gdwThreadsPerProcessor;
  1470. }
  1471. if (dwCount <= 0)
  1472. {
  1473. dwCount = 1;
  1474. }
  1475. while (dwCount > 0)
  1476. {
  1477. gEventNotificationThreadParams.phThreads =
  1478. ServerAlloc( sizeof (HANDLE) * dwCount );
  1479. if (!gEventNotificationThreadParams.phThreads)
  1480. {
  1481. --dwCount;
  1482. continue;
  1483. }
  1484. gEventNotificationThreadParams.pWatchDogStruct =
  1485. ServerAlloc( sizeof (WATCHDOGSTRUCT) * dwCount );
  1486. if (!gEventNotificationThreadParams.pWatchDogStruct)
  1487. {
  1488. ServerFree (gEventNotificationThreadParams.phThreads);
  1489. --dwCount;
  1490. continue;
  1491. }
  1492. break;
  1493. }
  1494. gEventNotificationThreadParams.dwNumThreads = dwCount;
  1495. for (i = 0; i < gEventNotificationThreadParams.dwNumThreads;)
  1496. {
  1497. if ((gEventNotificationThreadParams.phThreads[i] =
  1498. CreateThread(
  1499. (LPSECURITY_ATTRIBUTES) NULL,
  1500. 0,
  1501. (LPTHREAD_START_ROUTINE) EventNotificationThread,
  1502. (LPVOID) ULongToPtr(i),
  1503. 0,
  1504. &dwTID
  1505. )))
  1506. {
  1507. i++;
  1508. }
  1509. else
  1510. {
  1511. LOG((TL_ERROR,
  1512. "CreateThread('EventNotificationThread') failed, " \
  1513. "err=%d",
  1514. GetLastError()
  1515. ));
  1516. gEventNotificationThreadParams.dwNumThreads--;
  1517. }
  1518. }
  1519. }
  1520. gdwServiceInitFlags |= SERVICE_INIT_EVENT_NOTIFICATION;
  1521. }
  1522. #endif
  1523. //
  1524. // Init Rpc server
  1525. //
  1526. gRundownLock.bIgnoreRundowns = FALSE;
  1527. {
  1528. RPC_STATUS status;
  1529. unsigned int fDontWait = FALSE;
  1530. BOOL fInited = FALSE;
  1531. SECURITY_DESCRIPTOR sd;
  1532. PSID psid = NULL;
  1533. PACL pdacl = NULL;
  1534. static SERVICE_SHUTDOWN_PARAMS s_ssp;
  1535. HANDLE hWait;
  1536. InitSecurityDescriptor (&sd, &psid, &pdacl);
  1537. s_ssp.hThreadMgmt = hThreadMgmt;
  1538. s_ssp.psid = psid;
  1539. s_ssp.pdacl = pdacl;
  1540. if (!bFatalError)
  1541. {
  1542. if (gbNTServer)
  1543. {
  1544. status = RpcServerUseProtseqEp(
  1545. TEXT("ncacn_np"),
  1546. (unsigned int) dwMaxCalls,
  1547. TEXT("\\pipe\\tapsrv"),
  1548. NULL
  1549. );
  1550. if (status)
  1551. {
  1552. LOG((TL_TRACE, "RpcServerUseProtseqEp(np) ret'd %d", status));
  1553. }
  1554. }
  1555. status = RpcServerUseProtseqEp(
  1556. TEXT("ncalrpc"),
  1557. (unsigned int) dwMaxCalls,
  1558. TEXT("tapsrvlpc"),
  1559. &sd
  1560. );
  1561. if (status)
  1562. {
  1563. LOG((TL_TRACE, "RpcServerUseProtseqEp(lrpc) ret'd %d", status));
  1564. }
  1565. status = RpcServerRegisterAuthInfo(
  1566. NULL,
  1567. RPC_C_AUTHN_WINNT,
  1568. NULL,
  1569. NULL
  1570. );
  1571. if (status)
  1572. {
  1573. LOG((TL_TRACE, "RpcServerRegisterAuthInfo ret'd %d", status));
  1574. }
  1575. #if MEMPHIS
  1576. if (!(hEvent = CreateEvent (NULL, TRUE, FALSE, "TapiSrvInited")))
  1577. {
  1578. LOG((TL_ERROR,
  1579. "CreateEvent ('TapiSrvInited') failed, err=%d",
  1580. GetLastError()
  1581. ));
  1582. }
  1583. SetEvent (hEvent);
  1584. #else
  1585. ReportStatusToSCMgr(
  1586. (gdwServiceState = SERVICE_RUNNING),
  1587. // service state
  1588. NO_ERROR, // exit code
  1589. 0, // checkpoint
  1590. 0 // wait hint
  1591. );
  1592. #endif
  1593. status = RpcServerListen(
  1594. (unsigned int)dwMinCalls,
  1595. (unsigned int)dwMaxCalls,
  1596. TRUE
  1597. );
  1598. if (status)
  1599. {
  1600. LOG((TL_TRACE, "RpcServerListen ret'd %d", status));
  1601. }
  1602. status = RpcServerRegisterIfEx(
  1603. tapsrv_ServerIfHandle, // interface to register
  1604. NULL, // MgrTypeUuid
  1605. NULL, // MgrEpv; null means use default
  1606. RPC_IF_AUTOLISTEN | RPC_IF_ALLOW_SECURE_ONLY,
  1607. dwMaxCalls,
  1608. NULL
  1609. );
  1610. if (status)
  1611. {
  1612. LOG((TL_TRACE, "RpcServerRegisterIfEx ret'd %d", status));
  1613. }
  1614. //
  1615. // In TAPI server machine with a few thousands of lines or more,
  1616. // ServerInit will take considerable amount of time, the
  1617. // first user who does a lineInitialize will be hit with this
  1618. // delay. Also the first person who does MMC management will also
  1619. // hit a delay waiting for the server to collect information. Both
  1620. // affects people's perception of TAPI performance.
  1621. //
  1622. // Solution:
  1623. // 1. We put ServerInit to be done immediately after the server
  1624. // is up. This way, as long as user does not come too fast, he won't
  1625. // be penalized for being the first.
  1626. // 2. We now try to build the management cache immediately
  1627. // instead of waiting until MMC is used. This way, when MMC is started
  1628. // the user do not have to wait.
  1629. //
  1630. // Of course, in both of the above cases, if a user tries to use
  1631. // TAPI server before all the dusts settle down. He will have to
  1632. // wait.
  1633. //
  1634. gbServerInited = FALSE;
  1635. if (TapiGlobals.dwFlags & TAPIGLOBALS_SERVER)
  1636. {
  1637. TapiEnterCriticalSection (&TapiGlobals.CritSec);
  1638. if (TapiGlobals.dwNumLineInits == 0 &&
  1639. TapiGlobals.dwNumPhoneInits == 0)
  1640. {
  1641. if (ServerInit(FALSE) == S_OK)
  1642. {
  1643. gbServerInited = TRUE;
  1644. }
  1645. }
  1646. // Holde a reference here to prevent ServerShutdown
  1647. TapiLeaveCriticalSection (&TapiGlobals.CritSec);
  1648. UpdateTapiSCP (TRUE, NULL, NULL);
  1649. EnterCriticalSection (&gMgmtCritSec);
  1650. UpdateLastWriteTime(TRUE);
  1651. BuildDeviceInfoList(TRUE);
  1652. UpdateLastWriteTime(FALSE);
  1653. BuildDeviceInfoList(FALSE);
  1654. LeaveCriticalSection (&gMgmtCritSec);
  1655. }
  1656. gdwServiceInitFlags |= SERVICE_INIT_RPC;
  1657. if (ghEventService == NULL ||
  1658. !RegisterWaitForSingleObject(
  1659. &hWait,
  1660. ghEventService,
  1661. ServiceShutdown,
  1662. (PVOID)&s_ssp,
  1663. INFINITE,
  1664. WT_EXECUTEONLYONCE
  1665. )
  1666. )
  1667. {
  1668. ServiceShutdown ((PVOID) &s_ssp, FALSE);
  1669. }
  1670. }
  1671. if (bFatalError)
  1672. {
  1673. ServiceShutdown ((PVOID) &s_ssp, FALSE);
  1674. }
  1675. }
  1676. }
  1677. VOID CALLBACK ServiceShutdown (
  1678. PVOID lpParam,
  1679. BOOLEAN fTimeOut
  1680. )
  1681. {
  1682. SERVICE_SHUTDOWN_PARAMS *pssp = (SERVICE_SHUTDOWN_PARAMS *)lpParam;
  1683. HANDLE hThreadMgmt;
  1684. PSID psid;
  1685. PACL pdacl;
  1686. DWORD i;
  1687. if (pssp == NULL)
  1688. {
  1689. return;
  1690. }
  1691. hThreadMgmt = pssp->hThreadMgmt;
  1692. psid = pssp->psid;
  1693. pdacl = pssp->pdacl;
  1694. // Mark Tapi server to be inactive for service stop
  1695. if (TapiGlobals.dwFlags & TAPIGLOBALS_SERVER)
  1696. {
  1697. // Wait max 20 seconds for Management thread to terminiate
  1698. if (hThreadMgmt)
  1699. {
  1700. WaitForSingleObject (hThreadMgmt, 20000);
  1701. CloseHandle (hThreadMgmt);
  1702. }
  1703. }
  1704. if (gbNTServer && (gdwServiceInitFlags & SERVICE_INIT_CRITSEC_GLOB_CRITSEC) )
  1705. {
  1706. TapiEnterCriticalSection (&TapiGlobals.CritSec);
  1707. if (TapiGlobals.dwNumLineInits == 0 &&
  1708. TapiGlobals.dwNumPhoneInits == 0 &&
  1709. gbServerInited
  1710. )
  1711. {
  1712. ServerShutdown();
  1713. }
  1714. TapiLeaveCriticalSection (&TapiGlobals.CritSec);
  1715. }
  1716. ServerFree (psid);
  1717. ServerFree (pdacl);
  1718. gbSPEventHandlerThreadExit = TRUE;
  1719. //
  1720. // If there are any clients left then tear them down. This will
  1721. // cause any existing service providers to get unloaded, etc.
  1722. //
  1723. {
  1724. PTCLIENT ptClient;
  1725. while ((ptClient = TapiGlobals.ptClients) != NULL)
  1726. {
  1727. if (!CleanUpClient (ptClient, TRUE))
  1728. {
  1729. //
  1730. // CleanUpClient will only return FALSE if another
  1731. // thread is cleaning up the specified tClient, or
  1732. // if the pointer is really bad.
  1733. //
  1734. // So, we'll spin for a little while waiting to see
  1735. // if the tClient gets removed from the list, & if
  1736. // not assume that we're experiencing heap
  1737. // corruption or some such, and manually shutdown.
  1738. //
  1739. for (i = 0; ptClient == TapiGlobals.ptClients && i < 10; i++)
  1740. {
  1741. Sleep (100);
  1742. }
  1743. if (i >= 10)
  1744. {
  1745. TapiEnterCriticalSection (&TapiGlobals.CritSec);
  1746. if (TapiGlobals.dwNumLineInits ||
  1747. TapiGlobals.dwNumPhoneInits)
  1748. {
  1749. ServerShutdown ();
  1750. }
  1751. TapiLeaveCriticalSection (&TapiGlobals.CritSec);
  1752. break;
  1753. }
  1754. }
  1755. }
  1756. }
  1757. //
  1758. // Tell the SPEventHandlerThread(s) to terminate
  1759. //
  1760. for (i = 0; i < gdwNumSPEventHandlerThreads; i++)
  1761. {
  1762. EnterCriticalSection (&aSPEventHandlerThreadInfo[i].CritSec);
  1763. SetEvent (aSPEventHandlerThreadInfo[i].hEvent);
  1764. LeaveCriticalSection (&aSPEventHandlerThreadInfo[i].CritSec);
  1765. }
  1766. //
  1767. // Disable rundowns & wait for any active rundowns to complete
  1768. //
  1769. while (InterlockedExchange (&gRundownLock.lCookie, 1) == 1)
  1770. {
  1771. Sleep (50);
  1772. }
  1773. gRundownLock.bIgnoreRundowns = TRUE;
  1774. InterlockedExchange (&gRundownLock.lCookie, 0);
  1775. while (gRundownLock.lNumRundowns != 0)
  1776. {
  1777. Sleep (50);
  1778. }
  1779. #if TELE_SERVER
  1780. //
  1781. // Wait for the EventNotificationThread's to terminate,
  1782. // then clean up the related resources
  1783. //
  1784. if ( (TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) &&
  1785. (gdwServiceInitFlags & SERVICE_INIT_EVENT_NOTIFICATION)
  1786. )
  1787. {
  1788. gEventNotificationThreadParams.bExit = TRUE;
  1789. while (gEventNotificationThreadParams.dwNumThreads)
  1790. {
  1791. SetEvent (gEventNotificationThreadParams.hEvent);
  1792. Sleep (100);
  1793. }
  1794. CloseHandle (gEventNotificationThreadParams.hEvent);
  1795. ServerFree (gEventNotificationThreadParams.phThreads);
  1796. ServerFree (gEventNotificationThreadParams.pWatchDogStruct);
  1797. }
  1798. if (gdwServiceInitFlags & SERVICE_INIT_MANAGEMENT_DLL)
  1799. {
  1800. CleanUpManagementMemory();
  1801. }
  1802. #endif
  1803. ServerFree (TapiGlobals.pszComputerName);
  1804. //
  1805. // Wait for the SPEVentHandlerThread(s) to terminate
  1806. //
  1807. while (glNumActiveSPEventHandlerThreads)
  1808. {
  1809. Sleep (100);
  1810. }
  1811. for (i = 0; i < gdwNumSPEventHandlerThreads; i++)
  1812. {
  1813. CloseHandle (aSPEventHandlerThreadInfo[i].hEvent);
  1814. DeleteCriticalSection (&aSPEventHandlerThreadInfo[i].CritSec);
  1815. }
  1816. if (aSPEventHandlerThreadInfo != (&gSPEventHandlerThreadInfo))
  1817. {
  1818. ServerFree (aSPEventHandlerThreadInfo);
  1819. }
  1820. //
  1821. // Free up resources
  1822. //
  1823. if (gdwServiceInitFlags & SERVICE_INIT_CRITSEC_MGMT)
  1824. DeleteCriticalSection (&gMgmtCritSec);
  1825. if (gdwServiceInitFlags & SERVICE_INIT_CRITSEC_GLOB_CRITSEC)
  1826. TapiDeleteCriticalSection (&TapiGlobals.CritSec);
  1827. if (gdwServiceInitFlags & SERVICE_INIT_CRITSEC_GLOB_REMOTESP)
  1828. DeleteCriticalSection (&TapiGlobals.RemoteSPCritSec);
  1829. if (gdwServiceInitFlags & SERVICE_INIT_CRITSEC_CNCLIENTMSG)
  1830. DeleteCriticalSection (&gCnClientMsgPendingCritSec);
  1831. if (gdwServiceInitFlags & SERVICE_INIT_CRITSEC_DGCLIENTMSG)
  1832. DeleteCriticalSection (&gDgClientMsgPendingCritSec);
  1833. if (gdwServiceInitFlags & SERVICE_INIT_CRITSEC_SAFEMUTEX)
  1834. DeleteCriticalSection (&gSafeMutexCritSec);
  1835. if (gdwServiceInitFlags & SERVICE_INIT_CRITSEC_REMOTECLI)
  1836. DeleteCriticalSection (&gRemoteCliEventBufCritSec);
  1837. if (gdwServiceInitFlags & SERVICE_INIT_CRITSEC_PRILIST)
  1838. DeleteCriticalSection (&gPriorityListCritSec);
  1839. if (gdwServiceInitFlags & SERVICE_INIT_CRITSEC_MGMTDLLS)
  1840. DeleteCriticalSection (&gManagementDllsCritSec);
  1841. if (gdwServiceInitFlags & SERVICE_INIT_CRITSEC_DLLLIST)
  1842. DeleteCriticalSection (&gDllListCritSec);
  1843. if (gdwServiceInitFlags & SERVICE_INIT_CRITSEC_CLIENTHND)
  1844. DeleteCriticalSection (&gClientHandleCritSec);
  1845. //
  1846. // Free ICON resources
  1847. //
  1848. if (TapiGlobals.hLineIcon)
  1849. {
  1850. DestroyIcon (TapiGlobals.hLineIcon);
  1851. TapiGlobals.hLineIcon = NULL;
  1852. }
  1853. if (TapiGlobals.hPhoneIcon)
  1854. {
  1855. DestroyIcon (TapiGlobals.hPhoneIcon);
  1856. TapiGlobals.hPhoneIcon = NULL;
  1857. }
  1858. if (gdwServiceInitFlags & SERVICE_INIT_LOCKTABLE)
  1859. {
  1860. for (i = 0; i < gdwNumLockTableEntries; i++)
  1861. {
  1862. DeleteCriticalSection (&gLockTable[i]);
  1863. }
  1864. if (gLockTable != gLockTableCritSecs)
  1865. {
  1866. ServerFree (gLockTable);
  1867. }
  1868. }
  1869. DeleteHandleTable (ghHandleTable);
  1870. ghHandleTable = NULL;
  1871. if (ghTapisrvHeap != GetProcessHeap())
  1872. {
  1873. HeapDestroy (ghTapisrvHeap);
  1874. }
  1875. if (ghEventService)
  1876. {
  1877. CloseHandle (ghEventService);
  1878. ghEventService = NULL;
  1879. }
  1880. #if MEMPHIS
  1881. // CloseHandle (hEvent);
  1882. #else
  1883. //
  1884. // Report the stopped status to the service control manager.
  1885. //
  1886. if (NULL != ghSCMAutostartEvent)
  1887. {
  1888. CloseHandle (ghSCMAutostartEvent);
  1889. }
  1890. if (gdwServiceInitFlags & SERVICE_INIT_SCM_REGISTERED)
  1891. {
  1892. ReportStatusToSCMgr ((gdwServiceState = SERVICE_STOPPED), 0, 0, 0);
  1893. }
  1894. #endif
  1895. gdwServiceInitFlags = 0;
  1896. //
  1897. // When SERVICE MAIN FUNCTION returns in a single service
  1898. // process, the StartServiceCtrlDispatcher function in
  1899. // the main thread returns, terminating the process.
  1900. //
  1901. LOG((TL_TRACE, "ServiceMain: exit"));
  1902. TRACELOGDEREGISTER();
  1903. return;
  1904. }
  1905. BOOL
  1906. PASCAL
  1907. QueueSPEvent(
  1908. PSPEVENT pSPEvent
  1909. )
  1910. {
  1911. //
  1912. // If there are multiple SPEventHandlerThread's running then make
  1913. // sure to always queue events for a particular object to the same
  1914. // SPEventHandlerThread so that we can preserve message ordering.
  1915. // Without doing this call state messages might be received out of
  1916. // order (or discarded altogether, if processed before a MakeCall
  1917. // completion routine run, etc), etc.
  1918. //
  1919. BOOL bSetEvent;
  1920. ULONG_PTR htXxx;
  1921. PSPEVENTHANDLERTHREADINFO pInfo;
  1922. switch (pSPEvent->dwType)
  1923. {
  1924. case SP_LINE_EVENT:
  1925. case SP_PHONE_EVENT:
  1926. htXxx = (ULONG_PTR)pSPEvent->htLine;
  1927. break;
  1928. case TASYNC_KEY:
  1929. htXxx = ((PASYNCREQUESTINFO) pSPEvent)->htXxx;
  1930. break;
  1931. default:
  1932. LOG((TL_ERROR, "QueueSPEvent: bad pSPEvent=x%p", pSPEvent));
  1933. #if DBG
  1934. if (gfBreakOnSeriousProblems)
  1935. {
  1936. DebugBreak();
  1937. }
  1938. #endif
  1939. return FALSE;
  1940. }
  1941. pInfo = (gdwNumSPEventHandlerThreads > 1 ?
  1942. aSPEventHandlerThreadInfo + MAP_HANDLE_TO_SP_EVENT_QUEUE_ID (htXxx) :
  1943. aSPEventHandlerThreadInfo
  1944. );
  1945. if (gbQueueSPEvents)
  1946. {
  1947. EnterCriticalSection (&pInfo->CritSec);
  1948. bSetEvent = IsListEmpty (&pInfo->ListHead);
  1949. InsertTailList (&pInfo->ListHead, &pSPEvent->ListEntry);
  1950. LeaveCriticalSection (&pInfo->CritSec);
  1951. if (bSetEvent)
  1952. {
  1953. SetEvent (pInfo->hEvent);
  1954. }
  1955. return TRUE;
  1956. }
  1957. return FALSE;
  1958. }
  1959. BOOL
  1960. PASCAL
  1961. DequeueSPEvent(
  1962. PSPEVENTHANDLERTHREADINFO pInfo,
  1963. PSPEVENT *ppSPEvent
  1964. )
  1965. {
  1966. BOOL bResult;
  1967. LIST_ENTRY *pEntry;
  1968. EnterCriticalSection (&pInfo->CritSec);
  1969. if ((bResult = !IsListEmpty (&pInfo->ListHead)))
  1970. {
  1971. pEntry = RemoveHeadList (&pInfo->ListHead);
  1972. *ppSPEvent = CONTAINING_RECORD (pEntry, SPEVENT, ListEntry);
  1973. }
  1974. if (IsListEmpty (&pInfo->ListHead))
  1975. {
  1976. ResetEvent (pInfo->hEvent);
  1977. }
  1978. LeaveCriticalSection (&pInfo->CritSec);
  1979. return bResult;
  1980. }
  1981. void
  1982. SPEventHandlerThread(
  1983. PSPEVENTHANDLERTHREADINFO pInfo
  1984. )
  1985. {
  1986. //
  1987. // This thread processes the events & completion notifications
  1988. // indicated to us by an SP at a previous time/thread context.
  1989. // There are a couple of reasons for doing this in a separate
  1990. // thread rather than within the SP's thread context:
  1991. //
  1992. // 1. for some msgs (i.e. XXX_CLOSE) TAPI will call back
  1993. // into the SP, which it may not be expecting
  1994. //
  1995. // 2. we don't want to block the SP's thread by processing
  1996. // the msg, forwarding it on to the appropriate clients,
  1997. // etc
  1998. //
  1999. LOG((TL_INFO,
  2000. "SPEventHandlerThread: enter (tid=%d)",
  2001. GetCurrentThreadId()
  2002. ));
  2003. if (!SetThreadPriority(
  2004. GetCurrentThread(),
  2005. THREAD_PRIORITY_ABOVE_NORMAL
  2006. ))
  2007. {
  2008. LOG((TL_ERROR, "Could not raise priority of SPEventHandlerThread"));
  2009. }
  2010. while (1)
  2011. {
  2012. PSPEVENT pSPEvent;
  2013. #if TELE_SERVER
  2014. //
  2015. // Timeout no more than gdwRpcTimeout to check on threads...
  2016. //
  2017. {
  2018. #if DBG
  2019. DWORD dwReturnValue;
  2020. dwReturnValue =
  2021. #endif
  2022. WaitForSingleObject (pInfo->hEvent, gdwRpcTimeout);
  2023. #if DBG
  2024. if ( WAIT_TIMEOUT == dwReturnValue )
  2025. LOG((TL_ERROR, "Timed out waiting for an sp event..."));
  2026. else
  2027. LOG((TL_INFO, "Found an sp event..."));
  2028. #endif
  2029. }
  2030. #else
  2031. WaitForSingleObject (pInfo->hEvent, INFINITE);
  2032. #endif
  2033. while (DequeueSPEvent (pInfo, &pSPEvent))
  2034. {
  2035. LOG((TL_INFO, "Got an spevent"));
  2036. switch (pSPEvent->dwType)
  2037. {
  2038. case SP_LINE_EVENT:
  2039. LineEventProc(
  2040. pSPEvent->htLine,
  2041. pSPEvent->htCall,
  2042. pSPEvent->dwMsg,
  2043. pSPEvent->dwParam1,
  2044. pSPEvent->dwParam2,
  2045. pSPEvent->dwParam3
  2046. );
  2047. ServerFree (pSPEvent);
  2048. break;
  2049. case TASYNC_KEY:
  2050. CompletionProc(
  2051. (PASYNCREQUESTINFO) pSPEvent,
  2052. ((PASYNCREQUESTINFO) pSPEvent)->lResult
  2053. );
  2054. DereferenceObject(
  2055. ghHandleTable,
  2056. ((PASYNCREQUESTINFO) pSPEvent)->dwLocalRequestID,
  2057. 1
  2058. );
  2059. break;
  2060. case SP_PHONE_EVENT:
  2061. PhoneEventProc(
  2062. pSPEvent->htPhone,
  2063. pSPEvent->dwMsg,
  2064. pSPEvent->dwParam1,
  2065. pSPEvent->dwParam2,
  2066. pSPEvent->dwParam3
  2067. );
  2068. ServerFree (pSPEvent);
  2069. break;
  2070. }
  2071. }
  2072. #if TELE_SERVER
  2073. //
  2074. // Check the remotesp event threads to make sure no
  2075. // one is hung in an RPC call
  2076. //
  2077. if (TapiGlobals.dwFlags & TAPIGLOBALS_SERVER)
  2078. {
  2079. DWORD dwCount = gEventNotificationThreadParams.dwNumThreads;
  2080. DWORD dwTickCount = GetTickCount();
  2081. DWORD dwStartCount, dwDiff;
  2082. RPC_STATUS status;
  2083. while (dwCount)
  2084. {
  2085. dwCount--;
  2086. dwStartCount = gEventNotificationThreadParams.
  2087. pWatchDogStruct[dwCount].dwTickCount;
  2088. if ( gEventNotificationThreadParams.
  2089. pWatchDogStruct[dwCount].ptClient &&
  2090. ( ( dwTickCount - dwStartCount ) > gdwRpcTimeout ) )
  2091. {
  2092. // did it wrap?
  2093. if ((((LONG)dwStartCount) < 0) && ((LONG)dwTickCount) > 0)
  2094. {
  2095. dwDiff = dwTickCount + (0 - ((LONG)dwStartCount));
  2096. if (dwDiff <= gdwRpcTimeout)
  2097. {
  2098. continue;
  2099. }
  2100. }
  2101. // Kill the chicken!
  2102. LOG((TL_INFO,
  2103. "Calling RpcCancelThread on thread #%lx",
  2104. gEventNotificationThreadParams.phThreads[dwCount]
  2105. ));
  2106. gEventNotificationThreadParams.
  2107. pWatchDogStruct[dwCount].ptClient = NULL;
  2108. status = RpcCancelThread(
  2109. gEventNotificationThreadParams.phThreads[dwCount]
  2110. );
  2111. }
  2112. }
  2113. }
  2114. #endif
  2115. if (gbSPEventHandlerThreadExit)
  2116. {
  2117. //
  2118. // ServiceMain has stopped listening, so we want to exit NOW
  2119. //
  2120. break;
  2121. }
  2122. //
  2123. // Check to see if all the clients are gone, and if so wait a
  2124. // while to see if anyone else attaches. If no one else attaches
  2125. // in the specified amount of time then shut down.
  2126. //
  2127. // don't quit if we're a server
  2128. //
  2129. // don't quit if we've not yet ever had anyone attach (like a service
  2130. // that has a dependency on us, but has not yet done a lineInit)
  2131. //
  2132. //
  2133. // don't quit if SCM didn't finish to start the automatic services;
  2134. // there may be services that depend on us to start
  2135. //
  2136. if ( !gbAutostartDone &&
  2137. ghSCMAutostartEvent &&
  2138. WAIT_OBJECT_0 == WaitForSingleObject(ghSCMAutostartEvent, 0)
  2139. )
  2140. {
  2141. gbAutostartDone = TRUE;
  2142. }
  2143. if (TapiGlobals.ptClients == NULL &&
  2144. !(TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) &&
  2145. gfWeHadAtLeastOneClient &&
  2146. gbAutostartDone)
  2147. {
  2148. DWORD dwDeferredShutdownTimeout, dwSleepInterval,
  2149. dwLoopCount, i;
  2150. RPC_STATUS status;
  2151. HKEY hKey;
  2152. #ifdef MEMPHIS
  2153. dwDeferredShutdownTimeout = 4; // 4 seconds
  2154. #else
  2155. dwDeferredShutdownTimeout = 120; // 120 seconds
  2156. #endif
  2157. dwSleepInterval = 250; // 250 milliseconds
  2158. if (RegOpenKeyEx(
  2159. HKEY_LOCAL_MACHINE,
  2160. gszRegKeyTelephony,
  2161. 0,
  2162. KEY_ALL_ACCESS,
  2163. &hKey
  2164. ) == ERROR_SUCCESS)
  2165. {
  2166. DWORD dwDataSize = sizeof (DWORD), dwDataType;
  2167. if (RegQueryValueEx(
  2168. hKey,
  2169. TEXT("DeferredShutdownTimeout"),
  2170. 0,
  2171. &dwDataType,
  2172. (LPBYTE) &dwDeferredShutdownTimeout,
  2173. &dwDataSize
  2174. ) == ERROR_SUCCESS )
  2175. {
  2176. LOG((TL_ERROR,
  2177. "Overriding Shutdown Timeout: %lu",
  2178. dwDeferredShutdownTimeout
  2179. ));
  2180. }
  2181. RegCloseKey (hKey);
  2182. }
  2183. dwLoopCount = dwDeferredShutdownTimeout * 1000 / dwSleepInterval;
  2184. for (i = 0; i < dwLoopCount; i++)
  2185. {
  2186. if (gbSPEventHandlerThreadExit)
  2187. {
  2188. i = dwLoopCount;
  2189. break;
  2190. }
  2191. Sleep (dwSleepInterval);
  2192. if (TapiGlobals.ptClients != NULL)
  2193. {
  2194. break;
  2195. }
  2196. }
  2197. if (i == dwLoopCount)
  2198. {
  2199. //
  2200. // The 1st SPEVentHandlerThread instance is in charge of
  2201. // tearing down the rpc server listen
  2202. //
  2203. if (pInfo == aSPEventHandlerThreadInfo)
  2204. {
  2205. #if MEMPHIS
  2206. #else
  2207. ReportStatusToSCMgr(
  2208. (gdwServiceState = SERVICE_STOP_PENDING),
  2209. 0,
  2210. (gdwCheckPoint = 0),
  2211. gdwWaitHint
  2212. );
  2213. #endif
  2214. RpcServerUnregisterIf (tapsrv_ServerIfHandle, NULL, TRUE);
  2215. if (ghEventService)
  2216. {
  2217. SetEvent (ghEventService);
  2218. }
  2219. #if DBG
  2220. DumpHandleList();
  2221. #endif
  2222. }
  2223. break;
  2224. }
  2225. }
  2226. }
  2227. InterlockedDecrement (&glNumActiveSPEventHandlerThreads);
  2228. LOG((TL_TRACE, "SPEventHandlerThread: exit (pid=%d)", GetCurrentThreadId()));
  2229. ExitThread (0);
  2230. }
  2231. DWORD
  2232. InitSecurityDescriptor(
  2233. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  2234. PSID * ppSid,
  2235. PACL * ppDacl
  2236. )
  2237. {
  2238. #if MEMPHIS
  2239. return FALSE;
  2240. #else
  2241. //
  2242. // Note: this code was borrowed from Steve Cobb, who borrowed from RASMAN
  2243. //
  2244. DWORD dwResult;
  2245. DWORD cbDaclSize;
  2246. PULONG pSubAuthority;
  2247. PSID pObjSid = NULL;
  2248. PACL pDacl = NULL;
  2249. SID_IDENTIFIER_AUTHORITY SidIdentifierWorldAuth =
  2250. SECURITY_WORLD_SID_AUTHORITY;
  2251. //
  2252. // The do - while(FALSE) statement is used so that the break statement
  2253. // maybe used insted of the goto statement, to execute a clean up and
  2254. // and exit action.
  2255. //
  2256. do
  2257. {
  2258. dwResult = 0;
  2259. //
  2260. // Set up the SID for the admins that will be allowed to have
  2261. // access. This SID will have 1 sub-authorities
  2262. // SECURITY_BUILTIN_DOMAIN_RID.
  2263. //
  2264. if (!(pObjSid = (PSID) ServerAlloc (GetSidLengthRequired (1))))
  2265. {
  2266. dwResult = GetLastError();
  2267. LOG((TL_ERROR, "GetSidLengthRequired() failed, err=%d", dwResult));
  2268. break;
  2269. }
  2270. if (!InitializeSid (pObjSid, &SidIdentifierWorldAuth, 1))
  2271. {
  2272. dwResult = GetLastError();
  2273. LOG((TL_ERROR, "InitializeSid() failed, err=%d", dwResult));
  2274. break;
  2275. }
  2276. //
  2277. // Set the sub-authorities
  2278. //
  2279. pSubAuthority = GetSidSubAuthority (pObjSid, 0);
  2280. *pSubAuthority = SECURITY_WORLD_RID;
  2281. //
  2282. // Set up the DACL that will allow all processeswith the above
  2283. // SID all access. It should be large enough to hold all ACEs.
  2284. //
  2285. cbDaclSize = sizeof(ACCESS_ALLOWED_ACE) +
  2286. GetLengthSid (pObjSid) +
  2287. sizeof(ACL);
  2288. if (!(pDacl = (PACL) ServerAlloc (cbDaclSize)))
  2289. {
  2290. dwResult = GetLastError ();
  2291. break;
  2292. }
  2293. if (!InitializeAcl (pDacl, cbDaclSize, ACL_REVISION2))
  2294. {
  2295. dwResult = GetLastError();
  2296. LOG((TL_ERROR, "InitializeAcl() failed, err=%d", dwResult));
  2297. break;
  2298. }
  2299. //
  2300. // Add the ACE to the DACL
  2301. //
  2302. if (!AddAccessAllowedAce(
  2303. pDacl,
  2304. ACL_REVISION2,
  2305. STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
  2306. pObjSid
  2307. ))
  2308. {
  2309. dwResult = GetLastError();
  2310. LOG((TL_ERROR, "AddAccessAllowedAce() failed, err=%d", dwResult));
  2311. break;
  2312. }
  2313. //
  2314. // Create the security descriptor an put the DACL in it.
  2315. //
  2316. if (!InitializeSecurityDescriptor (pSecurityDescriptor, 1))
  2317. {
  2318. dwResult = GetLastError();
  2319. LOG((TL_ERROR,
  2320. "InitializeSecurityDescriptor() failed, err=%d",
  2321. dwResult
  2322. ));
  2323. break;
  2324. }
  2325. if (!SetSecurityDescriptorDacl(
  2326. pSecurityDescriptor,
  2327. TRUE,
  2328. pDacl,
  2329. FALSE
  2330. ))
  2331. {
  2332. dwResult = GetLastError();
  2333. LOG((TL_ERROR, "SetSecurityDescriptorDacl() failed, err=%d",dwResult));
  2334. break;
  2335. }
  2336. //
  2337. // Set owner for the descriptor
  2338. //
  2339. if (!SetSecurityDescriptorOwner(
  2340. pSecurityDescriptor,
  2341. NULL,
  2342. FALSE
  2343. ))
  2344. {
  2345. dwResult = GetLastError();
  2346. LOG((TL_ERROR, "SetSecurityDescriptorOwnr() failed, err=%d",dwResult));
  2347. break;
  2348. }
  2349. //
  2350. // Set group for the descriptor
  2351. //
  2352. if (!SetSecurityDescriptorGroup(
  2353. pSecurityDescriptor,
  2354. NULL,
  2355. FALSE
  2356. ))
  2357. {
  2358. dwResult = GetLastError();
  2359. LOG((TL_ERROR,"SetSecurityDescriptorGroup() failed, err=%d",dwResult));
  2360. break;
  2361. }
  2362. } while (FALSE);
  2363. *ppSid = pObjSid;
  2364. *ppDacl = pDacl;
  2365. return dwResult;
  2366. #endif
  2367. }
  2368. void
  2369. EventNotificationThread(
  2370. LPVOID pParams
  2371. )
  2372. {
  2373. struct
  2374. {
  2375. HANDLE hMailslot;
  2376. DWORD dwData;
  2377. } *pBuf;
  2378. DWORD dwID = PtrToUlong (pParams),
  2379. dwBufSize = 512,
  2380. dwTimeout = INFINITE;
  2381. PTCLIENT ptClient;
  2382. LIST_ENTRY *pEntry;
  2383. LOG((TL_TRACE, "EventNotificationThread: enter"));
  2384. if (!SetThreadPriority(
  2385. GetCurrentThread(),
  2386. THREAD_PRIORITY_ABOVE_NORMAL
  2387. ))
  2388. {
  2389. LOG((TL_ERROR, "Could not raise priority of EventNotificationThread"));
  2390. }
  2391. //
  2392. // The following will make control return to the thread as soon
  2393. // as RpcCancelThread() is called
  2394. //
  2395. if ( RpcMgmtSetCancelTimeout (0) != RPC_S_OK )
  2396. {
  2397. LOG((TL_ERROR, "Could not set the RPC cancel timeout"));
  2398. }
  2399. pBuf = ServerAlloc (dwBufSize);
  2400. if (!pBuf)
  2401. {
  2402. goto ExitHere;
  2403. }
  2404. while (1)
  2405. {
  2406. //
  2407. // Wait for someone to tell us there's clients to notify
  2408. //
  2409. if (dwID == 0)
  2410. {
  2411. Sleep (DGCLIENT_TIMEOUT);
  2412. walkDgClient_list:
  2413. if (gEventNotificationThreadParams.bExit)
  2414. {
  2415. break;
  2416. }
  2417. //
  2418. // Check to see if there are any connectionless clients
  2419. // that we should notify.
  2420. //
  2421. if (!IsListEmpty (&DgClientMsgPendingListHead))
  2422. {
  2423. DWORD i, j, dwTickCount, dwBytesWritten, dwNeededSize;
  2424. //
  2425. // Build a list of connectionless clients that we should
  2426. // notify of pending events
  2427. //
  2428. // Note: the fact that we're in the critical section & the
  2429. // tClient is in the list means that we can safely access
  2430. // the tClient.
  2431. //
  2432. dwTickCount = GetTickCount();
  2433. EnterCriticalSection (&gDgClientMsgPendingCritSec);
  2434. pEntry = DgClientMsgPendingListHead.Flink;
  2435. for(
  2436. i = 0, dwNeededSize = sizeof (*pBuf);
  2437. pEntry != &DgClientMsgPendingListHead;
  2438. dwNeededSize += sizeof (*pBuf)
  2439. )
  2440. {
  2441. do
  2442. {
  2443. ptClient = CONTAINING_RECORD(
  2444. pEntry,
  2445. TCLIENT,
  2446. MsgPendingListEntry
  2447. );
  2448. pEntry = pEntry->Flink;
  2449. if ((ptClient->dwDgRetryTimeoutTickCount - dwTickCount)
  2450. & 0x80000000)
  2451. {
  2452. //
  2453. // Check the last time the client retrieved
  2454. // events, & if it's been too long then nuke
  2455. // them.
  2456. //
  2457. // Ideally, RPC should notify us of a
  2458. // disconnected client via our rundown routine.
  2459. // But we have seen in rstress that this is not
  2460. // always the case (in fact, we wind up with 2
  2461. // or more active instances of the same client
  2462. // machine!), and so we use this watchdog scheme
  2463. // for backup. Otherwise, a stale client might
  2464. // have lines open w/ owner or monitor privs
  2465. // and it's event queue would grow & grow.
  2466. //
  2467. if ((dwTickCount -
  2468. ptClient->dwDgEventsRetrievedTickCount) >
  2469. gdwRpcTimeout)
  2470. {
  2471. LOG((TL_ERROR,
  2472. "EventNotificationThread: timeout, " \
  2473. "cleaning up Dg client=x%p",
  2474. ptClient
  2475. ));
  2476. LeaveCriticalSection(
  2477. &gDgClientMsgPendingCritSec
  2478. );
  2479. CleanUpClient (ptClient, FALSE);
  2480. goto walkDgClient_list;
  2481. }
  2482. //
  2483. // Grow the buffer if necessary
  2484. //
  2485. if (dwNeededSize > dwBufSize)
  2486. {
  2487. LPVOID p;
  2488. if ((p = ServerAlloc (dwBufSize + 512)))
  2489. {
  2490. CopyMemory (p, pBuf, dwBufSize);
  2491. ServerFree (pBuf);
  2492. (LPVOID) pBuf = p;
  2493. dwBufSize += 512;
  2494. }
  2495. else
  2496. {
  2497. pEntry = &DgClientMsgPendingListHead;
  2498. break;
  2499. }
  2500. }
  2501. ptClient->dwDgRetryTimeoutTickCount = dwTickCount +
  2502. DGCLIENT_TIMEOUT;
  2503. pBuf[i].hMailslot =
  2504. ptClient->hValidEventBufferDataEvent;
  2505. try
  2506. {
  2507. if (ptClient->ptLineApps)
  2508. {
  2509. pBuf[i].dwData = (DWORD)
  2510. ptClient->ptLineApps->InitContext;
  2511. }
  2512. else
  2513. {
  2514. pBuf[i].dwData = 0;
  2515. }
  2516. }
  2517. myexcept
  2518. {
  2519. pBuf[i].dwData = 0;
  2520. }
  2521. i++;
  2522. break;
  2523. }
  2524. } while (pEntry != &DgClientMsgPendingListHead);
  2525. }
  2526. LeaveCriticalSection (&gDgClientMsgPendingCritSec);
  2527. //
  2528. // Notify those clients
  2529. //
  2530. for (j = 0; j < i; j++)
  2531. {
  2532. if (!WriteFile(
  2533. pBuf[j].hMailslot,
  2534. &pBuf[j].dwData,
  2535. sizeof (DWORD),
  2536. &dwBytesWritten,
  2537. (LPOVERLAPPED) NULL
  2538. ))
  2539. {
  2540. LOG((TL_ERROR,
  2541. "EventNotificationThread: Writefile(mailslot) " \
  2542. "failed, err=%d",
  2543. GetLastError()
  2544. ));
  2545. }
  2546. }
  2547. }
  2548. continue;
  2549. }
  2550. else
  2551. {
  2552. WaitForSingleObject(
  2553. gEventNotificationThreadParams.hEvent,
  2554. INFINITE
  2555. );
  2556. }
  2557. if (gEventNotificationThreadParams.bExit)
  2558. {
  2559. break;
  2560. }
  2561. if (!IsListEmpty (&CnClientMsgPendingListHead))
  2562. {
  2563. //
  2564. // Try to find a remote client with pending messages that no
  2565. // other EventNotificationThread is currently servicing.
  2566. // If we find one, then mark it busy, remove it from the
  2567. // list, & then break out of the loop.
  2568. //
  2569. // Note: the fact that we're in the critical section & the
  2570. // tClient is in the list means that we can safely access
  2571. // the tClient.
  2572. //
  2573. findCnClientMsgPending:
  2574. EnterCriticalSection (&gCnClientMsgPendingCritSec);
  2575. for(
  2576. pEntry = CnClientMsgPendingListHead.Flink;
  2577. pEntry != &CnClientMsgPendingListHead;
  2578. pEntry = pEntry->Flink
  2579. )
  2580. {
  2581. ptClient = CONTAINING_RECORD(
  2582. pEntry,
  2583. TCLIENT,
  2584. MsgPendingListEntry
  2585. );
  2586. if (!ptClient->dwCnBusy)
  2587. {
  2588. ptClient->dwCnBusy = 1;
  2589. RemoveEntryList (pEntry);
  2590. ptClient->MsgPendingListEntry.Flink =
  2591. ptClient->MsgPendingListEntry.Blink = NULL;
  2592. break;
  2593. }
  2594. }
  2595. LeaveCriticalSection (&gCnClientMsgPendingCritSec);
  2596. //
  2597. // If a remote client was found then copy all it's event
  2598. // data over to our local buffer & send it off
  2599. //
  2600. if (pEntry != &CnClientMsgPendingListHead)
  2601. {
  2602. if (WaitForExclusiveClientAccess (ptClient))
  2603. {
  2604. DWORD dwMoveSize,
  2605. dwMoveSizeWrapped,
  2606. dwRetryCount;
  2607. PCONTEXT_HANDLE_TYPE2 phContext;
  2608. //
  2609. // We want to copy all the events in the tClient's
  2610. // buffer to our local buffer in one shot, so see
  2611. // if we need to grow our buffer first
  2612. //
  2613. if (ptClient->dwEventBufferUsedSize > dwBufSize)
  2614. {
  2615. LPVOID p;
  2616. if (!(p = ServerAlloc(
  2617. ptClient->dwEventBufferUsedSize
  2618. )))
  2619. {
  2620. UNLOCKTCLIENT (ptClient);
  2621. break;
  2622. }
  2623. ServerFree (pBuf);
  2624. (LPVOID) pBuf = p;
  2625. dwBufSize = ptClient->dwEventBufferUsedSize;
  2626. }
  2627. if (ptClient->pDataOut < ptClient->pDataIn)
  2628. {
  2629. dwMoveSize = (DWORD)
  2630. (ptClient->pDataIn - ptClient->pDataOut);
  2631. dwMoveSizeWrapped = 0;
  2632. }
  2633. else
  2634. {
  2635. dwMoveSize = ptClient->dwEventBufferTotalSize - (DWORD)
  2636. (ptClient->pDataOut - ptClient->pEventBuffer);
  2637. dwMoveSizeWrapped = (DWORD) (ptClient->pDataIn -
  2638. ptClient->pEventBuffer);
  2639. }
  2640. CopyMemory (pBuf, ptClient->pDataOut, dwMoveSize);
  2641. if (dwMoveSizeWrapped)
  2642. {
  2643. CopyMemory(
  2644. pBuf + dwMoveSize,
  2645. ptClient->pEventBuffer,
  2646. dwMoveSizeWrapped
  2647. );
  2648. }
  2649. ptClient->dwEventBufferUsedSize = 0;
  2650. ptClient->pDataIn =
  2651. ptClient->pDataOut = ptClient->pEventBuffer;
  2652. phContext = ptClient->phContext;
  2653. UNLOCKTCLIENT (ptClient);
  2654. //
  2655. // Set the watchdog entry for this thread indicating
  2656. // what client we're talking to & when we started
  2657. //
  2658. gEventNotificationThreadParams.pWatchDogStruct[dwID].
  2659. dwTickCount = GetTickCount();
  2660. gEventNotificationThreadParams.pWatchDogStruct[dwID].
  2661. ptClient = ptClient;
  2662. //
  2663. // Send the data
  2664. //
  2665. dwRetryCount = gdwRpcRetryCount;
  2666. while (dwRetryCount)
  2667. {
  2668. RpcTryExcept
  2669. {
  2670. RemoteSPEventProc(
  2671. phContext,
  2672. (unsigned char *) pBuf,
  2673. dwMoveSize + dwMoveSizeWrapped
  2674. );
  2675. dwRetryCount = 0;
  2676. }
  2677. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode()))
  2678. {
  2679. unsigned long ulResult = RpcExceptionCode();
  2680. LOG((TL_ERROR,
  2681. "EventNotificationThread: exception #%d",
  2682. ulResult
  2683. ));
  2684. if ((ulResult == RPC_S_CALL_CANCELLED) ||
  2685. (ulResult == ERROR_INVALID_HANDLE))
  2686. {
  2687. LOG((TL_ERROR,
  2688. "EventNotificationThread: rpc timeout " \
  2689. "(ptClient=x%p)",
  2690. ptClient
  2691. ));
  2692. //
  2693. // The canceled because of a timeout.
  2694. // Flag the context, so we don't try
  2695. // to call it again!
  2696. //
  2697. CleanUpClient (ptClient, FALSE);
  2698. //
  2699. // When using TCP, or SPX, RPC will probably
  2700. // toast the session context, so we'll not
  2701. // be able to call to the client again.
  2702. //
  2703. // (If RpcCancelThread() is called and the
  2704. // server ACKs within the time set int
  2705. // RpcMgmtSetCancelTimeout(), RPC
  2706. // (well, the underlying transport) _won't_
  2707. // kill the context, but how likely is that...)
  2708. //
  2709. dwRetryCount = 1; // so it'll go to 0 after --
  2710. }
  2711. dwRetryCount--;
  2712. }
  2713. RpcEndExcept
  2714. }
  2715. gEventNotificationThreadParams.pWatchDogStruct[dwID].
  2716. ptClient = NULL;
  2717. //
  2718. // Safely reset the tClient.dwCnBusy flag
  2719. //
  2720. if (WaitForExclusiveClientAccess (ptClient))
  2721. {
  2722. ptClient->dwCnBusy = 0;
  2723. UNLOCKTCLIENT (ptClient);
  2724. }
  2725. }
  2726. goto findCnClientMsgPending;
  2727. }
  2728. }
  2729. dwTimeout = INFINITE;
  2730. ResetEvent (gEventNotificationThreadParams.hEvent);
  2731. }
  2732. ExitHere:
  2733. ServerFree (pBuf);
  2734. CloseHandle (gEventNotificationThreadParams.phThreads[dwID]);
  2735. InterlockedDecrement(
  2736. (LPLONG) &gEventNotificationThreadParams.dwNumThreads
  2737. );
  2738. LOG((TL_TRACE, "EventNotificationThread: exit"));
  2739. ExitThread (0);
  2740. }
  2741. void
  2742. __RPC_FAR *
  2743. __RPC_API
  2744. midl_user_allocate(
  2745. size_t len
  2746. )
  2747. {
  2748. return (ServerAlloc(len));
  2749. }
  2750. void
  2751. __RPC_API
  2752. midl_user_free(
  2753. void __RPC_FAR * ptr
  2754. )
  2755. {
  2756. ServerFree (ptr);
  2757. }
  2758. #if TELE_SERVER
  2759. // implement these functions!
  2760. void
  2761. ManagementAddLineProc(
  2762. PTCLIENT ptClient,
  2763. DWORD dwReserved
  2764. )
  2765. {
  2766. ASYNCEVENTMSG msg;
  2767. // this should sent linedevstate_reinit message to remotesp
  2768. msg.TotalSize = sizeof(msg);
  2769. msg.InitContext = ptClient->ptLineApps->InitContext;
  2770. msg.fnPostProcessProcHandle = 0;
  2771. msg.hDevice = 0;
  2772. msg.Msg = LINE_LINEDEVSTATE;
  2773. msg.OpenContext = 0;
  2774. msg.Param1 = LINEDEVSTATE_REINIT;
  2775. msg.Param2 = RSP_MSG;
  2776. msg.Param3 = 0;
  2777. msg.Param4 = 0;
  2778. WriteEventBuffer (ptClient, &msg);
  2779. }
  2780. void
  2781. ManagementAddPhoneProc(
  2782. PTCLIENT ptClient,
  2783. DWORD dwReserved
  2784. )
  2785. {
  2786. ASYNCEVENTMSG msg;
  2787. // this should sent linedevstate_reinit message to remotesp
  2788. msg.TotalSize = sizeof(msg);
  2789. msg.InitContext = ptClient->ptLineApps->InitContext;
  2790. msg.fnPostProcessProcHandle = 0;
  2791. msg.hDevice = 0;
  2792. msg.Msg = LINE_LINEDEVSTATE;
  2793. msg.OpenContext = 0;
  2794. msg.Param1 = LINEDEVSTATE_REINIT;
  2795. msg.Param2 = RSP_MSG;
  2796. msg.Param3 = 0;
  2797. msg.Param4 = 0;
  2798. WriteEventBuffer (ptClient, &msg);
  2799. }
  2800. void
  2801. CleanUpManagementMemory(
  2802. )
  2803. {
  2804. PTMANAGEDLLINFO pDll, pDllHold;
  2805. PPERMANENTIDARRAYHEADER pIDArray, pArrayHold;
  2806. if (!(TapiGlobals.dwFlags & TAPIGLOBALS_SERVER))
  2807. {
  2808. return;
  2809. }
  2810. (TapiGlobals.pMapperDll->aProcs[TC_FREE])();
  2811. FreeLibrary(TapiGlobals.pMapperDll->hDll);
  2812. ServerFree (TapiGlobals.pMapperDll->pszName);
  2813. ServerFree (TapiGlobals.pMapperDll);
  2814. TapiGlobals.pMapperDll = NULL;
  2815. if (TapiGlobals.pManageDllList)
  2816. {
  2817. pDll = TapiGlobals.pManageDllList->pFirst;
  2818. while (pDll)
  2819. {
  2820. (pDll->aProcs[TC_FREE])();
  2821. FreeLibrary (pDll->hDll);
  2822. ServerFree (pDll->pszName);
  2823. pDllHold = pDll->pNext;
  2824. ServerFree (pDll);
  2825. pDll = pDllHold;
  2826. }
  2827. ServerFree (TapiGlobals.pManageDllList);
  2828. TapiGlobals.pManageDllList = NULL;
  2829. }
  2830. pIDArray = TapiGlobals.pIDArrays;
  2831. while (pIDArray)
  2832. {
  2833. ServerFree (pIDArray->pLineElements);
  2834. ServerFree (pIDArray->pPhoneElements);
  2835. pArrayHold = pIDArray->pNext;
  2836. ServerFree (pIDArray);
  2837. pIDArray = pArrayHold;
  2838. }
  2839. }
  2840. void
  2841. GetProviderSortedArray(
  2842. DWORD dwProviderID,
  2843. PPERMANENTIDARRAYHEADER *ppArrayHeader
  2844. )
  2845. {
  2846. *ppArrayHeader = TapiGlobals.pIDArrays;
  2847. // look for the provider in the list
  2848. while (*ppArrayHeader)
  2849. {
  2850. if ((*ppArrayHeader)->dwPermanentProviderID == dwProviderID)
  2851. {
  2852. return;
  2853. }
  2854. *ppArrayHeader = (*ppArrayHeader)->pNext;
  2855. }
  2856. LOG((TL_ERROR,
  2857. "Couldn't find Provider - id %d pIDArrays %p",
  2858. dwProviderID,
  2859. TapiGlobals.pIDArrays
  2860. ));
  2861. *ppArrayHeader = NULL;
  2862. return;
  2863. }
  2864. BOOL
  2865. GetLinePermanentIdFromDeviceID(
  2866. PTCLIENT ptClient,
  2867. DWORD dwDeviceID,
  2868. LPTAPIPERMANENTID pID
  2869. )
  2870. {
  2871. LPDWORD pDevices = ptClient->pLineDevices;
  2872. DWORD dwCount = ptClient->dwLineDevices;
  2873. while (dwCount)
  2874. {
  2875. dwCount--;
  2876. if (pDevices[dwCount] == dwDeviceID)
  2877. {
  2878. pID->dwProviderID = ptClient->pLineMap[dwCount].dwProviderID;
  2879. pID->dwDeviceID = ptClient->pLineMap[dwCount].dwDeviceID;
  2880. return TRUE;
  2881. }
  2882. }
  2883. LOG((TL_INFO,
  2884. "GetLinePermanentIdFromDeviceID failed for %d device",
  2885. dwDeviceID
  2886. ));
  2887. return FALSE;
  2888. }
  2889. BOOL
  2890. GetPhonePermanentIdFromDeviceID(
  2891. PTCLIENT ptClient,
  2892. DWORD dwDeviceID,
  2893. LPTAPIPERMANENTID pID
  2894. )
  2895. {
  2896. LPDWORD pDevices = ptClient->pPhoneDevices;
  2897. DWORD dwCount = ptClient->dwPhoneDevices;
  2898. while (dwCount)
  2899. {
  2900. dwCount--;
  2901. if (pDevices[dwCount] == dwDeviceID)
  2902. {
  2903. pID->dwProviderID = ptClient->pPhoneMap[dwCount].dwProviderID;
  2904. pID->dwDeviceID = ptClient->pPhoneMap[dwCount].dwDeviceID;
  2905. return TRUE;
  2906. }
  2907. }
  2908. LOG((TL_INFO,
  2909. "GetPhonePermanentIdFromDeviceID failed for %d device",
  2910. dwDeviceID
  2911. ));
  2912. return FALSE;
  2913. }
  2914. DWORD
  2915. GetDeviceIDFromPermanentID(
  2916. TAPIPERMANENTID ID,
  2917. BOOL bLine
  2918. )
  2919. /*++
  2920. Gets the regulare tapi device ID from the permanent ID
  2921. --*/
  2922. {
  2923. PPERMANENTIDARRAYHEADER pArrayHeader;
  2924. PPERMANENTIDELEMENT pArray;
  2925. LONG lLow, lHigh, lMid;
  2926. DWORD dwTotalElements;
  2927. DWORD dwPermanentID;
  2928. dwPermanentID = ID.dwDeviceID;
  2929. // get the array corresponding to this provider ID
  2930. GetProviderSortedArray (ID.dwProviderID, &pArrayHeader);
  2931. if (!pArrayHeader)
  2932. {
  2933. LOG((TL_ERROR, "Couldn't find the provider in the permanent array list!"));
  2934. return 0xFFFFFFFF;
  2935. }
  2936. //
  2937. // Serialize access to the device array
  2938. //
  2939. while (InterlockedExchange (&pArrayHeader->lCookie, 1) == 1)
  2940. {
  2941. Sleep (10);
  2942. }
  2943. // set up stuff for search
  2944. // dwCurrent is a total - subtract one to make it an index into array.
  2945. if (bLine)
  2946. {
  2947. lHigh = (LONG)(pArrayHeader->dwCurrentLines - 1);
  2948. pArray = pArrayHeader->pLineElements;
  2949. dwTotalElements = pArrayHeader->dwNumLines;
  2950. }
  2951. else
  2952. {
  2953. lHigh = (LONG)(pArrayHeader->dwCurrentPhones - 1);
  2954. pArray = pArrayHeader->pPhoneElements;
  2955. dwTotalElements = pArrayHeader->dwNumPhones;
  2956. }
  2957. lLow = 0;
  2958. // binary search through the provider's id array
  2959. // this search is from a book, so it must be right.
  2960. while (lHigh >= lLow)
  2961. {
  2962. lMid = (lHigh + lLow) / 2;
  2963. if (dwPermanentID == pArray[lMid].dwPermanentID)
  2964. {
  2965. InterlockedExchange (&pArrayHeader->lCookie, 0);
  2966. return pArray[lMid].dwDeviceID;
  2967. }
  2968. if (dwPermanentID < pArray[lMid].dwPermanentID)
  2969. {
  2970. lHigh = lMid-1;
  2971. }
  2972. else
  2973. {
  2974. lLow = lMid+1;
  2975. }
  2976. }
  2977. InterlockedExchange (&pArrayHeader->lCookie, 0);
  2978. return 0xFFFFFFFF;
  2979. }
  2980. void
  2981. InsertIntoTable(
  2982. BOOL bLine,
  2983. DWORD dwDeviceID,
  2984. PTPROVIDER ptProvider,
  2985. DWORD dwPermanentID
  2986. )
  2987. {
  2988. PPERMANENTIDARRAYHEADER pArrayHeader;
  2989. PPERMANENTIDELEMENT pArray;
  2990. LONG lLow, lHigh, lMid;
  2991. DWORD dwTotalElements, dwCurrentElements;
  2992. GetProviderSortedArray (ptProvider->dwPermanentProviderID, &pArrayHeader);
  2993. if (!pArrayHeader)
  2994. {
  2995. LOG((TL_ERROR, "Couldn't find the provider in the permanent array list!"));
  2996. return;
  2997. }
  2998. //
  2999. // Serialize access to the device array
  3000. //
  3001. while (InterlockedExchange (&pArrayHeader->lCookie, 1) == 1)
  3002. {
  3003. Sleep (10);
  3004. }
  3005. //
  3006. // set up stuff for search
  3007. // dwCurrent is a total - subtract one to make it an index into array.
  3008. //
  3009. if (bLine)
  3010. {
  3011. dwCurrentElements = pArrayHeader->dwCurrentLines;
  3012. pArray = pArrayHeader->pLineElements;
  3013. dwTotalElements = pArrayHeader->dwNumLines;
  3014. }
  3015. else
  3016. {
  3017. dwCurrentElements = pArrayHeader->dwCurrentPhones;
  3018. pArray = pArrayHeader->pPhoneElements;
  3019. dwTotalElements = pArrayHeader->dwNumPhones;
  3020. }
  3021. lLow = 0;
  3022. lHigh = dwCurrentElements-1;
  3023. // binary search
  3024. if (dwCurrentElements > 0)
  3025. {
  3026. while (TRUE)
  3027. {
  3028. lMid = ( lHigh + lLow ) / 2 + ( lHigh + lLow ) % 2;
  3029. if (lHigh < lLow)
  3030. {
  3031. break;
  3032. }
  3033. if (pArray[lMid].dwPermanentID == dwPermanentID)
  3034. {
  3035. LOG((TL_ERROR,
  3036. "Trying to insert an item already in the perm ID array"
  3037. ));
  3038. LOG((TL_ERROR,
  3039. "Provider %s, %s array, ID 0x%lu",
  3040. ptProvider->szFileName,
  3041. (bLine ? "Line" : "Phone"),
  3042. dwPermanentID
  3043. ));
  3044. }
  3045. if (pArray[lMid].dwPermanentID > dwPermanentID)
  3046. {
  3047. lHigh = lMid-1;
  3048. }
  3049. else
  3050. {
  3051. lLow = lMid+1;
  3052. }
  3053. }
  3054. }
  3055. //
  3056. // Grow the table if necessary
  3057. //
  3058. if (dwCurrentElements >= dwTotalElements)
  3059. {
  3060. PPERMANENTIDELEMENT pNewArray;
  3061. // realloc array by doubling it
  3062. if (!(pNewArray = ServerAlloc(
  3063. dwTotalElements * 2 * sizeof(PERMANENTIDELEMENT)
  3064. )))
  3065. {
  3066. InterlockedExchange (&pArrayHeader->lCookie, 0);
  3067. return;
  3068. }
  3069. // copy old stuff over
  3070. CopyMemory(
  3071. pNewArray,
  3072. pArray,
  3073. dwTotalElements * sizeof(PERMANENTIDELEMENT)
  3074. );
  3075. // free old array
  3076. ServerFree (pArray);
  3077. // save new array
  3078. if (bLine)
  3079. {
  3080. pArrayHeader->dwNumLines = dwTotalElements * 2;
  3081. pArray = pArrayHeader->pLineElements = pNewArray;
  3082. }
  3083. else
  3084. {
  3085. pArrayHeader->dwNumPhones = dwTotalElements * 2;
  3086. pArray = pArrayHeader->pPhoneElements = pNewArray;
  3087. }
  3088. }
  3089. // dwCurrentElements is a count (1 based), lLow is an index (0 based)
  3090. // if lLow is < dwcurrent, then it's getting inserted somewhere in the
  3091. // middle of the array, so scootch all the other elements out.
  3092. if (lLow < (LONG)dwCurrentElements)
  3093. {
  3094. MoveMemory(
  3095. &(pArray[lLow+1]),
  3096. &(pArray[lLow]),
  3097. sizeof(PERMANENTIDELEMENT) * (dwCurrentElements - lLow)
  3098. );
  3099. }
  3100. if (lLow > (LONG)dwCurrentElements)
  3101. {
  3102. LOG((TL_INFO,
  3103. "InsertIntoTable: lLow %d > dwCurrentElements %d",
  3104. lLow,
  3105. dwCurrentElements
  3106. ));
  3107. }
  3108. pArray[lLow].dwPermanentID = dwPermanentID;
  3109. pArray[lLow].dwDeviceID = dwDeviceID;
  3110. if (bLine)
  3111. {
  3112. pArrayHeader->dwCurrentLines++;
  3113. }
  3114. else
  3115. {
  3116. pArrayHeader->dwCurrentPhones++;
  3117. }
  3118. InterlockedExchange (&pArrayHeader->lCookie, 0);
  3119. }
  3120. void
  3121. FreeDll(
  3122. PTMANAGEDLLINFO pDll
  3123. )
  3124. {
  3125. }
  3126. LONG
  3127. AddProviderToIdArrayList(
  3128. PTPROVIDER ptProvider,
  3129. DWORD dwNumLines,
  3130. DWORD dwNumPhones
  3131. )
  3132. /*++
  3133. Adds a new provider corresponding array to the list of
  3134. permanent device ID arrays
  3135. --*/
  3136. {
  3137. PPERMANENTIDARRAYHEADER pNewArray;
  3138. //
  3139. // Alloc a header & arrays for this provider (make sure at least
  3140. // 1 entry in each array)
  3141. //
  3142. if (!(pNewArray = ServerAlloc(sizeof(PERMANENTIDARRAYHEADER))))
  3143. {
  3144. return LINEERR_NOMEM;
  3145. }
  3146. dwNumLines = (dwNumLines ? dwNumLines : 1);
  3147. dwNumPhones = (dwNumPhones ? dwNumPhones : 1);
  3148. pNewArray->pLineElements = ServerAlloc(
  3149. sizeof(PERMANENTIDELEMENT) * dwNumLines
  3150. );
  3151. pNewArray->pPhoneElements = ServerAlloc(
  3152. sizeof(PERMANENTIDELEMENT) * dwNumPhones
  3153. );
  3154. if ((!pNewArray->pLineElements) || (!pNewArray->pPhoneElements))
  3155. {
  3156. ServerFree (pNewArray->pLineElements);
  3157. ServerFree (pNewArray->pPhoneElements);
  3158. ServerFree (pNewArray);
  3159. return LINEERR_NOMEM;
  3160. }
  3161. //
  3162. // Initialize elements
  3163. //
  3164. pNewArray->dwNumLines = dwNumLines;
  3165. pNewArray->dwNumPhones = dwNumPhones;
  3166. pNewArray->dwCurrentLines = 0;
  3167. pNewArray->dwCurrentPhones = 0;
  3168. pNewArray->dwPermanentProviderID = ptProvider->dwPermanentProviderID;
  3169. //
  3170. // Insert at the beginning of the list
  3171. //
  3172. pNewArray->pNext = TapiGlobals.pIDArrays;
  3173. TapiGlobals.pIDArrays = pNewArray;
  3174. return 0;
  3175. }
  3176. LONG
  3177. GetDeviceAccess(
  3178. PTMANAGEDLLINFO pDll,
  3179. PTCLIENT ptClient,
  3180. HMANAGEMENTCLIENT hClient
  3181. )
  3182. /*++
  3183. Calls the mapper DLL to get the access map arrays for a client
  3184. --*/
  3185. {
  3186. LONG lResult;
  3187. DWORD dwLineDevs, dwPhoneDevs, dwCount;
  3188. DWORD dwNumLinesHold, dwNumPhonesHold, dwRealDevs;
  3189. LPTAPIPERMANENTID pLineMap = NULL, pPhoneMap = NULL;
  3190. #define DEFAULTACCESSDEVS 3
  3191. dwLineDevs = DEFAULTACCESSDEVS;
  3192. dwPhoneDevs = DEFAULTACCESSDEVS;
  3193. // alloc an default array size
  3194. if (!(pLineMap = ServerAlloc (dwLineDevs * sizeof (TAPIPERMANENTID))))
  3195. {
  3196. goto GetDeviceAccess_MemoryError;
  3197. }
  3198. if (!(pPhoneMap = ServerAlloc (dwPhoneDevs * sizeof (TAPIPERMANENTID))))
  3199. {
  3200. goto GetDeviceAccess_MemoryError;
  3201. }
  3202. // call the mapper dll
  3203. // LOG((TL_INFO, "Calling GetDeviceAccess in mapper DLL"));
  3204. while (TRUE)
  3205. {
  3206. dwNumLinesHold = dwLineDevs;
  3207. dwNumPhonesHold = dwPhoneDevs;
  3208. lResult = (pDll->aProcs[TC_GETDEVICEACCESS])(
  3209. hClient,
  3210. ptClient,
  3211. pLineMap,
  3212. &dwLineDevs,
  3213. pPhoneMap,
  3214. &dwPhoneDevs
  3215. );
  3216. if (lResult == LINEERR_STRUCTURETOOSMALL)
  3217. {
  3218. if (dwLineDevs < dwNumLinesHold)
  3219. {
  3220. LOG((TL_ERROR,
  3221. "Returned STRUCTURETOOSMALL, but specified less " \
  3222. "line devs in TAPICLINET_GETDEVICEACCESS"
  3223. ));
  3224. }
  3225. if (dwPhoneDevs < dwNumPhonesHold)
  3226. {
  3227. LOG((TL_ERROR,
  3228. "Returned STRUCTURETOOSMALL, but specified less " \
  3229. "phone devs in TAPICLINET_GETDEVICEACCESS"
  3230. ));
  3231. }
  3232. // realloc
  3233. ServerFree (pLineMap);
  3234. if (!(pLineMap = ServerAlloc(
  3235. dwLineDevs * sizeof (TAPIPERMANENTID)
  3236. )))
  3237. {
  3238. goto GetDeviceAccess_MemoryError;
  3239. }
  3240. ServerFree (pPhoneMap);
  3241. if (!(pPhoneMap = ServerAlloc(
  3242. dwPhoneDevs * sizeof ( TAPIPERMANENTID)
  3243. )))
  3244. {
  3245. goto GetDeviceAccess_MemoryError;
  3246. }
  3247. }
  3248. else
  3249. {
  3250. break;
  3251. }
  3252. }
  3253. // if still an error
  3254. if (lResult)
  3255. {
  3256. LOG((TL_ERROR, "GetDeviceAccess failed - error %lu", lResult));
  3257. ServerFree (pLineMap);
  3258. ServerFree (pPhoneMap);
  3259. return lResult;
  3260. }
  3261. if (dwLineDevs > dwNumLinesHold)
  3262. {
  3263. LOG((TL_ERROR, "Returned dwLineDevs greater that the buffer specified in TAPICLIENT_GETDEVICEACCESS"));
  3264. LOG((TL_ERROR, " Will only use the number the buffer can hold"));
  3265. dwLineDevs = dwNumLinesHold;
  3266. }
  3267. if (dwPhoneDevs > dwNumPhonesHold)
  3268. {
  3269. LOG((TL_ERROR, "Returned dwPhoneDevs greater that the buffer specified in TAPICLIENT_GETDEVICEACCESS"));
  3270. LOG((TL_ERROR, " Will only use the number the buffer can hold"));
  3271. dwPhoneDevs = dwNumPhonesHold;
  3272. }
  3273. // alloc another array for regular tapi device IDs
  3274. if (!(ptClient->pLineDevices = ServerAlloc( dwLineDevs * sizeof (DWORD) ) ) )
  3275. {
  3276. goto GetDeviceAccess_MemoryError;
  3277. }
  3278. // alloc a permanent ID array
  3279. if (!(ptClient->pLineMap = ServerAlloc( dwLineDevs * sizeof (TAPIPERMANENTID) ) ) )
  3280. {
  3281. goto GetDeviceAccess_MemoryError;
  3282. }
  3283. // loop through all the mapped elements and get the regular
  3284. // tapi device ID
  3285. dwRealDevs = 0;
  3286. for (dwCount = 0; dwCount < dwLineDevs; dwCount++)
  3287. {
  3288. DWORD dwID;
  3289. dwID = GetDeviceIDFromPermanentID(
  3290. pLineMap[dwCount],
  3291. TRUE
  3292. );
  3293. // make sure it's a good id
  3294. if ( dwID != 0xffffffff )
  3295. {
  3296. // save it
  3297. ptClient->pLineDevices[dwRealDevs] = dwID;
  3298. ptClient->pLineMap[dwRealDevs].dwProviderID = pLineMap[dwCount].dwProviderID;
  3299. ptClient->pLineMap[dwRealDevs].dwDeviceID = pLineMap[dwCount].dwDeviceID;
  3300. // inc real devs
  3301. dwRealDevs++;
  3302. }
  3303. }
  3304. // save the real number of devices
  3305. ptClient->dwLineDevices = dwRealDevs;
  3306. // free the line map
  3307. ServerFree (pLineMap);
  3308. // now do phone devices
  3309. if (!(ptClient->pPhoneDevices = ServerAlloc( dwPhoneDevs * sizeof (DWORD) ) ) )
  3310. {
  3311. goto GetDeviceAccess_MemoryError;
  3312. }
  3313. if (!(ptClient->pPhoneMap = ServerAlloc( dwPhoneDevs * sizeof (TAPIPERMANENTID) ) ) )
  3314. {
  3315. goto GetDeviceAccess_MemoryError;
  3316. }
  3317. dwRealDevs = 0;
  3318. for (dwCount = 0; dwCount < dwPhoneDevs; dwCount++)
  3319. {
  3320. DWORD dwID;
  3321. dwID = GetDeviceIDFromPermanentID(
  3322. pPhoneMap[dwCount],
  3323. FALSE
  3324. );
  3325. if ( 0xffffffff != dwID )
  3326. {
  3327. ptClient->pPhoneDevices[dwRealDevs] = dwID;
  3328. ptClient->pPhoneMap[dwRealDevs].dwProviderID = pPhoneMap[dwCount].dwProviderID;
  3329. ptClient->pPhoneMap[dwRealDevs].dwDeviceID = pPhoneMap[dwCount].dwDeviceID;
  3330. dwRealDevs++;
  3331. }
  3332. }
  3333. // save the real number of devices
  3334. ptClient->dwPhoneDevices = dwRealDevs;
  3335. // free the original map
  3336. ServerFree (pPhoneMap);
  3337. return 0;
  3338. GetDeviceAccess_MemoryError:
  3339. if (pLineMap != NULL)
  3340. ServerFree (pLineMap);
  3341. if (pPhoneMap != NULL)
  3342. ServerFree (pPhoneMap);
  3343. if (ptClient->pLineMap != NULL)
  3344. ServerFree (ptClient->pLineMap);
  3345. if (ptClient->pPhoneMap != NULL)
  3346. ServerFree (ptClient->pPhoneMap);
  3347. return LINEERR_NOMEM;
  3348. }
  3349. LONG
  3350. InitializeClient(
  3351. PTCLIENT ptClient
  3352. )
  3353. {
  3354. PTMANAGEDLLINFO pDll;
  3355. PTMANAGEDLLLISTHEADER pDllList;
  3356. PTCLIENTHANDLE pClientHandle = NULL;
  3357. LONG lResult = 0;
  3358. if (!(TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) ||
  3359. IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR))
  3360. {
  3361. return 0;
  3362. }
  3363. // call the mapper DLL
  3364. pDll = TapiGlobals.pMapperDll;
  3365. lResult = (pDll->aProcs[TC_CLIENTINITIALIZE])(
  3366. ptClient->pszDomainName,
  3367. ptClient->pszUserName,
  3368. ptClient->pszComputerName,
  3369. &ptClient->hMapper
  3370. );
  3371. if (lResult != 0)
  3372. {
  3373. // error on init
  3374. LOG((TL_ERROR, "ClientInitialize internal failure - error %lu", lResult));
  3375. //LOG((TL_ERROR, "Disabling the Telephony server! (2)"));
  3376. //TapiGlobals.bServer = FALSE;
  3377. //CleanUpManagementMemory();
  3378. return lResult;
  3379. }
  3380. if (lResult = GetDeviceAccess(
  3381. pDll,
  3382. ptClient,
  3383. ptClient->hMapper
  3384. ))
  3385. {
  3386. LOG((TL_ERROR, "GetDeviceAccess failed - error x%lx", lResult));
  3387. //LOG((TL_ERROR, "Disabling the Telephony server! (3)"));
  3388. //TapiGlobals.bServer = FALSE;
  3389. //CleanUpManagementMemory();
  3390. return lResult;
  3391. }
  3392. // get the manage dll list
  3393. GetManageDllListPointer(&pDllList);
  3394. if (pDllList && (pDll = pDllList->pFirst))
  3395. {
  3396. if (!(pClientHandle = ServerAlloc(sizeof(TCLIENTHANDLE))))
  3397. {
  3398. lResult = LINEERR_NOMEM;
  3399. goto clientinit_exit;
  3400. }
  3401. ptClient->pClientHandles = pClientHandle;
  3402. while (pDll)
  3403. {
  3404. // walk the list and call init for this client
  3405. pClientHandle->dwID = pDll->dwID;
  3406. pClientHandle->fValid = TRUE;
  3407. // call init
  3408. if (lResult = (pDll->aProcs[TC_CLIENTINITIALIZE])(
  3409. ptClient->pszDomainName,
  3410. ptClient->pszUserName,
  3411. ptClient->pszComputerName,
  3412. &pClientHandle->hClient
  3413. ))
  3414. {
  3415. // failed client init
  3416. LOG((TL_ERROR, "ClientInitialize failed for %ls, result x%lx", pDll->pszName, lResult));
  3417. pClientHandle->fValid = FALSE;
  3418. }
  3419. lResult = 0;
  3420. // if there's another DLL, setup another structure
  3421. if (pDll = pDll->pNext)
  3422. {
  3423. if (!(pClientHandle->pNext = ServerAlloc(sizeof(TCLIENTHANDLE))))
  3424. {
  3425. lResult = LINEERR_NOMEM;
  3426. goto clientinit_exit;
  3427. }
  3428. pClientHandle = pClientHandle->pNext;
  3429. }
  3430. }
  3431. }
  3432. clientinit_exit:
  3433. FreeManageDllListPointer(pDllList);
  3434. return lResult;
  3435. }
  3436. #endif
  3437. LONG
  3438. ClientAttach(
  3439. PCONTEXT_HANDLE_TYPE *pphContext,
  3440. long lProcessID,
  3441. long *phAsyncEventsEvent,
  3442. wchar_t *pszDomainUser,
  3443. wchar_t *pszMachineIn
  3444. )
  3445. {
  3446. PTCLIENT ptClient;
  3447. wchar_t *pszMachine;
  3448. wchar_t *pProtocolSequence;
  3449. wchar_t *pProtocolEndpoint;
  3450. wchar_t *pPlaceHolder;
  3451. LONG lResult = 0;
  3452. LOG((TL_TRACE,
  3453. "ClientAttach: enter, pid=x%x, user='%ls', machine='%ls'",
  3454. lProcessID,
  3455. pszDomainUser,
  3456. pszMachineIn
  3457. ));
  3458. //
  3459. // The new remotesp will send in pszMachine thus:
  3460. // machinename"binding0"endpoint0" ... bindingN"endpointN"
  3461. //
  3462. pszMachine = pszMachineIn;
  3463. if ( pPlaceHolder = wcschr( pszMachineIn, L'\"' ) )
  3464. {
  3465. *pPlaceHolder = L'\0';
  3466. pProtocolSequence = pPlaceHolder + 1;
  3467. }
  3468. //
  3469. // Alloc & init a tClient struct
  3470. //
  3471. if (!(ptClient = ServerAlloc (sizeof(TCLIENT))))
  3472. {
  3473. goto ClientAttach_error0;
  3474. }
  3475. ptClient->htClient = NewObject(
  3476. ghHandleTable, ptClient, NULL);
  3477. if (ptClient->htClient == 0)
  3478. {
  3479. ServerFree(ptClient);
  3480. goto ClientAttach_error0;
  3481. }
  3482. if (!(ptClient->pEventBuffer = ServerAlloc(
  3483. INITIAL_EVENT_BUFFER_SIZE
  3484. )))
  3485. {
  3486. goto ClientAttach_error1;
  3487. }
  3488. ptClient->dwEventBufferTotalSize = INITIAL_EVENT_BUFFER_SIZE;
  3489. ptClient->dwEventBufferUsedSize = 0;
  3490. ptClient->pDataIn = ptClient->pDataOut = ptClient->pEventBuffer;
  3491. ptClient->pClientHandles = NULL;
  3492. #if TELE_SERVER
  3493. if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) ||
  3494. ((lProcessID == 0xfffffffd) && gbNTServer))
  3495. {
  3496. #define NAMEBUFSIZE 96
  3497. WCHAR szAccountName[NAMEBUFSIZE],
  3498. szDomainName[NAMEBUFSIZE];
  3499. DWORD dwInfoBufferSize, dwSize,
  3500. dwAccountNameSize = NAMEBUFSIZE *sizeof(WCHAR),
  3501. dwDomainNameSize = NAMEBUFSIZE *sizeof(WCHAR);
  3502. HANDLE hThread, hAccessToken;
  3503. LPWSTR InfoBuffer = NULL;
  3504. PSID psidAdministrators;
  3505. SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
  3506. UINT x;
  3507. PTOKEN_USER ptuUser;
  3508. SID_NAME_USE use;
  3509. RPC_STATUS status;
  3510. //
  3511. // If an authorized user did a NET PAUSE TAPISRV, don't allow new
  3512. // remote clients.
  3513. //
  3514. if ( TapiGlobals.dwFlags & TAPIGLOBALS_PAUSED )
  3515. {
  3516. if ((lProcessID == 0xffffffff) || (lProcessID == 0xfffffffd))
  3517. {
  3518. LOG((TL_ERROR, "A client tried to attach, but TAPISRV is PAUSED"));
  3519. goto Admin_error;
  3520. }
  3521. }
  3522. if ((status = RpcImpersonateClient (0)) != RPC_S_OK)
  3523. {
  3524. LOG((TL_ERROR,
  3525. "ClientAttach: RpcImpersonateClient failed, err=%d",
  3526. status
  3527. ));
  3528. goto Admin_error;
  3529. }
  3530. hThread = GetCurrentThread(); // Note: no need to close this handle
  3531. if (!OpenThreadToken (hThread, TOKEN_READ, FALSE, &hAccessToken))
  3532. {
  3533. LOG((TL_ERROR,
  3534. "ClientAttach: OpenThreadToken failed, err=%d",
  3535. GetLastError()
  3536. ));
  3537. RpcRevertToSelf();
  3538. goto Admin_error;
  3539. }
  3540. dwSize = 2048;
  3541. alloc_infobuffer:
  3542. dwInfoBufferSize = 0;
  3543. if (!(InfoBuffer = (LPWSTR) ServerAlloc (dwSize)))
  3544. {
  3545. CloseHandle (hAccessToken);
  3546. RpcRevertToSelf();
  3547. goto ClientAttach_error2;
  3548. }
  3549. // first get the user name and domain name
  3550. ptuUser = (PTOKEN_USER) InfoBuffer;
  3551. if (!GetTokenInformation(
  3552. hAccessToken,
  3553. TokenUser,
  3554. InfoBuffer,
  3555. dwSize,
  3556. &dwInfoBufferSize
  3557. ))
  3558. {
  3559. LOG((TL_ERROR,
  3560. "ClientAttach: GetTokenInformation failed, err=%d",
  3561. GetLastError()
  3562. ));
  3563. ServerFree (InfoBuffer);
  3564. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  3565. {
  3566. dwSize *= 2;
  3567. goto alloc_infobuffer;
  3568. }
  3569. CloseHandle (hAccessToken);
  3570. RpcRevertToSelf();
  3571. goto Admin_error;
  3572. }
  3573. if (!LookupAccountSidW(
  3574. NULL,
  3575. ptuUser->User.Sid,
  3576. szAccountName,
  3577. &dwAccountNameSize,
  3578. szDomainName,
  3579. &dwDomainNameSize,
  3580. &use
  3581. ))
  3582. {
  3583. LOG((TL_ERROR,
  3584. "ClientAttach: LookupAccountSidW failed, err=%d",
  3585. GetLastError()
  3586. ));
  3587. ServerFree (InfoBuffer);
  3588. CloseHandle (hAccessToken);
  3589. RpcRevertToSelf();
  3590. goto Admin_error;
  3591. }
  3592. LOG((TL_INFO,
  3593. "ClientAttach: LookupAccountSidW: User name %ls Domain name %ls",
  3594. szAccountName,
  3595. szDomainName
  3596. ));
  3597. //
  3598. // Get administrator status
  3599. //
  3600. if (AllocateAndInitializeSid(
  3601. &siaNtAuthority,
  3602. 2,
  3603. SECURITY_BUILTIN_DOMAIN_RID,
  3604. DOMAIN_ALIAS_RID_ADMINS,
  3605. 0, 0, 0, 0, 0, 0,
  3606. &psidAdministrators
  3607. )
  3608. )
  3609. {
  3610. BOOL bAdmin = FALSE;
  3611. RESET_FLAG(ptClient->dwFlags,PTCLIENT_FLAG_ADMINISTRATOR);
  3612. if (!CheckTokenMembership(
  3613. hAccessToken,
  3614. psidAdministrators,
  3615. &bAdmin
  3616. ))
  3617. {
  3618. LOG((TL_ERROR,
  3619. "ClientAttach: CheckTokenMembership failed, err=%d",
  3620. GetLastError()
  3621. ));
  3622. }
  3623. //
  3624. // If both the client & server machine has blank
  3625. // password for local administrator account, and if
  3626. // remotesp runs in local admin account on remote machine
  3627. // NTLM will actually think RPC request is from
  3628. // server_machine\administrator, thus falsely set
  3629. // bAdmin to be true.
  3630. //
  3631. if (bAdmin && lProcessID == 0xffffffff)
  3632. {
  3633. WCHAR szLocalComp[NAMEBUFSIZE];
  3634. dwSize = sizeof(szLocalComp) / sizeof(WCHAR);
  3635. if (GetComputerNameW (
  3636. szLocalComp,
  3637. &dwSize
  3638. ) &&
  3639. _wcsicmp (szLocalComp, szDomainName) == 0
  3640. )
  3641. {
  3642. bAdmin = FALSE;
  3643. wcsncpy (
  3644. szDomainName,
  3645. pszMachine,
  3646. sizeof(szLocalComp) / sizeof(WCHAR)
  3647. );
  3648. szDomainName[sizeof(szLocalComp) / sizeof(WCHAR) - 1] = 0;
  3649. }
  3650. }
  3651. if (bAdmin)
  3652. {
  3653. SET_FLAG(ptClient->dwFlags,PTCLIENT_FLAG_ADMINISTRATOR);
  3654. }
  3655. FreeSid (psidAdministrators);
  3656. if (!IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR))
  3657. {
  3658. //
  3659. // Check to see if client is a TAPI admin, as
  3660. // specified in the TAPI MMC Snapin. This is
  3661. // determined simply by looking for a
  3662. // <Domain>\<User>=1 value under the TapiAdministrators
  3663. // section in tsec.ini.
  3664. //
  3665. wcscpy ((WCHAR *) InfoBuffer, szDomainName);
  3666. wcscat ((WCHAR *) InfoBuffer, L"\\");
  3667. wcscat ((WCHAR *) InfoBuffer, szAccountName);
  3668. if (GetPrivateProfileIntW(
  3669. gszTapiAdministrators,
  3670. (LPCWSTR) InfoBuffer,
  3671. 0,
  3672. gszFileName
  3673. ) == 1)
  3674. {
  3675. SET_FLAG(ptClient->dwFlags,PTCLIENT_FLAG_ADMINISTRATOR);
  3676. }
  3677. }
  3678. }
  3679. else
  3680. {
  3681. LOG((TL_ERROR,
  3682. "ClientAttach: AllocateAndInitializeSid failed, err=%d",
  3683. GetLastError()
  3684. ));
  3685. ServerFree (InfoBuffer);
  3686. CloseHandle (hAccessToken);
  3687. RpcRevertToSelf();
  3688. goto Admin_error;
  3689. }
  3690. ServerFree (InfoBuffer);
  3691. CloseHandle (hAccessToken);
  3692. RpcRevertToSelf();
  3693. //
  3694. // Save the user, domain, & machine names
  3695. //
  3696. ptClient->dwUserNameSize =
  3697. (lstrlenW (szAccountName) + 1) * sizeof (WCHAR);
  3698. if (!(ptClient->pszUserName = ServerAlloc (ptClient->dwUserNameSize)))
  3699. {
  3700. goto ClientAttach_error2;
  3701. }
  3702. wcscpy (ptClient->pszUserName, szAccountName);
  3703. if (!(ptClient->pszDomainName = ServerAlloc(
  3704. (lstrlenW (szDomainName) + 1) * sizeof(WCHAR)
  3705. )))
  3706. {
  3707. goto ClientAttach_error3;
  3708. }
  3709. wcscpy (ptClient->pszDomainName, szDomainName);
  3710. if ((lProcessID == 0xffffffff) || (lProcessID == 0xfffffffd))
  3711. {
  3712. ptClient->dwComputerNameSize =
  3713. (1 + lstrlenW (pszMachine)) * sizeof(WCHAR);
  3714. if (!(ptClient->pszComputerName = ServerAlloc(
  3715. ptClient->dwComputerNameSize
  3716. )))
  3717. {
  3718. goto ClientAttach_error4;
  3719. }
  3720. wcscpy (ptClient->pszComputerName, pszMachine);
  3721. }
  3722. }
  3723. else
  3724. {
  3725. ptClient->dwUserNameSize =
  3726. (lstrlenW (pszDomainUser) + 1) * sizeof(WCHAR);
  3727. if (!(ptClient->pszUserName = ServerAlloc (ptClient->dwUserNameSize)))
  3728. {
  3729. goto ClientAttach_error2;
  3730. }
  3731. wcscpy (ptClient->pszUserName, pszDomainUser);
  3732. }
  3733. #else
  3734. ptClient->dwUserNameSize = (lstrlenW (pszDomainUser) + 1) * sizeof(WCHAR);
  3735. if (!(ptClient->pszUserName = ServerAlloc (ptClient->dwUserNameSize)))
  3736. {
  3737. goto ClientAttach_error2;
  3738. }
  3739. wcscpy (ptClient->pszUserName, pszDomainUser);
  3740. #endif
  3741. if (lProcessID == 0xffffffff)
  3742. {
  3743. //
  3744. // This is a remote client
  3745. //
  3746. #if TELE_SERVER
  3747. if (0 == (TapiGlobals.dwFlags & TAPIGLOBALS_SERVER))
  3748. #endif
  3749. {
  3750. //
  3751. // This machine has been set up to _not_ be a server so fail
  3752. //
  3753. ServerFree (ptClient->pszUserName);
  3754. LOG((TL_ERROR,
  3755. "ClientAttach: attach request received, but this is " \
  3756. "not a telephony svr!"
  3757. ));
  3758. goto Admin_error;
  3759. }
  3760. #if TELE_SERVER
  3761. //
  3762. // Special hack introduced because in SP4 beta I nullified the
  3763. // entry in gaFuncs[] corresponding to the old-lOpenInt /
  3764. // new-xNegotiateAPIVersionForAllDevices. So if a newer
  3765. // remotesp tries to send a NegoAllDevices request to an
  3766. // SP4 beta then tapisrv on the server will blow up.
  3767. //
  3768. // By setting *phAsyncEventsEvent = to a secret value remotesp
  3769. // knows whether or not it's ok to send a NegoAllDevices request.
  3770. //
  3771. *phAsyncEventsEvent = 0xa5c369a5;
  3772. //
  3773. // If pszDomainUser is non-empty then it contains the
  3774. // name of a mailslot that we can open & write to to
  3775. // indicate when async events are pending for this client.
  3776. //
  3777. if (wcslen (pszDomainUser) > 0)
  3778. {
  3779. ptClient->hProcess = (HANDLE) DG_CLIENT;
  3780. if ((ptClient->hMailslot = CreateFileW(
  3781. pszDomainUser,
  3782. GENERIC_WRITE,
  3783. FILE_SHARE_READ,
  3784. (LPSECURITY_ATTRIBUTES) NULL,
  3785. OPEN_EXISTING,
  3786. FILE_ATTRIBUTE_NORMAL,
  3787. (HANDLE) NULL
  3788. )) != INVALID_HANDLE_VALUE)
  3789. {
  3790. goto ClientAttach_AddClientToList;
  3791. }
  3792. LOG((TL_ERROR,
  3793. "ClientAttach: CreateFile(%ws) failed, err=%d",
  3794. pszDomainUser,
  3795. GetLastError()
  3796. ));
  3797. LOG((TL_ERROR,
  3798. "ClientAttach: trying connection-oriented approach...",
  3799. pszDomainUser,
  3800. GetLastError()
  3801. ));
  3802. }
  3803. ptClient->hProcess = (HANDLE) CN_CLIENT;
  3804. //
  3805. //
  3806. //
  3807. {
  3808. RPC_STATUS status;
  3809. PCONTEXT_HANDLE_TYPE2 phContext = NULL;
  3810. WCHAR *pszStringBinding = NULL;
  3811. WCHAR *pszMachineName;
  3812. BOOL bError;
  3813. // Allocate enough incase we have to prepend...
  3814. pszMachineName = ServerAlloc(
  3815. (lstrlenW(pszMachine) + 3) * sizeof(WCHAR)
  3816. );
  3817. if (!pszMachineName)
  3818. {
  3819. goto ClientAttach_error5;
  3820. }
  3821. //
  3822. // Should we prepend whackwhack?
  3823. //
  3824. if (!_wcsicmp (L"ncacn_np", pProtocolSequence))
  3825. {
  3826. //
  3827. // Yes. It's needed for named pipes
  3828. //
  3829. pszMachineName[0] = '\\';
  3830. pszMachineName[1] = '\\';
  3831. wcscpy (pszMachineName + 2, pszMachine);
  3832. }
  3833. else
  3834. {
  3835. //
  3836. // Don't prepend \\
  3837. //
  3838. wcscpy (pszMachineName, pszMachine);
  3839. }
  3840. //
  3841. // Serialize access to hRemoteSP
  3842. //
  3843. EnterCriticalSection (&TapiGlobals.RemoteSPCritSec);
  3844. //
  3845. // Try to find a protseq/endpoint pair in the list passed
  3846. // to us by the client that works ok
  3847. //
  3848. find_protocol_sequence:
  3849. do
  3850. {
  3851. //
  3852. // New strings look like: prot1"ep1"prot2"ep2"\0
  3853. // ...where there's one or more protseq/enpoint combos,
  3854. // each members of which is followed by a dbl-quote char
  3855. //
  3856. // Old strings look like: prot"ep\0
  3857. // ...where there's only one protseq/endpoint combo,
  3858. // and the endpoint member is followed by a \0 (no dbl-quote)
  3859. //
  3860. pPlaceHolder = wcschr (pProtocolSequence, L'\"');
  3861. *pPlaceHolder = L'\0';
  3862. pProtocolEndpoint = pPlaceHolder + 1;
  3863. if ((pPlaceHolder = wcschr (pProtocolEndpoint, L'\"')))
  3864. {
  3865. *pPlaceHolder = L'\0';
  3866. }
  3867. else
  3868. {
  3869. //
  3870. // If this is an old-style string then munge
  3871. // pPlaceHolder such that the error handling
  3872. // code down below doesn't jump back up here
  3873. // to get the next protseq/endpoint combo
  3874. //
  3875. pPlaceHolder = pProtocolEndpoint +
  3876. wcslen (pProtocolEndpoint) - 1;
  3877. }
  3878. RpcTryExcept
  3879. {
  3880. status = RpcStringBindingComposeW(
  3881. NULL, // uuid
  3882. pProtocolSequence,
  3883. pszMachineName, // server name
  3884. pProtocolEndpoint,
  3885. NULL, // options
  3886. &pszStringBinding
  3887. );
  3888. if (status != 0)
  3889. {
  3890. LOG((TL_ERROR,
  3891. "ClientAttach: RpcStringBindingComposeW " \
  3892. "failed, err=%d",
  3893. status
  3894. ));
  3895. }
  3896. status = RpcBindingFromStringBindingW(
  3897. pszStringBinding,
  3898. &hRemoteSP
  3899. );
  3900. if (status != 0)
  3901. {
  3902. LOG((TL_ERROR,
  3903. "ClientAttach: RpcBindingFromStringBinding " \
  3904. "failed, err=%d",
  3905. status
  3906. ));
  3907. LOG((TL_INFO,
  3908. "\t szMachine=%ws, protseq=%ws endpoint=%ws",
  3909. pszMachine,
  3910. pProtocolSequence,
  3911. pProtocolEndpoint
  3912. ));
  3913. }
  3914. }
  3915. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode()))
  3916. {
  3917. //
  3918. // Set status != 0 so our error handler below executes
  3919. //
  3920. status = 1;
  3921. }
  3922. RpcEndExcept
  3923. if (status != 0)
  3924. {
  3925. RpcStringFreeW (&pszStringBinding);
  3926. pProtocolSequence = pPlaceHolder + 1;
  3927. }
  3928. } while (status != 0 && *pProtocolSequence);
  3929. if (status != 0)
  3930. {
  3931. LOG((TL_ERROR,
  3932. "ClientAttach: error, can't find a usable protseq"
  3933. ));
  3934. LeaveCriticalSection (&TapiGlobals.RemoteSPCritSec);
  3935. ServerFree (pszMachineName);
  3936. goto ClientAttach_error5;
  3937. }
  3938. LOG((TL_TRACE,
  3939. "ClientAttach: szMachine=%ws trying protseq=%ws endpoint=%ws",
  3940. pszMachine,
  3941. pProtocolSequence,
  3942. pProtocolEndpoint
  3943. ));
  3944. RpcTryExcept
  3945. {
  3946. status = RpcBindingSetAuthInfo(
  3947. hRemoteSP,
  3948. NULL,
  3949. RPC_C_AUTHN_LEVEL_DEFAULT,
  3950. RPC_C_AUTHN_WINNT,
  3951. NULL,
  3952. 0
  3953. );
  3954. RemoteSPAttach ((PCONTEXT_HANDLE_TYPE2 *) &phContext);
  3955. bError = FALSE;
  3956. }
  3957. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode()))
  3958. {
  3959. LOG((TL_ERROR,
  3960. "ClientAttach: RemoteSPAttach failed. Exception %d",
  3961. RpcExceptionCode()
  3962. ));
  3963. bError = TRUE;
  3964. }
  3965. RpcEndExcept
  3966. RpcTryExcept
  3967. {
  3968. RpcBindingFree (&hRemoteSP);
  3969. RpcStringFreeW (&pszStringBinding);
  3970. }
  3971. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode()))
  3972. {
  3973. // do nothing
  3974. }
  3975. RpcEndExcept
  3976. LeaveCriticalSection (&TapiGlobals.RemoteSPCritSec);
  3977. if (bError)
  3978. {
  3979. //
  3980. // If there's at least one other protocol we can try
  3981. // then go for it, otherwise jump to error handler
  3982. //
  3983. pProtocolSequence = pPlaceHolder + 1;
  3984. if (*pProtocolSequence)
  3985. {
  3986. EnterCriticalSection (&TapiGlobals.RemoteSPCritSec);
  3987. goto find_protocol_sequence;
  3988. }
  3989. ServerFree (pszMachineName);
  3990. goto ClientAttach_error5;
  3991. }
  3992. ServerFree (pszMachineName);
  3993. // RevertToSelf();
  3994. ptClient->phContext = phContext;
  3995. }
  3996. #endif // TELE_SERVER
  3997. }
  3998. else if (lProcessID == 0xfffffffd)
  3999. {
  4000. if (!gbNTServer)
  4001. {
  4002. lResult = LINEERR_OPERATIONFAILED;
  4003. goto ClientAttach_error5;
  4004. }
  4005. //
  4006. // Deny the access if not the admin
  4007. //
  4008. if (!IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR))
  4009. {
  4010. lResult = TAPIERR_NOTADMIN;
  4011. goto ClientAttach_error5;
  4012. }
  4013. ptClient->hProcess = (HANDLE) MMC_CLIENT;
  4014. #if WIN64
  4015. *phAsyncEventsEvent = 0x64646464;
  4016. #else
  4017. *phAsyncEventsEvent = 0x32323232;
  4018. #endif
  4019. }
  4020. else
  4021. {
  4022. RPC_STATUS rpcStatus;
  4023. //
  4024. // Open a handle to the client process. We will use this to duplicate an
  4025. // event handle into that process.
  4026. //
  4027. rpcStatus = RpcImpersonateClient (NULL);
  4028. if (RPC_S_OK != rpcStatus)
  4029. {
  4030. LOG((TL_ERROR,
  4031. "RpcImpersonateClient failed, err=%d",
  4032. rpcStatus));
  4033. goto ClientAttach_error5;
  4034. }
  4035. if (!(ptClient->hProcess = OpenProcess(
  4036. PROCESS_DUP_HANDLE,
  4037. FALSE,
  4038. lProcessID
  4039. )))
  4040. {
  4041. LOG((TL_ERROR,
  4042. "OpenProcess(pid=x%x) failed, err=%d",
  4043. lProcessID,
  4044. GetLastError()
  4045. ));
  4046. RpcRevertToSelf ();
  4047. goto ClientAttach_error5;
  4048. }
  4049. //
  4050. // This is a local client, so set up all the event buffer stuff
  4051. //
  4052. ptClient->dwComputerNameSize = TapiGlobals.dwComputerNameSize;
  4053. ptClient->pszComputerName = TapiGlobals.pszComputerName;
  4054. if (!(ptClient->hValidEventBufferDataEvent = CreateEvent(
  4055. (LPSECURITY_ATTRIBUTES) NULL,
  4056. TRUE, // manual-reset
  4057. FALSE, // nonsignaled
  4058. NULL // unnamed
  4059. )))
  4060. {
  4061. RpcRevertToSelf ();
  4062. goto ClientAttach_error5;
  4063. }
  4064. if (!DuplicateHandle(
  4065. TapiGlobals.hProcess,
  4066. ptClient->hValidEventBufferDataEvent,
  4067. ptClient->hProcess,
  4068. (HANDLE *) phAsyncEventsEvent,
  4069. 0,
  4070. FALSE,
  4071. DUPLICATE_SAME_ACCESS
  4072. ))
  4073. {
  4074. LOG((TL_ERROR,
  4075. "ClientAttach: DupHandle failed, err=%d",
  4076. GetLastError()
  4077. ));
  4078. }
  4079. RpcRevertToSelf ();
  4080. //
  4081. // Load the priority lists if we haven't already done so
  4082. //
  4083. if (gbPriorityListsInitialized == FALSE)
  4084. {
  4085. RPC_STATUS status;
  4086. if ((status = RpcImpersonateClient (0)) != RPC_S_OK)
  4087. {
  4088. LOG((TL_ERROR,
  4089. "ClientAttach: RpcImpersonateClient failed, err=%d",
  4090. status
  4091. ));
  4092. lResult = LINEERR_OPERATIONFAILED;
  4093. goto ClientAttach_error5;
  4094. }
  4095. EnterCriticalSection (&gPriorityListCritSec);
  4096. if (gbPriorityListsInitialized == FALSE)
  4097. {
  4098. HKEY hKeyHandoffPriorities, hKeyCurrentUser;
  4099. LONG lResult;
  4100. gbPriorityListsInitialized = TRUE;
  4101. if (ERROR_SUCCESS ==
  4102. (lResult = RegOpenCurrentUser (KEY_ALL_ACCESS, &hKeyCurrentUser)))
  4103. {
  4104. if ((lResult = RegOpenKeyEx(
  4105. hKeyCurrentUser,
  4106. gszRegKeyHandoffPriorities,
  4107. 0,
  4108. KEY_READ,
  4109. &hKeyHandoffPriorities
  4110. )) == ERROR_SUCCESS)
  4111. {
  4112. HKEY hKeyMediaModes;
  4113. DWORD dwDisp;
  4114. if ((lResult = RegCreateKeyEx(
  4115. hKeyHandoffPriorities,
  4116. gszRegKeyHandoffPrioritiesMediaModes,
  4117. 0,
  4118. TEXT(""),
  4119. REG_OPTION_NON_VOLATILE,
  4120. KEY_ALL_ACCESS,
  4121. NULL,
  4122. &hKeyMediaModes,
  4123. &dwDisp
  4124. )) == ERROR_SUCCESS)
  4125. {
  4126. GetMediaModesPriorityLists(
  4127. hKeyMediaModes,
  4128. &(TapiGlobals.pPriLists)
  4129. );
  4130. RegCloseKey( hKeyMediaModes );
  4131. }
  4132. GetPriorityList(
  4133. hKeyHandoffPriorities,
  4134. gszRequestMakeCallW,
  4135. &TapiGlobals.pszReqMakeCallPriList
  4136. );
  4137. GetPriorityList(
  4138. hKeyHandoffPriorities,
  4139. gszRequestMediaCallW,
  4140. &TapiGlobals.pszReqMediaCallPriList
  4141. );
  4142. RegCloseKey (hKeyHandoffPriorities);
  4143. }
  4144. else
  4145. {
  4146. LOG((TL_ERROR,
  4147. "RegOpenKey('\\HandoffPri') failed, err=%ld",
  4148. lResult
  4149. ));
  4150. }
  4151. RegCloseKey (hKeyCurrentUser);
  4152. }
  4153. else
  4154. {
  4155. LOG((TL_ERROR,
  4156. "RegOpenCurrentUser failed, err=%ld",
  4157. lResult
  4158. ));
  4159. }
  4160. }
  4161. LeaveCriticalSection (&gPriorityListCritSec);
  4162. if (status == RPC_S_OK)
  4163. {
  4164. RpcRevertToSelf ();
  4165. }
  4166. }
  4167. }
  4168. //
  4169. // Add tClient to global list
  4170. //
  4171. ClientAttach_AddClientToList:
  4172. TapiEnterCriticalSection (&TapiGlobals.CritSec);
  4173. if ((ptClient->pNext = TapiGlobals.ptClients))
  4174. {
  4175. ptClient->pNext->pPrev = ptClient;
  4176. }
  4177. TapiGlobals.ptClients = ptClient;
  4178. gfWeHadAtLeastOneClient = TRUE;
  4179. ptClient->dwKey = TCLIENT_KEY;
  4180. {
  4181. PTPROVIDER ptProvider;
  4182. ptProvider = TapiGlobals.ptProviders;
  4183. while (NULL != ptProvider)
  4184. {
  4185. if (NULL != ptProvider->apfn[SP_PROVIDERCHECKFORNEWUSER])
  4186. {
  4187. CallSP1(
  4188. ptProvider->apfn[SP_PROVIDERCHECKFORNEWUSER],
  4189. "providerCheckForNewUser",
  4190. SP_FUNC_SYNC,
  4191. (DWORD)ptProvider->dwPermanentProviderID
  4192. );
  4193. }
  4194. ptProvider = ptProvider->pNext;
  4195. }
  4196. }
  4197. TapiLeaveCriticalSection (&TapiGlobals.CritSec);
  4198. //
  4199. // Fill in return values
  4200. //
  4201. *pphContext = (PCONTEXT_HANDLE_TYPE) UIntToPtr(ptClient->htClient);
  4202. PerfBlock.dwClientApps++;
  4203. return 0;
  4204. //
  4205. // Error cleanup
  4206. //
  4207. Admin_error:
  4208. ServerFree (ptClient->pEventBuffer);
  4209. DereferenceObject (ghHandleTable,
  4210. ptClient->htClient, 1);
  4211. return LINEERR_OPERATIONFAILED;
  4212. ClientAttach_error5:
  4213. if (ptClient->pszComputerName != TapiGlobals.pszComputerName)
  4214. {
  4215. ServerFree (ptClient->pszComputerName);
  4216. }
  4217. #if TELE_SERVER
  4218. ClientAttach_error4:
  4219. #endif
  4220. ServerFree (ptClient->pszDomainName);
  4221. #if TELE_SERVER
  4222. ClientAttach_error3:
  4223. #endif
  4224. ServerFree (ptClient->pszUserName);
  4225. ClientAttach_error2:
  4226. ServerFree (ptClient->pEventBuffer);
  4227. ClientAttach_error1:
  4228. DereferenceObject (ghHandleTable,
  4229. ptClient->htClient, 1);
  4230. ClientAttach_error0:
  4231. if (lResult == 0)
  4232. {
  4233. lResult = LINEERR_NOMEM;
  4234. }
  4235. return lResult;
  4236. }
  4237. void
  4238. ClientRequest(
  4239. PCONTEXT_HANDLE_TYPE phContext,
  4240. unsigned char *pBuffer,
  4241. long lNeededSize,
  4242. long *plUsedSize
  4243. )
  4244. {
  4245. PTAPI32_MSG pMsg = (PTAPI32_MSG) pBuffer;
  4246. DWORD dwFuncIndex;
  4247. PTCLIENT ptClient = NULL;
  4248. DWORD objectToDereference = DWORD_CAST((ULONG_PTR)phContext,__FILE__,__LINE__);
  4249. if (lNeededSize < sizeof (TAPI32_MSG) ||
  4250. *plUsedSize < sizeof (ULONG_PTR)) // sizeof (pMsg->u.Req_Func)
  4251. {
  4252. pMsg->u.Ack_ReturnValue = LINEERR_INVALPARAM;
  4253. goto ExitHere;
  4254. }
  4255. dwFuncIndex = pMsg->u.Req_Func;
  4256. ptClient = ReferenceObject(
  4257. ghHandleTable,
  4258. objectToDereference,
  4259. TCLIENT_KEY);
  4260. if (ptClient == NULL)
  4261. {
  4262. pMsg->u.Ack_ReturnValue = TAPIERR_INVALRPCCONTEXT;
  4263. goto ExitHere;
  4264. }
  4265. //
  4266. // Old (nt4sp4, win98) clients pass across a usedSize
  4267. // == 3 * sizeof(DWORD) for the xgetAsyncEvents request,
  4268. // so we have to special case them when checking buf size
  4269. //
  4270. if (*plUsedSize < (long) (dwFuncIndex == xGetAsyncEvents ?
  4271. 3 * sizeof (ULONG_PTR) : sizeof (TAPI32_MSG)))
  4272. {
  4273. goto ExitHere;
  4274. }
  4275. *plUsedSize = sizeof (LONG_PTR);
  4276. if (dwFuncIndex >= xLastFunc)
  4277. {
  4278. pMsg->u.Ack_ReturnValue = LINEERR_OPERATIONUNAVAIL;
  4279. }
  4280. else if (ptClient->dwKey == TCLIENT_KEY)
  4281. {
  4282. pMsg->u.Ack_ReturnValue = TAPI_SUCCESS;
  4283. (*gaFuncs[dwFuncIndex])(
  4284. ptClient,
  4285. pMsg,
  4286. lNeededSize - sizeof(TAPI32_MSG),
  4287. pBuffer + sizeof(TAPI32_MSG),
  4288. plUsedSize
  4289. );
  4290. }
  4291. else
  4292. {
  4293. pMsg->u.Ack_ReturnValue = LINEERR_REINIT;
  4294. }
  4295. ExitHere:
  4296. if (ptClient)
  4297. {
  4298. DereferenceObject(
  4299. ghHandleTable,
  4300. ptClient->htClient,
  4301. 1);
  4302. }
  4303. return;
  4304. }
  4305. void
  4306. ClientDetach(
  4307. PCONTEXT_HANDLE_TYPE *pphContext
  4308. )
  4309. {
  4310. PTCLIENT ptClient;
  4311. DWORD objectToDereference = DWORD_CAST((ULONG_PTR)(*pphContext),__FILE__,__LINE__);
  4312. LOG((TL_TRACE, "ClientDetach: enter"));
  4313. ptClient = ReferenceObject(
  4314. ghHandleTable,
  4315. objectToDereference,
  4316. TCLIENT_KEY);
  4317. if (ptClient == NULL)
  4318. {
  4319. goto ExitHere;
  4320. }
  4321. {
  4322. if (!IS_REMOTE_CLIENT (ptClient))
  4323. {
  4324. //
  4325. // Write the pri lists to the registry when a local client
  4326. // detaches.
  4327. //
  4328. {
  4329. HKEY hKeyHandoffPriorities, hKeyCurrentUser;
  4330. LONG lResult;
  4331. DWORD dwDisposition;
  4332. RPC_STATUS status;
  4333. if ((status = RpcImpersonateClient (0)) == RPC_S_OK)
  4334. {
  4335. if (ERROR_SUCCESS ==
  4336. (lResult = RegOpenCurrentUser (KEY_ALL_ACCESS, &hKeyCurrentUser)))
  4337. {
  4338. if ((lResult = RegCreateKeyEx(
  4339. hKeyCurrentUser,
  4340. gszRegKeyHandoffPriorities,
  4341. 0,
  4342. TEXT(""),
  4343. REG_OPTION_NON_VOLATILE,
  4344. KEY_SET_VALUE,
  4345. (LPSECURITY_ATTRIBUTES) NULL,
  4346. &hKeyHandoffPriorities,
  4347. &dwDisposition
  4348. )) == ERROR_SUCCESS)
  4349. {
  4350. HKEY hKeyHandoffPrioritiesMediaModes;
  4351. EnterCriticalSection (&gPriorityListCritSec);
  4352. RegDeleteKey(
  4353. hKeyHandoffPriorities,
  4354. gszRegKeyHandoffPrioritiesMediaModes
  4355. );
  4356. if ((lResult = RegCreateKeyEx(
  4357. hKeyHandoffPriorities,
  4358. gszRegKeyHandoffPrioritiesMediaModes,
  4359. 0,
  4360. TEXT(""),
  4361. REG_OPTION_NON_VOLATILE,
  4362. KEY_SET_VALUE,
  4363. (LPSECURITY_ATTRIBUTES) NULL,
  4364. &hKeyHandoffPrioritiesMediaModes,
  4365. &dwDisposition
  4366. )) == ERROR_SUCCESS)
  4367. {
  4368. SetMediaModesPriorityList(
  4369. hKeyHandoffPrioritiesMediaModes,
  4370. TapiGlobals.pPriLists
  4371. );
  4372. RegCloseKey( hKeyHandoffPrioritiesMediaModes );
  4373. }
  4374. SetPriorityList(
  4375. hKeyHandoffPriorities,
  4376. gszRequestMakeCallW,
  4377. TapiGlobals.pszReqMakeCallPriList
  4378. );
  4379. SetPriorityList(
  4380. hKeyHandoffPriorities,
  4381. gszRequestMediaCallW,
  4382. TapiGlobals.pszReqMediaCallPriList
  4383. );
  4384. LeaveCriticalSection (&gPriorityListCritSec);
  4385. RegCloseKey (hKeyHandoffPriorities);
  4386. }
  4387. else
  4388. {
  4389. LOG((TL_ERROR,
  4390. "RegCreateKeyEx('\\HandoffPri') failed, err=%ld",
  4391. lResult
  4392. ));
  4393. }
  4394. RegCloseKey (hKeyCurrentUser);
  4395. }
  4396. else
  4397. {
  4398. LOG((TL_ERROR,
  4399. "RegOpenCurrentUser failed, err=%ld",
  4400. lResult
  4401. ));
  4402. }
  4403. RpcRevertToSelf ();
  4404. }
  4405. else
  4406. {
  4407. LOG((TL_ERROR, "ClientDetach: RpcImpersonateClient failed, err=%d", status));
  4408. }
  4409. }
  4410. }
  4411. }
  4412. PCONTEXT_HANDLE_TYPE_rundown (*pphContext);
  4413. *pphContext = (PCONTEXT_HANDLE_TYPE) NULL;
  4414. PerfBlock.dwClientApps--;
  4415. LOG((TL_TRACE, "ClientDetach: exit"));
  4416. ExitHere:
  4417. if (ptClient)
  4418. {
  4419. DereferenceObject( ghHandleTable,
  4420. ptClient->htClient, 1);
  4421. }
  4422. return;
  4423. }
  4424. BOOL
  4425. CleanUpClient(
  4426. PTCLIENT ptClient,
  4427. BOOL bRundown
  4428. )
  4429. /*++
  4430. This function separates out the freeing of client resources
  4431. and removing it from the client list from actually freeing
  4432. the client. For the case where the client timed out we want to
  4433. clean up all the client's resources. However, the client can
  4434. potentially still call in to tapisrv, so we can't free the
  4435. client handle (or it will fault in lineprolog / phoneprolog).
  4436. --*/
  4437. {
  4438. BOOL bResult, bExit;
  4439. CleanUpClient_lockClient:
  4440. try
  4441. {
  4442. LOCKTCLIENT (ptClient);
  4443. }
  4444. myexcept
  4445. {
  4446. // do nothing
  4447. }
  4448. try
  4449. {
  4450. if (bRundown)
  4451. {
  4452. switch (ptClient->dwKey)
  4453. {
  4454. case TCLIENT_KEY:
  4455. //
  4456. // Invalidate the key & proceed with clean up
  4457. //
  4458. ptClient->dwKey = INVAL_KEY;
  4459. bExit = FALSE;
  4460. break;
  4461. case TZOMBIECLIENT_KEY:
  4462. //
  4463. // An EventNotificationThread already cleaned up this client,
  4464. // so invalidate the key, exit & return TRUE
  4465. //
  4466. ptClient->dwKey = INVAL_KEY;
  4467. bResult = bExit = TRUE;
  4468. break;
  4469. case TCLIENTCLEANUP_KEY:
  4470. //
  4471. // An EventNotificationThread is cleaning up this client.
  4472. // Release the lock, wait a little while, then try again.
  4473. //
  4474. UNLOCKTCLIENT (ptClient);
  4475. Sleep (50);
  4476. goto CleanUpClient_lockClient;
  4477. default:
  4478. //
  4479. // This is not a valid tClient, so exit & return FALSE
  4480. //
  4481. bResult = FALSE;
  4482. bExit = TRUE;
  4483. break;
  4484. }
  4485. }
  4486. else // called by EventNotificationThread on timeout
  4487. {
  4488. if (ptClient->dwKey == TCLIENT_KEY)
  4489. {
  4490. //
  4491. // Mark the key as "doing cleanup", then proceed
  4492. //
  4493. bExit = FALSE;
  4494. ptClient->dwKey = TCLIENTCLEANUP_KEY;
  4495. }
  4496. else
  4497. {
  4498. //
  4499. // Either the tClient is invalid or it's being cleaned
  4500. // up by someone else, so exit & return FALSE
  4501. //
  4502. bResult = FALSE;
  4503. bExit = TRUE;
  4504. }
  4505. }
  4506. }
  4507. myexcept
  4508. {
  4509. bResult = FALSE;
  4510. bExit = TRUE;
  4511. }
  4512. try
  4513. {
  4514. UNLOCKTCLIENT (ptClient);
  4515. }
  4516. myexcept
  4517. {
  4518. // do nothing
  4519. }
  4520. if (bExit)
  4521. {
  4522. return bResult;
  4523. }
  4524. // Clear the MMC write lock if any
  4525. if (IS_FLAG_SET (ptClient->dwFlags, PTCLIENT_FLAG_LOCKEDMMCWRITE))
  4526. {
  4527. EnterCriticalSection (&gMgmtCritSec);
  4528. gbLockMMCWrite = FALSE;
  4529. LeaveCriticalSection (&gMgmtCritSec);
  4530. }
  4531. #if TELE_SERVER
  4532. if (IS_REMOTE_CLIENT (ptClient) &&
  4533. ptClient->MsgPendingListEntry.Flink)
  4534. {
  4535. CRITICAL_SECTION *pCS = (IS_REMOTE_CN_CLIENT (ptClient) ?
  4536. &gCnClientMsgPendingCritSec :
  4537. &gDgClientMsgPendingCritSec);
  4538. EnterCriticalSection (pCS);
  4539. if (ptClient->MsgPendingListEntry.Flink)
  4540. {
  4541. RemoveEntryList (&ptClient->MsgPendingListEntry);
  4542. }
  4543. LeaveCriticalSection (pCS);
  4544. }
  4545. #endif
  4546. TapiEnterCriticalSection (&TapiGlobals.CritSec);
  4547. try
  4548. {
  4549. if (ptClient->pNext)
  4550. {
  4551. ptClient->pNext->pPrev = ptClient->pPrev;
  4552. }
  4553. if (ptClient->pPrev)
  4554. {
  4555. ptClient->pPrev->pNext = ptClient->pNext;
  4556. }
  4557. else
  4558. {
  4559. TapiGlobals.ptClients = ptClient->pNext;
  4560. }
  4561. }
  4562. myexcept
  4563. {
  4564. // simply continue
  4565. }
  4566. TapiLeaveCriticalSection (&TapiGlobals.CritSec);
  4567. #if TELE_SERVER
  4568. if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) &&
  4569. !IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR))
  4570. {
  4571. HMANAGEMENTCLIENT htClient;
  4572. PTMANAGEDLLINFO pDll;
  4573. (TapiGlobals.pMapperDll->aProcs[TC_CLIENTSHUTDOWN])(ptClient->hMapper);
  4574. if (TapiGlobals.pManageDllList)
  4575. {
  4576. pDll = TapiGlobals.pManageDllList->pFirst;
  4577. while (pDll)
  4578. {
  4579. if (GetTCClient (pDll, ptClient, TC_CLIENTSHUTDOWN, &htClient))
  4580. {
  4581. try
  4582. {
  4583. (pDll->aProcs[TC_CLIENTSHUTDOWN])(htClient);
  4584. }
  4585. myexcept
  4586. {
  4587. LOG((TL_ERROR, "CLIENT DLL had a problem: x%p",ptClient));
  4588. break;
  4589. }
  4590. }
  4591. pDll = pDll->pNext;
  4592. }
  4593. }
  4594. }
  4595. //
  4596. // If client was remote then detach
  4597. //
  4598. if (IS_REMOTE_CN_CLIENT (ptClient) && bRundown)
  4599. {
  4600. RpcTryExcept
  4601. {
  4602. RemoteSPDetach (&ptClient->phContext);
  4603. }
  4604. RpcExcept (I_RpcExceptionFilter(RpcExceptionCode()))
  4605. {
  4606. unsigned long ulResult = RpcExceptionCode();
  4607. LOG((TL_ERROR,
  4608. "rundown: exception #%d detaching from remotesp",
  4609. ulResult
  4610. ));
  4611. if (ulResult == RPC_S_SERVER_TOO_BUSY)
  4612. {
  4613. }
  4614. else
  4615. {
  4616. }
  4617. }
  4618. RpcEndExcept
  4619. }
  4620. #endif
  4621. //
  4622. // Close all XxxApps
  4623. //
  4624. while (ptClient->ptLineApps)
  4625. {
  4626. DestroytLineApp (ptClient->ptLineApps->hLineApp);
  4627. }
  4628. while (ptClient->ptPhoneApps)
  4629. {
  4630. DestroytPhoneApp (ptClient->ptPhoneApps->hPhoneApp);
  4631. }
  4632. //
  4633. // Clean up any existing ProviderXxx dialog instances
  4634. //
  4635. {
  4636. PTAPIDIALOGINSTANCE pProviderXxxDlgInst =
  4637. ptClient->pProviderXxxDlgInsts,
  4638. pNextProviderXxxDlgInst;
  4639. while (pProviderXxxDlgInst)
  4640. {
  4641. TAPI32_MSG params;
  4642. params.u.Req_Func = 0;
  4643. params.Params[0] = pProviderXxxDlgInst->htDlgInst;
  4644. params.Params[1] = LINEERR_OPERATIONFAILED;
  4645. pNextProviderXxxDlgInst = pProviderXxxDlgInst->pNext;
  4646. FreeDialogInstance(
  4647. ptClient,
  4648. (PFREEDIALOGINSTANCE_PARAMS) &params,
  4649. sizeof (params),
  4650. NULL,
  4651. NULL
  4652. );
  4653. pProviderXxxDlgInst = pNextProviderXxxDlgInst;
  4654. }
  4655. }
  4656. //
  4657. // Clean up associated resources
  4658. //
  4659. if (!IS_REMOTE_CLIENT (ptClient))
  4660. {
  4661. CloseHandle (ptClient->hProcess);
  4662. }
  4663. if (!IS_REMOTE_CN_CLIENT (ptClient))
  4664. {
  4665. CloseHandle (ptClient->hValidEventBufferDataEvent);
  4666. }
  4667. ServerFree (ptClient->pEventBuffer);
  4668. ServerFree (ptClient->pszUserName);
  4669. if (ptClient->pszComputerName != TapiGlobals.pszComputerName)
  4670. {
  4671. ServerFree (ptClient->pszComputerName);
  4672. }
  4673. #if TELE_SERVER
  4674. if (TapiGlobals.dwFlags & TAPIGLOBALS_SERVER)
  4675. {
  4676. ServerFree (ptClient->pszDomainName);
  4677. if (!IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR))
  4678. // security DLL handles
  4679. {
  4680. ServerFree (ptClient->pClientHandles);
  4681. ServerFree (ptClient->pLineMap);
  4682. ServerFree (ptClient->pLineDevices);
  4683. ServerFree (ptClient->pPhoneMap);
  4684. ServerFree (ptClient->pPhoneDevices);
  4685. }
  4686. }
  4687. #endif
  4688. //
  4689. // If we're called due to timeout then reset key to == ZOMBIE
  4690. // so that another thread doing rundown knows that it's ok
  4691. // to free the tClient object
  4692. //
  4693. if (!bRundown)
  4694. {
  4695. ptClient->dwKey = TZOMBIECLIENT_KEY;
  4696. }
  4697. return TRUE;
  4698. }
  4699. void
  4700. __RPC_USER
  4701. PCONTEXT_HANDLE_TYPE_rundown(
  4702. PCONTEXT_HANDLE_TYPE phContext
  4703. )
  4704. {
  4705. DWORD i;
  4706. PTCLIENT ptClient;
  4707. DWORD objectToDereference = DWORD_CAST((ULONG_PTR)phContext,__FILE__,__LINE__);
  4708. ptClient = ReferenceObject (
  4709. ghHandleTable,
  4710. objectToDereference,
  4711. TCLIENT_KEY);
  4712. if (ptClient == NULL)
  4713. {
  4714. goto ExitHere;
  4715. }
  4716. LOG((TL_TRACE, "PCONTEXT_HANDLE_TYPE_rundown: enter (ptClient=x%p)",ptClient));
  4717. while (InterlockedExchange (&gRundownLock.lCookie, 1) == 1)
  4718. {
  4719. Sleep (50);
  4720. }
  4721. if (!gRundownLock.bIgnoreRundowns)
  4722. {
  4723. InterlockedIncrement (&gRundownLock.lNumRundowns);
  4724. InterlockedExchange (&gRundownLock.lCookie, 0);
  4725. //
  4726. // Wrap the following in a try/except because we definitely
  4727. // want to make sure we decrement gRundownLock.lRundownCount
  4728. //
  4729. try
  4730. {
  4731. if (CleanUpClient (ptClient, TRUE))
  4732. {
  4733. DereferenceObject (
  4734. ghHandleTable,
  4735. ptClient->htClient,
  4736. 1);
  4737. //
  4738. // If this was the last client then alert the
  4739. // SPEventHandlerThread(s) that it should begin
  4740. // it's deferred shutdown countdown
  4741. //
  4742. if (!TapiGlobals.ptClients)
  4743. {
  4744. for (i = 0; i < gdwNumSPEventHandlerThreads; i++)
  4745. {
  4746. EnterCriticalSection(
  4747. &aSPEventHandlerThreadInfo[i].CritSec
  4748. );
  4749. SetEvent (aSPEventHandlerThreadInfo[i].hEvent);
  4750. LeaveCriticalSection(
  4751. &aSPEventHandlerThreadInfo[i].CritSec
  4752. );
  4753. }
  4754. }
  4755. }
  4756. }
  4757. myexcept
  4758. {
  4759. }
  4760. InterlockedDecrement (&gRundownLock.lNumRundowns);
  4761. }
  4762. else
  4763. {
  4764. InterlockedExchange (&gRundownLock.lCookie, 0);
  4765. }
  4766. ExitHere:
  4767. if (ptClient)
  4768. {
  4769. DereferenceObject(ghHandleTable,
  4770. ptClient->htClient, 1);
  4771. }
  4772. LOG((TL_TRACE, "PCONTEXT_HANDLE_TYPE_rundown: exit"));
  4773. return;
  4774. }
  4775. #if DBG
  4776. LPVOID
  4777. WINAPI
  4778. ServerAllocReal(
  4779. DWORD dwSize,
  4780. DWORD dwLine,
  4781. PSTR pszFile
  4782. )
  4783. #else
  4784. LPVOID
  4785. WINAPI
  4786. ServerAllocReal(
  4787. DWORD dwSize
  4788. )
  4789. #endif
  4790. {
  4791. LPVOID p;
  4792. #if DBG
  4793. dwSize += sizeof (MYMEMINFO);
  4794. #endif
  4795. p = HeapAlloc (ghTapisrvHeap, HEAP_ZERO_MEMORY, dwSize);
  4796. #if DBG
  4797. if (p)
  4798. {
  4799. ((PMYMEMINFO) p)->dwLine = dwLine;
  4800. ((PMYMEMINFO) p)->pszFile = pszFile;
  4801. p = (LPVOID) (((PMYMEMINFO) p) + 1);
  4802. }
  4803. else
  4804. {
  4805. static BOOL fBeenThereDoneThat = FALSE;
  4806. static DWORD fBreakOnAllocFailed = 0;
  4807. if ( !fBeenThereDoneThat )
  4808. {
  4809. HKEY hKey;
  4810. TCHAR szTapisrvDebugBreak[] = TEXT("TapisrvDebugBreak");
  4811. fBeenThereDoneThat = TRUE;
  4812. if (RegOpenKeyEx(
  4813. HKEY_LOCAL_MACHINE,
  4814. gszRegKeyTelephony,
  4815. 0,
  4816. KEY_ALL_ACCESS,
  4817. &hKey
  4818. ) == ERROR_SUCCESS)
  4819. {
  4820. DWORD dwDataSize = sizeof (DWORD), dwDataType;
  4821. RegQueryValueEx(
  4822. hKey,
  4823. szTapisrvDebugBreak,
  4824. 0,
  4825. &dwDataType,
  4826. (LPBYTE) &fBreakOnAllocFailed,
  4827. &dwDataSize
  4828. );
  4829. dwDataSize = sizeof (DWORD);
  4830. RegCloseKey (hKey);
  4831. LOG((TL_ERROR, "BreakOnAllocFailed=%ld", fBreakOnAllocFailed));
  4832. }
  4833. }
  4834. if ( fBreakOnAllocFailed )
  4835. {
  4836. DebugBreak();
  4837. }
  4838. }
  4839. #endif
  4840. return p;
  4841. }
  4842. VOID
  4843. WINAPI
  4844. ServerFree(
  4845. LPVOID p
  4846. )
  4847. {
  4848. if (!p)
  4849. {
  4850. return;
  4851. }
  4852. #if DBG
  4853. //
  4854. // Fill the buffer (but not the MYMEMINFO header) with 0xa1's
  4855. // to facilitate debugging
  4856. //
  4857. {
  4858. LPVOID p2 = p;
  4859. DWORD dwSize;
  4860. p = (LPVOID) (((PMYMEMINFO) p) - 1);
  4861. dwSize = (DWORD) HeapSize (ghTapisrvHeap, 0, p);
  4862. if ((dwSize != 0xFFFFFFFF) && (dwSize > sizeof (MYMEMINFO)))
  4863. {
  4864. FillMemory(
  4865. p2,
  4866. dwSize - sizeof (MYMEMINFO),
  4867. 0xa1
  4868. );
  4869. }
  4870. }
  4871. #endif
  4872. HeapFree (ghTapisrvHeap, 0, p);
  4873. }
  4874. #if DBG
  4875. void
  4876. DumpHandleList()
  4877. {
  4878. #ifdef INTERNALBUILD
  4879. PMYHANDLEINFO pHold;
  4880. if (gpHandleFirst == NULL)
  4881. {
  4882. LOG((TL_ERROR, "All mutexes deallocated"));
  4883. return;
  4884. }
  4885. pHold = gpHandleFirst;
  4886. while (pHold)
  4887. {
  4888. LOG((TL_INFO, "DumpHandleList - MUTEX %lx, FILE %s, LINE %d", pHold->hMutex, pHold->pszFile, pHold->dwLine));
  4889. pHold = pHold->pNext;
  4890. }
  4891. if (gbBreakOnLeak)
  4892. {
  4893. DebugBreak();
  4894. }
  4895. #endif
  4896. }
  4897. #endif
  4898. BOOL
  4899. PASCAL
  4900. MyDuplicateHandle(
  4901. HANDLE hSource,
  4902. LPHANDLE phTarget
  4903. )
  4904. {
  4905. if (!DuplicateHandle(
  4906. TapiGlobals.hProcess,
  4907. hSource,
  4908. TapiGlobals.hProcess,
  4909. phTarget,
  4910. 0,
  4911. FALSE,
  4912. DUPLICATE_SAME_ACCESS
  4913. ))
  4914. {
  4915. LOG((TL_ERROR,
  4916. "MyDuplicateHandle: DuplicateHandle failed, err=%ld",
  4917. GetLastError()
  4918. ));
  4919. return FALSE;
  4920. }
  4921. return TRUE;
  4922. }
  4923. #if DBG
  4924. HANDLE
  4925. MyRealCreateMutex(
  4926. PSTR pFile,
  4927. DWORD dwLine
  4928. )
  4929. #else
  4930. HANDLE
  4931. MyRealCreateMutex(
  4932. void
  4933. )
  4934. #endif
  4935. {
  4936. HANDLE hMutex;
  4937. hMutex = CreateMutex(
  4938. NULL, // no security attrs
  4939. FALSE, // unowned
  4940. NULL // unnamed
  4941. );
  4942. return (hMutex);
  4943. }
  4944. BOOL
  4945. WaitForMutex(
  4946. HANDLE hMutex,
  4947. HANDLE *phMutex,
  4948. BOOL *pbDupedMutex,
  4949. LPVOID pWidget,
  4950. DWORD dwKey,
  4951. DWORD dwTimeout
  4952. )
  4953. {
  4954. DWORD dwResult;
  4955. // note that waitformutex and code that uses the mutex must be
  4956. // wrapped in a try except because the object could possibly
  4957. // go away even though the thread has the mutex
  4958. //
  4959. // First try to instantaneously grab the specified mutex. We wrap
  4960. // this in a critical section and preface it with widget validation
  4961. // to make sure that we don't happen grab a pWidget->hMutex right
  4962. // after it is released and right before it is closed by some other
  4963. // thread "T2" in a DestroyWidget routine. This scenario could cause
  4964. // deadlock, since there could be thread "T3" waiting on this mutex
  4965. // (or a dup'd handle), and this thread "T1" would have no way to
  4966. // release the mutex (the handle having been subsequently closed by
  4967. // thread "T2" calling DestroyWidget above).
  4968. //
  4969. EnterCriticalSection (&gSafeMutexCritSec);
  4970. if (pWidget)
  4971. {
  4972. try
  4973. {
  4974. if (*((LPDWORD) pWidget) != dwKey)
  4975. {
  4976. LeaveCriticalSection (&gSafeMutexCritSec);
  4977. return FALSE;
  4978. }
  4979. }
  4980. myexcept
  4981. {
  4982. LeaveCriticalSection (&gSafeMutexCritSec);
  4983. return FALSE;
  4984. }
  4985. }
  4986. switch ((dwResult = WaitForSingleObject (hMutex, 0)))
  4987. {
  4988. case WAIT_OBJECT_0:
  4989. LeaveCriticalSection (&gSafeMutexCritSec);
  4990. *phMutex = hMutex;
  4991. *pbDupedMutex = FALSE;
  4992. return TRUE;
  4993. //case WAIT_ABANDONED:
  4994. //assert: no calling thread should ever be terminated!
  4995. default:
  4996. break;
  4997. }
  4998. LeaveCriticalSection (&gSafeMutexCritSec);
  4999. //
  5000. // If here we failed to instantaneously grab the specified mutex.
  5001. // Try to dup it, and then wait on the dup'd handle. We do this so
  5002. // that each thread which grabs a mutex is guaranteed to have a valid
  5003. // handle to release at some future time, as the original hMutex might
  5004. // get closed by some other thread calling a DestroyWidget routine.
  5005. //
  5006. if (!DuplicateHandle(
  5007. TapiGlobals.hProcess,
  5008. hMutex,
  5009. TapiGlobals.hProcess,
  5010. phMutex,
  5011. 0,
  5012. FALSE,
  5013. DUPLICATE_SAME_ACCESS
  5014. ))
  5015. {
  5016. return FALSE;
  5017. }
  5018. WaitForMutex_wait:
  5019. switch ((dwResult = WaitForSingleObject (*phMutex, dwTimeout)))
  5020. {
  5021. case WAIT_OBJECT_0:
  5022. *pbDupedMutex = TRUE;
  5023. return TRUE;
  5024. case WAIT_TIMEOUT:
  5025. try
  5026. {
  5027. if (*((LPDWORD) pWidget) == dwKey)
  5028. {
  5029. goto WaitForMutex_wait;
  5030. }
  5031. }
  5032. myexcept
  5033. {
  5034. // just fall thru without blowing up
  5035. }
  5036. MyCloseMutex (*phMutex);
  5037. break;
  5038. //case WAIT_ABANDONED:
  5039. //assert: no calling thread should ever be terminated!
  5040. default:
  5041. break;
  5042. }
  5043. return FALSE;
  5044. }
  5045. void
  5046. MyReleaseMutex(
  5047. HANDLE hMutex,
  5048. BOOL bCloseMutex
  5049. )
  5050. {
  5051. if (hMutex)
  5052. {
  5053. ReleaseMutex (hMutex);
  5054. if (bCloseMutex)
  5055. {
  5056. MyCloseMutex (hMutex);
  5057. }
  5058. }
  5059. }
  5060. void
  5061. MyCloseMutex(
  5062. HANDLE hMutex
  5063. )
  5064. {
  5065. if (hMutex)
  5066. {
  5067. CloseHandle (hMutex);
  5068. }
  5069. }
  5070. void
  5071. CALLBACK
  5072. CompletionProcSP(
  5073. DWORD dwRequestID,
  5074. LONG lResult
  5075. )
  5076. {
  5077. PASYNCREQUESTINFO pAsyncRequestInfo;
  5078. if ((pAsyncRequestInfo = ReferenceObject(
  5079. ghHandleTable,
  5080. dwRequestID,
  5081. TASYNC_KEY
  5082. )))
  5083. {
  5084. #if DBG
  5085. char szResult[32];
  5086. LOG((TL_TRACE,
  5087. "CompletionProcSP: enter, dwReqID=x%x, lResult=%s",
  5088. dwRequestID,
  5089. MapResultCodeToText (lResult, szResult)
  5090. ));
  5091. #else
  5092. LOG((TL_TRACE,
  5093. "CompletionProcSP: enter, dwReqID=x%x, lResult=x%x",
  5094. dwRequestID,
  5095. lResult
  5096. ));
  5097. #endif
  5098. pAsyncRequestInfo->lResult = lResult;
  5099. DereferenceObject (ghHandleTable, dwRequestID, 1);
  5100. }
  5101. else
  5102. {
  5103. LOG((TL_ERROR, "CompletionProcSP: bad dwRequestID=x%x", dwRequestID));
  5104. #if DBG
  5105. if (gfBreakOnSeriousProblems)
  5106. {
  5107. DebugBreak();
  5108. }
  5109. #endif
  5110. return;
  5111. }
  5112. if (!QueueSPEvent ((PSPEVENT) pAsyncRequestInfo))
  5113. {
  5114. //
  5115. // If here we're going thru shutdown & service provider
  5116. // is completing any outstanding events, so process this
  5117. // inline so it gets cleaned up right now.
  5118. //
  5119. CompletionProc (pAsyncRequestInfo, lResult);
  5120. DereferenceObject (ghHandleTable, dwRequestID, 1);
  5121. }
  5122. }
  5123. VOID
  5124. PASCAL
  5125. CompletionProc(
  5126. PASYNCREQUESTINFO pAsyncRequestInfo,
  5127. LONG lResult
  5128. )
  5129. {
  5130. //
  5131. // Assumes pAsyncRequestInfo has been verified upon entry.
  5132. //
  5133. // If the tClient is bad WriteEventBuffer should handle it ok,
  5134. // as should any post-processing routine.
  5135. //
  5136. ASYNCEVENTMSG msg[2], *pMsg = msg;
  5137. #if DBG
  5138. {
  5139. char szResult[32];
  5140. LOG((TL_TRACE,
  5141. "CompletionProc: enter, dwReqID=x%x, lResult=%s",
  5142. pAsyncRequestInfo->dwLocalRequestID,
  5143. MapResultCodeToText (lResult, szResult)
  5144. ));
  5145. }
  5146. #else
  5147. LOG((TL_TRACE,
  5148. "CompletionProc: enter, dwReqID=x%x, lResult=x%x",
  5149. pAsyncRequestInfo->dwLocalRequestID,
  5150. lResult
  5151. ));
  5152. #endif
  5153. pAsyncRequestInfo->dwKey = INVAL_KEY;
  5154. //
  5155. // Init the msg we'll send to client
  5156. //
  5157. pMsg->TotalSize = sizeof (ASYNCEVENTMSG);
  5158. pMsg->InitContext = pAsyncRequestInfo->InitContext;
  5159. pMsg->fnPostProcessProcHandle = pAsyncRequestInfo->hfnClientPostProcessProc;
  5160. pMsg->hDevice = 0;
  5161. pMsg->Msg = ((pAsyncRequestInfo->dwLineFlags & 1) ?
  5162. LINE_REPLY : PHONE_REPLY);
  5163. pMsg->OpenContext = pAsyncRequestInfo->OpenContext;
  5164. pMsg->Param1 = pAsyncRequestInfo->dwRemoteRequestID;
  5165. pMsg->Param2 = lResult;
  5166. pMsg->Param3 = 0;
  5167. //
  5168. // If there's a post processing proc call it. Note that ppprocs can
  5169. // create their own msg to pass, so we need to check for this case.
  5170. // Finally, write the msg to the client's event buffer.
  5171. //
  5172. if (pAsyncRequestInfo->pfnPostProcess)
  5173. {
  5174. LPVOID pBuf = NULL;
  5175. (*pAsyncRequestInfo->pfnPostProcess)(pAsyncRequestInfo, pMsg, &pBuf);
  5176. WriteEventBuffer (pAsyncRequestInfo->ptClient, (pBuf ? pBuf : pMsg));
  5177. if (pBuf)
  5178. {
  5179. ServerFree (pBuf);
  5180. }
  5181. }
  5182. else
  5183. {
  5184. WriteEventBuffer (pAsyncRequestInfo->ptClient, pMsg);
  5185. }
  5186. // caller will free pAsyncRequestInfo
  5187. }
  5188. void
  5189. WriteEventBuffer(
  5190. PTCLIENT ptClient,
  5191. PASYNCEVENTMSG pMsg
  5192. )
  5193. {
  5194. BOOL bSignalRemote = FALSE;
  5195. DWORD dwMoveSize = (DWORD) pMsg->TotalSize,
  5196. dwMoveSizeWrapped = 0,
  5197. dwPreviousUsedSize,
  5198. dwData;
  5199. HANDLE hMailslot;
  5200. #if DBG
  5201. if (dwMoveSize & 0x3)
  5202. {
  5203. LOG((TL_ERROR,
  5204. "WriteEventBuffer: ERROR! bad MsgSize=x%x (Msg=x%x, pCli=x%p)",
  5205. dwMoveSize,
  5206. pMsg->Msg,
  5207. ptClient
  5208. ));
  5209. }
  5210. #endif
  5211. LOG((TL_TRACE, "WriteEventBuffer - enter"));
  5212. if (WaitForExclusiveClientAccess (ptClient))
  5213. {
  5214. //
  5215. // Check to see if we need to grow the event buffer
  5216. //
  5217. if (dwMoveSize > (ptClient->dwEventBufferTotalSize -
  5218. ptClient->dwEventBufferUsedSize))
  5219. {
  5220. DWORD dwMoveSize2, dwMoveSizeWrapped2,
  5221. dwNewEventBufferTotalSize;
  5222. LPBYTE pNewEventBuffer;
  5223. //
  5224. // Do some math to have the total be a multiple
  5225. // of sizeof(ASYNCEVENTMSG)
  5226. //
  5227. dwNewEventBufferTotalSize =
  5228. ptClient->dwEventBufferTotalSize +
  5229. ( (( dwMoveSize / sizeof(ASYNCEVENTMSG) ) + 20 )
  5230. * sizeof(ASYNCEVENTMSG));
  5231. if (!(pNewEventBuffer = ServerAlloc(
  5232. dwNewEventBufferTotalSize
  5233. )))
  5234. {
  5235. UNLOCKTCLIENT (ptClient);
  5236. return;
  5237. }
  5238. if (ptClient->dwEventBufferUsedSize != 0)
  5239. {
  5240. if (ptClient->pDataIn > ptClient->pDataOut)
  5241. {
  5242. dwMoveSize2 = (DWORD) (ptClient->pDataIn -
  5243. ptClient->pDataOut);
  5244. dwMoveSizeWrapped2 = 0;
  5245. }
  5246. else
  5247. {
  5248. dwMoveSize2 = (DWORD)
  5249. ((ptClient->pEventBuffer +
  5250. ptClient->dwEventBufferTotalSize) -
  5251. ptClient->pDataOut);
  5252. dwMoveSizeWrapped2 = (DWORD)
  5253. (ptClient->pDataIn -
  5254. ptClient->pEventBuffer);
  5255. }
  5256. CopyMemory(
  5257. pNewEventBuffer,
  5258. ptClient->pDataOut,
  5259. dwMoveSize2
  5260. );
  5261. if (dwMoveSizeWrapped2)
  5262. {
  5263. CopyMemory(
  5264. pNewEventBuffer + dwMoveSize2,
  5265. ptClient->pEventBuffer,
  5266. dwMoveSizeWrapped2
  5267. );
  5268. }
  5269. ptClient->pDataIn = pNewEventBuffer +
  5270. dwMoveSize2 + dwMoveSizeWrapped2;
  5271. }
  5272. else
  5273. {
  5274. ptClient->pDataIn = pNewEventBuffer;
  5275. }
  5276. ServerFree (ptClient->pEventBuffer);
  5277. ptClient->pDataOut =
  5278. ptClient->pEventBuffer = pNewEventBuffer;
  5279. ptClient->dwEventBufferTotalSize =
  5280. dwNewEventBufferTotalSize;
  5281. }
  5282. //
  5283. // Compute the MoveSize's, do the copy(ies), & update the pointers
  5284. //
  5285. if (ptClient->pDataIn >= ptClient->pDataOut)
  5286. {
  5287. DWORD dwFreeSize = ptClient->dwEventBufferTotalSize -
  5288. (DWORD) (ptClient->pDataIn -
  5289. ptClient->pEventBuffer);
  5290. if (dwMoveSize > dwFreeSize)
  5291. {
  5292. dwMoveSizeWrapped = dwMoveSize - dwFreeSize;
  5293. dwMoveSize = dwFreeSize;
  5294. }
  5295. }
  5296. CopyMemory (ptClient->pDataIn, (LPBYTE) pMsg, dwMoveSize);
  5297. if (dwMoveSizeWrapped != 0)
  5298. {
  5299. CopyMemory(
  5300. ptClient->pEventBuffer,
  5301. ((LPBYTE) pMsg) + dwMoveSize,
  5302. dwMoveSizeWrapped
  5303. );
  5304. ptClient->pDataIn = ptClient->pEventBuffer +
  5305. dwMoveSizeWrapped;
  5306. }
  5307. else
  5308. {
  5309. ptClient->pDataIn += dwMoveSize;
  5310. if (ptClient->pDataIn >= (ptClient->pEventBuffer +
  5311. ptClient->dwEventBufferTotalSize))
  5312. {
  5313. ptClient->pDataIn = ptClient->pEventBuffer;
  5314. }
  5315. }
  5316. dwPreviousUsedSize = ptClient->dwEventBufferUsedSize;
  5317. ptClient->dwEventBufferUsedSize += (DWORD) pMsg->TotalSize;
  5318. if (!IS_REMOTE_CLIENT (ptClient))
  5319. {
  5320. LOG((TL_TRACE, "WriteEventBuffer: SetEvent %p for local client", ptClient->hValidEventBufferDataEvent));
  5321. SetEvent (ptClient->hValidEventBufferDataEvent);
  5322. }
  5323. else if (dwPreviousUsedSize == 0)
  5324. {
  5325. if (IS_REMOTE_CN_CLIENT (ptClient))
  5326. {
  5327. EnterCriticalSection (&gCnClientMsgPendingCritSec);
  5328. InsertTailList(
  5329. &CnClientMsgPendingListHead,
  5330. &ptClient->MsgPendingListEntry
  5331. );
  5332. LeaveCriticalSection (&gCnClientMsgPendingCritSec);
  5333. hMailslot = NULL;
  5334. bSignalRemote = TRUE;
  5335. }
  5336. else
  5337. {
  5338. if (dwPreviousUsedSize == 0)
  5339. {
  5340. ptClient->dwDgEventsRetrievedTickCount = GetTickCount();
  5341. }
  5342. EnterCriticalSection (&gDgClientMsgPendingCritSec);
  5343. InsertTailList(
  5344. &DgClientMsgPendingListHead,
  5345. &ptClient->MsgPendingListEntry
  5346. );
  5347. LeaveCriticalSection (&gDgClientMsgPendingCritSec);
  5348. hMailslot = ptClient->hMailslot;
  5349. if (ptClient->ptLineApps != NULL)
  5350. {
  5351. dwData = (DWORD) ptClient->ptLineApps->InitContext;
  5352. }
  5353. else
  5354. {
  5355. dwData = 0;
  5356. }
  5357. bSignalRemote = TRUE;
  5358. }
  5359. }
  5360. UNLOCKTCLIENT (ptClient);
  5361. if (bSignalRemote)
  5362. {
  5363. if (hMailslot)
  5364. {
  5365. DWORD dwBytesWritten;
  5366. if (!WriteFile(
  5367. hMailslot,
  5368. &dwData,
  5369. sizeof (DWORD),
  5370. &dwBytesWritten,
  5371. (LPOVERLAPPED) NULL
  5372. ))
  5373. {
  5374. LOG((TL_ERROR,
  5375. "WriteEventBuffer: Writefile(mailslot) " \
  5376. "failed, err=%d",
  5377. GetLastError()
  5378. ));
  5379. }
  5380. else
  5381. {
  5382. ptClient->dwDgRetryTimeoutTickCount =
  5383. GetTickCount() +
  5384. 2 * DGCLIENT_TIMEOUT;
  5385. }
  5386. }
  5387. else
  5388. {
  5389. SetEvent (gEventNotificationThreadParams.hEvent);
  5390. }
  5391. }
  5392. } else {
  5393. LOG((TL_ERROR, "WriteEventBuffer: - WaitForExclusiveClientAccess returns 0"));
  5394. }
  5395. }
  5396. LONG
  5397. GetPermLineIDAndInsertInTable(
  5398. PTPROVIDER ptProvider,
  5399. DWORD dwDeviceID,
  5400. DWORD dwSPIVersion
  5401. )
  5402. {
  5403. #if TELE_SERVER
  5404. LONG lResult = 0;
  5405. DWORD dwSize;
  5406. LPLINEDEVCAPS pCaps;
  5407. if (!ptProvider || !ptProvider->apfn[SP_LINEGETDEVCAPS])
  5408. {
  5409. return LINEERR_OPERATIONFAILED;
  5410. }
  5411. dwSize = sizeof (LINEDEVCAPS);
  5412. if (!(pCaps = ServerAlloc (dwSize)))
  5413. {
  5414. return LINEERR_NOMEM;
  5415. }
  5416. pCaps->dwTotalSize =
  5417. pCaps->dwUsedSize =
  5418. pCaps->dwNeededSize = dwSize;
  5419. if ((lResult = CallSP4(
  5420. ptProvider->apfn[SP_LINEGETDEVCAPS],
  5421. "lineGetDevCaps",
  5422. SP_FUNC_SYNC,
  5423. (DWORD)dwDeviceID,
  5424. (DWORD)dwSPIVersion,
  5425. (DWORD)0,
  5426. (ULONG_PTR) pCaps
  5427. )) == 0)
  5428. {
  5429. //
  5430. // add to sorted array
  5431. //
  5432. InsertIntoTable(
  5433. TRUE,
  5434. dwDeviceID,
  5435. ptProvider,
  5436. pCaps->dwPermanentLineID
  5437. );
  5438. }
  5439. ServerFree (pCaps);
  5440. return lResult;
  5441. #else
  5442. return 0;
  5443. #endif
  5444. }
  5445. LONG
  5446. AddLine(
  5447. PTPROVIDER ptProvider,
  5448. DWORD dwDeviceID,
  5449. BOOL bInit
  5450. )
  5451. {
  5452. DWORD dwSPIVersion;
  5453. HANDLE hMutex = NULL;
  5454. PTLINELOOKUPTABLE pLookup;
  5455. if (ptProvider->apfn[SP_LINENEGOTIATETSPIVERSION] == NULL)
  5456. {
  5457. return LINEERR_OPERATIONUNAVAIL;
  5458. }
  5459. //
  5460. // First try to negotiate an SPI ver for this device, and alloc the
  5461. // necessary resources
  5462. //
  5463. if (CallSP4(
  5464. ptProvider->apfn[SP_LINENEGOTIATETSPIVERSION],
  5465. "lineNegotiateTSPIVersion",
  5466. SP_FUNC_SYNC,
  5467. (DWORD)dwDeviceID,
  5468. (DWORD)TAPI_VERSION1_0,
  5469. (DWORD)TAPI_VERSION_CURRENT,
  5470. (ULONG_PTR) &dwSPIVersion
  5471. ) != 0)
  5472. {
  5473. //
  5474. // Device failed version negotiation, so we'll keep the id around
  5475. // (since the id's for the devices that follow have already been
  5476. // assigned) but mark this device as bad
  5477. //
  5478. ptProvider = NULL;
  5479. }
  5480. else if (!(hMutex = MyCreateMutex ()))
  5481. {
  5482. LOG((TL_ERROR,
  5483. "AddLine: MyCreateMutex failed, err=%d",
  5484. GetLastError()
  5485. ));
  5486. return LINEERR_OPERATIONFAILED;
  5487. }
  5488. //
  5489. // Now walk the lookup table to find a free entry
  5490. //
  5491. pLookup = TapiGlobals.pLineLookup;
  5492. while (pLookup->pNext)
  5493. {
  5494. pLookup = pLookup->pNext;
  5495. }
  5496. if (pLookup->dwNumUsedEntries == pLookup->dwNumTotalEntries)
  5497. {
  5498. PTLINELOOKUPTABLE pNewLookup;
  5499. if (bInit)
  5500. {
  5501. //
  5502. // If we're initializing we want to put everything in one big table
  5503. //
  5504. if (!(pNewLookup = ServerAlloc(
  5505. sizeof (TLINELOOKUPTABLE) +
  5506. (2 * pLookup->dwNumTotalEntries - 1) *
  5507. sizeof (TLINELOOKUPENTRY)
  5508. )))
  5509. {
  5510. return LINEERR_NOMEM;
  5511. }
  5512. pNewLookup->dwNumTotalEntries = 2 * pLookup->dwNumTotalEntries;
  5513. pNewLookup->dwNumUsedEntries = pLookup->dwNumTotalEntries;
  5514. CopyMemory(
  5515. pNewLookup->aEntries,
  5516. pLookup->aEntries,
  5517. pLookup->dwNumTotalEntries * sizeof (TLINELOOKUPENTRY)
  5518. );
  5519. ServerFree (pLookup);
  5520. TapiGlobals.pLineLookup = pNewLookup;
  5521. }
  5522. else
  5523. {
  5524. if (!(pNewLookup = ServerAlloc(
  5525. sizeof (TLINELOOKUPTABLE) +
  5526. (pLookup->dwNumTotalEntries - 1) *
  5527. sizeof (TLINELOOKUPENTRY)
  5528. )))
  5529. {
  5530. return LINEERR_NOMEM;
  5531. }
  5532. pNewLookup->dwNumTotalEntries = pLookup->dwNumTotalEntries;
  5533. pLookup->pNext = pNewLookup;
  5534. }
  5535. pLookup = pNewLookup;
  5536. }
  5537. //
  5538. // Initialize the entry
  5539. //
  5540. {
  5541. DWORD index = pLookup->dwNumUsedEntries;
  5542. pLookup->aEntries[index].dwSPIVersion = dwSPIVersion;
  5543. pLookup->aEntries[index].hMutex = hMutex;
  5544. pLookup->aEntries[index].ptProvider = ptProvider;
  5545. if (ptProvider &&
  5546. lstrcmpi(ptProvider->szFileName, TEXT("remotesp.tsp")) == 0)
  5547. {
  5548. pLookup->aEntries[index].bRemote = TRUE;
  5549. }
  5550. }
  5551. pLookup->dwNumUsedEntries++;
  5552. #if TELE_SERVER
  5553. //
  5554. // If this is an NT Server we want to be able to set user
  5555. // permissions regardless of whether or not TAPI server
  5556. // functionality is enabled. This allows an admin to set
  5557. // stuff up while the server is "offline".
  5558. //
  5559. if (gbNTServer)
  5560. {
  5561. GetPermLineIDAndInsertInTable (ptProvider, dwDeviceID, dwSPIVersion);
  5562. }
  5563. #endif
  5564. return 0;
  5565. }
  5566. DWORD
  5567. GetNumLineLookupEntries ()
  5568. {
  5569. PTLINELOOKUPTABLE pLineLookup;
  5570. DWORD dwNumLines;
  5571. pLineLookup = TapiGlobals.pLineLookup;
  5572. dwNumLines = 0;
  5573. while (pLineLookup)
  5574. {
  5575. dwNumLines += pLineLookup->dwNumUsedEntries;
  5576. pLineLookup = pLineLookup->pNext;
  5577. }
  5578. return dwNumLines;
  5579. }
  5580. LONG
  5581. GetPermPhoneIDAndInsertInTable(
  5582. PTPROVIDER ptProvider,
  5583. DWORD dwDeviceID,
  5584. DWORD dwSPIVersion
  5585. )
  5586. {
  5587. #if TELE_SERVER
  5588. LONG lResult = 0;
  5589. DWORD dwSize;
  5590. LPPHONECAPS pCaps;
  5591. if (!ptProvider->apfn[SP_PHONEGETDEVCAPS])
  5592. {
  5593. return PHONEERR_OPERATIONFAILED;
  5594. }
  5595. dwSize = sizeof (PHONECAPS);
  5596. if (!(pCaps = ServerAlloc (dwSize)))
  5597. {
  5598. return PHONEERR_NOMEM;
  5599. }
  5600. pCaps->dwTotalSize =
  5601. pCaps->dwUsedSize =
  5602. pCaps->dwNeededSize = dwSize;
  5603. if ((lResult = CallSP4(
  5604. ptProvider->apfn[SP_PHONEGETDEVCAPS],
  5605. "phoneGetCaps",
  5606. SP_FUNC_SYNC,
  5607. (DWORD)dwDeviceID,
  5608. (DWORD)dwSPIVersion,
  5609. (DWORD)0,
  5610. (ULONG_PTR) pCaps
  5611. )) == 0)
  5612. {
  5613. //
  5614. // add to sorted array
  5615. //
  5616. InsertIntoTable(
  5617. FALSE,
  5618. dwDeviceID,
  5619. ptProvider,
  5620. pCaps->dwPermanentPhoneID
  5621. );
  5622. }
  5623. ServerFree (pCaps);
  5624. return lResult;
  5625. #else
  5626. return 0;
  5627. #endif
  5628. }
  5629. LONG
  5630. AddPhone(
  5631. PTPROVIDER ptProvider,
  5632. DWORD dwDeviceID,
  5633. BOOL bInit
  5634. )
  5635. {
  5636. DWORD dwSPIVersion;
  5637. HANDLE hMutex = NULL;
  5638. PTPHONELOOKUPTABLE pLookup;
  5639. if (ptProvider->apfn[SP_PHONENEGOTIATETSPIVERSION] == NULL)
  5640. {
  5641. return PHONEERR_OPERATIONUNAVAIL;
  5642. }
  5643. //
  5644. // First try to negotiate an SPI ver for this device, and alloc the
  5645. // necessary resources
  5646. //
  5647. if (CallSP4(
  5648. ptProvider->apfn[SP_PHONENEGOTIATETSPIVERSION],
  5649. "phoneNegotiateTSPIVersion",
  5650. SP_FUNC_SYNC,
  5651. (DWORD)dwDeviceID,
  5652. (DWORD)TAPI_VERSION1_0,
  5653. (DWORD)TAPI_VERSION_CURRENT,
  5654. (ULONG_PTR) &dwSPIVersion
  5655. ) != 0)
  5656. {
  5657. //
  5658. // Device failed version negotiation, so we'll keep the id around
  5659. // (since the id's for the devices that follow have already been
  5660. // assigned) but mark this device as bad
  5661. //
  5662. return PHONEERR_OPERATIONFAILED;
  5663. }
  5664. else if (!(hMutex = MyCreateMutex ()))
  5665. {
  5666. LOG((TL_ERROR,
  5667. "AddPhone: MyCreateMutex failed, err=%d",
  5668. GetLastError()
  5669. ));
  5670. return PHONEERR_OPERATIONFAILED;
  5671. }
  5672. //
  5673. // Now walk the lookup table to find a free entry
  5674. //
  5675. pLookup = TapiGlobals.pPhoneLookup;
  5676. while (pLookup->pNext)
  5677. {
  5678. pLookup = pLookup->pNext;
  5679. }
  5680. if (pLookup->dwNumUsedEntries == pLookup->dwNumTotalEntries)
  5681. {
  5682. PTPHONELOOKUPTABLE pNewLookup;
  5683. if (bInit)
  5684. {
  5685. //
  5686. // If we're initializing we want to put everything in one big table
  5687. //
  5688. if (!(pNewLookup = ServerAlloc(
  5689. sizeof (TPHONELOOKUPTABLE) +
  5690. (2 * pLookup->dwNumTotalEntries - 1) *
  5691. sizeof (TPHONELOOKUPENTRY)
  5692. )))
  5693. {
  5694. return PHONEERR_NOMEM;
  5695. }
  5696. pNewLookup->dwNumTotalEntries = 2 * pLookup->dwNumTotalEntries;
  5697. pNewLookup->dwNumUsedEntries = pLookup->dwNumTotalEntries;
  5698. CopyMemory(
  5699. pNewLookup->aEntries,
  5700. pLookup->aEntries,
  5701. pLookup->dwNumTotalEntries * sizeof (TPHONELOOKUPENTRY)
  5702. );
  5703. ServerFree (pLookup);
  5704. TapiGlobals.pPhoneLookup = pNewLookup;
  5705. }
  5706. else
  5707. {
  5708. if (!(pNewLookup = ServerAlloc(
  5709. sizeof (TPHONELOOKUPTABLE) +
  5710. (pLookup->dwNumTotalEntries - 1) *
  5711. sizeof (TPHONELOOKUPENTRY)
  5712. )))
  5713. {
  5714. return PHONEERR_NOMEM;
  5715. }
  5716. pNewLookup->dwNumTotalEntries = pLookup->dwNumTotalEntries;
  5717. pLookup->pNext = pNewLookup;
  5718. }
  5719. pLookup = pNewLookup;
  5720. }
  5721. //
  5722. // Initialize the entry
  5723. //
  5724. {
  5725. DWORD index = pLookup->dwNumUsedEntries;
  5726. pLookup->aEntries[index].dwSPIVersion = dwSPIVersion;
  5727. pLookup->aEntries[index].hMutex = hMutex;
  5728. pLookup->aEntries[index].ptProvider = ptProvider;
  5729. }
  5730. pLookup->dwNumUsedEntries++;
  5731. #if TELE_SERVER
  5732. //
  5733. // If this is an NT Server we want to be able to set user
  5734. // permissions regardless of whether or not TAPI server
  5735. // functionality is enabled. This allows an admin to set
  5736. // stuff up while the server is "offline".
  5737. //
  5738. if (gbNTServer)
  5739. {
  5740. GetPermPhoneIDAndInsertInTable (ptProvider, dwDeviceID, dwSPIVersion);
  5741. }
  5742. #endif
  5743. return 0;
  5744. }
  5745. DWORD
  5746. GetNumPhoneLookupEntries ()
  5747. {
  5748. PTPHONELOOKUPTABLE pPhoneLookup;
  5749. DWORD dwNumPhones;
  5750. pPhoneLookup = TapiGlobals.pPhoneLookup;
  5751. dwNumPhones = 0;
  5752. while (pPhoneLookup)
  5753. {
  5754. dwNumPhones += pPhoneLookup->dwNumUsedEntries;
  5755. pPhoneLookup = pPhoneLookup->pNext;
  5756. }
  5757. return dwNumPhones;
  5758. }
  5759. void
  5760. PASCAL
  5761. GetMediaModesPriorityLists(
  5762. HKEY hKeyHandoffPriorities,
  5763. PRILISTSTRUCT **ppList
  5764. )
  5765. {
  5766. #define REGNAMESIZE ( 10 * sizeof(TCHAR) )
  5767. DWORD dwCount;
  5768. DWORD dwType, dwNameSize, dwNumBytes;
  5769. TCHAR *pszName;
  5770. *ppList = NULL;
  5771. TapiGlobals.dwTotalPriorityLists = 0;
  5772. TapiGlobals.dwUsedPriorityLists = 0;
  5773. dwNameSize = REGNAMESIZE;
  5774. pszName = ServerAlloc( dwNameSize*sizeof(TCHAR) );
  5775. if (NULL == pszName)
  5776. {
  5777. return;
  5778. }
  5779. // alloc structures plus some
  5780. *ppList = ( PRILISTSTRUCT * ) ServerAlloc( (sizeof(PRILISTSTRUCT)) * 5);
  5781. if (NULL == (*ppList))
  5782. {
  5783. LOG((TL_ERROR, "ServerAlloc failed in GetMediaModesPriorityLists"));
  5784. ServerFree( pszName );
  5785. return;
  5786. }
  5787. TapiGlobals.dwTotalPriorityLists = 5;
  5788. TapiGlobals.dwUsedPriorityLists = 0;
  5789. dwCount = 0;
  5790. while ( TRUE )
  5791. {
  5792. if (TapiGlobals.dwUsedPriorityLists == TapiGlobals.dwTotalPriorityLists)
  5793. {
  5794. // realloc
  5795. PRILISTSTRUCT * pNewList;
  5796. pNewList = ServerAlloc( sizeof(PRILISTSTRUCT) * (2*TapiGlobals.dwTotalPriorityLists) );
  5797. if (NULL == pNewList)
  5798. {
  5799. LOG((TL_ERROR, "ServerAlloc failed in GetMediaModesPriorityLists 2"));
  5800. ServerFree( pszName );
  5801. return;
  5802. }
  5803. CopyMemory(
  5804. pNewList,
  5805. *ppList,
  5806. sizeof( PRILISTSTRUCT ) * TapiGlobals.dwTotalPriorityLists
  5807. );
  5808. ServerFree( *ppList );
  5809. *ppList = pNewList;
  5810. TapiGlobals.dwTotalPriorityLists *= 2;
  5811. }
  5812. dwNameSize = REGNAMESIZE;
  5813. if ( ERROR_SUCCESS != RegEnumValue(
  5814. hKeyHandoffPriorities,
  5815. dwCount,
  5816. pszName,
  5817. &dwNameSize,
  5818. NULL,
  5819. NULL,
  5820. NULL,
  5821. NULL
  5822. ) )
  5823. {
  5824. break;
  5825. }
  5826. (*ppList)[dwCount].dwMediaModes =
  5827. (DWORD) _ttol( pszName );
  5828. if ((RegQueryValueEx(
  5829. hKeyHandoffPriorities,
  5830. pszName,
  5831. NULL,
  5832. &dwType,
  5833. NULL,
  5834. &dwNumBytes
  5835. )) == ERROR_SUCCESS &&
  5836. (dwNumBytes != 0))
  5837. {
  5838. // pszPriotiryList needs to be wide because we pack it into one of our
  5839. // little structures and these structures are always WCHAR.
  5840. LPWSTR pszPriorityList;
  5841. // convert from the bytes needed to hold a TCHAR into the bytes to hold a WCHAR
  5842. dwNumBytes *= sizeof(WCHAR)/sizeof(TCHAR);
  5843. pszPriorityList = ServerAlloc ( dwNumBytes + sizeof(WCHAR));
  5844. // need an extra WCHAR for the extra '"'
  5845. if (NULL != pszPriorityList)
  5846. {
  5847. pszPriorityList[0] = L'"';
  5848. if ((TAPIRegQueryValueExW(
  5849. hKeyHandoffPriorities,
  5850. pszName,
  5851. NULL,
  5852. &dwType,
  5853. (LPBYTE)(pszPriorityList + 1),
  5854. &dwNumBytes
  5855. )) == ERROR_SUCCESS)
  5856. {
  5857. _wcsupr( pszPriorityList );
  5858. (*ppList)[dwCount].pszPriList = pszPriorityList;
  5859. LOG((TL_INFO, "PriList: %ls=%ls", pszName, pszPriorityList));
  5860. }
  5861. }
  5862. }
  5863. TapiGlobals.dwUsedPriorityLists++;
  5864. dwCount++;
  5865. }
  5866. ServerFree( pszName );
  5867. }
  5868. void
  5869. PASCAL
  5870. GetPriorityList(
  5871. HKEY hKeyHandoffPriorities,
  5872. const TCHAR *pszListName,
  5873. WCHAR **ppszPriorityList
  5874. )
  5875. {
  5876. LONG lResult;
  5877. DWORD dwType, dwNumBytes;
  5878. *ppszPriorityList = NULL;
  5879. if ((lResult = TAPIRegQueryValueExW(
  5880. hKeyHandoffPriorities,
  5881. pszListName,
  5882. NULL,
  5883. &dwType,
  5884. NULL,
  5885. &dwNumBytes
  5886. )) == ERROR_SUCCESS &&
  5887. (dwNumBytes != 0))
  5888. {
  5889. // Once again, this is going to get packed into a struct and we always use
  5890. // wide chars for things packed in structs.
  5891. WCHAR *pszPriorityList = ServerAlloc ( dwNumBytes + sizeof(WCHAR));
  5892. // need an extra WCHAR for the extra '"'
  5893. if (pszPriorityList)
  5894. {
  5895. pszPriorityList[0] = L'"';
  5896. if ((lResult = TAPIRegQueryValueExW(
  5897. hKeyHandoffPriorities,
  5898. pszListName,
  5899. NULL,
  5900. &dwType,
  5901. (LPBYTE)(pszPriorityList + 1),
  5902. &dwNumBytes
  5903. )) == ERROR_SUCCESS)
  5904. {
  5905. _wcsupr( pszPriorityList );
  5906. *ppszPriorityList = pszPriorityList;
  5907. LOG((TL_INFO, "PriList: %ls=%ls", pszListName, pszPriorityList));
  5908. }
  5909. }
  5910. else
  5911. {
  5912. //
  5913. // Don't bother with the failure to alloc a priority list
  5914. // (list defaults to NULL anyway), we'll deal with a lack
  5915. // of memory at a later time
  5916. //
  5917. *ppszPriorityList = NULL;
  5918. }
  5919. }
  5920. else
  5921. {
  5922. *ppszPriorityList = NULL;
  5923. LOG((TL_INFO, "PriList: %ls=NULL", pszListName));
  5924. }
  5925. }
  5926. LONG
  5927. ServerInit(
  5928. BOOL fReinit
  5929. )
  5930. {
  5931. UINT uiNumProviders, i, j;
  5932. HKEY hKeyTelephony, hKeyProviders;
  5933. DWORD dwDataSize, dwDataType, dwNameHash;
  5934. TCHAR *psz;
  5935. LONG lResult = 0;
  5936. DWORD dw1, dw2;
  5937. //
  5938. // Clean up our private heap
  5939. //
  5940. if (ghTapisrvHeap != GetProcessHeap())
  5941. {
  5942. HeapCompact (ghTapisrvHeap, 0);
  5943. }
  5944. //
  5945. // Initialize the globals
  5946. //
  5947. if (!fReinit)
  5948. {
  5949. TapiGlobals.ptProviders = NULL;
  5950. TapiGlobals.pLineLookup = (PTLINELOOKUPTABLE) ServerAlloc(
  5951. sizeof (TLINELOOKUPTABLE) +
  5952. (DEF_NUM_LOOKUP_ENTRIES - 1) * sizeof (TLINELOOKUPENTRY)
  5953. );
  5954. if (!(TapiGlobals.pLineLookup))
  5955. {
  5956. lResult = LINEERR_NOMEM;
  5957. goto ExitHere;
  5958. }
  5959. TapiGlobals.pLineLookup->dwNumTotalEntries = DEF_NUM_LOOKUP_ENTRIES;
  5960. TapiGlobals.pPhoneLookup = (PTPHONELOOKUPTABLE) ServerAlloc(
  5961. sizeof (TPHONELOOKUPTABLE) +
  5962. (DEF_NUM_LOOKUP_ENTRIES - 1) * sizeof (TPHONELOOKUPENTRY)
  5963. );
  5964. if (!(TapiGlobals.pPhoneLookup))
  5965. {
  5966. ServerFree(TapiGlobals.pLineLookup);
  5967. TapiGlobals.pLineLookup = NULL;
  5968. lResult = LINEERR_NOMEM;
  5969. goto ExitHere;
  5970. }
  5971. TapiGlobals.pPhoneLookup->dwNumTotalEntries = DEF_NUM_LOOKUP_ENTRIES;
  5972. gbQueueSPEvents = TRUE;
  5973. OnProxySCPInit ();
  5974. }
  5975. //
  5976. // Determine number of providers
  5977. //
  5978. RegOpenKeyEx(
  5979. HKEY_LOCAL_MACHINE,
  5980. gszRegKeyTelephony,
  5981. 0,
  5982. KEY_ALL_ACCESS,
  5983. &hKeyTelephony
  5984. );
  5985. RegOpenKeyEx(
  5986. HKEY_LOCAL_MACHINE,
  5987. gszRegKeyProviders,
  5988. 0,
  5989. KEY_ALL_ACCESS,
  5990. &hKeyProviders
  5991. );
  5992. dwDataSize = sizeof(uiNumProviders);
  5993. uiNumProviders = 0;
  5994. RegQueryValueEx(
  5995. hKeyProviders,
  5996. gszNumProviders,
  5997. 0,
  5998. &dwDataType,
  5999. (LPBYTE) &uiNumProviders,
  6000. &dwDataSize
  6001. );
  6002. LOG((TL_INFO, "ServerInit: NumProviders=%d", uiNumProviders));
  6003. //
  6004. // Load & init the providers
  6005. //
  6006. for (i = 0; i < uiNumProviders; i++)
  6007. {
  6008. #define FILENAME_SIZE 128
  6009. TCHAR szFilename[FILENAME_SIZE];
  6010. TCHAR buf[32];
  6011. LONG lResult;
  6012. DWORD dwNumLines, dwNumPhones, dwPermanentProviderID;
  6013. PTPROVIDER ptProvider;
  6014. BOOL fEnumDevices;
  6015. fEnumDevices = FALSE;
  6016. wsprintf(buf, TEXT("%s%d"), gszProviderID, i);
  6017. dwDataSize = sizeof(dwPermanentProviderID);
  6018. dwPermanentProviderID = 0;
  6019. RegQueryValueEx(
  6020. hKeyProviders,
  6021. buf, //"ProviderID#"
  6022. 0,
  6023. &dwDataType,
  6024. (LPBYTE) &dwPermanentProviderID,
  6025. &dwDataSize
  6026. );
  6027. //
  6028. // Back to the main section
  6029. //
  6030. dwDataSize = FILENAME_SIZE;
  6031. wsprintf(buf, TEXT("%s%d"), gszProviderFilename, i);
  6032. RegQueryValueEx(
  6033. hKeyProviders,
  6034. buf, // "ProviderFilename#"
  6035. 0,
  6036. &dwDataType,
  6037. (LPBYTE) szFilename,
  6038. &dwDataSize
  6039. );
  6040. szFilename[dwDataSize/sizeof(TCHAR)] = TEXT('\0');
  6041. //
  6042. // Compute name hash
  6043. //
  6044. dwNameHash = 0;
  6045. psz = szFilename;
  6046. while (*psz)
  6047. {
  6048. dwNameHash += (DWORD)(*psz);
  6049. psz++;
  6050. }
  6051. //
  6052. // If fReinit, make sure the provider is not already in
  6053. //
  6054. if (fReinit)
  6055. {
  6056. PTPROVIDER ptProvider2;
  6057. BOOL fFound = FALSE;
  6058. ptProvider2 = TapiGlobals.ptProviders;
  6059. while (ptProvider2)
  6060. {
  6061. if ((ptProvider2->dwNameHash == dwNameHash) &&
  6062. (lstrcmpi(ptProvider2->szFileName, szFilename) == 0))
  6063. {
  6064. fFound = TRUE;
  6065. break;
  6066. }
  6067. ptProvider2 = ptProvider2->pNext;
  6068. }
  6069. if (fFound)
  6070. {
  6071. continue;
  6072. }
  6073. }
  6074. LOG((TL_INFO, "ServerInit: ProviderFilename=%S", szFilename));
  6075. if (!(ptProvider = (PTPROVIDER) ServerAlloc(
  6076. sizeof(TPROVIDER) + ((lstrlen(szFilename) + 1) * sizeof(TCHAR))
  6077. )))
  6078. {
  6079. break;
  6080. }
  6081. if (!(ptProvider->hDll = LoadLibrary(szFilename)))
  6082. {
  6083. LOG((TL_ERROR,
  6084. "ServerInit: LoadLibrary(%S) failed, err=x%x",
  6085. szFilename,
  6086. GetLastError()
  6087. ));
  6088. ServerFree (ptProvider);
  6089. continue;
  6090. }
  6091. ptProvider->dwNameHash = dwNameHash;
  6092. lstrcpy(ptProvider->szFileName, szFilename);
  6093. //
  6094. // Get all the TSPI proc addrs
  6095. //
  6096. for (j = 0; gaszTSPIFuncNames[j]; j++)
  6097. {
  6098. ptProvider->apfn[j] = (TSPIPROC) GetProcAddress(
  6099. ptProvider->hDll,
  6100. (LPCSTR) gaszTSPIFuncNames[j]
  6101. );
  6102. }
  6103. dwNumLines = dwNumPhones = 0;
  6104. //
  6105. // A real quick check to see if a couple of required entrypoints
  6106. // are exported
  6107. //
  6108. if (!ptProvider->apfn[SP_LINENEGOTIATETSPIVERSION] ||
  6109. !ptProvider->apfn[SP_PROVIDERENUMDEVICES] ||
  6110. !ptProvider->apfn[SP_PROVIDERINIT] ||
  6111. !ptProvider->apfn[SP_PROVIDERSHUTDOWN]
  6112. )
  6113. {
  6114. goto ServerInit_validateEntrypoints;
  6115. }
  6116. //
  6117. // Do global provider version negotiation
  6118. //
  6119. lResult = CallSP4(
  6120. ptProvider->apfn[SP_LINENEGOTIATETSPIVERSION],
  6121. "lineNegotiateTSPIVersion",
  6122. SP_FUNC_SYNC,
  6123. (DWORD)INITIALIZE_NEGOTIATION,
  6124. (DWORD)TAPI_VERSION1_0,
  6125. (DWORD)TAPI_VERSION_CURRENT,
  6126. (ULONG_PTR) &ptProvider->dwSPIVersion
  6127. );
  6128. if (lResult != 0)
  6129. {
  6130. provider_init_error:
  6131. if (fEnumDevices)
  6132. {
  6133. lResult = CallSP2(
  6134. ptProvider->apfn[SP_PROVIDERSHUTDOWN],
  6135. "providerShutdown",
  6136. SP_FUNC_SYNC,
  6137. (DWORD)ptProvider->dwSPIVersion,
  6138. (DWORD)ptProvider->dwPermanentProviderID
  6139. );
  6140. }
  6141. if (ptProvider->hMutex)
  6142. {
  6143. MyCloseMutex (ptProvider->hMutex);
  6144. }
  6145. if (ptProvider->hHashTableReaderEvent)
  6146. {
  6147. CloseHandle (ptProvider->hHashTableReaderEvent);
  6148. }
  6149. if (ptProvider->pHashTable)
  6150. {
  6151. ServerFree (ptProvider->pHashTable);
  6152. }
  6153. FreeLibrary (ptProvider->hDll);
  6154. ServerFree (ptProvider);
  6155. continue;
  6156. }
  6157. //
  6158. // Try to enum the devices if provider supports it, otherwise
  6159. // try grabbing the num lines & phones from ProviderN section
  6160. //
  6161. lResult = CallSP6(
  6162. ptProvider->apfn[SP_PROVIDERENUMDEVICES],
  6163. "providerEnumDevices",
  6164. SP_FUNC_SYNC,
  6165. (DWORD)dwPermanentProviderID,
  6166. (ULONG_PTR) &dwNumLines,
  6167. (ULONG_PTR) &dwNumPhones,
  6168. (ULONG_PTR) ptProvider,
  6169. (ULONG_PTR) LineEventProcSP,
  6170. (ULONG_PTR) PhoneEventProcSP
  6171. );
  6172. if (lResult != 0)
  6173. {
  6174. LOG((TL_ERROR,
  6175. "ServerInit: %s: failed TSPI_providerEnumDevices, err=x%x" \
  6176. " - skipping it...",
  6177. szFilename,
  6178. lResult
  6179. ));
  6180. goto provider_init_error;
  6181. }
  6182. //
  6183. // Init the provider
  6184. //
  6185. // !!! HACK ALERT: for kmddsp pass ptr's to dwNumXxxs
  6186. //
  6187. {
  6188. BOOL bKmddsp;
  6189. LOG((TL_INFO, "ServerInit: %s: Calling TSPI_providerInit", szFilename));
  6190. if (lstrcmpi(szFilename, TEXT("kmddsp.tsp")) == 0)
  6191. {
  6192. bKmddsp = TRUE;
  6193. }
  6194. else
  6195. {
  6196. bKmddsp = FALSE;
  6197. if (lstrcmpi(szFilename, TEXT("remotesp.tsp")) == 0)
  6198. {
  6199. pRemoteSP = ptProvider;
  6200. }
  6201. }
  6202. lResult = CallSP8(
  6203. ptProvider->apfn[SP_PROVIDERINIT],
  6204. "providerInit",
  6205. SP_FUNC_SYNC,
  6206. (DWORD)ptProvider->dwSPIVersion,
  6207. (DWORD)dwPermanentProviderID,
  6208. (DWORD)GetNumLineLookupEntries (),
  6209. (DWORD)GetNumPhoneLookupEntries (),
  6210. (bKmddsp ? (ULONG_PTR) &dwNumLines : (ULONG_PTR) dwNumLines),
  6211. (bKmddsp ? (ULONG_PTR) &dwNumPhones : (ULONG_PTR) dwNumPhones),
  6212. (ULONG_PTR) CompletionProcSP,
  6213. (ULONG_PTR) &ptProvider->dwTSPIOptions
  6214. );
  6215. }
  6216. if (lResult != 0)
  6217. {
  6218. LOG((TL_ERROR,
  6219. "ServerInit: %s: failed TSPI_providerInit, err=x%x" \
  6220. " - skipping it...",
  6221. szFilename,
  6222. lResult
  6223. ));
  6224. goto provider_init_error;
  6225. }
  6226. LOG((TL_INFO,
  6227. "ServerInit: %s init'd, dwNumLines=%ld, dwNumPhones=%ld",
  6228. szFilename,
  6229. dwNumLines,
  6230. dwNumPhones
  6231. ));
  6232. fEnumDevices = TRUE;
  6233. //
  6234. // Now that we know if we have line and/or phone devs check for
  6235. // the required entry points
  6236. //
  6237. ServerInit_validateEntrypoints:
  6238. {
  6239. DWORD adwRequiredEntrypointIndices[] =
  6240. {
  6241. SP_LINENEGOTIATETSPIVERSION,
  6242. SP_PROVIDERINIT,
  6243. SP_PROVIDERSHUTDOWN,
  6244. SP_PHONENEGOTIATETSPIVERSION,
  6245. 0xffffffff
  6246. };
  6247. BOOL bRequiredEntrypointsExported = TRUE;
  6248. //
  6249. // If this provider doesn't support any phone devices then
  6250. // it isn't required to export phone funcs
  6251. //
  6252. if (dwNumPhones == 0)
  6253. {
  6254. adwRequiredEntrypointIndices[3] = 0xffffffff;
  6255. }
  6256. for (j = 0; adwRequiredEntrypointIndices[j] != 0xffffffff; j++)
  6257. {
  6258. if (ptProvider->apfn[adwRequiredEntrypointIndices[j]]
  6259. == (TSPIPROC) NULL)
  6260. {
  6261. LOG((TL_ERROR,
  6262. "ServerInit: %s: can't init, function [%s] " \
  6263. "not exported",
  6264. szFilename,
  6265. (LPCSTR) gaszTSPIFuncNames[
  6266. adwRequiredEntrypointIndices[j]
  6267. ]
  6268. ));
  6269. bRequiredEntrypointsExported = FALSE;
  6270. }
  6271. }
  6272. if (bRequiredEntrypointsExported == FALSE)
  6273. {
  6274. FreeLibrary (ptProvider->hDll);
  6275. ServerFree (ptProvider);
  6276. continue;
  6277. }
  6278. }
  6279. ptProvider->dwPermanentProviderID = dwPermanentProviderID;
  6280. //
  6281. //
  6282. //
  6283. ptProvider->hMutex = MyCreateMutex();
  6284. //
  6285. // Initialize the call hub hash table for this provider
  6286. //
  6287. MyInitializeCriticalSection (&ptProvider->HashTableCritSec, 1000);
  6288. ptProvider->hHashTableReaderEvent = CreateEvent(
  6289. (LPSECURITY_ATTRIBUTES) NULL,
  6290. FALSE, // auto reset
  6291. FALSE, // initially non-signaled
  6292. NULL // unnamed
  6293. );
  6294. ptProvider->dwNumHashTableEntries = TapiPrimes[0];
  6295. ptProvider->pHashTable = ServerAlloc(
  6296. ptProvider->dwNumHashTableEntries * sizeof (THASHTABLEENTRY)
  6297. );
  6298. if (ptProvider->pHashTable)
  6299. {
  6300. PTHASHTABLEENTRY pEntry = ptProvider->pHashTable;
  6301. for (j = 0; j < ptProvider->dwNumHashTableEntries; j++, pEntry++)
  6302. {
  6303. InitializeListHead (&pEntry->CallHubList);
  6304. }
  6305. }
  6306. else
  6307. {
  6308. ptProvider->dwNumHashTableEntries = 0;
  6309. }
  6310. if (ptProvider->hMutex == NULL ||
  6311. ptProvider->hHashTableReaderEvent == NULL ||
  6312. ptProvider->pHashTable == NULL
  6313. )
  6314. {
  6315. DeleteCriticalSection (&ptProvider->HashTableCritSec);
  6316. goto provider_init_error;
  6317. }
  6318. #if TELE_SERVER
  6319. //
  6320. // If this is an NT Server we want to be able to set user
  6321. // permissions regardless of whether or not TAPI server
  6322. // functionality is enabled. This allows an admin to set
  6323. // stuff up while the server is "offline".
  6324. //
  6325. if (gbNTServer)
  6326. {
  6327. LONG lResult;
  6328. lResult = AddProviderToIdArrayList(
  6329. ptProvider,
  6330. dwNumLines,
  6331. dwNumPhones
  6332. );
  6333. if (lResult != 0)
  6334. {
  6335. LOG((TL_ERROR,
  6336. "ServerInit: %s: failed AddProviderToIdArrayList [x%x]" \
  6337. " - skipping it...",
  6338. ptProvider->szFileName,
  6339. lResult
  6340. ));
  6341. DeleteCriticalSection (&ptProvider->HashTableCritSec);
  6342. goto provider_init_error;
  6343. }
  6344. }
  6345. #endif
  6346. //
  6347. // Do version negotiation on each device & add them to lookup lists
  6348. //
  6349. {
  6350. DWORD dwDeviceIDBase;
  6351. dwDeviceIDBase = GetNumLineLookupEntries ();
  6352. for (j = dwDeviceIDBase; j < (dwDeviceIDBase + dwNumLines); j++)
  6353. {
  6354. if (AddLine (ptProvider, j, !fReinit))
  6355. {
  6356. }
  6357. }
  6358. dwDeviceIDBase = GetNumPhoneLookupEntries ();
  6359. for (j = dwDeviceIDBase; j < (dwDeviceIDBase + dwNumPhones); j++)
  6360. {
  6361. if (AddPhone (ptProvider, j, !fReinit))
  6362. {
  6363. }
  6364. }
  6365. }
  6366. //
  6367. // Add provider to head of list, mark as valid
  6368. //
  6369. ptProvider->pPrev = NULL;
  6370. ptProvider->pNext = TapiGlobals.ptProviders;
  6371. if (TapiGlobals.ptProviders)
  6372. {
  6373. TapiGlobals.ptProviders->pPrev = ptProvider;
  6374. }
  6375. TapiGlobals.ptProviders = ptProvider;
  6376. ptProvider->dwKey = TPROVIDER_KEY;
  6377. }
  6378. RegCloseKey (hKeyProviders);
  6379. RegCloseKey (hKeyTelephony);
  6380. //
  6381. // Save lookup lists & num devices
  6382. //
  6383. if (fReinit)
  6384. {
  6385. dw1 = TapiGlobals.dwNumLines;
  6386. dw2 = TapiGlobals.dwNumPhones;
  6387. }
  6388. TapiGlobals.dwNumLines = GetNumLineLookupEntries ();
  6389. TapiGlobals.dwNumPhones = GetNumPhoneLookupEntries ();
  6390. //
  6391. // Notify those apps about these new line/phone devices
  6392. //
  6393. if (fReinit)
  6394. {
  6395. // TAPI 1.4 and above get LINE_CREATE for each line
  6396. for (i = dw1; i < TapiGlobals.dwNumLines; ++i)
  6397. {
  6398. SendAMsgToAllLineApps(
  6399. TAPI_VERSION1_4 | 0x80000000,
  6400. LINE_CREATE, // Msg
  6401. i, // Param1
  6402. 0, // Param2
  6403. 0 // Param3
  6404. );
  6405. }
  6406. // TAPI 1.3 get LINE_LINEDEVSTATE with LINEDEVSTATE_REINIT
  6407. if (dw1 < TapiGlobals.dwNumLines)
  6408. {
  6409. SendAMsgToAllLineApps(
  6410. TAPI_VERSION1_0,
  6411. LINE_LINEDEVSTATE,
  6412. LINEDEVSTATE_REINIT,
  6413. 0,
  6414. 0);
  6415. }
  6416. // TAPI 1.4 and above get PHONE_CREATE for each phone
  6417. for (i = dw2; i < TapiGlobals.dwNumPhones; ++i)
  6418. {
  6419. SendAMsgToAllPhoneApps(
  6420. TAPI_VERSION1_4 | 0x80000000,
  6421. PHONE_CREATE, // Msg
  6422. i, // Param1
  6423. 0, // Param2
  6424. 0 // Param3
  6425. );
  6426. }
  6427. // TAPI 1.3 gets PHONE_STATE with PHONESTATE_REINIT
  6428. if (dw2 < TapiGlobals.dwNumPhones)
  6429. {
  6430. SendAMsgToAllPhoneApps(
  6431. TAPI_VERSION1_0,
  6432. PHONE_STATE,
  6433. PHONESTATE_REINIT,
  6434. 0,
  6435. 0);
  6436. }
  6437. for (i = dw1; i < TapiGlobals.dwNumLines; ++i)
  6438. {
  6439. AppendNewDeviceInfo (TRUE, i);
  6440. }
  6441. for (i = dw2; i < TapiGlobals.dwNumPhones; ++i)
  6442. {
  6443. AppendNewDeviceInfo (FALSE, i);
  6444. }
  6445. }
  6446. // init perf stuff
  6447. PerfBlock.dwLines = TapiGlobals.dwNumLines;
  6448. PerfBlock.dwPhones = TapiGlobals.dwNumPhones;
  6449. ExitHere:
  6450. return lResult;
  6451. }
  6452. #if TELE_SERVER
  6453. #ifndef UNICODE
  6454. #pragma message( "ERROR: TELE_SERVER builds must define UNICODE" )
  6455. #endif
  6456. BOOL
  6457. LoadNewDll(PTMANAGEDLLINFO pDll)
  6458. {
  6459. DWORD dwCount;
  6460. LONG lResult;
  6461. // verify pointers. should we do more?
  6462. if (!pDll || !pDll->pszName)
  6463. {
  6464. return FALSE;
  6465. }
  6466. // load dll
  6467. pDll->hDll = LoadLibraryW(pDll->pszName);
  6468. // if it fails, return
  6469. if (!pDll->hDll)
  6470. {
  6471. LOG((TL_ERROR,
  6472. "LoadLibrary failed for management DLL %ls - error x%lx",
  6473. pDll->pszName,
  6474. GetLastError()
  6475. ));
  6476. return FALSE;
  6477. }
  6478. if ((!(pDll->aProcs[TC_CLIENTINITIALIZE] = (CLIENTPROC) GetProcAddress(
  6479. pDll->hDll,
  6480. gaszTCFuncNames[TC_CLIENTINITIALIZE]
  6481. ))) ||
  6482. (!(pDll->aProcs[TC_CLIENTSHUTDOWN] = (CLIENTPROC) GetProcAddress(
  6483. pDll->hDll,
  6484. gaszTCFuncNames[TC_CLIENTSHUTDOWN]
  6485. ))) ||
  6486. (!(pDll->aProcs[TC_LOAD] = (CLIENTPROC) GetProcAddress(
  6487. pDll->hDll,
  6488. gaszTCFuncNames[TC_LOAD]
  6489. ))) ||
  6490. (!(pDll->aProcs[TC_FREE] = (CLIENTPROC) GetProcAddress(
  6491. pDll->hDll,
  6492. gaszTCFuncNames[TC_FREE]
  6493. ))))
  6494. {
  6495. // must export client init and client shutdown
  6496. LOG((TL_ERROR, "Management DLL %ls does not export Load, Free, ClientIntialize or ClientShutdown", pDll->pszName));
  6497. LOG((TL_ERROR, " The DLL will not be used"));
  6498. FreeLibrary(pDll->hDll);
  6499. return FALSE;
  6500. }
  6501. // get proc addresses
  6502. for (dwCount = 0; dwCount < TC_LASTPROCNUMBER; dwCount++)
  6503. {
  6504. pDll->aProcs[dwCount] = (CLIENTPROC) GetProcAddress(
  6505. pDll->hDll,
  6506. gaszTCFuncNames[dwCount]
  6507. );
  6508. }
  6509. pDll->dwAPIVersion = TAPI_VERSION_CURRENT;
  6510. lResult = (pDll->aProcs[TC_LOAD])(
  6511. &pDll->dwAPIVersion,
  6512. ManagementAddLineProc,
  6513. ManagementAddPhoneProc,
  6514. 0
  6515. );
  6516. if (lResult)
  6517. {
  6518. LOG((TL_ERROR, "Management DLL %ls returned %xlx from TAPICLIENT_Load", pDll->pszName, lResult));
  6519. LOG((TL_ERROR, " The DLL will not be used"));
  6520. FreeLibrary(pDll->hDll);
  6521. return FALSE;
  6522. }
  6523. if ((pDll->dwAPIVersion > TAPI_VERSION_CURRENT) || (pDll->dwAPIVersion < TAPI_VERSION2_1))
  6524. {
  6525. LOG((TL_INFO,
  6526. "Management DLL %ls returned an invalid API version - x%lx",
  6527. pDll->pszName,
  6528. pDll->dwAPIVersion
  6529. ));
  6530. LOG((TL_INFO, " Will use version x%lx", TAPI_VERSION_CURRENT));
  6531. pDll->dwAPIVersion = TAPI_VERSION_CURRENT;
  6532. }
  6533. return TRUE;
  6534. }
  6535. // Only exists for TELE_SERVER, which implies NT and thus Unicode. As
  6536. // such it is safe to assume that TCHAR == WCHAR for these.
  6537. void
  6538. ReadAndInitMapper()
  6539. {
  6540. PTMANAGEDLLINFO pMapperInfo;
  6541. HKEY hKey;
  6542. DWORD dwDataSize, dwDataType, dwCount;
  6543. LPBYTE pHold;
  6544. LONG lResult;
  6545. assert( sizeof(TCHAR) == sizeof(WCHAR) );
  6546. if (!(TapiGlobals.dwFlags & TAPIGLOBALS_SERVER))
  6547. {
  6548. return;
  6549. }
  6550. if ( ! ( pMapperInfo = ServerAlloc( sizeof(TMANAGEDLLINFO) ) ) )
  6551. {
  6552. LOG((TL_ERROR, "ServerAlloc failed in ReadAndInitMap"));
  6553. TapiGlobals.dwFlags &= ~(TAPIGLOBALS_SERVER);
  6554. return;
  6555. }
  6556. // grab server specific stuff from registry
  6557. RegOpenKeyEx(
  6558. HKEY_LOCAL_MACHINE,
  6559. gszRegKeyServer,
  6560. 0,
  6561. KEY_ALL_ACCESS,
  6562. &hKey
  6563. );
  6564. dwDataSize = 0;
  6565. RegQueryValueExW(
  6566. hKey,
  6567. gszMapperDll,
  6568. 0,
  6569. &dwDataType,
  6570. NULL,
  6571. &dwDataSize
  6572. );
  6573. if (dwDataSize == 0)
  6574. {
  6575. LOG((TL_ERROR, "Cannot init client/server stuff (registry damaged?)"));
  6576. RegCloseKey( hKey );
  6577. ServerFree(pMapperInfo);
  6578. TapiGlobals.dwFlags &= ~(TAPIGLOBALS_SERVER);
  6579. return;
  6580. }
  6581. if (!(pHold = ServerAlloc(dwDataSize)))
  6582. {
  6583. LOG((TL_ERROR, "Alloc failed in ReadAndInitMap(o)"));
  6584. TapiGlobals.dwFlags &= ~(TAPIGLOBALS_SERVER);
  6585. ServerFree(pMapperInfo);
  6586. return;
  6587. }
  6588. RegQueryValueExW(
  6589. hKey,
  6590. gszMapperDll,
  6591. 0,
  6592. &dwDataType,
  6593. pHold,
  6594. &dwDataSize
  6595. );
  6596. RegCloseKey( hKey );
  6597. // LOG((TL_INFO, "MapperDll is %ls", pHold));
  6598. if (!(pMapperInfo->hDll = LoadLibraryW((LPWSTR)pHold)))
  6599. {
  6600. LOG((TL_ERROR, "Serious internal failure loading client/server DLL . Error %lu", pHold, GetLastError()));
  6601. ServerFree( pHold );
  6602. ServerFree( pMapperInfo );
  6603. TapiGlobals.dwFlags &= ~(TAPIGLOBALS_SERVER);
  6604. return;
  6605. }
  6606. // don't need these two for the mapper
  6607. pMapperInfo->pNext = NULL;
  6608. // save the name
  6609. pMapperInfo->pszName = (LPWSTR)pHold;
  6610. // get proc addresses for the first 5 api
  6611. for (dwCount = 0; dwCount < 5; dwCount ++)
  6612. {
  6613. if (!(pMapperInfo->aProcs[dwCount] = (CLIENTPROC) GetProcAddress(
  6614. pMapperInfo->hDll,
  6615. gaszTCFuncNames[dwCount]
  6616. )))
  6617. {
  6618. // one of these addresses failed. remove DLL
  6619. LOG((TL_INFO, "MapperDLL does not export %s. Server functionality disabled", gaszTCFuncNames[dwCount]));
  6620. LOG((TL_INFO, "Disabling the Telephony server! (8)"));
  6621. FreeLibrary(pMapperInfo->hDll);
  6622. ServerFree(pMapperInfo->pszName);
  6623. ServerFree(pMapperInfo);
  6624. TapiGlobals.pMapperDll = NULL;
  6625. TapiGlobals.dwFlags &= ~(TAPIGLOBALS_SERVER);
  6626. return;
  6627. }
  6628. }
  6629. pMapperInfo->dwAPIVersion = TAPI_VERSION_CURRENT;
  6630. lResult = (pMapperInfo->aProcs[TC_LOAD])(
  6631. &pMapperInfo->dwAPIVersion,
  6632. ManagementAddLineProc,
  6633. ManagementAddPhoneProc,
  6634. 0
  6635. );
  6636. if (lResult)
  6637. {
  6638. LOG((TL_INFO, "Client/server loadup - x%lx.", lResult));
  6639. FreeLibrary(pMapperInfo->hDll);
  6640. ServerFree(pMapperInfo->pszName);
  6641. ServerFree(pMapperInfo);
  6642. TapiGlobals.pMapperDll = NULL;
  6643. TapiGlobals.dwFlags &= ~(TAPIGLOBALS_SERVER);
  6644. return;
  6645. }
  6646. if ((pMapperInfo->dwAPIVersion > TAPI_VERSION_CURRENT) || (pMapperInfo->dwAPIVersion < TAPI_VERSION2_1))
  6647. {
  6648. LOG((TL_ERROR, "Internal version mismatch! Check that all components are in sync x%lx", pMapperInfo->dwAPIVersion));
  6649. LOG((TL_INFO, " Will use version x%lx", TAPI_VERSION_CURRENT));
  6650. pMapperInfo->dwAPIVersion = TAPI_VERSION_CURRENT;
  6651. }
  6652. TapiGlobals.pMapperDll = pMapperInfo;
  6653. }
  6654. LONG
  6655. FreeOldDllListProc(
  6656. PTMANAGEDLLLISTHEADER pDllList
  6657. )
  6658. {
  6659. PTMANAGEDLLINFO pDll, pNext;
  6660. #if DBG
  6661. DWORD dwCount = 0;
  6662. #endif
  6663. SetThreadPriority(
  6664. GetCurrentThread(),
  6665. THREAD_PRIORITY_LOWEST
  6666. );
  6667. // wait until count is 0
  6668. while (pDllList->lCount > 0)
  6669. {
  6670. Sleep(100);
  6671. #if DBG
  6672. dwCount++;
  6673. if (dwCount > 100)
  6674. {
  6675. LOG((TL_INFO, "FreeOldDllListProc still waiting after 10 seconds"));
  6676. }
  6677. #endif
  6678. }
  6679. EnterCriticalSection(&gManagementDllsCritSec);
  6680. // walk the list
  6681. pDll = pDllList->pFirst;
  6682. while (pDll)
  6683. {
  6684. // free all resources
  6685. if (pDll->hDll)
  6686. {
  6687. (pDll->aProcs[TC_FREE])();
  6688. FreeLibrary(pDll->hDll);
  6689. }
  6690. ServerFree(pDll->pszName);
  6691. pNext = pDll->pNext;
  6692. ServerFree(pDll);
  6693. pDll = pNext;
  6694. }
  6695. // free header
  6696. ServerFree(pDllList);
  6697. LeaveCriticalSection(&gManagementDllsCritSec);
  6698. return 0;
  6699. }
  6700. void
  6701. ManagementProc(
  6702. LONG l
  6703. )
  6704. {
  6705. HKEY hKey = NULL;
  6706. DWORD dw, dwDSObjTTLTicks;
  6707. HANDLE hEventNotify = NULL;
  6708. HANDLE aHandles[2];
  6709. if (ERROR_SUCCESS != RegOpenKeyEx(
  6710. HKEY_LOCAL_MACHINE,
  6711. gszRegKeyServer,
  6712. 0,
  6713. KEY_READ,
  6714. &hKey
  6715. ))
  6716. {
  6717. LOG((TL_ERROR, "RegOpenKeyExW failed in ManagementProc"));
  6718. goto ExitHere;
  6719. }
  6720. hEventNotify = CreateEvent (NULL, FALSE, FALSE, NULL);
  6721. if (hEventNotify == NULL)
  6722. {
  6723. goto ExitHere;
  6724. }
  6725. aHandles[0] = hEventNotify;
  6726. aHandles[1] = ghEventService;
  6727. // Compute TAPISRV SCP refresh interval in ticks
  6728. // gdwTapiSCPTTL is expressed in terms of minutes
  6729. dwDSObjTTLTicks = gdwTapiSCPTTL * 60 * 1000 / 2;
  6730. while (TRUE)
  6731. {
  6732. RegNotifyChangeKeyValue(
  6733. hKey,
  6734. TRUE,
  6735. REG_NOTIFY_CHANGE_LAST_SET,
  6736. hEventNotify,
  6737. TRUE
  6738. );
  6739. dw = WaitForMultipleObjects (
  6740. sizeof(aHandles) / sizeof(HANDLE),
  6741. aHandles,
  6742. FALSE,
  6743. dwDSObjTTLTicks
  6744. );
  6745. if (dw == WAIT_OBJECT_0)
  6746. {
  6747. // Notified of the registry change
  6748. ReadAndInitManagementDlls();
  6749. }
  6750. else if (dw == WAIT_OBJECT_0 + 1)
  6751. {
  6752. // the service is shutting down, update
  6753. // DS about this and break out
  6754. UpdateTapiSCP (FALSE, NULL, NULL);
  6755. break;
  6756. }
  6757. else if (dw == WAIT_TIMEOUT)
  6758. {
  6759. // Time to refresh our DS registration now
  6760. UpdateTapiSCP (TRUE, NULL, NULL);
  6761. }
  6762. }
  6763. ExitHere:
  6764. if (hKey)
  6765. {
  6766. RegCloseKey(hKey);
  6767. }
  6768. if (hEventNotify)
  6769. {
  6770. CloseHandle (hEventNotify);
  6771. }
  6772. }
  6773. //////////////////////////////////////////////////////////////////////
  6774. //
  6775. // ReadAndInitManagementDLLs()
  6776. //
  6777. // This procedure will read the management dll list from the registry
  6778. // It will then go through that list, and create a linked list of
  6779. // TMANAGEDLLINFO structures to hold all the info about those DLLs
  6780. //
  6781. // If there is already a list of these DLLs in TapiGlobals, this procedure
  6782. // will then go through that list and determine which of the old DLLs
  6783. // are in the new list. For the matches, it will simply copy over
  6784. // the info about that DLL, and zero out the fields in the old list
  6785. //
  6786. // It will go through the new list. Entries that are not already
  6787. // filled in will get initialized.
  6788. //
  6789. // Then it will save the new list in TapiGlobals.
  6790. //
  6791. // If an old list existed, it will create a thread that will wait
  6792. // for this old list to be freed
  6793. //
  6794. // The procedure isn't real efficient, but I believe it's thread safe.
  6795. // Additionally, changing the security DLLs should happen very infrequently,
  6796. // and the list of DLLs should be very short.
  6797. //
  6798. //////////////////////////////////////////////////////////////////////
  6799. void
  6800. ReadAndInitManagementDlls()
  6801. {
  6802. DWORD dwDataSize, dwDataType, dwTID;
  6803. HKEY hKey;
  6804. LPWSTR pDLLs, pHold1, pHold2;
  6805. DWORD dwCount = 0;
  6806. PTMANAGEDLLINFO pManageDll, pHoldDll, pNewHoldDll, pPrevDll, pTempDll;
  6807. PTMANAGEDLLLISTHEADER pNewDllList = NULL, pHoldDllList;
  6808. BOOL bBreak = FALSE;
  6809. //
  6810. // If it's not a server, we have no business here.
  6811. //
  6812. if (!(TapiGlobals.dwFlags & TAPIGLOBALS_SERVER))
  6813. {
  6814. return;
  6815. }
  6816. EnterCriticalSection(&gManagementDllsCritSec);
  6817. // get info from registry
  6818. RegOpenKeyEx(
  6819. HKEY_LOCAL_MACHINE,
  6820. gszRegKeyServer,
  6821. 0,
  6822. KEY_ALL_ACCESS,
  6823. &hKey
  6824. );
  6825. dwDataSize = 0;
  6826. RegQueryValueExW(
  6827. hKey,
  6828. gszManagementDlls,
  6829. 0,
  6830. &dwDataType,
  6831. NULL,
  6832. &dwDataSize
  6833. );
  6834. if (dwDataSize == 0)
  6835. {
  6836. LOG((TL_ERROR, "No management DLLs present on this server"));
  6837. // if there was previously a list
  6838. // free it.
  6839. if (TapiGlobals.pManageDllList)
  6840. {
  6841. HANDLE hThread;
  6842. pHoldDllList = TapiGlobals.pManageDllList;
  6843. EnterCriticalSection( &gDllListCritSec );
  6844. TapiGlobals.pManageDllList = NULL;
  6845. LeaveCriticalSection( &gDllListCritSec );
  6846. // create a thread to wait for the
  6847. // list and free it
  6848. hThread = CreateThread(
  6849. NULL,
  6850. 0,
  6851. (LPTHREAD_START_ROUTINE)FreeOldDllListProc,
  6852. pHoldDllList,
  6853. 0,
  6854. &dwTID
  6855. );
  6856. CloseHandle( hThread );
  6857. }
  6858. RegCloseKey( hKey );
  6859. LeaveCriticalSection(&gManagementDllsCritSec);
  6860. return;
  6861. }
  6862. if (!(pDLLs = ServerAlloc(dwDataSize)))
  6863. {
  6864. RegCloseKey( hKey );
  6865. LeaveCriticalSection(&gManagementDllsCritSec);
  6866. return;
  6867. }
  6868. RegQueryValueExW(
  6869. hKey,
  6870. gszManagementDlls,
  6871. 0,
  6872. &dwDataType,
  6873. (LPBYTE)pDLLs,
  6874. &dwDataSize
  6875. );
  6876. RegCloseKey( hKey );
  6877. // alloc new list header and first element
  6878. if (!(pNewDllList = (PTMANAGEDLLLISTHEADER) ServerAlloc( sizeof( TMANAGEDLLLISTHEADER ) ) ) )
  6879. {
  6880. ServerFree( pDLLs );
  6881. LeaveCriticalSection(&gManagementDllsCritSec);
  6882. return;
  6883. }
  6884. pNewDllList->lCount = 0;
  6885. if (!(pNewDllList->pFirst = ServerAlloc( sizeof( TMANAGEDLLINFO ) ) ) )
  6886. {
  6887. ServerFree( pDLLs );
  6888. ServerFree( pNewDllList );
  6889. LeaveCriticalSection(&gManagementDllsCritSec);
  6890. return;
  6891. }
  6892. // now, go through the list of dll names and initialize
  6893. // the new TMANAGEDLLINFO list
  6894. pHold1 = pHold2 = pDLLs;
  6895. pManageDll = pNewDllList->pFirst;
  6896. while (TRUE)
  6897. {
  6898. // find end or "
  6899. while (*pHold1 && *pHold1 != L'"')
  6900. pHold1++;
  6901. // null terminate name
  6902. if (*pHold1)
  6903. {
  6904. *pHold1 = '\0';
  6905. }
  6906. else
  6907. {
  6908. bBreak = TRUE;
  6909. }
  6910. LOG((TL_INFO, "Management DLL %d is %ls", dwCount, pHold2));
  6911. // alloc space for name and procaddresses
  6912. pManageDll->pszName = ServerAlloc( ( lstrlenW( pHold2 ) + 1 ) * sizeof (WCHAR) );
  6913. if (!pManageDll->pszName)
  6914. {
  6915. goto ExitHere;
  6916. }
  6917. // save name
  6918. wcscpy(
  6919. pManageDll->pszName,
  6920. pHold2
  6921. );
  6922. // save ID
  6923. pManageDll->dwID = gdwDllIDs++;
  6924. // if we're at the end of the list,
  6925. // break out
  6926. if (bBreak)
  6927. break;
  6928. // otherwise, skip over null
  6929. pHold1++;
  6930. // save beginning of next name
  6931. pHold2 = pHold1;
  6932. // inc count
  6933. dwCount++;
  6934. // prepare next buffer
  6935. if (!(pManageDll->pNext = ServerAlloc( sizeof ( TMANAGEDLLINFO ) ) ) )
  6936. {
  6937. goto ExitHere;
  6938. }
  6939. pManageDll = pManageDll->pNext;
  6940. }
  6941. // if an old list exists, walk through and copy over Dlls that have
  6942. // not changed
  6943. pHoldDllList = TapiGlobals.pManageDllList;
  6944. if (pHoldDllList)
  6945. {
  6946. pHoldDll = pHoldDllList->pFirst;
  6947. while (pHoldDll)
  6948. {
  6949. pNewHoldDll = pNewDllList->pFirst;
  6950. // walk through list of new dlls
  6951. while (pNewHoldDll)
  6952. {
  6953. // if they are the same
  6954. if (!lstrcmpiW(
  6955. pNewHoldDll->pszName,
  6956. pHoldDll->pszName
  6957. )
  6958. )
  6959. {
  6960. // save info
  6961. memcpy(
  6962. pNewHoldDll->aProcs,
  6963. pHoldDll->aProcs,
  6964. sizeof( pHoldDll->aProcs )
  6965. );
  6966. pNewHoldDll->hDll = pHoldDll->hDll;
  6967. pNewHoldDll->dwID = pHoldDll->dwID;
  6968. // NULL old hDll so we know that
  6969. // we have it
  6970. pHoldDll->hDll = NULL;
  6971. break;
  6972. }
  6973. pNewHoldDll = pNewHoldDll->pNext;
  6974. } // while pNewHoldDll
  6975. pHoldDll = pHoldDll->pNext;
  6976. } // while pHoldDll
  6977. }
  6978. // walk through the new list and init items that
  6979. // have not been initialized already
  6980. pNewHoldDll = pNewDllList->pFirst;
  6981. pPrevDll = NULL;
  6982. while (pNewHoldDll)
  6983. {
  6984. if (!pNewHoldDll->hDll)
  6985. {
  6986. // try to load the new dll
  6987. if (!LoadNewDll(pNewHoldDll))
  6988. {
  6989. // it failed
  6990. if (pPrevDll)
  6991. {
  6992. pPrevDll->pNext = pNewHoldDll->pNext;
  6993. ServerFree(pNewHoldDll);
  6994. pNewHoldDll = pPrevDll;
  6995. }
  6996. else
  6997. {
  6998. pNewDllList->pFirst = pNewHoldDll->pNext;
  6999. ServerFree(pNewHoldDll);
  7000. pNewHoldDll = pNewDllList->pFirst;
  7001. continue;
  7002. }
  7003. }
  7004. }
  7005. // next dll
  7006. pPrevDll = pNewHoldDll;
  7007. pNewHoldDll = pNewHoldDll->pNext;
  7008. }
  7009. if (pNewDllList->pFirst == NULL)
  7010. {
  7011. // all the DLLs failed to load, or the DLL list was empty
  7012. ServerFree( pNewDllList );
  7013. pNewDllList = NULL;
  7014. }
  7015. // save old list pointer
  7016. pHoldDllList = TapiGlobals.pManageDllList;
  7017. // replace the list
  7018. EnterCriticalSection( &gDllListCritSec );
  7019. TapiGlobals.pManageDllList = pNewDllList;
  7020. pNewDllList = NULL;
  7021. LeaveCriticalSection( &gDllListCritSec );
  7022. if (pHoldDllList)
  7023. {
  7024. HANDLE hThread;
  7025. // create a thread to wait for the
  7026. // list and free it
  7027. hThread = CreateThread(
  7028. NULL,
  7029. 0,
  7030. (LPTHREAD_START_ROUTINE)FreeOldDllListProc,
  7031. pHoldDllList,
  7032. 0,
  7033. &dwTID
  7034. );
  7035. CloseHandle( hThread );
  7036. }
  7037. ExitHere:
  7038. ServerFree( pDLLs );
  7039. // Error during pNewDllList allocation
  7040. if (pNewDllList != NULL)
  7041. {
  7042. pManageDll = pNewDllList->pFirst;
  7043. while (pManageDll != NULL)
  7044. {
  7045. pTempDll = pManageDll;
  7046. pManageDll = pManageDll->pNext;
  7047. ServerFree (pTempDll->pszName);
  7048. ServerFree (pTempDll);
  7049. }
  7050. ServerFree( pNewDllList );
  7051. }
  7052. LeaveCriticalSection(&gManagementDllsCritSec);
  7053. return;
  7054. }
  7055. void
  7056. GetManageDllListPointer(
  7057. PTMANAGEDLLLISTHEADER * ppDllList
  7058. )
  7059. {
  7060. EnterCriticalSection( &gDllListCritSec );
  7061. if (TapiGlobals.pManageDllList != NULL)
  7062. {
  7063. TapiGlobals.pManageDllList->lCount++;
  7064. }
  7065. *ppDllList = TapiGlobals.pManageDllList;
  7066. LeaveCriticalSection( &gDllListCritSec );
  7067. }
  7068. void
  7069. FreeManageDllListPointer(
  7070. PTMANAGEDLLLISTHEADER pDllList
  7071. )
  7072. {
  7073. EnterCriticalSection( &gDllListCritSec );
  7074. if (pDllList != NULL)
  7075. {
  7076. pDllList->lCount--;
  7077. if ( pDllList->lCount < 0 )
  7078. {
  7079. LOG((TL_INFO, "pDllList->lCount is less than 0 - pDllList %p", pDllList));
  7080. }
  7081. }
  7082. LeaveCriticalSection( &gDllListCritSec );
  7083. }
  7084. #endif
  7085. void
  7086. PASCAL
  7087. SetMediaModesPriorityList(
  7088. HKEY hKeyPri,
  7089. PRILISTSTRUCT * pPriList
  7090. )
  7091. {
  7092. DWORD dwCount;
  7093. for (dwCount = 0; dwCount<TapiGlobals.dwUsedPriorityLists; dwCount++)
  7094. {
  7095. TCHAR szName[REGNAMESIZE];
  7096. if ( (NULL == pPriList[dwCount].pszPriList) ||
  7097. (L'\0' == *(pPriList[dwCount].pszPriList)) )
  7098. {
  7099. // What if there USED TO be an entry, but the app setpri to 0, then this
  7100. // entry would be '\0', but the registry entry would still be there.
  7101. continue;
  7102. }
  7103. wsprintf(
  7104. szName,
  7105. TEXT("%d"),
  7106. pPriList[dwCount].dwMediaModes
  7107. );
  7108. TAPIRegSetValueExW(
  7109. hKeyPri,
  7110. szName,
  7111. 0,
  7112. REG_SZ,
  7113. (LPBYTE)( (pPriList[dwCount].pszPriList) + 1 ),
  7114. (lstrlenW(pPriList[dwCount].pszPriList)) * sizeof (WCHAR)
  7115. );
  7116. }
  7117. }
  7118. void
  7119. PASCAL
  7120. SetPriorityList(
  7121. HKEY hKeyHandoffPriorities,
  7122. const TCHAR *pszListName,
  7123. WCHAR *pszPriorityList
  7124. )
  7125. {
  7126. if (pszPriorityList == NULL)
  7127. {
  7128. //
  7129. // There is no pri list for this media mode or ReqXxxCall,
  7130. // so delete any existing value from the registry
  7131. //
  7132. RegDeleteValue (hKeyHandoffPriorities, pszListName);
  7133. }
  7134. else
  7135. {
  7136. //
  7137. // Add the pri list to the registry (note that we don't
  7138. // add the preceding '"')
  7139. //
  7140. TAPIRegSetValueExW(
  7141. hKeyHandoffPriorities,
  7142. pszListName,
  7143. 0,
  7144. REG_SZ,
  7145. (LPBYTE)(pszPriorityList + 1),
  7146. lstrlenW (pszPriorityList) * sizeof (WCHAR)
  7147. );
  7148. }
  7149. }
  7150. LONG
  7151. ServerShutdown(
  7152. void
  7153. )
  7154. {
  7155. DWORD i, j;
  7156. PTPROVIDER ptProvider;
  7157. //
  7158. // Reset the flag that says it's ok to queue sp events, & then wait
  7159. // for the SPEventHandlerThread(s) to clean up the SP event queue(s)
  7160. //
  7161. gbQueueSPEvents = FALSE;
  7162. //
  7163. // Set a reasonable cap on the max time we'll sit here
  7164. // Don't wait for a message to be dispatched if called
  7165. // from "net stop tapisrv"
  7166. //
  7167. i = 10 * 20; // 200 * 100msecs = 20 seconds
  7168. while (i && !gbSPEventHandlerThreadExit)
  7169. {
  7170. for (j = 0; j < gdwNumSPEventHandlerThreads; j++)
  7171. {
  7172. if (!IsListEmpty (&aSPEventHandlerThreadInfo[j].ListHead))
  7173. {
  7174. break;
  7175. }
  7176. }
  7177. if (j == gdwNumSPEventHandlerThreads)
  7178. {
  7179. break;
  7180. }
  7181. Sleep (100);
  7182. i--;
  7183. }
  7184. //
  7185. // For each provider call the shutdown proc & then unload
  7186. //
  7187. ptProvider = TapiGlobals.ptProviders;
  7188. while (ptProvider)
  7189. {
  7190. PTPROVIDER ptNextProvider = ptProvider->pNext;
  7191. LONG lResult;
  7192. lResult = CallSP2(
  7193. ptProvider->apfn[SP_PROVIDERSHUTDOWN],
  7194. "providerShutdown",
  7195. SP_FUNC_SYNC,
  7196. (DWORD)ptProvider->dwSPIVersion,
  7197. (DWORD)ptProvider->dwPermanentProviderID
  7198. );
  7199. FreeLibrary (ptProvider->hDll);
  7200. MyCloseMutex (ptProvider->hMutex);
  7201. CloseHandle (ptProvider->hHashTableReaderEvent);
  7202. DeleteCriticalSection (&ptProvider->HashTableCritSec);
  7203. ServerFree (ptProvider->pHashTable);
  7204. ServerFree (ptProvider);
  7205. ptProvider = ptNextProvider;
  7206. }
  7207. TapiGlobals.ptProviders = NULL;
  7208. //
  7209. // Clean up lookup tables
  7210. //
  7211. while (TapiGlobals.pLineLookup)
  7212. {
  7213. PTLINELOOKUPTABLE pLookup = TapiGlobals.pLineLookup;
  7214. for (i = 0; i < pLookup->dwNumUsedEntries; i++)
  7215. {
  7216. if (!pLookup->aEntries[i].bRemoved)
  7217. {
  7218. MyCloseMutex (pLookup->aEntries[i].hMutex);
  7219. }
  7220. }
  7221. TapiGlobals.pLineLookup = pLookup->pNext;
  7222. ServerFree (pLookup);
  7223. }
  7224. while (TapiGlobals.pPhoneLookup)
  7225. {
  7226. PTPHONELOOKUPTABLE pLookup = TapiGlobals.pPhoneLookup;
  7227. for (i = 0; i < pLookup->dwNumUsedEntries; i++)
  7228. {
  7229. if (!pLookup->aEntries[i].bRemoved)
  7230. {
  7231. MyCloseMutex (pLookup->aEntries[i].hMutex);
  7232. }
  7233. }
  7234. TapiGlobals.pPhoneLookup = pLookup->pNext;
  7235. ServerFree (pLookup);
  7236. }
  7237. #if MEMPHIS
  7238. // Don't write perf stuff as there is no PERFMON on Win9x
  7239. #else
  7240. {
  7241. TCHAR szPerfNumLines[] = TEXT("Perf1");
  7242. TCHAR szPerfNumPhones[] =TEXT("Perf2");
  7243. HKEY hKeyTelephony;
  7244. DWORD dwValue;
  7245. if (ERROR_SUCCESS ==
  7246. RegOpenKeyEx(
  7247. HKEY_LOCAL_MACHINE,
  7248. gszRegKeyTelephony,
  7249. 0,
  7250. KEY_ALL_ACCESS,
  7251. &hKeyTelephony
  7252. ))
  7253. {
  7254. dwValue = TapiGlobals.dwNumLines + 'PERF';
  7255. RegSetValueEx(
  7256. hKeyTelephony,
  7257. szPerfNumLines,
  7258. 0,
  7259. REG_DWORD,
  7260. (LPBYTE)&dwValue,
  7261. sizeof(DWORD)
  7262. );
  7263. dwValue = TapiGlobals.dwNumPhones + 'PERF';
  7264. RegSetValueEx(
  7265. hKeyTelephony,
  7266. szPerfNumPhones,
  7267. 0,
  7268. REG_DWORD,
  7269. (LPBYTE)&dwValue,
  7270. sizeof(DWORD)
  7271. );
  7272. RegCloseKey(hKeyTelephony);
  7273. }
  7274. }
  7275. #endif
  7276. //
  7277. // Reset globals
  7278. //
  7279. TapiGlobals.dwFlags &= ~(TAPIGLOBALS_REINIT);
  7280. {
  7281. PPERMANENTIDARRAYHEADER pIDArray = TapiGlobals.pIDArrays, pArrayHold;
  7282. while (pIDArray)
  7283. {
  7284. ServerFree (pIDArray->pLineElements);
  7285. ServerFree (pIDArray->pPhoneElements);
  7286. pArrayHold = pIDArray->pNext;
  7287. ServerFree (pIDArray);
  7288. pIDArray = pArrayHold;
  7289. }
  7290. TapiGlobals.pIDArrays = NULL;
  7291. if (gpLineInfoList)
  7292. {
  7293. ServerFree (gpLineInfoList);
  7294. gpLineInfoList = NULL;
  7295. ZeroMemory (&gftLineLastWrite, sizeof(gftLineLastWrite));
  7296. }
  7297. if (gpPhoneInfoList)
  7298. {
  7299. ServerFree (gpPhoneInfoList);
  7300. gpPhoneInfoList = NULL;
  7301. ZeroMemory (&gftPhoneLastWrite, sizeof(gftPhoneLastWrite));
  7302. }
  7303. if (gpLineDevFlags)
  7304. {
  7305. ServerFree (gpLineDevFlags);
  7306. gpLineDevFlags = NULL;
  7307. gdwNumFlags = 0;
  7308. }
  7309. gbLockMMCWrite = FALSE;
  7310. OnProxySCPShutdown ();
  7311. }
  7312. return 0;
  7313. }
  7314. void
  7315. WINAPI
  7316. GetAsyncEvents(
  7317. PTCLIENT ptClient,
  7318. PGETEVENTS_PARAMS pParams,
  7319. DWORD dwParamsBufferSize,
  7320. LPBYTE pDataBuf,
  7321. LPDWORD pdwNumBytesReturned
  7322. )
  7323. {
  7324. DWORD dwMoveSize, dwMoveSizeWrapped;
  7325. LOG((TL_TRACE, "GetAsyncEvents: enter (TID=%d)", GetCurrentThreadId()));
  7326. LOG((TL_INFO,
  7327. "M ebfused:x%lx pEvtBuf: 0x%p pDataOut:0x%p pDataIn:0x%p",
  7328. ptClient->dwEventBufferUsedSize,
  7329. ptClient->pEventBuffer,
  7330. ptClient->pDataOut,
  7331. ptClient->pDataIn
  7332. ));
  7333. //
  7334. // Verify size/offset/string params given our input buffer/size
  7335. //
  7336. if (pParams->dwTotalBufferSize > dwParamsBufferSize)
  7337. {
  7338. pParams->lResult = LINEERR_OPERATIONFAILED;
  7339. return;
  7340. }
  7341. //
  7342. // Copy data from ptClient's event buffer
  7343. //
  7344. // An optimization to be made is to alert client (via dwNeededSize)
  7345. // that it might want to alloc a larger buffer when msg traffic is
  7346. // real high
  7347. //
  7348. if (WaitForExclusiveClientAccess (ptClient))
  7349. {
  7350. _TryAgain:
  7351. if (ptClient->dwEventBufferUsedSize == 0)
  7352. {
  7353. if (!IS_REMOTE_CLIENT (ptClient))
  7354. {
  7355. ResetEvent (ptClient->hValidEventBufferDataEvent);
  7356. }
  7357. pParams->dwNeededBufferSize =
  7358. pParams->dwUsedBufferSize = 0;
  7359. *pdwNumBytesReturned = sizeof (TAPI32_MSG);
  7360. RESET_FLAG (ptClient->dwFlags, PTCLIENT_FLAG_SKIPFIRSTMESSAGE);
  7361. goto GetAsyncEvents_releaseMutex;
  7362. }
  7363. if (ptClient->pDataOut < ptClient->pDataIn)
  7364. {
  7365. dwMoveSize = (DWORD) (ptClient->pDataIn - ptClient->pDataOut);
  7366. dwMoveSizeWrapped = 0;
  7367. }
  7368. else
  7369. {
  7370. dwMoveSize = ptClient->dwEventBufferTotalSize -
  7371. (DWORD) (ptClient->pDataOut - ptClient->pEventBuffer);
  7372. dwMoveSizeWrapped = (DWORD)
  7373. (ptClient->pDataIn - ptClient->pEventBuffer);
  7374. }
  7375. if (ptClient->dwEventBufferUsedSize <= pParams->dwTotalBufferSize)
  7376. {
  7377. //
  7378. // If here the size of the queued event data is less than the
  7379. // client buffer size, so we can just blast the bits into the
  7380. // client buffer & return. Also make sure to reset the "events
  7381. // pending" event
  7382. //
  7383. CopyMemory (pDataBuf, ptClient->pDataOut, dwMoveSize);
  7384. if (dwMoveSizeWrapped)
  7385. {
  7386. CopyMemory(
  7387. pDataBuf + dwMoveSize,
  7388. ptClient->pEventBuffer,
  7389. dwMoveSizeWrapped
  7390. );
  7391. }
  7392. ptClient->dwEventBufferUsedSize = 0;
  7393. ptClient->pDataOut = ptClient->pDataIn = ptClient->pEventBuffer;
  7394. RESET_FLAG (ptClient->dwFlags, PTCLIENT_FLAG_SKIPFIRSTMESSAGE);
  7395. if (!IS_REMOTE_CLIENT (ptClient))
  7396. {
  7397. ResetEvent (ptClient->hValidEventBufferDataEvent);
  7398. }
  7399. pParams->dwNeededBufferSize =
  7400. pParams->dwUsedBufferSize = dwMoveSize + dwMoveSizeWrapped;
  7401. *pdwNumBytesReturned = sizeof (TAPI32_MSG) +
  7402. pParams->dwUsedBufferSize;
  7403. }
  7404. else
  7405. {
  7406. //
  7407. // If here the size of the queued event data exceeds that
  7408. // of the client buffer. Since our events aren't all the
  7409. // same size we need to copy them over one by one, making
  7410. // sure we don't overflow the client buffer. Don't reset
  7411. // the "events pending" event, so async events thread will
  7412. // call us again as soon as it's done processing messages
  7413. // in the buffer.
  7414. //
  7415. DWORD dwBytesLeftInClientBuffer = pParams->dwTotalBufferSize,
  7416. dwDataOffset = 0, dwDataOffsetWrapped = 0;
  7417. DWORD dwTotalMoveSize = dwMoveSize;
  7418. LOG((TL_TRACE, "GetAsyncEvents: event data exceeds client buffer"));
  7419. pParams->dwNeededBufferSize = ptClient->dwEventBufferUsedSize;
  7420. while (1)
  7421. {
  7422. DWORD dwMsgSize = (DWORD) ((PASYNCEVENTMSG)
  7423. (ptClient->pDataOut + dwDataOffset))->TotalSize;
  7424. if (dwMsgSize > dwBytesLeftInClientBuffer)
  7425. {
  7426. if ((pParams->dwUsedBufferSize = dwDataOffset) != 0)
  7427. {
  7428. ptClient->dwEventBufferUsedSize -= dwDataOffset;
  7429. ptClient->pDataOut += dwDataOffset;
  7430. }
  7431. else
  7432. {
  7433. //
  7434. // Special case: the 1st msg is bigger than the entire
  7435. // buffer
  7436. //
  7437. if (IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_SKIPFIRSTMESSAGE))
  7438. {
  7439. DWORD dwBytesToTheEndOfTheBuffer = ptClient->dwEventBufferTotalSize - (DWORD)(ptClient->pDataOut - ptClient->pEventBuffer);
  7440. // This is the second time the client tries to get
  7441. // this message, with too small a buffer. We can
  7442. // assume that the client cannot allocate enough
  7443. // memory, so skip this message...
  7444. RESET_FLAG(ptClient->dwFlags, PTCLIENT_FLAG_SKIPFIRSTMESSAGE);
  7445. if (dwMsgSize > dwBytesToTheEndOfTheBuffer)
  7446. {
  7447. // This means that this message wraps around...
  7448. dwBytesToTheEndOfTheBuffer = dwMsgSize - dwBytesToTheEndOfTheBuffer;
  7449. ptClient->pDataOut = ptClient->pEventBuffer + dwBytesToTheEndOfTheBuffer;
  7450. }
  7451. else
  7452. {
  7453. ptClient->pDataOut += dwMsgSize;
  7454. }
  7455. ptClient->dwEventBufferUsedSize -= dwMsgSize;
  7456. goto _TryAgain;
  7457. }
  7458. else
  7459. {
  7460. // Set the flag, so next time we'll skip the message
  7461. // if the buffer will still be too small.
  7462. SET_FLAG(ptClient->dwFlags, PTCLIENT_FLAG_SKIPFIRSTMESSAGE);
  7463. }
  7464. }
  7465. *pdwNumBytesReturned = sizeof (TAPI32_MSG) +
  7466. pParams->dwUsedBufferSize;
  7467. goto GetAsyncEvents_releaseMutex;
  7468. }
  7469. dwBytesLeftInClientBuffer -= dwMsgSize;
  7470. if (dwMsgSize <= dwMoveSize)
  7471. {
  7472. //
  7473. // Msg isn't wrapped, a single copy will do
  7474. //
  7475. CopyMemory(
  7476. pDataBuf + dwDataOffset,
  7477. ptClient->pDataOut + dwDataOffset,
  7478. dwMsgSize
  7479. );
  7480. //
  7481. // Check to see if the msg ran to the end of the buffer,
  7482. // & break to the wrapped data code if so
  7483. //
  7484. if ((dwDataOffset += dwMsgSize) >= dwTotalMoveSize)
  7485. {
  7486. ptClient->pDataOut = ptClient->pEventBuffer;
  7487. break;
  7488. }
  7489. }
  7490. else
  7491. {
  7492. //
  7493. // This msg is wrapped. We need to do two copies, then
  7494. // break out of this loop to the wrapped data code
  7495. //
  7496. CopyMemory(
  7497. pDataBuf + dwDataOffset,
  7498. ptClient->pDataOut + dwDataOffset,
  7499. dwMoveSize
  7500. );
  7501. dwDataOffset += dwMoveSize;
  7502. CopyMemory(
  7503. pDataBuf + dwDataOffset,
  7504. ptClient->pEventBuffer,
  7505. dwMsgSize - dwMoveSize
  7506. );
  7507. dwDataOffset += ( dwMsgSize - dwMoveSize);
  7508. ptClient->pDataOut = ptClient->pEventBuffer +
  7509. (dwMsgSize - dwMoveSize);
  7510. break;
  7511. }
  7512. dwMoveSize -= dwMsgSize;
  7513. }
  7514. while (1)
  7515. {
  7516. DWORD dwMsgSize = (DWORD)
  7517. ((PASYNCEVENTMSG) (ptClient->pDataOut +
  7518. dwDataOffsetWrapped))->TotalSize;
  7519. if (dwMsgSize > dwBytesLeftInClientBuffer)
  7520. {
  7521. ptClient->dwEventBufferUsedSize -= dwDataOffset;
  7522. ptClient->pDataOut += dwDataOffsetWrapped;
  7523. pParams->dwUsedBufferSize = dwDataOffset;
  7524. *pdwNumBytesReturned = sizeof (TAPI32_MSG) +
  7525. pParams->dwUsedBufferSize;
  7526. goto GetAsyncEvents_releaseMutex;
  7527. }
  7528. //
  7529. // Msg isn't wrapped, a single copy will do
  7530. //
  7531. CopyMemory(
  7532. pDataBuf + dwDataOffset,
  7533. ptClient->pDataOut + dwDataOffsetWrapped,
  7534. dwMsgSize
  7535. );
  7536. dwDataOffset += dwMsgSize;
  7537. dwDataOffsetWrapped += dwMsgSize;
  7538. dwBytesLeftInClientBuffer -= dwMsgSize;
  7539. }
  7540. }
  7541. LOG((TL_TRACE, "GetAsyncEvents: return dwUsedBufferSize:x%lx",
  7542. pParams->dwUsedBufferSize ));
  7543. GetAsyncEvents_releaseMutex:
  7544. if (ptClient->MsgPendingListEntry.Flink)
  7545. {
  7546. //
  7547. // This is a remote Dg client.
  7548. //
  7549. // If there is no more data in the event buffer then remove
  7550. // this client from the DgClientMsgPendingList(Head) so the
  7551. // EventNotificationThread will stop monitoring it.
  7552. //
  7553. // Else, update the tClient's Retry & EventsRetrieved tick
  7554. // counts.
  7555. //
  7556. if (ptClient->dwEventBufferUsedSize == 0)
  7557. {
  7558. EnterCriticalSection (&gDgClientMsgPendingCritSec);
  7559. RemoveEntryList (&ptClient->MsgPendingListEntry);
  7560. ptClient->MsgPendingListEntry.Flink =
  7561. ptClient->MsgPendingListEntry.Blink = NULL;
  7562. LeaveCriticalSection (&gDgClientMsgPendingCritSec);
  7563. }
  7564. else
  7565. {
  7566. ptClient->dwDgEventsRetrievedTickCount = GetTickCount();
  7567. ptClient->dwDgRetryTimeoutTickCount =
  7568. ptClient->dwDgEventsRetrievedTickCount +
  7569. 3 * DGCLIENT_TIMEOUT;
  7570. }
  7571. }
  7572. UNLOCKTCLIENT (ptClient);
  7573. }
  7574. }
  7575. void
  7576. WINAPI
  7577. GetUIDllName(
  7578. PTCLIENT ptClient,
  7579. PGETUIDLLNAME_PARAMS pParams,
  7580. DWORD dwParamsBufferSize,
  7581. LPBYTE pDataBuf,
  7582. LPDWORD pdwNumBytesReturned
  7583. )
  7584. {
  7585. LONG lResult = 0;
  7586. TSPIPROC pfnTSPI_providerUIIdentify = (TSPIPROC) NULL;
  7587. PTAPIDIALOGINSTANCE ptDlgInst = (PTAPIDIALOGINSTANCE) NULL;
  7588. PTLINELOOKUPENTRY pLookupEntry = NULL;
  7589. DWORD dwObjectID = pParams->dwObjectID;
  7590. LOG((TL_TRACE, "Entering GetUIDllName"));
  7591. switch (pParams->dwObjectType)
  7592. {
  7593. case TUISPIDLL_OBJECT_LINEID:
  7594. {
  7595. #if TELE_SERVER
  7596. if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) &&
  7597. !IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR))
  7598. {
  7599. if (pParams->dwObjectID >= ptClient->dwLineDevices)
  7600. {
  7601. pParams->lResult = LINEERR_OPERATIONFAILED;
  7602. return;
  7603. }
  7604. dwObjectID = ptClient->pLineDevices[pParams->dwObjectID];
  7605. }
  7606. #endif
  7607. if (TapiGlobals.dwNumLineInits == 0 )
  7608. {
  7609. lResult = LINEERR_UNINITIALIZED;
  7610. break;
  7611. }
  7612. pLookupEntry = GetLineLookupEntry (dwObjectID);
  7613. if (!pLookupEntry)
  7614. {
  7615. lResult = (TapiGlobals.dwNumLineInits == 0 ?
  7616. LINEERR_UNINITIALIZED : LINEERR_BADDEVICEID);
  7617. }
  7618. else if (!pLookupEntry->ptProvider || pLookupEntry->bRemoved)
  7619. {
  7620. lResult = LINEERR_NODEVICE;
  7621. }
  7622. else if (!(pfnTSPI_providerUIIdentify =
  7623. pLookupEntry->ptProvider->apfn[SP_PROVIDERUIIDENTIFY]))
  7624. {
  7625. lResult = LINEERR_OPERATIONUNAVAIL;
  7626. }
  7627. break;
  7628. }
  7629. case TUISPIDLL_OBJECT_PHONEID:
  7630. {
  7631. #if TELE_SERVER
  7632. if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) &&
  7633. !IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR))
  7634. {
  7635. if (pParams->dwObjectID >= ptClient->dwPhoneDevices)
  7636. {
  7637. pParams->lResult = PHONEERR_OPERATIONFAILED;
  7638. return;
  7639. }
  7640. dwObjectID = ptClient->pPhoneDevices[pParams->dwObjectID];
  7641. }
  7642. #endif
  7643. if (TapiGlobals.dwNumPhoneInits == 0 )
  7644. {
  7645. lResult = PHONEERR_UNINITIALIZED;
  7646. break;
  7647. }
  7648. pLookupEntry = (PTLINELOOKUPENTRY) GetPhoneLookupEntry (dwObjectID);
  7649. if (!pLookupEntry)
  7650. {
  7651. lResult = (TapiGlobals.dwNumPhoneInits == 0 ?
  7652. PHONEERR_UNINITIALIZED : PHONEERR_BADDEVICEID);
  7653. }
  7654. else if (!pLookupEntry->ptProvider || pLookupEntry->bRemoved)
  7655. {
  7656. lResult = PHONEERR_NODEVICE;
  7657. }
  7658. else if (!(pfnTSPI_providerUIIdentify =
  7659. pLookupEntry->ptProvider->apfn[SP_PROVIDERUIIDENTIFY]))
  7660. {
  7661. lResult = PHONEERR_OPERATIONUNAVAIL;
  7662. }
  7663. break;
  7664. }
  7665. case TUISPIDLL_OBJECT_PROVIDERID:
  7666. LOG((TL_INFO, "Looking for provider..."));
  7667. if (!(ptDlgInst = ServerAlloc (sizeof (TAPIDIALOGINSTANCE))))
  7668. {
  7669. lResult = LINEERR_NOMEM;
  7670. goto GetUIDllName_return;
  7671. }
  7672. ptDlgInst->htDlgInst = NewObject(ghHandleTable, ptDlgInst, NULL);
  7673. if (0 == ptDlgInst->htDlgInst)
  7674. {
  7675. ServerFree (ptDlgInst);
  7676. lResult = LINEERR_NOMEM;
  7677. goto GetUIDllName_return;
  7678. }
  7679. if (pParams->dwProviderFilenameOffset == TAPI_NO_DATA)
  7680. {
  7681. //
  7682. // This is a providerConfig or -Remove request. Loop thru the
  7683. // list of installed providers, trying to find one with a
  7684. // matching PPID.
  7685. //
  7686. int i, iNumProviders;
  7687. TCHAR szProviderXxxN[32];
  7688. HKEY hKeyProviders;
  7689. DWORD dwDataSize;
  7690. DWORD dwDataType;
  7691. DWORD dwTemp;
  7692. if (RegOpenKeyEx(
  7693. HKEY_LOCAL_MACHINE,
  7694. gszRegKeyProviders,
  7695. 0,
  7696. KEY_ALL_ACCESS,
  7697. &hKeyProviders
  7698. ) != ERROR_SUCCESS)
  7699. {
  7700. LOG((TL_ERROR,
  7701. "RegOpenKeyEx(/Providers) failed, err=%d",
  7702. GetLastError()
  7703. ));
  7704. DereferenceObject (ghHandleTable, ptDlgInst->htDlgInst, 1);
  7705. lResult = LINEERR_OPERATIONFAILED;
  7706. goto GetUIDllName_return;
  7707. }
  7708. dwDataSize = sizeof(iNumProviders);
  7709. iNumProviders = 0;
  7710. RegQueryValueEx(
  7711. hKeyProviders,
  7712. gszNumProviders,
  7713. 0,
  7714. &dwDataType,
  7715. (LPBYTE) &iNumProviders,
  7716. &dwDataSize
  7717. );
  7718. for (i = 0; i < iNumProviders; i++)
  7719. {
  7720. wsprintf(szProviderXxxN, TEXT("%s%d"), gszProviderID, i);
  7721. dwDataSize = sizeof(dwTemp);
  7722. dwTemp = 0;
  7723. RegQueryValueEx(
  7724. hKeyProviders,
  7725. szProviderXxxN,
  7726. 0,
  7727. &dwDataType,
  7728. (LPBYTE)&dwTemp,
  7729. &dwDataSize
  7730. );
  7731. if (dwTemp == pParams->dwObjectID)
  7732. {
  7733. //
  7734. // We found the provider, try to load it & get ptrs
  7735. // to the relevant funcs
  7736. //
  7737. TCHAR szProviderFilename[MAX_PATH];
  7738. wsprintf(szProviderXxxN, TEXT("%s%d"), gszProviderFilename, i);
  7739. dwDataSize = MAX_PATH*sizeof(TCHAR);
  7740. RegQueryValueEx(
  7741. hKeyProviders,
  7742. szProviderXxxN,
  7743. 0,
  7744. &dwDataType,
  7745. (LPBYTE)szProviderFilename,
  7746. &dwDataSize
  7747. );
  7748. if (!(ptDlgInst->hTsp = LoadLibrary(szProviderFilename)))
  7749. {
  7750. LOG((TL_ERROR,
  7751. "LoadLibrary('%s') failed - err=%d",
  7752. szProviderFilename,
  7753. GetLastError()
  7754. ));
  7755. lResult = LINEERR_OPERATIONFAILED;
  7756. goto clean_up_dlg_inst;
  7757. }
  7758. if (!(pfnTSPI_providerUIIdentify = (TSPIPROC) GetProcAddress(
  7759. ptDlgInst->hTsp,
  7760. (LPCSTR) gaszTSPIFuncNames[SP_PROVIDERUIIDENTIFY]
  7761. )))
  7762. {
  7763. LOG((TL_ERROR,
  7764. "GetProcAddress(TSPI_providerUIIdentify) " \
  7765. "on [%s] failed, err=%d",
  7766. szProviderFilename,
  7767. GetLastError()
  7768. ));
  7769. lResult = LINEERR_OPERATIONUNAVAIL;
  7770. goto clean_up_dlg_inst;
  7771. }
  7772. ptDlgInst->pfnTSPI_providerGenericDialogData = (TSPIPROC)
  7773. GetProcAddress(
  7774. ptDlgInst->hTsp,
  7775. (LPCSTR) gaszTSPIFuncNames[SP_PROVIDERGENERICDIALOGDATA]
  7776. );
  7777. ptDlgInst->dwPermanentProviderID = pParams->dwObjectID;
  7778. ptDlgInst->bRemoveProvider = pParams->bRemoveProvider;
  7779. break;
  7780. }
  7781. }
  7782. RegCloseKey (hKeyProviders);
  7783. if (i == iNumProviders)
  7784. {
  7785. LOG((TL_ERROR, "Ran out of list..."));
  7786. lResult = LINEERR_INVALPARAM;
  7787. #ifdef MEMPHIS
  7788. {
  7789. HANDLE hTsp;
  7790. FARPROC pfn;
  7791. // might be a 16 bit service provider
  7792. // call into tsp3216l.tsp and as it
  7793. // to handle this
  7794. if ( hTsp = LoadLibrary("tsp3216l.tsp"))
  7795. {
  7796. if (pfn = GetProcAddress(
  7797. hTsp,
  7798. "Xxx16BitProvider"
  7799. ))
  7800. {
  7801. lResult = (*pfn)(
  7802. pParams->bRemoveProvider?REMOVEPROVIDER:CONFIGPROVIDER,
  7803. pParams->dwObjectID,
  7804. NULL
  7805. );
  7806. if (lResult == 0)
  7807. {
  7808. lResult = TAPI16BITSUCCESS;
  7809. }
  7810. }
  7811. else
  7812. {
  7813. lResult = LINEERR_OPERATIONFAILED;
  7814. }
  7815. FreeLibrary( hTsp );
  7816. }
  7817. else
  7818. {
  7819. lResult = LINEERR_INVALPARAM;
  7820. }
  7821. }
  7822. goto clean_up_dlg_inst;
  7823. #endif
  7824. }
  7825. }
  7826. else
  7827. {
  7828. //
  7829. // This is a providerInstall request. Try to load the provider
  7830. // and get ptrs to the relevant funcs, then retrieve & increment
  7831. // the next provider ID value in the ini file (careful to wrap
  7832. // next PPID at 64K-1).
  7833. //
  7834. TCHAR *pszProviderFilename;
  7835. DWORD dwNameLength;
  7836. HKEY hKeyProviders;
  7837. DWORD dwDataSize;
  7838. DWORD dwDataType;
  7839. DWORD dwTemp;
  7840. //
  7841. // Verify size/offset/string params given our input buffer/size
  7842. //
  7843. if (IsBadStringParam(
  7844. dwParamsBufferSize,
  7845. pDataBuf,
  7846. pParams->dwProviderFilenameOffset
  7847. ))
  7848. {
  7849. pParams->lResult = LINEERR_OPERATIONFAILED;
  7850. DereferenceObject (ghHandleTable, ptDlgInst->htDlgInst, 1);
  7851. return;
  7852. }
  7853. pszProviderFilename = (PTSTR)(pDataBuf + pParams->dwProviderFilenameOffset);
  7854. if (!(ptDlgInst->hTsp = LoadLibrary(pszProviderFilename)))
  7855. {
  7856. LOG((TL_ERROR,
  7857. "LoadLibrary('%s') failed err=%d",
  7858. pszProviderFilename,
  7859. GetLastError()
  7860. ));
  7861. lResult = LINEERR_OPERATIONFAILED;
  7862. #ifdef MEMPHIS
  7863. {
  7864. HANDLE hTsp;
  7865. TSPIPROC pfn;
  7866. // might be a 16 bit service provider
  7867. // call into tsp3216l.tsp and as it
  7868. // to handle this
  7869. if ( hTsp = LoadLibrary(TEXT("tsp3216l.tsp")))
  7870. {
  7871. if ( pfn = (TSPIPROC)GetProcAddress(
  7872. hTsp,
  7873. "Xxx16BitProvider"
  7874. ))
  7875. {
  7876. RegOpenKeyEx(
  7877. HKEY_LOCAL_MACHINE,
  7878. gszRegKeyProviders,
  7879. 0,
  7880. KEY_ALL_ACCESS,
  7881. &hKeyProviders
  7882. );
  7883. dwDataSize = sizeof (DWORD);
  7884. pParams->dwObjectID = 1;
  7885. RegQueryValueEx(
  7886. hKeyProviders,
  7887. gszNextProviderID,
  7888. 0,
  7889. &dwDataType,
  7890. (LPBYTE) &(pParams->dwObjectID),
  7891. &dwDataSize
  7892. );
  7893. dwTemp = ((pParams->dwObjectID + 1) & 0xffff0000) ?
  7894. 1 : (pParams->dwObjectID + 1);
  7895. RegSetValueEx(
  7896. hKeyProviders,
  7897. gszNextProviderID,
  7898. 0,
  7899. REG_DWORD,
  7900. (LPBYTE) &dwTemp,
  7901. sizeof(DWORD)
  7902. );
  7903. RegCloseKey (hKeyProviders);
  7904. lResult = (*pfn)(
  7905. ADDPROVIDER,
  7906. pParams->dwObjectID,
  7907. pszProviderFilename
  7908. );
  7909. if (lResult == 0)
  7910. {
  7911. lResult = TAPI16BITSUCCESS;
  7912. }
  7913. }
  7914. else
  7915. {
  7916. lResult = LINEERR_OPERATIONFAILED;
  7917. }
  7918. FreeLibrary( hTsp );
  7919. }
  7920. else
  7921. {
  7922. lResult = LINEERR_OPERATIONFAILED;
  7923. }
  7924. }
  7925. #endif
  7926. // note: no matter if the XxxProvider call succeeds or fails,
  7927. // we want this goto statement.
  7928. // 16bit service providers are completely handled
  7929. // in the XxxProvider call.
  7930. goto clean_up_dlg_inst;
  7931. }
  7932. if (!(pfnTSPI_providerUIIdentify = (TSPIPROC) GetProcAddress(
  7933. ptDlgInst->hTsp,
  7934. (LPCSTR) gaszTSPIFuncNames[SP_PROVIDERUIIDENTIFY]
  7935. )))
  7936. {
  7937. lResult = LINEERR_OPERATIONUNAVAIL;
  7938. goto clean_up_dlg_inst;
  7939. }
  7940. dwNameLength = (lstrlen(pszProviderFilename) + 1) * sizeof(TCHAR);
  7941. if (!(ptDlgInst->pszProviderFilename = ServerAlloc (dwNameLength)))
  7942. {
  7943. lResult = LINEERR_NOMEM;
  7944. goto clean_up_dlg_inst;
  7945. }
  7946. CopyMemory(
  7947. ptDlgInst->pszProviderFilename,
  7948. pszProviderFilename,
  7949. dwNameLength
  7950. );
  7951. ptDlgInst->pfnTSPI_providerGenericDialogData = (TSPIPROC) GetProcAddress(
  7952. ptDlgInst->hTsp,
  7953. (LPCSTR) gaszTSPIFuncNames[SP_PROVIDERGENERICDIALOGDATA]
  7954. );
  7955. RegOpenKeyEx(
  7956. HKEY_LOCAL_MACHINE,
  7957. gszRegKeyProviders,
  7958. 0,
  7959. KEY_ALL_ACCESS,
  7960. &hKeyProviders
  7961. );
  7962. dwDataSize = sizeof (DWORD);
  7963. ptDlgInst->dwPermanentProviderID = 1;
  7964. RegQueryValueEx(
  7965. hKeyProviders,
  7966. gszNextProviderID,
  7967. 0,
  7968. &dwDataType,
  7969. (LPBYTE) &(ptDlgInst->dwPermanentProviderID),
  7970. &dwDataSize
  7971. );
  7972. pParams->dwObjectID = ptDlgInst->dwPermanentProviderID;
  7973. dwTemp = ((ptDlgInst->dwPermanentProviderID+1) & 0xffff0000) ?
  7974. 1 : (ptDlgInst->dwPermanentProviderID + 1);
  7975. RegSetValueEx(
  7976. hKeyProviders,
  7977. gszNextProviderID,
  7978. 0,
  7979. REG_DWORD,
  7980. (LPBYTE) &dwTemp,
  7981. sizeof(DWORD)
  7982. );
  7983. RegCloseKey (hKeyProviders);
  7984. }
  7985. break;
  7986. }
  7987. if (pfnTSPI_providerUIIdentify)
  7988. {
  7989. if (pLookupEntry && (lstrcmpi(
  7990. pLookupEntry->ptProvider->szFileName,
  7991. TEXT("remotesp.tsp")
  7992. ) == 0)
  7993. )
  7994. {
  7995. // ok - hack alert
  7996. // a special case for remotesp to give it more info
  7997. // we're passing the device ID and device type over to remotesp
  7998. // so it can intelligently call over to the remote tapisrv
  7999. // the RSP_MSG is just a key for remotesp to
  8000. // check to make sure that the info is there
  8001. LPDWORD lpdwHold = (LPDWORD)pDataBuf;
  8002. lpdwHold[0] = RSP_MSG;
  8003. lpdwHold[1] = dwObjectID;
  8004. lpdwHold[2] = pParams->dwObjectType;
  8005. }
  8006. if ((lResult = CallSP1(
  8007. pfnTSPI_providerUIIdentify,
  8008. "providerUIIdentify",
  8009. SP_FUNC_SYNC,
  8010. (ULONG_PTR) pDataBuf
  8011. )) == 0)
  8012. {
  8013. pParams->dwUIDllNameOffset = 0;
  8014. pParams->dwUIDllNameSize = (lstrlenW((PWSTR)pDataBuf) + 1)*sizeof(WCHAR);
  8015. *pdwNumBytesReturned = sizeof (TAPI32_MSG) +
  8016. pParams->dwUIDllNameSize;
  8017. if (ptDlgInst)
  8018. {
  8019. ptDlgInst->dwKey = TDLGINST_KEY;
  8020. if ((ptDlgInst->pNext =
  8021. ptClient->pProviderXxxDlgInsts))
  8022. {
  8023. ptDlgInst->pNext->pPrev = ptDlgInst;
  8024. }
  8025. ptClient->pProviderXxxDlgInsts = ptDlgInst;
  8026. pParams->htDlgInst = ptDlgInst->htDlgInst;
  8027. }
  8028. }
  8029. else if (ptDlgInst)
  8030. {
  8031. clean_up_dlg_inst:
  8032. if (ptDlgInst->hTsp)
  8033. {
  8034. FreeLibrary (ptDlgInst->hTsp);
  8035. }
  8036. if (ptDlgInst->pszProviderFilename)
  8037. {
  8038. ServerFree (ptDlgInst->pszProviderFilename);
  8039. }
  8040. DereferenceObject (ghHandleTable, ptDlgInst->htDlgInst, 1);
  8041. }
  8042. }
  8043. GetUIDllName_return:
  8044. pParams->lResult = lResult;
  8045. }
  8046. void
  8047. WINAPI
  8048. TUISPIDLLCallback(
  8049. PTCLIENT ptClient,
  8050. PUIDLLCALLBACK_PARAMS pParams,
  8051. DWORD dwParamsBufferSize,
  8052. LPBYTE pDataBuf,
  8053. LPDWORD pdwNumBytesReturned
  8054. )
  8055. {
  8056. LONG lResult;
  8057. ULONG_PTR objectID = pParams->ObjectID;
  8058. TSPIPROC pfnTSPI_providerGenericDialogData = NULL;
  8059. //
  8060. // Verify size/offset/string params given our input buffer/size
  8061. //
  8062. if (ISBADSIZEOFFSET(
  8063. dwParamsBufferSize,
  8064. 0,
  8065. pParams->dwParamsInSize,
  8066. pParams->dwParamsInOffset,
  8067. sizeof(DWORD),
  8068. "TUISPIDLLCallback",
  8069. "pParams->ParamsIn"
  8070. ))
  8071. {
  8072. pParams->lResult = LINEERR_OPERATIONFAILED;
  8073. return;
  8074. }
  8075. switch (pParams->dwObjectType)
  8076. {
  8077. case TUISPIDLL_OBJECT_LINEID:
  8078. {
  8079. PTLINELOOKUPENTRY pLine;
  8080. #if TELE_SERVER
  8081. if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) &&
  8082. !IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR))
  8083. {
  8084. if ((DWORD) pParams->ObjectID >= ptClient->dwLineDevices)
  8085. {
  8086. pParams->lResult = LINEERR_OPERATIONFAILED;
  8087. return;
  8088. }
  8089. objectID = ptClient->pLineDevices[pParams->ObjectID];
  8090. }
  8091. #endif
  8092. pLine = GetLineLookupEntry ((DWORD) objectID);
  8093. if (!pLine)
  8094. {
  8095. lResult = LINEERR_INVALPARAM;
  8096. }
  8097. else if (!pLine->ptProvider)
  8098. {
  8099. lResult = LINEERR_OPERATIONFAILED;
  8100. }
  8101. else
  8102. {
  8103. pfnTSPI_providerGenericDialogData =
  8104. pLine->ptProvider->apfn[SP_PROVIDERGENERICDIALOGDATA];
  8105. }
  8106. break;
  8107. }
  8108. case TUISPIDLL_OBJECT_PHONEID:
  8109. {
  8110. PTPHONELOOKUPENTRY pPhone;
  8111. #if TELE_SERVER
  8112. if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) &&
  8113. !IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR))
  8114. {
  8115. if ((DWORD) pParams->ObjectID >= ptClient->dwPhoneDevices)
  8116. {
  8117. pParams->lResult = PHONEERR_OPERATIONFAILED;
  8118. return;
  8119. }
  8120. objectID = ptClient->pPhoneDevices[pParams->ObjectID];
  8121. }
  8122. #endif
  8123. pPhone = GetPhoneLookupEntry ((DWORD) objectID);
  8124. if (!pPhone)
  8125. {
  8126. lResult = LINEERR_INVALPARAM;
  8127. }
  8128. else if (!pPhone->ptProvider)
  8129. {
  8130. lResult = LINEERR_OPERATIONFAILED;
  8131. }
  8132. else
  8133. {
  8134. pfnTSPI_providerGenericDialogData =
  8135. pPhone->ptProvider->apfn[SP_PROVIDERGENERICDIALOGDATA];
  8136. }
  8137. break;
  8138. }
  8139. case TUISPIDLL_OBJECT_PROVIDERID:
  8140. {
  8141. PTAPIDIALOGINSTANCE ptDlgInst =
  8142. ptClient->pProviderXxxDlgInsts;
  8143. while (ptDlgInst)
  8144. {
  8145. if ((DWORD) pParams->ObjectID == ptDlgInst->dwPermanentProviderID)
  8146. {
  8147. pfnTSPI_providerGenericDialogData =
  8148. ptDlgInst->pfnTSPI_providerGenericDialogData;
  8149. break;
  8150. }
  8151. ptDlgInst = ptDlgInst->pNext;
  8152. }
  8153. break;
  8154. }
  8155. case TUISPIDLL_OBJECT_DIALOGINSTANCE:
  8156. {
  8157. PTAPIDIALOGINSTANCE ptDlgInst;
  8158. try
  8159. {
  8160. ptDlgInst = ReferenceObject (ghHandleTable, pParams->ObjectID, TDLGINST_KEY);
  8161. if (NULL == ptDlgInst)
  8162. {
  8163. pfnTSPI_providerGenericDialogData = NULL;
  8164. break;
  8165. }
  8166. objectID = (ULONG_PTR)ptDlgInst->hdDlgInst;
  8167. pfnTSPI_providerGenericDialogData =
  8168. ptDlgInst->ptProvider->apfn[SP_PROVIDERGENERICDIALOGDATA];
  8169. DereferenceObject (ghHandleTable, pParams->ObjectID, 1);
  8170. }
  8171. myexcept
  8172. {
  8173. // just fall thru
  8174. }
  8175. break;
  8176. }
  8177. }
  8178. if (pfnTSPI_providerGenericDialogData)
  8179. {
  8180. if ((lResult = CallSP4(
  8181. pfnTSPI_providerGenericDialogData,
  8182. "providerGenericDialogData",
  8183. SP_FUNC_SYNC,
  8184. (ULONG_PTR) objectID,
  8185. (DWORD)pParams->dwObjectType,
  8186. (ULONG_PTR) (pDataBuf + pParams->dwParamsInOffset),
  8187. (DWORD)pParams->dwParamsInSize
  8188. )) == 0)
  8189. {
  8190. pParams->dwParamsOutOffset = pParams->dwParamsInOffset;
  8191. pParams->dwParamsOutSize = pParams->dwParamsInSize;
  8192. *pdwNumBytesReturned = sizeof (TAPI32_MSG) +
  8193. pParams->dwParamsOutSize +
  8194. pParams->dwParamsOutOffset;
  8195. }
  8196. }
  8197. else
  8198. {
  8199. lResult = LINEERR_OPERATIONFAILED;
  8200. }
  8201. pParams->lResult = lResult;
  8202. }
  8203. void
  8204. WINAPI
  8205. FreeDialogInstance(
  8206. PTCLIENT ptClient,
  8207. PFREEDIALOGINSTANCE_PARAMS pParams,
  8208. DWORD dwParamsBufferSize,
  8209. LPBYTE pDataBuf,
  8210. LPDWORD pdwNumBytesReturned
  8211. )
  8212. {
  8213. HKEY hKeyProviders;
  8214. DWORD dwDataSize;
  8215. DWORD dwDataType;
  8216. DWORD dwTemp;
  8217. PTAPIDIALOGINSTANCE ptDlgInst = ReferenceObject (ghHandleTable, pParams->htDlgInst, TDLGINST_KEY);
  8218. LOG((TL_TRACE, "FreeDialogInstance: enter, pDlgInst=x%p", ptDlgInst));
  8219. try
  8220. {
  8221. if (ptDlgInst->dwKey != TDLGINST_KEY)
  8222. {
  8223. pParams->lResult = LINEERR_OPERATIONFAILED;
  8224. }
  8225. else
  8226. {
  8227. ptDlgInst->dwKey = INVAL_KEY;
  8228. }
  8229. }
  8230. myexcept
  8231. {
  8232. pParams->lResult = LINEERR_OPERATIONFAILED;
  8233. }
  8234. if (pParams->lResult)
  8235. {
  8236. return;
  8237. }
  8238. if (ptDlgInst->hTsp)
  8239. {
  8240. //
  8241. // This dlg inst was a client doing a providerConfig, -Install, or
  8242. // -Remove
  8243. //
  8244. if (ptDlgInst->pszProviderFilename)
  8245. {
  8246. if (pParams->lUIDllResult == 0)
  8247. {
  8248. //
  8249. // Successful provider install
  8250. //
  8251. DWORD iNumProviders;
  8252. TCHAR szProviderXxxN[32];
  8253. TCHAR szProviderXxxNA[32];
  8254. if (RegOpenKeyEx(
  8255. HKEY_LOCAL_MACHINE,
  8256. gszRegKeyProviders,
  8257. 0,
  8258. KEY_ALL_ACCESS,
  8259. &hKeyProviders
  8260. ) != ERROR_SUCCESS)
  8261. {
  8262. goto bail;
  8263. }
  8264. dwDataSize = sizeof(iNumProviders);
  8265. iNumProviders = 0;
  8266. RegQueryValueEx(
  8267. hKeyProviders,
  8268. gszNumProviders,
  8269. 0,
  8270. &dwDataType,
  8271. (LPBYTE) &iNumProviders,
  8272. &dwDataSize
  8273. );
  8274. wsprintf(
  8275. szProviderXxxNA,
  8276. TEXT("%s%d"),
  8277. gszProviderID,
  8278. iNumProviders
  8279. );
  8280. RegSetValueEx(
  8281. hKeyProviders,
  8282. szProviderXxxNA,
  8283. 0,
  8284. REG_DWORD,
  8285. (LPBYTE) &ptDlgInst->dwPermanentProviderID,
  8286. sizeof(DWORD)
  8287. );
  8288. wsprintf(
  8289. szProviderXxxN,
  8290. TEXT("%s%d"),
  8291. gszProviderFilename,
  8292. iNumProviders
  8293. );
  8294. RegSetValueEx(
  8295. hKeyProviders,
  8296. szProviderXxxN,
  8297. 0,
  8298. REG_SZ,
  8299. (LPBYTE) ptDlgInst->pszProviderFilename,
  8300. (lstrlen((PTSTR)ptDlgInst->pszProviderFilename) + 1)*sizeof(TCHAR)
  8301. );
  8302. iNumProviders++;
  8303. RegSetValueEx(
  8304. hKeyProviders,
  8305. gszNumProviders,
  8306. 0,
  8307. REG_DWORD,
  8308. (LPBYTE) &iNumProviders,
  8309. sizeof(DWORD)
  8310. );
  8311. RegCloseKey( hKeyProviders );
  8312. //
  8313. // If the tapisrv is already INITed, ReInit it to load the provider
  8314. //
  8315. TapiEnterCriticalSection (&TapiGlobals.CritSec);
  8316. if ((TapiGlobals.dwNumLineInits != 0) ||
  8317. (TapiGlobals.dwNumPhoneInits != 0) ||
  8318. (TapiGlobals.dwFlags & TAPIGLOBALS_SERVER))
  8319. {
  8320. pParams->lResult = ServerInit(TRUE);
  8321. }
  8322. TapiLeaveCriticalSection (&TapiGlobals.CritSec);
  8323. }
  8324. else
  8325. {
  8326. //
  8327. // Unsuccessful provider install. See if we can decrement
  8328. // NextProviderID to free up the unused ID.
  8329. //
  8330. DWORD iNextProviderID;
  8331. if (RegOpenKeyEx(
  8332. HKEY_LOCAL_MACHINE,
  8333. gszRegKeyProviders,
  8334. 0,
  8335. KEY_ALL_ACCESS,
  8336. &hKeyProviders
  8337. ) != ERROR_SUCCESS)
  8338. {
  8339. goto bail;
  8340. }
  8341. dwDataSize = sizeof(iNextProviderID);
  8342. iNextProviderID = 0;
  8343. RegQueryValueEx(
  8344. hKeyProviders,
  8345. gszNextProviderID,
  8346. 0,
  8347. &dwDataType,
  8348. (LPBYTE)&iNextProviderID,
  8349. &dwDataSize
  8350. );
  8351. if ((ptDlgInst->dwPermanentProviderID + 1) == iNextProviderID)
  8352. {
  8353. RegSetValueEx(
  8354. hKeyProviders,
  8355. gszNextProviderID,
  8356. 0,
  8357. REG_DWORD,
  8358. (LPBYTE) &(ptDlgInst->dwPermanentProviderID),
  8359. sizeof(DWORD)
  8360. );
  8361. }
  8362. RegCloseKey (hKeyProviders);
  8363. }
  8364. ServerFree (ptDlgInst->pszProviderFilename);
  8365. }
  8366. else if (ptDlgInst->bRemoveProvider)
  8367. {
  8368. if (pParams->lUIDllResult == 0)
  8369. {
  8370. //
  8371. // Successful provider remove. Find the index of the
  8372. // provider in the list, then move all the providers
  8373. // that follow up a notch.
  8374. //
  8375. DWORD iNumProviders, i;
  8376. TCHAR szProviderXxxN[32];
  8377. TCHAR buf[MAX_PATH];
  8378. if (RegOpenKeyEx(
  8379. HKEY_LOCAL_MACHINE,
  8380. gszRegKeyProviders,
  8381. 0,
  8382. KEY_ALL_ACCESS,
  8383. &hKeyProviders
  8384. ) != ERROR_SUCCESS)
  8385. {
  8386. goto bail;
  8387. }
  8388. dwDataSize = sizeof(iNumProviders);
  8389. iNumProviders = 0;
  8390. RegQueryValueEx(
  8391. hKeyProviders,
  8392. gszNumProviders,
  8393. 0,
  8394. &dwDataType,
  8395. (LPBYTE) &iNumProviders,
  8396. &dwDataSize
  8397. );
  8398. for (i = 0; i < iNumProviders; i++)
  8399. {
  8400. wsprintf(szProviderXxxN, TEXT("%s%d"), gszProviderID, i);
  8401. dwDataSize = sizeof(dwTemp);
  8402. dwTemp = 0;
  8403. RegQueryValueEx(
  8404. hKeyProviders,
  8405. szProviderXxxN,
  8406. 0,
  8407. &dwDataType,
  8408. (LPBYTE) &dwTemp,
  8409. &dwDataSize
  8410. );
  8411. if (dwTemp == ptDlgInst->dwPermanentProviderID)
  8412. {
  8413. break;
  8414. }
  8415. }
  8416. for (; i < (iNumProviders - 1); i++)
  8417. {
  8418. wsprintf(szProviderXxxN, TEXT("%s%d"), gszProviderID, i + 1);
  8419. dwDataSize = sizeof(buf);
  8420. RegQueryValueEx(
  8421. hKeyProviders,
  8422. szProviderXxxN,
  8423. 0,
  8424. &dwDataType,
  8425. (LPBYTE) buf,
  8426. &dwDataSize
  8427. );
  8428. buf[dwDataSize/sizeof(TCHAR)] = TEXT('\0');
  8429. wsprintf(szProviderXxxN, TEXT("%s%d"), gszProviderID, i);
  8430. RegSetValueEx(
  8431. hKeyProviders,
  8432. szProviderXxxN,
  8433. 0,
  8434. REG_DWORD,
  8435. (LPBYTE) buf,
  8436. sizeof (DWORD)
  8437. );
  8438. wsprintf(szProviderXxxN, TEXT("%s%d"), gszProviderFilename, i+1);
  8439. dwDataSize = MAX_PATH*sizeof(TCHAR);
  8440. RegQueryValueEx(
  8441. hKeyProviders,
  8442. szProviderXxxN,
  8443. 0,
  8444. &dwDataType,
  8445. (LPBYTE) buf,
  8446. &dwDataSize
  8447. );
  8448. buf[dwDataSize/sizeof(TCHAR)] = TEXT('\0');
  8449. wsprintf(szProviderXxxN, TEXT("%s%d"), gszProviderFilename, i);
  8450. RegSetValueEx(
  8451. hKeyProviders,
  8452. szProviderXxxN,
  8453. 0,
  8454. REG_SZ,
  8455. (LPBYTE) buf,
  8456. (lstrlen(buf) + 1) * sizeof(TCHAR)
  8457. );
  8458. }
  8459. //
  8460. // Remove the last ProviderID# & ProviderFilename# entries
  8461. //
  8462. wsprintf(szProviderXxxN, TEXT("%s%d"), gszProviderID, i);
  8463. RegDeleteValue(hKeyProviders, szProviderXxxN);
  8464. wsprintf(szProviderXxxN, TEXT("%s%d"), gszProviderFilename, i);
  8465. RegDeleteValue(hKeyProviders, szProviderXxxN);
  8466. //
  8467. // Decrement the total num providers to load
  8468. //
  8469. iNumProviders--;
  8470. RegSetValueEx(
  8471. hKeyProviders,
  8472. gszNumProviders,
  8473. 0,
  8474. REG_DWORD,
  8475. (LPBYTE)&iNumProviders,
  8476. sizeof(DWORD)
  8477. );
  8478. //
  8479. // Remove user/line association with this provider
  8480. //
  8481. {
  8482. WCHAR * pSectionNames = NULL;
  8483. WCHAR * pSectionNames2 = NULL;
  8484. WCHAR * pszLinePhoneSave = NULL;
  8485. DWORD dwSize, dwSize2;
  8486. DWORD dwResult;
  8487. WCHAR szBuf[20];
  8488. WCHAR * aszKeys[] = {gszLines, gszPhones};
  8489. // Only NT server cares about tsec.ini
  8490. if (!gbNTServer)
  8491. {
  8492. goto Exit;
  8493. }
  8494. // Get the list of DomainUser names
  8495. LOG((TL_INFO, "FreeDialogInstance: getting user names"));
  8496. do
  8497. {
  8498. if (pSectionNames)
  8499. {
  8500. ServerFree (pSectionNames);
  8501. dwSize *= 2;
  8502. }
  8503. else
  8504. {
  8505. dwSize = 256;
  8506. }
  8507. if (!(pSectionNames =
  8508. ServerAlloc (dwSize * sizeof (WCHAR))))
  8509. {
  8510. goto Exit;
  8511. }
  8512. pSectionNames[0] = L'\0';
  8513. dwResult = GetPrivateProfileSectionNamesW(
  8514. pSectionNames,
  8515. dwSize,
  8516. gszFileName
  8517. );
  8518. } while (dwResult >= (dwSize - 2));
  8519. pSectionNames2 = pSectionNames;
  8520. dwSize = 64 * sizeof(WCHAR);
  8521. pszLinePhoneSave = ServerAlloc(dwSize);
  8522. if (pszLinePhoneSave == NULL)
  8523. {
  8524. LOG((TL_ERROR,
  8525. "FreeDialogInstance: Memory failure"));
  8526. goto Exit;
  8527. }
  8528. dwSize2 = wsprintfW (szBuf, L"%d",
  8529. ptDlgInst->dwPermanentProviderID);
  8530. // Remove all the devices associated with this domain/user
  8531. while (*pSectionNames)
  8532. {
  8533. WCHAR *psz, *psz2;
  8534. BOOL bWriteBack;
  8535. int iasz;
  8536. for (iasz = 0;
  8537. iasz < sizeof(aszKeys) / sizeof(WCHAR *); ++iasz)
  8538. {
  8539. bWriteBack = FALSE;
  8540. dwResult = MyGetPrivateProfileString(
  8541. pSectionNames,
  8542. aszKeys[iasz],
  8543. gszEmptyString,
  8544. &pszLinePhoneSave,
  8545. &dwSize);
  8546. if (dwResult == 0)
  8547. {
  8548. psz = pszLinePhoneSave;
  8549. while (*psz)
  8550. {
  8551. if (wcsncmp(psz, szBuf, dwSize2) == 0)
  8552. {
  8553. bWriteBack = TRUE;
  8554. psz2 = psz + dwSize2;
  8555. if (*psz2 != L',') // Comma?
  8556. {
  8557. LOG((TL_ERROR,
  8558. "FreeDialogInstance: "
  8559. "Corrupted tsec.ini"));
  8560. goto Exit;
  8561. }
  8562. ++ psz2; // Skip comma
  8563. // Skip the permanent device ID
  8564. while ((*psz2 != L',') && (*psz2 != 0))
  8565. {
  8566. ++psz2;
  8567. }
  8568. if (*psz2 == 0) // Last one
  8569. {
  8570. if (psz > pszLinePhoneSave)
  8571. *(psz - 1) = 0;
  8572. else
  8573. *pszLinePhoneSave = 0;
  8574. break;
  8575. }
  8576. else
  8577. {
  8578. int i = 0;
  8579. ++psz2; // skip the comma
  8580. while (*psz2)
  8581. {
  8582. psz[i++] = *psz2;
  8583. ++psz2;
  8584. }
  8585. psz[i] = 0;
  8586. }
  8587. }
  8588. else
  8589. {
  8590. // Skip the provider ID
  8591. while ((*psz != 0) && (*psz != L','))
  8592. {
  8593. ++ psz;
  8594. }
  8595. if (*psz == 0)
  8596. break;
  8597. ++ psz;
  8598. // Skip the permanent device ID
  8599. while ((*psz != 0) && (*psz != L','))
  8600. {
  8601. ++ psz;
  8602. }
  8603. if (*psz == 0)
  8604. break;
  8605. ++ psz;
  8606. }
  8607. }
  8608. if (bWriteBack)
  8609. {
  8610. WritePrivateProfileStringW(
  8611. pSectionNames,
  8612. aszKeys[iasz],
  8613. pszLinePhoneSave,
  8614. gszFileName
  8615. );
  8616. }
  8617. } // dwResult == 0
  8618. }
  8619. // Advance to the next domain user
  8620. while (*pSectionNames != 0)
  8621. {
  8622. ++pSectionNames;
  8623. }
  8624. ++pSectionNames;
  8625. }
  8626. Exit:
  8627. ServerFree(pSectionNames2);
  8628. ServerFree(pszLinePhoneSave);
  8629. }
  8630. //
  8631. // if tapi init'd shutdown each provider
  8632. //
  8633. {
  8634. PTLINELOOKUPENTRY pLineEntry;
  8635. PTPHONELOOKUPENTRY pPhoneEntry;
  8636. DWORD dw;
  8637. PTPROVIDER ptProvider;
  8638. PPERMANENTIDARRAYHEADER pIDArray, *ppLastArray;
  8639. PTPROVIDER *pptProvider;
  8640. //
  8641. // LINE_REMOVE / PHONE_REMOVE will try to enter gMgmtCritSec while in
  8642. // TapiGlobals.CritSec.
  8643. // Need to enter gMgmtCritSec here, to avoid deadlock
  8644. //
  8645. EnterCriticalSection (&gMgmtCritSec);
  8646. TapiEnterCriticalSection (&TapiGlobals.CritSec);
  8647. //
  8648. // Find ptProvider
  8649. //
  8650. ptProvider = TapiGlobals.ptProviders;
  8651. while (ptProvider)
  8652. {
  8653. if (ptProvider->dwPermanentProviderID ==
  8654. ptDlgInst->dwPermanentProviderID)
  8655. {
  8656. break;
  8657. }
  8658. ptProvider = ptProvider->pNext;
  8659. }
  8660. if (ptProvider == NULL)
  8661. {
  8662. LeaveCriticalSection (&gMgmtCritSec);
  8663. TapiLeaveCriticalSection (&TapiGlobals.CritSec);
  8664. goto bail;
  8665. }
  8666. //
  8667. // Remove all the lines/phones belong to this provider.
  8668. //
  8669. for (dw = 0; dw < TapiGlobals.dwNumLines; ++dw)
  8670. {
  8671. pLineEntry = GetLineLookupEntry (dw);
  8672. if (pLineEntry &&
  8673. pLineEntry->ptProvider == ptProvider &&
  8674. !pLineEntry->bRemoved)
  8675. {
  8676. LineEventProc (
  8677. 0,
  8678. 0,
  8679. LINE_REMOVE,
  8680. dw,
  8681. 0,
  8682. 0
  8683. );
  8684. }
  8685. }
  8686. for (dw = 0; dw < TapiGlobals.dwNumPhones; ++dw)
  8687. {
  8688. pPhoneEntry = GetPhoneLookupEntry (dw);
  8689. if (pPhoneEntry &&
  8690. pPhoneEntry->ptProvider == ptProvider &&
  8691. !pPhoneEntry->bRemoved)
  8692. {
  8693. PhoneEventProc (
  8694. 0,
  8695. PHONE_REMOVE,
  8696. dw,
  8697. 0,
  8698. 0
  8699. );
  8700. }
  8701. }
  8702. LeaveCriticalSection (&gMgmtCritSec);
  8703. //
  8704. // Remove the provider ID array associate with this provider
  8705. //
  8706. ppLastArray = &(TapiGlobals.pIDArrays);
  8707. while ((*ppLastArray) != NULL &&
  8708. ((*ppLastArray)->dwPermanentProviderID !=
  8709. ptProvider->dwPermanentProviderID)
  8710. )
  8711. {
  8712. ppLastArray = &((*ppLastArray)->pNext);
  8713. }
  8714. if (pIDArray = (*ppLastArray))
  8715. {
  8716. *ppLastArray = pIDArray->pNext;
  8717. ServerFree (pIDArray->pLineElements);
  8718. ServerFree (pIDArray->pPhoneElements);
  8719. ServerFree (pIDArray);
  8720. }
  8721. else
  8722. {
  8723. // Should not be here
  8724. }
  8725. //
  8726. // Remove ptProvider from the global link list
  8727. //
  8728. if (ptProvider->pNext)
  8729. {
  8730. ptProvider->pNext->pPrev = ptProvider->pPrev;
  8731. }
  8732. if (ptProvider->pPrev)
  8733. {
  8734. ptProvider->pPrev->pNext = ptProvider->pNext;
  8735. }
  8736. else
  8737. {
  8738. TapiGlobals.ptProviders = ptProvider->pNext;
  8739. }
  8740. //
  8741. // Now shutdown and unload the TSP provider
  8742. //
  8743. CallSP2(
  8744. ptProvider->apfn[SP_PROVIDERSHUTDOWN],
  8745. "providerShutdown",
  8746. SP_FUNC_SYNC,
  8747. (DWORD)ptProvider->dwSPIVersion,
  8748. (DWORD)ptProvider->dwPermanentProviderID
  8749. );
  8750. // Wait for 5 seconds for ongoing calls to finish
  8751. Sleep (5000);
  8752. FreeLibrary (ptProvider->hDll);
  8753. MyCloseMutex (ptProvider->hMutex);
  8754. CloseHandle (ptProvider->hHashTableReaderEvent);
  8755. DeleteCriticalSection (&ptProvider->HashTableCritSec);
  8756. ServerFree (ptProvider->pHashTable);
  8757. ServerFree (ptProvider);
  8758. TapiLeaveCriticalSection (&TapiGlobals.CritSec);
  8759. }
  8760. }
  8761. else
  8762. {
  8763. //
  8764. // Unsuccessful provider remove, nothing to do
  8765. //
  8766. }
  8767. }
  8768. else
  8769. {
  8770. //
  8771. // Nothing to do for providerConfig (success or fail)
  8772. //
  8773. }
  8774. bail:
  8775. FreeLibrary (ptDlgInst->hTsp);
  8776. pParams->lResult = pParams->lUIDllResult;
  8777. }
  8778. else if (ptDlgInst->ptProvider->apfn[SP_PROVIDERFREEDIALOGINSTANCE])
  8779. {
  8780. //
  8781. // The was a provider-initiated dlg inst, so tell
  8782. // the provider to free it's inst
  8783. //
  8784. CallSP1(
  8785. ptDlgInst->ptProvider->apfn[SP_PROVIDERFREEDIALOGINSTANCE],
  8786. "providerFreeDialogInstance",
  8787. SP_FUNC_SYNC,
  8788. (ULONG_PTR) ptDlgInst->hdDlgInst
  8789. );
  8790. }
  8791. //
  8792. // Remove the dialog instance from the tClient's list & then free it
  8793. //
  8794. if (WaitForExclusiveClientAccess (ptClient))
  8795. {
  8796. if (ptDlgInst->pNext)
  8797. {
  8798. ptDlgInst->pNext->pPrev = ptDlgInst->pPrev;
  8799. }
  8800. if (ptDlgInst->pPrev)
  8801. {
  8802. ptDlgInst->pPrev->pNext = ptDlgInst->pNext;
  8803. }
  8804. else if (ptDlgInst->hTsp)
  8805. {
  8806. ptClient->pProviderXxxDlgInsts = ptDlgInst->pNext;
  8807. }
  8808. else
  8809. {
  8810. ptClient->pGenericDlgInsts = ptDlgInst->pNext;
  8811. }
  8812. UNLOCKTCLIENT (ptClient);
  8813. }
  8814. DereferenceObject (ghHandleTable, pParams->htDlgInst, 2);
  8815. }
  8816. BOOL
  8817. GetNewClientHandle(
  8818. PTCLIENT ptClient,
  8819. PTMANAGEDLLINFO pDll,
  8820. HMANAGEMENTCLIENT *phClient
  8821. )
  8822. {
  8823. BOOL fResult = TRUE;
  8824. PTCLIENTHANDLE pClientHandle, pNewClientHandle;
  8825. if (!(pNewClientHandle = ServerAlloc (sizeof (TCLIENTHANDLE))))
  8826. {
  8827. return FALSE;
  8828. }
  8829. pNewClientHandle->pNext = NULL;
  8830. pNewClientHandle->fValid = TRUE;
  8831. pNewClientHandle->dwID = pDll->dwID;
  8832. // call init
  8833. if ((pDll->aProcs[TC_CLIENTINITIALIZE])(
  8834. ptClient->pszDomainName,
  8835. ptClient->pszUserName,
  8836. ptClient->pszComputerName,
  8837. &pNewClientHandle->hClient
  8838. ))
  8839. {
  8840. // error - zero out the handle
  8841. pNewClientHandle->hClient = (HMANAGEMENTCLIENT) NULL;
  8842. pNewClientHandle->fValid = FALSE;
  8843. fResult = FALSE;
  8844. }
  8845. // save it no matter what
  8846. // insert at beginning of list
  8847. pClientHandle = ptClient->pClientHandles;
  8848. ptClient->pClientHandles = pNewClientHandle;
  8849. pNewClientHandle->pNext = pClientHandle;
  8850. *phClient = pNewClientHandle->hClient;
  8851. return fResult;
  8852. }
  8853. BOOL
  8854. GetTCClient(
  8855. PTMANAGEDLLINFO pDll,
  8856. PTCLIENT ptClient,
  8857. DWORD dwAPI,
  8858. HMANAGEMENTCLIENT *phClient
  8859. )
  8860. {
  8861. PTCLIENTHANDLE pClientHandle;
  8862. BOOL bResult;
  8863. if (!pDll->aProcs[dwAPI])
  8864. {
  8865. return FALSE;
  8866. }
  8867. pClientHandle = ptClient->pClientHandles;
  8868. while (pClientHandle)
  8869. {
  8870. if (pClientHandle->dwID == pDll->dwID)
  8871. {
  8872. break;
  8873. }
  8874. pClientHandle = pClientHandle->pNext;
  8875. }
  8876. if (pClientHandle)
  8877. {
  8878. if (!(pClientHandle->fValid))
  8879. {
  8880. return FALSE;
  8881. }
  8882. *phClient = pClientHandle->hClient;
  8883. return TRUE;
  8884. }
  8885. else
  8886. {
  8887. // OK - it's not in the list.
  8888. // get the critical section & check again
  8889. EnterCriticalSection(&gClientHandleCritSec);
  8890. pClientHandle = ptClient->pClientHandles;
  8891. while (pClientHandle)
  8892. {
  8893. if (pClientHandle->dwID == pDll->dwID)
  8894. {
  8895. break;
  8896. }
  8897. pClientHandle = pClientHandle->pNext;
  8898. }
  8899. if (pClientHandle)
  8900. {
  8901. if (!(pClientHandle->fValid))
  8902. {
  8903. LeaveCriticalSection(&gClientHandleCritSec);
  8904. return FALSE;
  8905. }
  8906. *phClient = pClientHandle->hClient;
  8907. LeaveCriticalSection(&gClientHandleCritSec);
  8908. return TRUE;
  8909. }
  8910. // still not there. add it...
  8911. bResult = GetNewClientHandle(
  8912. ptClient,
  8913. pDll,
  8914. phClient
  8915. );
  8916. LeaveCriticalSection(&gClientHandleCritSec);
  8917. return bResult;
  8918. }
  8919. }
  8920. //#pragma warning (default:4028)
  8921. #if DBG
  8922. char szBeforeSync[] = "Calling TSPI_%s";
  8923. char szBeforeAsync[] = "Calling TSPI_%s, dwReqID=x%x";
  8924. char szAfter[] = "TSPI_%s result=%s";
  8925. VOID
  8926. DbgPrt(
  8927. IN DWORD dwDbgLevel,
  8928. IN PUCHAR lpszFormat,
  8929. IN ...
  8930. )
  8931. /*++
  8932. Routine Description:
  8933. Formats the incoming debug message & calls DbgPrint
  8934. Arguments:
  8935. DbgLevel - level of message verboseness
  8936. DbgMessage - printf-style format string, followed by appropriate
  8937. list of arguments
  8938. Return Value:
  8939. --*/
  8940. {
  8941. if (dwDbgLevel <= gdwDebugLevel)
  8942. {
  8943. char buf[1024] = "TAPISRV (0x--------): ";
  8944. va_list ap;
  8945. wsprintfA( &buf[11], "%08lx", GetCurrentThreadId() );
  8946. buf[19] = ')';
  8947. va_start(ap, lpszFormat);
  8948. wvsprintfA(
  8949. &buf[22],
  8950. lpszFormat,
  8951. ap
  8952. );
  8953. lstrcatA(buf, "\n");
  8954. OutputDebugStringA (buf);
  8955. va_end(ap);
  8956. }
  8957. return;
  8958. }
  8959. char *aszLineErrors[] =
  8960. {
  8961. NULL,
  8962. "ALLOCATED",
  8963. "BADDEVICEID",
  8964. "BEARERMODEUNAVAIL",
  8965. "inval err value (0x80000004)", // 0x80000004 isn't valid err code
  8966. "CALLUNAVAIL",
  8967. "COMPLETIONOVERRUN",
  8968. "CONFERENCEFULL",
  8969. "DIALBILLING",
  8970. "DIALDIALTONE",
  8971. "DIALPROMPT",
  8972. "DIALQUIET",
  8973. "INCOMPATIBLEAPIVERSION",
  8974. "INCOMPATIBLEEXTVERSION",
  8975. "INIFILECORRUPT",
  8976. "INUSE",
  8977. "INVALADDRESS", // 0x80000010
  8978. "INVALADDRESSID",
  8979. "INVALADDRESSMODE",
  8980. "INVALADDRESSSTATE",
  8981. "INVALAPPHANDLE",
  8982. "INVALAPPNAME",
  8983. "INVALBEARERMODE",
  8984. "INVALCALLCOMPLMODE",
  8985. "INVALCALLHANDLE",
  8986. "INVALCALLPARAMS",
  8987. "INVALCALLPRIVILEGE",
  8988. "INVALCALLSELECT",
  8989. "INVALCALLSTATE",
  8990. "INVALCALLSTATELIST",
  8991. "INVALCARD",
  8992. "INVALCOMPLETIONID",
  8993. "INVALCONFCALLHANDLE", // 0x80000020
  8994. "INVALCONSULTCALLHANDLE",
  8995. "INVALCOUNTRYCODE",
  8996. "INVALDEVICECLASS",
  8997. "INVALDEVICEHANDLE",
  8998. "INVALDIALPARAMS",
  8999. "INVALDIGITLIST",
  9000. "INVALDIGITMODE",
  9001. "INVALDIGITS",
  9002. "INVALEXTVERSION",
  9003. "INVALGROUPID",
  9004. "INVALLINEHANDLE",
  9005. "INVALLINESTATE",
  9006. "INVALLOCATION",
  9007. "INVALMEDIALIST",
  9008. "INVALMEDIAMODE",
  9009. "INVALMESSAGEID", // 0x80000030
  9010. "inval err value (0x80000031)", // 0x80000031 isn't valid err code
  9011. "INVALPARAM",
  9012. "INVALPARKID",
  9013. "INVALPARKMODE",
  9014. "INVALPOINTER",
  9015. "INVALPRIVSELECT",
  9016. "INVALRATE",
  9017. "INVALREQUESTMODE",
  9018. "INVALTERMINALID",
  9019. "INVALTERMINALMODE",
  9020. "INVALTIMEOUT",
  9021. "INVALTONE",
  9022. "INVALTONELIST",
  9023. "INVALTONEMODE",
  9024. "INVALTRANSFERMODE",
  9025. "LINEMAPPERFAILED", // 0x80000040
  9026. "NOCONFERENCE",
  9027. "NODEVICE",
  9028. "NODRIVER",
  9029. "NOMEM",
  9030. "NOREQUEST",
  9031. "NOTOWNER",
  9032. "NOTREGISTERED",
  9033. "OPERATIONFAILED",
  9034. "OPERATIONUNAVAIL",
  9035. "RATEUNAVAIL",
  9036. "RESOURCEUNAVAIL",
  9037. "REQUESTOVERRUN",
  9038. "STRUCTURETOOSMALL",
  9039. "TARGETNOTFOUND",
  9040. "TARGETSELF",
  9041. "UNINITIALIZED", // 0x80000050
  9042. "USERUSERINFOTOOBIG",
  9043. "REINIT",
  9044. "ADDRESSBLOCKED",
  9045. "BILLINGREJECTED",
  9046. "INVALFEATURE",
  9047. "NOMULTIPLEINSTANCE",
  9048. "INVALAGENTID",
  9049. "INVALAGENTGROUP",
  9050. "INVALPASSWORD",
  9051. "INVALAGENTSTATE",
  9052. "INVALAGENTACTIVITY",
  9053. "DIALVOICEDETECT"
  9054. };
  9055. char *aszPhoneErrors[] =
  9056. {
  9057. "SUCCESS",
  9058. "ALLOCATED",
  9059. "BADDEVICEID",
  9060. "INCOMPATIBLEAPIVERSION",
  9061. "INCOMPATIBLEEXTVERSION",
  9062. "INIFILECORRUPT",
  9063. "INUSE",
  9064. "INVALAPPHANDLE",
  9065. "INVALAPPNAME",
  9066. "INVALBUTTONLAMPID",
  9067. "INVALBUTTONMODE",
  9068. "INVALBUTTONSTATE",
  9069. "INVALDATAID",
  9070. "INVALDEVICECLASS",
  9071. "INVALEXTVERSION",
  9072. "INVALHOOKSWITCHDEV",
  9073. "INVALHOOKSWITCHMODE", // 0x90000010
  9074. "INVALLAMPMODE",
  9075. "INVALPARAM",
  9076. "INVALPHONEHANDLE",
  9077. "INVALPHONESTATE",
  9078. "INVALPOINTER",
  9079. "INVALPRIVILEGE",
  9080. "INVALRINGMODE",
  9081. "NODEVICE",
  9082. "NODRIVER",
  9083. "NOMEM",
  9084. "NOTOWNER",
  9085. "OPERATIONFAILED",
  9086. "OPERATIONUNAVAIL",
  9087. "inval err value (0x9000001e)", // 0x9000001e isn't valid err code
  9088. "RESOURCEUNAVAIL",
  9089. "REQUESTOVERRUN", // 0x90000020
  9090. "STRUCTURETOOSMALL",
  9091. "UNINITIALIZED",
  9092. "REINIT"
  9093. };
  9094. char *aszTapiErrors[] =
  9095. {
  9096. "SUCCESS",
  9097. "DROPPED",
  9098. "NOREQUESTRECIPIENT",
  9099. "REQUESTQUEUEFULL",
  9100. "INVALDESTADDRESS",
  9101. "INVALWINDOWHANDLE",
  9102. "INVALDEVICECLASS",
  9103. "INVALDEVICEID",
  9104. "DEVICECLASSUNAVAIL",
  9105. "DEVICEIDUNAVAIL",
  9106. "DEVICEINUSE",
  9107. "DESTBUSY",
  9108. "DESTNOANSWER",
  9109. "DESTUNAVAIL",
  9110. "UNKNOWNWINHANDLE",
  9111. "UNKNOWNREQUESTID",
  9112. "REQUESTFAILED",
  9113. "REQUESTCANCELLED",
  9114. "INVALPOINTER"
  9115. };
  9116. char *
  9117. PASCAL
  9118. MapResultCodeToText(
  9119. LONG lResult,
  9120. char *pszResult
  9121. )
  9122. {
  9123. if (lResult == 0)
  9124. {
  9125. wsprintfA (pszResult, "SUCCESS");
  9126. }
  9127. else if (lResult > 0)
  9128. {
  9129. wsprintfA (pszResult, "x%x (completing async)", lResult);
  9130. }
  9131. else if (((DWORD) lResult) <= LINEERR_DIALVOICEDETECT)
  9132. {
  9133. lResult &= 0x0fffffff;
  9134. wsprintfA (pszResult, "LINEERR_%s", aszLineErrors[lResult]);
  9135. }
  9136. else if (((DWORD) lResult) <= PHONEERR_REINIT)
  9137. {
  9138. if (((DWORD) lResult) >= PHONEERR_ALLOCATED)
  9139. {
  9140. lResult &= 0x0fffffff;
  9141. wsprintfA (pszResult, "PHONEERR_%s", aszPhoneErrors[lResult]);
  9142. }
  9143. else
  9144. {
  9145. goto MapResultCodeToText_badErrorCode;
  9146. }
  9147. }
  9148. else if (((DWORD) lResult) <= ((DWORD) TAPIERR_DROPPED) &&
  9149. ((DWORD) lResult) >= ((DWORD) TAPIERR_INVALPOINTER))
  9150. {
  9151. lResult = ~lResult + 1;
  9152. wsprintfA (pszResult, "TAPIERR_%s", aszTapiErrors[lResult]);
  9153. }
  9154. else
  9155. {
  9156. MapResultCodeToText_badErrorCode:
  9157. wsprintfA (pszResult, "inval error value (x%x)");
  9158. }
  9159. return pszResult;
  9160. }
  9161. VOID
  9162. PASCAL
  9163. ValidateSyncSPResult(
  9164. LPCSTR lpszFuncName,
  9165. DWORD dwFlags,
  9166. ULONG_PTR Arg1,
  9167. LONG lResult
  9168. )
  9169. {
  9170. char szResult[32];
  9171. LOG((TL_INFO,
  9172. szAfter,
  9173. lpszFuncName,
  9174. MapResultCodeToText (lResult, szResult)
  9175. ));
  9176. if (dwFlags & SP_FUNC_ASYNC)
  9177. {
  9178. assert (lResult != 0);
  9179. if (lResult > 0)
  9180. {
  9181. assert (lResult == PtrToLong (Arg1) ||
  9182. PtrToLong (Arg1) == 0xfeeefeee || // pAsyncRequestInfo freed
  9183. PtrToLong (Arg1) == 0xa1a1a1a1);
  9184. }
  9185. }
  9186. else
  9187. {
  9188. assert (lResult <= 0);
  9189. }
  9190. }
  9191. LONG
  9192. WINAPI
  9193. CallSP1(
  9194. TSPIPROC pfn,
  9195. LPCSTR lpszFuncName,
  9196. DWORD dwFlags,
  9197. ULONG_PTR Arg1
  9198. )
  9199. {
  9200. LONG lResult;
  9201. LOG((TL_INFO, szBeforeSync, lpszFuncName));
  9202. lResult = (*pfn)(Arg1);
  9203. ValidateSyncSPResult (lpszFuncName, dwFlags, Arg1, lResult);
  9204. return lResult;
  9205. }
  9206. LONG
  9207. WINAPI
  9208. CallSP2(
  9209. TSPIPROC pfn,
  9210. LPCSTR lpszFuncName,
  9211. DWORD dwFlags,
  9212. ULONG_PTR Arg1,
  9213. ULONG_PTR Arg2
  9214. )
  9215. {
  9216. LONG lResult;
  9217. if (dwFlags & SP_FUNC_ASYNC)
  9218. {
  9219. LOG((TL_INFO, szBeforeAsync, lpszFuncName, Arg1));
  9220. }
  9221. else
  9222. {
  9223. LOG((TL_INFO, szBeforeSync, lpszFuncName));
  9224. }
  9225. lResult = (*pfn)(Arg1, Arg2);
  9226. ValidateSyncSPResult (lpszFuncName, dwFlags, Arg1, lResult);
  9227. return lResult;
  9228. }
  9229. LONG
  9230. WINAPI
  9231. CallSP3(
  9232. TSPIPROC pfn,
  9233. LPCSTR lpszFuncName,
  9234. DWORD dwFlags,
  9235. ULONG_PTR Arg1,
  9236. ULONG_PTR Arg2,
  9237. ULONG_PTR Arg3
  9238. )
  9239. {
  9240. LONG lResult;
  9241. if (dwFlags & SP_FUNC_ASYNC)
  9242. {
  9243. LOG((TL_INFO, szBeforeAsync, lpszFuncName, Arg1));
  9244. }
  9245. else
  9246. {
  9247. LOG((TL_INFO, szBeforeSync, lpszFuncName));
  9248. }
  9249. lResult = (*pfn)(Arg1, Arg2, Arg3);
  9250. ValidateSyncSPResult (lpszFuncName, dwFlags, Arg1, lResult);
  9251. return lResult;
  9252. }
  9253. LONG
  9254. WINAPI
  9255. CallSP4(
  9256. TSPIPROC pfn,
  9257. LPCSTR lpszFuncName,
  9258. DWORD dwFlags,
  9259. ULONG_PTR Arg1,
  9260. ULONG_PTR Arg2,
  9261. ULONG_PTR Arg3,
  9262. ULONG_PTR Arg4
  9263. )
  9264. {
  9265. LONG lResult;
  9266. if (dwFlags & SP_FUNC_ASYNC)
  9267. {
  9268. LOG((TL_INFO, szBeforeAsync, lpszFuncName, Arg1));
  9269. }
  9270. else
  9271. {
  9272. LOG((TL_INFO, szBeforeSync, lpszFuncName));
  9273. }
  9274. lResult = (*pfn)(Arg1, Arg2, Arg3, Arg4);
  9275. ValidateSyncSPResult (lpszFuncName, dwFlags, Arg1, lResult);
  9276. return lResult;
  9277. }
  9278. LONG
  9279. WINAPI
  9280. CallSP5(
  9281. TSPIPROC pfn,
  9282. LPCSTR lpszFuncName,
  9283. DWORD dwFlags,
  9284. ULONG_PTR Arg1,
  9285. ULONG_PTR Arg2,
  9286. ULONG_PTR Arg3,
  9287. ULONG_PTR Arg4,
  9288. ULONG_PTR Arg5
  9289. )
  9290. {
  9291. LONG lResult;
  9292. if (dwFlags & SP_FUNC_ASYNC)
  9293. {
  9294. LOG((TL_INFO, szBeforeAsync, lpszFuncName, Arg1));
  9295. }
  9296. else
  9297. {
  9298. LOG((TL_INFO, szBeforeSync, lpszFuncName));
  9299. }
  9300. lResult = (*pfn)(Arg1, Arg2, Arg3, Arg4, Arg5);
  9301. ValidateSyncSPResult (lpszFuncName, dwFlags, Arg1, lResult);
  9302. return lResult;
  9303. }
  9304. LONG
  9305. WINAPI
  9306. CallSP6(
  9307. TSPIPROC pfn,
  9308. LPCSTR lpszFuncName,
  9309. DWORD dwFlags,
  9310. ULONG_PTR Arg1,
  9311. ULONG_PTR Arg2,
  9312. ULONG_PTR Arg3,
  9313. ULONG_PTR Arg4,
  9314. ULONG_PTR Arg5,
  9315. ULONG_PTR Arg6
  9316. )
  9317. {
  9318. LONG lResult;
  9319. if (dwFlags & SP_FUNC_ASYNC)
  9320. {
  9321. LOG((TL_INFO, szBeforeAsync, lpszFuncName, Arg1));
  9322. }
  9323. else
  9324. {
  9325. LOG((TL_INFO, szBeforeSync, lpszFuncName));
  9326. }
  9327. lResult = (*pfn)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6);
  9328. ValidateSyncSPResult (lpszFuncName, dwFlags, Arg1, lResult);
  9329. return lResult;
  9330. }
  9331. LONG
  9332. WINAPI
  9333. CallSP7(
  9334. TSPIPROC pfn,
  9335. LPCSTR lpszFuncName,
  9336. DWORD dwFlags,
  9337. ULONG_PTR Arg1,
  9338. ULONG_PTR Arg2,
  9339. ULONG_PTR Arg3,
  9340. ULONG_PTR Arg4,
  9341. ULONG_PTR Arg5,
  9342. ULONG_PTR Arg6,
  9343. ULONG_PTR Arg7
  9344. )
  9345. {
  9346. LONG lResult;
  9347. if (dwFlags & SP_FUNC_ASYNC)
  9348. {
  9349. LOG((TL_INFO, szBeforeAsync, lpszFuncName, Arg1));
  9350. }
  9351. else
  9352. {
  9353. LOG((TL_INFO, szBeforeSync, lpszFuncName));
  9354. }
  9355. lResult = (*pfn)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7);
  9356. ValidateSyncSPResult (lpszFuncName, dwFlags, Arg1, lResult);
  9357. return lResult;
  9358. }
  9359. LONG
  9360. WINAPI
  9361. CallSP8(
  9362. TSPIPROC pfn,
  9363. LPCSTR lpszFuncName,
  9364. DWORD dwFlags,
  9365. ULONG_PTR Arg1,
  9366. ULONG_PTR Arg2,
  9367. ULONG_PTR Arg3,
  9368. ULONG_PTR Arg4,
  9369. ULONG_PTR Arg5,
  9370. ULONG_PTR Arg6,
  9371. ULONG_PTR Arg7,
  9372. ULONG_PTR Arg8
  9373. )
  9374. {
  9375. LONG lResult;
  9376. if (dwFlags & SP_FUNC_ASYNC)
  9377. {
  9378. LOG((TL_INFO, szBeforeAsync, lpszFuncName, Arg1));
  9379. }
  9380. else
  9381. {
  9382. LOG((TL_INFO, szBeforeSync, lpszFuncName));
  9383. }
  9384. lResult = (*pfn)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8);
  9385. ValidateSyncSPResult (lpszFuncName, dwFlags, Arg1, lResult);
  9386. return lResult;
  9387. }
  9388. LONG
  9389. WINAPI
  9390. CallSP9(
  9391. TSPIPROC pfn,
  9392. LPCSTR lpszFuncName,
  9393. DWORD dwFlags,
  9394. ULONG_PTR Arg1,
  9395. ULONG_PTR Arg2,
  9396. ULONG_PTR Arg3,
  9397. ULONG_PTR Arg4,
  9398. ULONG_PTR Arg5,
  9399. ULONG_PTR Arg6,
  9400. ULONG_PTR Arg7,
  9401. ULONG_PTR Arg8,
  9402. ULONG_PTR Arg9
  9403. )
  9404. {
  9405. LONG lResult;
  9406. if (dwFlags & SP_FUNC_ASYNC)
  9407. {
  9408. LOG((TL_INFO, szBeforeAsync, lpszFuncName, Arg1));
  9409. }
  9410. else
  9411. {
  9412. LOG((TL_INFO, szBeforeSync, lpszFuncName));
  9413. }
  9414. lResult = (*pfn)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9);
  9415. ValidateSyncSPResult (lpszFuncName, dwFlags, Arg1, lResult);
  9416. return lResult;
  9417. }
  9418. LONG
  9419. WINAPI
  9420. CallSP12(
  9421. TSPIPROC pfn,
  9422. LPCSTR lpszFuncName,
  9423. DWORD dwFlags,
  9424. ULONG_PTR Arg1,
  9425. ULONG_PTR Arg2,
  9426. ULONG_PTR Arg3,
  9427. ULONG_PTR Arg4,
  9428. ULONG_PTR Arg5,
  9429. ULONG_PTR Arg6,
  9430. ULONG_PTR Arg7,
  9431. ULONG_PTR Arg8,
  9432. ULONG_PTR Arg9,
  9433. ULONG_PTR Arg10,
  9434. ULONG_PTR Arg11,
  9435. ULONG_PTR Arg12
  9436. )
  9437. {
  9438. LONG lResult;
  9439. if (dwFlags & SP_FUNC_ASYNC)
  9440. {
  9441. LOG((TL_INFO, szBeforeAsync, lpszFuncName, Arg1));
  9442. }
  9443. else
  9444. {
  9445. LOG((TL_INFO, szBeforeSync, lpszFuncName));
  9446. }
  9447. lResult = (*pfn)(
  9448. Arg1,
  9449. Arg2,
  9450. Arg3,
  9451. Arg4,
  9452. Arg5,
  9453. Arg6,
  9454. Arg7,
  9455. Arg8,
  9456. Arg9,
  9457. Arg10,
  9458. Arg11,
  9459. Arg12
  9460. );
  9461. ValidateSyncSPResult (lpszFuncName, dwFlags, Arg1, lResult);
  9462. return lResult;
  9463. }
  9464. #endif // DBG
  9465. /*************************************************************************\
  9466. * BOOL InitPerf()
  9467. *
  9468. * Initialize global performance data
  9469. *
  9470. \**************************************************************************/
  9471. BOOL InitPerf()
  9472. {
  9473. FillMemory(&PerfBlock,
  9474. sizeof(PerfBlock),
  9475. 0);
  9476. return(TRUE);
  9477. }
  9478. BOOL VerifyDomainName (HKEY hKey)
  9479. {
  9480. #define MAX_DNS_NAME_LENGTH 255
  9481. DWORD dwType;
  9482. DWORD dwSize;
  9483. BOOL bReturn = TRUE;
  9484. LPTSTR pOldName = NULL;
  9485. LPTSTR pNewName = NULL;
  9486. do {
  9487. //
  9488. // Get the old domain name from registry
  9489. //
  9490. dwSize = 0;
  9491. if (ERROR_SUCCESS == RegQueryValueEx(
  9492. hKey,
  9493. gszDomainName,
  9494. NULL,
  9495. &dwType,
  9496. NULL,
  9497. &dwSize)
  9498. )
  9499. {
  9500. pOldName = ServerAlloc (dwSize);
  9501. if(!pOldName)
  9502. {
  9503. bReturn = FALSE;
  9504. break;
  9505. }
  9506. if (ERROR_SUCCESS != RegQueryValueEx(
  9507. hKey,
  9508. gszDomainName,
  9509. NULL,
  9510. &dwType,
  9511. (LPBYTE)pOldName,
  9512. &dwSize)
  9513. )
  9514. {
  9515. bReturn = FALSE;
  9516. break;
  9517. }
  9518. }
  9519. //
  9520. // Get the current domain name
  9521. //
  9522. dwSize = MAX_DNS_NAME_LENGTH + 1;
  9523. pNewName = ServerAlloc ( dwSize * sizeof (TCHAR));
  9524. if (!pNewName)
  9525. {
  9526. bReturn = FALSE;
  9527. break;
  9528. }
  9529. if (!GetComputerNameEx (ComputerNameDnsDomain, pNewName, &dwSize))
  9530. {
  9531. bReturn = FALSE;
  9532. LOG((TL_INFO, "VerifyDomainName: GetComputerNameEx failed - error x%x", GetLastError()));
  9533. break;
  9534. }
  9535. if (dwSize == 0)
  9536. {
  9537. // no domain name, save as empty string
  9538. pNewName [0] = TEXT('\0');
  9539. dwSize = 1;
  9540. }
  9541. if (!pOldName || _tcscmp(pOldName, pNewName))
  9542. {
  9543. //
  9544. // The domain has changed, save the new domain name
  9545. // We also need to discard the old SCP
  9546. //
  9547. if (ERROR_SUCCESS != RegSetValueEx (
  9548. hKey,
  9549. gszDomainName,
  9550. 0,
  9551. REG_SZ,
  9552. (LPBYTE)pNewName,
  9553. dwSize * sizeof(TCHAR)
  9554. ))
  9555. {
  9556. LOG((TL_INFO, "VerifyDomainName:RegSetValueEx (%S) failed", pNewName));
  9557. }
  9558. RegDeleteValue (
  9559. hKey,
  9560. gszRegTapisrvSCPGuid
  9561. );
  9562. }
  9563. } while (0);
  9564. ServerFree(pOldName);
  9565. ServerFree(pNewName);
  9566. return bReturn;
  9567. }