Leaked source code of windows server 2003
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.

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