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

464 lines
14 KiB

  1. /*
  2. * Copyright (c) Microsoft Corporation
  3. *
  4. * Module Name :
  5. * init.c
  6. *
  7. * Initilization functions
  8. * Where possible, code has been obtained from BINL server.
  9. *
  10. * Sadagopan Rajaram -- Oct 14, 1999
  11. *
  12. */
  13. #include "tcsrv.h"
  14. #include <ntddser.h>
  15. #include "tcsrvc.h"
  16. #include "proto.h"
  17. PHANDLE Threads;
  18. PCOM_PORT_INFO ComPortInfo;
  19. int ComPorts;
  20. SOCKET MainSocket;
  21. HANDLE TerminateService;
  22. CRITICAL_SECTION GlobalMutex;
  23. NTSTATUS Initialize(
  24. )
  25. /*++
  26. This function performs the initialization routine by opening the COM ports,
  27. allocating circular buffers for each of the COM ports. All these values are
  28. in the registry.
  29. Threads are started for reading from each of the COM ports. These buffers
  30. are protected by mutual exclusion variables.
  31. Caveat for me - Remember all the allocation done here. you need to free them
  32. when you leave the system.
  33. Return Value :
  34. Success if successful in doing everything, else an error code.
  35. --*/
  36. {
  37. int number=1;
  38. int i;
  39. HKEY hKey, hParameter;
  40. PCOM_PORT_INFO pTempInfo;
  41. NTSTATUS Status;
  42. LPTSTR name,device;
  43. int index;
  44. LONG RetVal;
  45. HANDLE lock;
  46. // Global variable carrying information about the COM ports.
  47. ComPortInfo = NULL;
  48. ComPorts = 0;
  49. RetVal = TCLock(&lock);
  50. if(RetVal != ERROR_SUCCESS){
  51. TCDebugPrint(("Cannot Lock Registry %d\n", RetVal));
  52. return RetVal;
  53. }
  54. RetVal = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  55. HKEY_TCSERV_PARAMETER_KEY,
  56. 0,
  57. KEY_ALL_ACCESS,
  58. &hKey
  59. );
  60. if(RetVal != ERROR_SUCCESS){
  61. TCDebugPrint(("Cannot open Registry Key %d\n", RetVal));
  62. return RetVal;
  63. }
  64. // Read the correct parameters from the registry until you get no more.
  65. index= 0;
  66. while(1) {
  67. RetVal = GetNextParameter(hKey,
  68. index,
  69. &hParameter,
  70. &name
  71. );
  72. if (RetVal == ERROR_NO_MORE_ITEMS) {
  73. TCUnlock(lock);
  74. TCDebugPrint(("Done with registry\n"));
  75. break;
  76. }
  77. if(RetVal != ERROR_SUCCESS){
  78. TCUnlock(lock);
  79. TCDebugPrint(("Problem with registry, %d\n", RetVal));
  80. return RetVal;
  81. }
  82. RetVal = GetNameOfDeviceFromRegistry(hParameter,
  83. &device
  84. );
  85. if(RetVal != ERROR_SUCCESS){
  86. TCFree(name);
  87. continue;
  88. }
  89. pTempInfo = GetComPortParameters(hParameter);
  90. RegCloseKey(hParameter);
  91. if(pTempInfo == NULL){
  92. TCFree(name);
  93. TCFree(device);
  94. RegCloseKey(hKey);
  95. TCUnlock(lock);
  96. return RetVal;
  97. }
  98. pTempInfo->Device.Buffer = device;
  99. pTempInfo->Name.Buffer = name;
  100. pTempInfo->Name.Length = (_tcslen(pTempInfo->Name.Buffer))*sizeof(TCHAR);
  101. pTempInfo->Device.Length = (_tcslen(pTempInfo->Device.Buffer)) * sizeof(TCHAR);
  102. Status = AddComPort(pTempInfo);
  103. // Open the Com port and start the worker thread.
  104. if(Status != STATUS_SUCCESS){
  105. FreeComPortInfo(pTempInfo);
  106. TCDebugPrint(("Could not initialize com port\n"));
  107. }
  108. index++;
  109. }
  110. return (STATUS_SUCCESS);
  111. }
  112. NTSTATUS
  113. AddComPort(
  114. PCOM_PORT_INFO pComPortInfo
  115. )
  116. /*++
  117. Adds a Com port to the global list and reallocates the threads and
  118. allows dynamic changes to the com ports being serviced.
  119. --*/
  120. {
  121. // Lock down the global data so that it is consistent.
  122. NTSTATUS Status;
  123. pComPortInfo->Events[0] = TerminateService;
  124. pComPortInfo->Events[1] = CreateEvent(NULL,TRUE,FALSE,NULL);
  125. if (pComPortInfo->Events[1]==NULL) {
  126. TCDebugPrint(("Event creation failed\n"));
  127. return(STATUS_NO_MEMORY);
  128. }
  129. pComPortInfo->Events[2] = CreateEvent(NULL,TRUE,FALSE,NULL);
  130. if (pComPortInfo->Events[2]==NULL) {
  131. TCDebugPrint(("Event creation failed\n"));
  132. return(STATUS_NO_MEMORY);
  133. }
  134. pComPortInfo->Overlapped.hEvent = pComPortInfo->Events[2];
  135. pComPortInfo->WriteOverlapped.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
  136. if (pComPortInfo->WriteOverlapped.hEvent==NULL) {
  137. TCDebugPrint(("Write Event creation failed\n"));
  138. return(STATUS_NO_MEMORY);
  139. }
  140. InitializeCriticalSection(&(pComPortInfo->Mutex));
  141. pComPortInfo->TerminateEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
  142. if(pComPortInfo->TerminateEvent== NULL){
  143. TCDebugPrint(("Terminate Event Creation Failed\n"));
  144. return(STATUS_NO_MEMORY);
  145. }
  146. pComPortInfo->Events[3] = CreateEvent(NULL,TRUE,FALSE,NULL);
  147. if(pComPortInfo->Events[3]== NULL){
  148. TCDebugPrint(("Terminate Event Creation Failed\n"));
  149. return(STATUS_NO_MEMORY);
  150. }
  151. pComPortInfo->ShuttingDown = FALSE;
  152. pComPortInfo->Deleted = FALSE;
  153. pComPortInfo->Sockets = NULL;
  154. pComPortInfo->Connections = NULL;
  155. pComPortInfo->Head=pComPortInfo->Tail =0;
  156. pComPortInfo->Number = 0;
  157. Status = InitializeComPort(pComPortInfo);
  158. if (Status == STATUS_SUCCESS) {
  159. return InitializeThread(pComPortInfo);
  160. }
  161. return Status;
  162. }
  163. NTSTATUS
  164. InitializeComPort(
  165. PCOM_PORT_INFO pComPortInfo
  166. )
  167. /*++
  168. Start a thread to do stuff. But before that, it must initialize the Com Port
  169. and fill out the rest of the data structure.
  170. --*/
  171. {
  172. HANDLE temp;
  173. NTSTATUS Status;
  174. OBJECT_ATTRIBUTES Obja;
  175. SERIAL_BAUD_RATE BaudRate;
  176. SERIAL_LINE_CONTROL LineControl;
  177. SERIAL_TIMEOUTS NewTimeouts;
  178. ULONG ModemStatus;
  179. int i;
  180. #ifdef UNICODE
  181. InitializeObjectAttributes(&Obja,
  182. &(pComPortInfo->Device),
  183. OBJ_CASE_INSENSITIVE,
  184. NULL,
  185. NULL
  186. );
  187. #else
  188. UNICODE_STRING str;
  189. int len;
  190. // Here is where uniformity breaks down :-)
  191. len = (_tcslen(pComPortInfo->Device.Buffer)+1)*sizeof(WCHAR);
  192. str.Buffer = (PWCHAR) TCAllocate(len,"Unicode");
  193. str.MaximumLength = len*sizeof(WCHAR);
  194. str.Length = 0;
  195. if(str.Buffer == NULL){
  196. return STATUS_NO_MEMORY;
  197. }
  198. len = mbstowcs(str.Buffer,
  199. pComPortInfo->Device.Buffer,
  200. _tcslen(pComPortInfo->Device.Buffer)+1
  201. );
  202. str.Buffer[len] = (TCHAR) 0;
  203. str.Length = wcslen(str.Buffer) * sizeof(WCHAR);
  204. InitializeObjectAttributes(&Obja,
  205. &str,
  206. OBJ_CASE_INSENSITIVE,
  207. NULL,
  208. NULL
  209. );
  210. #endif
  211. Status = NtCreateFile(&(pComPortInfo->ComPortHandle),
  212. GENERIC_READ | GENERIC_WRITE |SYNCHRONIZE,
  213. &Obja,
  214. &(pComPortInfo->IoStatus),
  215. 0,
  216. 0,
  217. FILE_SHARE_READ|FILE_SHARE_WRITE,
  218. FILE_OPEN,
  219. FILE_NON_DIRECTORY_FILE,
  220. 0,
  221. 0
  222. );
  223. #ifdef UNICODE
  224. #else
  225. TCFree(str.Buffer);
  226. #endif
  227. if (!NT_SUCCESS(Status)) {
  228. TCDebugPrint(("Opening Com Device Failure %x\n",Status));
  229. return Status;
  230. }
  231. // Set Com Port Parameters
  232. // Set the baud rate
  233. //
  234. BaudRate.BaudRate = pComPortInfo->BaudRate;
  235. Status = NtDeviceIoControlFile(pComPortInfo->ComPortHandle,
  236. NULL,
  237. NULL,
  238. NULL,
  239. &(pComPortInfo->IoStatus),
  240. IOCTL_SERIAL_SET_BAUD_RATE,
  241. &BaudRate,
  242. sizeof(SERIAL_BAUD_RATE),
  243. NULL,
  244. 0
  245. );
  246. if (!NT_SUCCESS(Status)) {
  247. NtClose(pComPortInfo->ComPortHandle);
  248. TCDebugPrint(("Can't set Baud rate %ld\n", Status));
  249. return Status;
  250. }
  251. //
  252. // Set 8-N-1 data
  253. //
  254. LineControl.WordLength = pComPortInfo->WordLength;
  255. LineControl.Parity = pComPortInfo->Parity;
  256. LineControl.StopBits = pComPortInfo->StopBits;
  257. Status = NtDeviceIoControlFile(pComPortInfo->ComPortHandle,
  258. NULL,
  259. NULL,
  260. NULL,
  261. &(pComPortInfo->IoStatus),
  262. IOCTL_SERIAL_SET_LINE_CONTROL,
  263. &LineControl,
  264. sizeof(SERIAL_LINE_CONTROL),
  265. NULL,
  266. 0
  267. );
  268. if (!NT_SUCCESS(Status)) {
  269. NtClose(pComPortInfo->ComPortHandle);
  270. TCDebugPrint(("Can't set line control %lx\n",Status));
  271. return Status;
  272. }
  273. //
  274. // Check if we have a carrier
  275. //
  276. Status = NtDeviceIoControlFile(pComPortInfo->ComPortHandle,
  277. NULL,
  278. NULL,
  279. NULL,
  280. &(pComPortInfo->IoStatus),
  281. IOCTL_SERIAL_GET_MODEMSTATUS,
  282. NULL,
  283. 0,
  284. &ModemStatus,
  285. sizeof(ULONG)
  286. );
  287. if (!NT_SUCCESS(Status)) {
  288. NtClose(pComPortInfo->ComPortHandle);
  289. TCDebugPrint(("Can't call the detect routine %lx\n",Status));
  290. return Status;
  291. }
  292. // BUGBUG - We do not bother about the presence of a carrier as the
  293. // machine to which this bridge is connected may be down.
  294. /*if ((ModemStatus & 0xB0) != 0xB0) {
  295. NtClose(pComPortInfo->ComPortHandle);
  296. TCDebugPrint(("Can't detect carrier %lx\n",ModemStatus));
  297. return STATUS_SERIAL_NO_DEVICE_INITED;
  298. }*/
  299. //
  300. // Set timeout values for reading
  301. // We should have a time out that reads from the read buffer
  302. // as many characters as there are asked for or waits for the
  303. // first available character
  304. //
  305. NewTimeouts.ReadIntervalTimeout = MAXULONG;
  306. NewTimeouts.ReadTotalTimeoutMultiplier = MAXULONG;
  307. NewTimeouts.ReadTotalTimeoutConstant = MAXULONG-1;
  308. NewTimeouts.WriteTotalTimeoutMultiplier = MAXULONG;
  309. NewTimeouts.WriteTotalTimeoutConstant = MAXULONG;
  310. Status = NtDeviceIoControlFile(pComPortInfo->ComPortHandle,
  311. NULL,
  312. NULL,
  313. NULL,
  314. &(pComPortInfo->IoStatus),
  315. IOCTL_SERIAL_SET_TIMEOUTS,
  316. &NewTimeouts,
  317. sizeof(SERIAL_TIMEOUTS),
  318. NULL,
  319. 0
  320. );
  321. if (!NT_SUCCESS(Status)) {
  322. NtClose(pComPortInfo->ComPortHandle);
  323. TCDebugPrint(("Can't set time out values %lx\n",Status));
  324. return Status;
  325. }
  326. return STATUS_SUCCESS;
  327. }
  328. NTSTATUS
  329. InitializeThread(
  330. PCOM_PORT_INFO pComPortInfo
  331. )
  332. {
  333. NTSTATUS Status;
  334. HANDLE ThreadHandle;
  335. PHANDLE NewThreads;
  336. ULONG ThreadID;
  337. ThreadHandle=CreateThread(NULL,
  338. THREAD_ALL_ACCESS,
  339. bridge,
  340. pComPortInfo,
  341. 0,
  342. &ThreadID
  343. );
  344. if(ThreadHandle == NULL){
  345. NtClose(pComPortInfo->ComPortHandle);
  346. TCDebugPrint(("Create Com Thread Failure %lx\n",GetLastError()));
  347. return GetLastError();
  348. }
  349. EnterCriticalSection(&GlobalMutex);
  350. if(ComPorts == 0){
  351. NewThreads = (PHANDLE) TCAllocate(sizeof(HANDLE), "Thread");
  352. }
  353. else{
  354. NewThreads = (PHANDLE) TCReAlloc(Threads,
  355. (ComPorts+1)*sizeof(HANDLE),"Reallocation");
  356. }
  357. if(NewThreads == NULL){
  358. SetEvent(pComPortInfo->Events[3]);
  359. NtClose(pComPortInfo->ComPortHandle);
  360. NtClose(ThreadHandle);
  361. LeaveCriticalSection(&GlobalMutex);
  362. return STATUS_NO_MEMORY;
  363. }
  364. Threads = NewThreads;
  365. Threads[ComPorts] = ThreadHandle;
  366. pComPortInfo->Next = ComPortInfo;
  367. ComPortInfo = pComPortInfo;
  368. ComPorts++;
  369. LeaveCriticalSection(&GlobalMutex);
  370. return STATUS_SUCCESS;
  371. }
  372. SOCKET
  373. ServerSocket(
  374. )
  375. /*++
  376. Standard server binding code
  377. --*/
  378. {
  379. struct sockaddr_in srv_addr;
  380. int status;
  381. WSADATA data;
  382. // Set the socket version to 2.2
  383. status=WSAStartup(514,&data);
  384. if(status){
  385. TCDebugPrint(("Cannot start up %d\n",status));
  386. return(INVALID_SOCKET);
  387. }
  388. TerminateService = CreateEvent(NULL,TRUE,FALSE,NULL);
  389. if(TerminateService == NULL){
  390. TCDebugPrint(("Cannot open Terminate Event %lx\n",GetLastError()));
  391. return INVALID_SOCKET;
  392. }
  393. MainSocket=WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
  394. if (MainSocket==INVALID_SOCKET){
  395. TCDebugPrint(("Could not open server socket %lx\n", WSAGetLastError()));
  396. return(MainSocket);
  397. }
  398. srv_addr.sin_family=AF_INET;
  399. srv_addr.sin_addr.s_addr=INADDR_ANY;
  400. // convert to network byte order.
  401. // yechh!! bind does not automatically do it and
  402. // I got hurts in testing. (was so used to
  403. // Unix big endian ordering == network byte ordering.
  404. srv_addr.sin_port=htons(SERVICE_PORT); /* specific port for server to listen on */
  405. /* Bind socket to the appropriate port and interface (INADDR_ANY) */
  406. if (bind(MainSocket,(LPSOCKADDR)&srv_addr,sizeof(srv_addr))==SOCKET_ERROR){
  407. TCDebugPrint(("Windows Sockets error %d: Couldn't bind socket.",
  408. WSAGetLastError()));
  409. return(INVALID_SOCKET);
  410. }
  411. // Initialize the Global Mutex variable
  412. InitializeCriticalSection(&GlobalMutex);
  413. return(MainSocket);
  414. }