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.

858 lines
26 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1994 - 1999
  6. //
  7. // File: client.c
  8. //
  9. //--------------------------------------------------------------------------
  10. /////////////////////////////////////////////////////////////////////////
  11. //
  12. // Filename: client.c
  13. //
  14. // Description: This file contains the source code for IPC performance.
  15. // This module is written using win32 API calls, and will
  16. // generate a console server app.
  17. //
  18. // Authors: Scott Holden (Translator from NT API to win32 API)
  19. // Mahesh Keni (Mahesh wrote this application using mostly
  20. // NT native API calls)
  21. //
  22. /////////////////////////////////////////////////////////////////////////
  23. #include "rawcom.h"
  24. #include "client.h"
  25. /************************************************************************/
  26. // Global variables
  27. /************************************************************************/
  28. struct client Clients[MAXCLIENTS];
  29. HANDLE Threads[MAXCLIENTS];
  30. HANDLE EventHandle;
  31. PCHAR ServerName=NULL;
  32. USHORT ThreadError=0;
  33. BOOLEAN Failure = FALSE;
  34. USHORT NClients = 1; // number of clients
  35. USHORT MachineNumber = 1; // This client Number
  36. USHORT IPCType = NP; // Ipc Type to be used
  37. ULONG SendSize = 32;
  38. ULONG NumSends = 1;
  39. ULONG RecvSize = 32;
  40. ULONG NumRecvs = 1;
  41. ULONG Iterations = 100; // number of Iterations
  42. DWORD Timeout;
  43. CHAR Xport[9]; // Xport type name
  44. CHAR TestCmd = 'P';
  45. // function pointers for redirecting calls according to Xport types
  46. NTSTATUS (* IPC_Initialize)();
  47. NTSTATUS (* IPC_PerClientInit)();
  48. NTSTATUS (* IPC_Connect_To_Server)();
  49. NTSTATUS (* IPC_Disconnect_From_Server)();
  50. NTSTATUS (* IPC_Cleanup)();
  51. NTSTATUS (* IPC_Allocate_Memory)();
  52. NTSTATUS (* IPC_DoHandshake)();
  53. NTSTATUS (* IPC_ReadFromIPC)();
  54. NTSTATUS (* IPC_WriteToIPC)();
  55. NTSTATUS (* IPC_XactIO)();
  56. NTSTATUS (* IPC_Deallocate_Memory)();
  57. NTSTATUS (* IPC_ThreadCleanUp)();
  58. // Later all of this should move under an union
  59. // Globals for NamedPipe
  60. /*
  61. OBJECT_ATTRIBUTES objectAttributes;
  62. UNICODE_STRING unicodePipeName;
  63. */
  64. LPCSTR pipeName;
  65. ULONG Quotas = 32768; // read/write quota
  66. ULONG PipeType = PIPE_TYPE_MESSAGE; // pipe type
  67. ULONG PipeMode = PIPE_READMODE_MESSAGE; // read mode
  68. ULONG BlockorNot = PIPE_NOWAIT; // non blocking
  69. // Globals for NetBIOS
  70. USHORT LanaCount = 1;
  71. USHORT LanaBase = 0;
  72. UCHAR NameNumber = 1;
  73. CHAR LocalName[NCBNAMSZ];
  74. CHAR RemoteName[NCBNAMSZ];
  75. // GLobals for Sockets
  76. PCHAR HostName;
  77. int AddrFly;
  78. // For XNS socket support
  79. CHAR Remote_Net_Number[4]; // NetNumber
  80. CHAR Remote_Node_Number[6]; // Card address
  81. /************************************************************************/
  82. void __cdecl main (
  83. IN USHORT argc,
  84. IN PSZ argv[],
  85. IN PSZ envp[]
  86. )
  87. {
  88. NTSTATUS mstatus;
  89. // DWORD Timeout;
  90. USHORT Cindex = 0; // client index
  91. OutputDebugString("Raw network client has started!\n");
  92. // initialize the Client & Server name
  93. mstatus = Parse_Cmd_Line(argc, argv);
  94. if (!NT_SUCCESS(mstatus)) {
  95. exit(1);
  96. }
  97. // Based on the xport type setup all the function pointers
  98. Setup_Function_Pointers();
  99. // do IPC dependent Initializing
  100. mstatus = IPC_Initialize(NClients, ServerName, CLI);
  101. if (!NT_SUCCESS(mstatus)) {
  102. exit(1);
  103. }
  104. // Now create worker threads to execute test scenarios
  105. // Create an event to synchronize all the client threads
  106. EventHandle = CreateEvent(NULL, // EventobjectAttributes,
  107. TRUE, // manual reset event
  108. FALSE, // initial state of the event is non-signalled
  109. NULL); // no name given to the event
  110. if (!EventHandle) {
  111. printf ("Failed to create an event err=%lx\n",mstatus);
  112. Cleanup();
  113. exit(1);
  114. }
  115. printf("Creating %s Client threads..", Xport);
  116. for (Cindex = 0; Cindex < NClients; Cindex++) {
  117. // do appropriate per client initialization
  118. mstatus = IPC_PerClientInit(Cindex, CLI);
  119. // set up parameters for other client threads
  120. Clients[Cindex].c_client_num = Cindex; // client number
  121. Clients[Cindex].c_reqbuf.Iterations = Iterations;
  122. Clients[Cindex].c_reqbuf.SendSize = SendSize;
  123. Clients[Cindex].c_reqbuf.RecvSize = RecvSize;
  124. Clients[Cindex].c_reqbuf.NumSends = NumSends;
  125. Clients[Cindex].c_reqbuf.NumRecvs = NumRecvs;
  126. Clients[Cindex].c_reqbuf.TestCmd = TestCmd;
  127. Clients[Cindex].c_reqbuf.ClientNumber = Cindex;
  128. // use win32 API instead of NT native so that NetBIOS works fine
  129. Clients[Cindex].c_hThHandle = CreateThread(
  130. NULL,
  131. 0,
  132. (LPTHREAD_START_ROUTINE)&CliService,
  133. (PUSHORT)&(Clients[Cindex].c_client_num),
  134. 0,
  135. (LPDWORD)&(Clients[Cindex].c_ThClientID));
  136. Threads[Cindex] = Clients[Cindex].c_hThHandle;
  137. printf("%d..",Cindex+1);
  138. }
  139. // printf("\n");
  140. // First delay the main thread to let worker threads to get ready
  141. mstatus = Delay_Trigger_Wait();
  142. if (!NT_SUCCESS(mstatus)) {
  143. printf ("Failed in Delay_Trigger_Wait: err=%lx\n",mstatus);
  144. Cleanup();
  145. }
  146. // If any error then interprete it otherwise display results
  147. if (ThreadError) {
  148. printf("Client Error=%d\n",ThreadError);
  149. }
  150. else {
  151. // display results for all the clients
  152. Display_Results();
  153. }
  154. // now do the cleanup. i.e. clear all memory and close all handles
  155. IPC_Cleanup();
  156. Cleanup();
  157. exit(0);
  158. } // main
  159. /************************************************************************/
  160. NTSTATUS
  161. Delay_Trigger_Wait(VOID)
  162. {
  163. NTSTATUS dstatus;
  164. DWORD Timeout = 1000;
  165. dstatus = SleepEx( Timeout, // 10 ms delay
  166. TRUE ); // alertable
  167. if (!NT_SUCCESS(dstatus)) {
  168. printf ("Failed on Delayed execution err=%lx\n",dstatus);
  169. return(dstatus);
  170. }
  171. dstatus = PulseEvent(EventHandle);
  172. if (!NT_SUCCESS(dstatus)) {
  173. printf ("Failed to Pulse an event err=%lx\n",dstatus);
  174. return(dstatus);
  175. }
  176. // then signals all the waiting threads to resume I/O to namedpipe
  177. // by sending a pulse event
  178. dstatus = Wait_For_Client_Threads();
  179. if (!NT_SUCCESS(dstatus)) {
  180. printf ("Failed on wait err=%lx\n",dstatus);
  181. return(dstatus);
  182. }
  183. // printf("wait done. now do the cleanup work\n");
  184. return(dstatus);
  185. }
  186. /************************************************************************/
  187. VOID
  188. CliService( // provide Client service
  189. IN PUSHORT pTindex
  190. )
  191. {
  192. NTSTATUS tstatus;
  193. USHORT tCindex;
  194. //IO_STATUS_BLOCK ioStatusBlock;
  195. USHORT error = 0;
  196. //UCHAR Retcode;
  197. ULONG Iterations;
  198. ULONG SendLen;
  199. ULONG RecvLen;
  200. DWORD StartTime;
  201. DWORD StopTime;
  202. DWORD Duration;
  203. BOOLEAN First = FALSE;
  204. tCindex = *pTindex;
  205. ThreadError = 0; // No error so far
  206. Failure = FALSE;
  207. MyDbgPrint("CLI: Connecting to Server\n");
  208. tstatus = IPC_Connect_To_Server(tCindex); // First connect to the server
  209. ThreadError = 1;
  210. FAIL_CHECK_EXIT(PERFCLI, "Connect to Srv", tstatus);
  211. // now open the sync event and wait on it till set by the main thread
  212. tstatus = WaitForSingleObjectEx(EventHandle, INFINITE, TRUE);
  213. ThreadError = 2;
  214. FAIL_CHECK_EXIT(PERFCLI, "Wait for Event", tstatus);
  215. MyDbgPrint("CLI: Doing Handshake \n");
  216. // Do the handshake before the actual test run. This will send a request
  217. // packet to the server with test details
  218. tstatus = IPC_DoHandshake(tCindex, CLI);
  219. ThreadError = 3;
  220. FAIL_CHECK_EXIT(PERFCLI, "Do Handshake ", tstatus);
  221. // Allocate memory required for recv and send buffers
  222. tstatus = IPC_Allocate_Memory(tCindex);
  223. ThreadError = 4;
  224. FAIL_CHECK_EXIT(PERFCLI, "Allocate Memory ", tstatus);
  225. // Now we are ready to run all the tests
  226. Iterations = Clients[tCindex].c_reqbuf.Iterations;
  227. StartTime = GetCurrentTime();
  228. while (Iterations--) {
  229. if (Clients[tCindex].c_reqbuf.TestCmd == 'P') {
  230. // Client first sends X messages and Receives Y messages.
  231. tstatus = IPC_WriteToIPC(tCindex, &SendLen, CLI);
  232. ThreadError = 5;
  233. FAIL_CHECK(PERFCLI, "Write to IPC", tstatus);
  234. // Check for send length here
  235. tstatus = IPC_ReadFromIPC(tCindex, &RecvLen, CLI);
  236. ThreadError = 6;
  237. FAIL_CHECK(PERFCLI, "Receive from IPC", tstatus);
  238. // Check for Receive length and data integrity here
  239. }
  240. else { // for 'U' or 'T' tests do transaction type I/O
  241. // Note that First is not used by the client
  242. tstatus = IPC_XactIO(tCindex, &SendLen, &RecvLen, CLI,First);
  243. ThreadError = 65;
  244. FAIL_CHECK(PERFCLI, "Xact from IPC", tstatus);
  245. }
  246. }
  247. StopTime = GetCurrentTime();
  248. Duration = StopTime - StartTime;
  249. Clients[tCindex].c_Duration = Duration; // in msecs
  250. // Deallocate all the memory
  251. tstatus = IPC_Deallocate_Memory(tCindex);
  252. if (!ThreadError) {ThreadError = 7;}
  253. FAIL_CHECK_EXIT(PERFCLI, "Deallocate Memory ", tstatus);
  254. // Disconnect from server
  255. tstatus = IPC_Disconnect_From_Server(tCindex);
  256. if (!ThreadError) {
  257. ThreadError = 8;
  258. }
  259. FAIL_CHECK_EXIT(PERFCLI, "Disconnect from Server ", tstatus);
  260. // Clear all flags so that we can print results
  261. if (!Failure) { ThreadError = 0; }
  262. // based on error return status
  263. TerminateThread(GetCurrentThread(), STATUS_SUCCESS);
  264. }
  265. /************************************************************************/
  266. /*++
  267. This routine is responsible for displaying results for all the client
  268. thread. It displays both per client and total throughput.
  269. --*/
  270. VOID
  271. Display_Results(VOID)
  272. {
  273. USHORT Cindex = 0;
  274. ULONG TotTps = 0L;
  275. ULONG TotSendThrpt = 0L;
  276. ULONG TotRecvThrpt = 0L;
  277. ULONG CliThrput = 0L;
  278. ULONG Remainder = 0L;
  279. ULONG BytesSent = 0L;
  280. ULONG BytesRcvd = 0L;
  281. BytesSent = (Clients[Cindex].c_reqbuf.SendSize) *
  282. (Clients[Cindex].c_reqbuf.NumSends) *
  283. (Clients[Cindex].c_reqbuf.Iterations);
  284. BytesRcvd = (Clients[Cindex].c_reqbuf.RecvSize) *
  285. (Clients[Cindex].c_reqbuf.NumRecvs) *
  286. (Clients[Cindex].c_reqbuf.Iterations);
  287. printf("Total: Trans: %ld Send: %lu Bytes Receive: %lu Bytes\n",
  288. (Clients[Cindex].c_reqbuf.NumSends *
  289. Clients[Cindex].c_reqbuf.Iterations),
  290. BytesSent,
  291. BytesRcvd);
  292. // Display all the results
  293. for (Cindex = 0; Cindex < NClients; Cindex++) {
  294. if (!(Clients[Cindex].c_Duration)) {
  295. Clients[Cindex].c_Duration++;
  296. }
  297. // First put the TPS number
  298. // Get total TPS
  299. CliThrput = (Clients[Cindex].c_reqbuf.NumSends * 1000) *
  300. (Clients[Cindex].c_reqbuf.Iterations);
  301. CliThrput /= Clients[Cindex].c_Duration;
  302. TotTps += CliThrput;
  303. printf("Cli:%d Dura: %ld ms Throughput: %ld TPS ",
  304. Cindex,
  305. Clients[Cindex].c_Duration,
  306. CliThrput);
  307. // Now put the BPS number
  308. // First get Send BPS numbers
  309. CliThrput= BytesSent / (Clients[Cindex].c_Duration);
  310. // now calculate the remainder and get first three digits
  311. Remainder = BytesSent - (Clients[Cindex].c_Duration * CliThrput);
  312. Remainder = (Remainder*1000)/Clients[Cindex].c_Duration;
  313. CliThrput = (CliThrput * 1000) + Remainder; // duration was in msec
  314. TotSendThrpt += CliThrput;
  315. printf(" Send: %ld BPS ",
  316. CliThrput);
  317. // First get Receive BPS numbers
  318. CliThrput = BytesRcvd / (Clients[Cindex].c_Duration);
  319. // now calculate the remainder and get first three digits
  320. Remainder = BytesRcvd - (Clients[Cindex].c_Duration * CliThrput);
  321. Remainder = (Remainder*1000)/Clients[Cindex].c_Duration;
  322. CliThrput = (CliThrput * 1000) + Remainder; // duration was in msec
  323. TotRecvThrpt += CliThrput;
  324. printf(" RecvThrpt: %ld BPS; \n", CliThrput );
  325. }
  326. printf("--------------------------------------------------------\n");
  327. printf("Total Throughput: %ld TPS ",TotTps);
  328. printf(" Send-BPS: %ld BPS ",TotSendThrpt);
  329. printf(" Recv-BPS: %ld BPS\n",TotRecvThrpt);
  330. }
  331. /************************************************************************/
  332. NTSTATUS
  333. Parse_Cmd_Line(USHORT argc, CHAR *argv[])
  334. {
  335. USHORT i;
  336. CHAR *s;
  337. NTSTATUS pstatus = 0L;
  338. BOOLEAN doingok = TRUE;
  339. if (argc > 12) {
  340. printf("Too many arguments \n");
  341. pstatus = -1L;
  342. }
  343. strncpy(Xport, NamePipe, 8);
  344. for (i=1; (doingok) && (i< argc); i++) {
  345. s = argv[i];
  346. if ((*s == '/') && ((*(s+2) == ':') || (*(s+3) == ':') ))
  347. {
  348. s++;
  349. switch(*s) {
  350. case 'a' : // Net number for XNS:SPX
  351. case 'A' :
  352. RtlCopyMemory( Remote_Net_Number,
  353. get_network_number((PCHAR)s+2),
  354. 4);
  355. if (Remote_Net_Number[0] == 'X') {
  356. printf("incorrect net number: ");
  357. printf(" e.g. /a:11223344 (8 hex) \n");
  358. Usage(argv[0]);
  359. pstatus = -1L;
  360. }
  361. break;
  362. case 'b' :
  363. case 'B' :
  364. LanaBase = (USHORT)atoi(s+2);
  365. break;
  366. case 'c' : // number of clients
  367. case 'C' :
  368. NClients = (USHORT)atoi(s+2);
  369. break;
  370. case 'l' :
  371. case 'L' :
  372. LanaCount = (USHORT)atoi(s+2);
  373. break;
  374. case 'm' :
  375. case 'M' :
  376. MachineNumber = (USHORT)atoi(s+2);
  377. break;
  378. case 'i' : // iterations
  379. case 'I' :
  380. Iterations = (USHORT)atoi(s+2);
  381. break;
  382. case 'n' : // number of Sends/Recvs
  383. case 'N' :
  384. switch(*(s+1)) {
  385. case 'r':
  386. case 'R':
  387. NumRecvs = (USHORT)atoi(s+3);
  388. break;
  389. case 's':
  390. case 'S':
  391. NumSends = (USHORT)atoi(s+3);
  392. break;
  393. default:
  394. doingok = FALSE;
  395. }
  396. break;
  397. case 'p' : // NamedPipe mode
  398. case 'P' :
  399. switch(*(s+2)) {
  400. case 'm':
  401. case 'M':
  402. PipeType = PIPE_TYPE_MESSAGE;
  403. PipeMode = PIPE_READMODE_MESSAGE;
  404. break;
  405. case 's':
  406. case 'S':
  407. PipeType = PIPE_TYPE_BYTE;
  408. PipeMode = PIPE_READMODE_BYTE;
  409. break;
  410. default:
  411. doingok = FALSE;
  412. }
  413. break;
  414. case 'r' : // Send size
  415. case 'R' :
  416. RecvSize = (USHORT)atoi(s+2);
  417. break;
  418. case 's' : // Send size
  419. case 'S' :
  420. SendSize = (USHORT)atoi(s+2);
  421. break;
  422. case 't' : // Test Command
  423. case 'T' :
  424. TestCmd =(UCHAR) *(s+2);
  425. switch(TestCmd){
  426. case 't': TestCmd = 'T'; break;
  427. case 'u':
  428. case 'U': TestCmd = 'U'; break;
  429. case 'P':
  430. case 'T':
  431. break;
  432. default :
  433. printf("incorrect test command\n");
  434. Usage(argv[0]);
  435. pstatus = -1L;
  436. }
  437. break;
  438. case 'h' : // Server Name or host IP address
  439. case 'H' :
  440. ServerName = (PCHAR)malloc(SRVNAME_LEN);
  441. strcpy(ServerName,(PCHAR)(s+2));
  442. // if XNS:SPX or IPX then get Node Address
  443. if ((IPCType == SCXNS)|| (IPCType == SCIPX)){
  444. RtlCopyMemory( Remote_Node_Number,
  445. get_node_number(ServerName),
  446. 6);
  447. if (Remote_Node_Number[0] == 'X') {
  448. printf("incorrect node number: ");
  449. printf("e.g. /h:112233445566 \n");
  450. Usage(argv[0]);
  451. pstatus = -1L;
  452. }
  453. }
  454. break;
  455. case 'x' : // Xport Type
  456. case 'X' :
  457. strncpy(Xport, (PUCHAR) (s+2), 8);
  458. if (!_stricmp(Xport,NamePipe)) {
  459. IPCType = NP;
  460. break;
  461. }
  462. if (!_stricmp(Xport,NetBIOS)) {
  463. IPCType = NB;
  464. break;
  465. }
  466. if (!_stricmp(Xport,SocketXNS)) {
  467. IPCType = SCXNS;
  468. AddrFly = AF_NS;
  469. break;
  470. }
  471. if (!_stricmp(Xport,SocketTCP)) {
  472. IPCType = SCTCP;
  473. AddrFly = AF_INET;
  474. break;
  475. }
  476. if (!_stricmp(Xport,UDP)) {
  477. IPCType = SCUDP;
  478. AddrFly = AF_INET;
  479. break;
  480. }
  481. if (!_stricmp(Xport,IPX)) {
  482. IPCType = SCIPX;
  483. AddrFly = AF_NS;
  484. break;
  485. }
  486. if (!_stricmp(Xport,DGNetBIOS)) {
  487. IPCType = DGNB;
  488. break;
  489. }
  490. // bad choice of Xport
  491. doingok = FALSE;
  492. break;
  493. default :
  494. doingok = FALSE;
  495. }
  496. }
  497. else {
  498. doingok = FALSE;
  499. }
  500. }
  501. if (!doingok) {
  502. Usage(argv[0]);
  503. pstatus = -1L;
  504. }
  505. else { // if successful then
  506. if ((IPCType == SCXNS) || (IPCType == SCIPX)) {
  507. // make server name a 10 byte address
  508. RtlCopyMemory(ServerName,Remote_Node_Number,6);
  509. RtlCopyMemory(ServerName+6,Remote_Net_Number,4);
  510. }
  511. if (((IPCType != NB) && (IPCType != NP) && (IPCType != DGNB)) &&
  512. (ServerName == NULL)) {
  513. printf("Please enter Server Address \n");
  514. pstatus = -1L;
  515. }
  516. }
  517. return(pstatus);
  518. }
  519. /************************************************************************/
  520. VOID Usage(char * PrgName)
  521. {
  522. fprintf(stderr, "Usage: %s [/c: ] [/h:] [/s:] [/r:] [/b:] [/l:]\n",PrgName);
  523. fprintf(stderr, " Opt Default Defines\n");
  524. fprintf(stderr, " === ======= =======\n");
  525. fprintf(stderr, " /c: 1 Number of clients\n");
  526. fprintf(stderr, " /h: NULL SrvName/HostIPaddr.\n");
  527. fprintf(stderr, " /Node Number for XNS\n");
  528. fprintf(stderr, " /I: 1000 Number of Iterations\n");
  529. fprintf(stderr, " /ns: 1 Number of Sends\n");
  530. fprintf(stderr, " /nr: 1 Number of Receives\n");
  531. fprintf(stderr, " /r: 32 Receive size\n");
  532. fprintf(stderr, " /s: 32 Send size\n");
  533. fprintf(stderr, " /t: NULL Special Test cmd,U,T\n");
  534. fprintf(stderr, " /x: Nmp Xport(IPC)type\n");
  535. fprintf(stderr, " Nmp/NetB/SockTCP/\n");
  536. fprintf(stderr, " SockXNS/UDP/IPX/DGNetB\n");
  537. fprintf(stderr, " For NNamedPipe: \n");
  538. fprintf(stderr, " /p: m Nmp : Pipe Type m/s\n");
  539. fprintf(stderr, " For NetBIOS: \n");
  540. fprintf(stderr, " /b: 0 NetB: lana base\n");
  541. fprintf(stderr, " /l: 1 NetB: lana count\n");
  542. fprintf(stderr, " /m: 1 machine number\n");
  543. fprintf(stderr, " For XNS: \n");
  544. fprintf(stderr, " /a: 1 Net Number for XNS\n");
  545. }
  546. /************************************************************************/
  547. /*++
  548. This routine sets up all the function pointers based on Xport type
  549. --*/
  550. VOID
  551. Setup_Function_Pointers()
  552. {
  553. // I could do real OOP here and just set up one pointer to all functions
  554. // based on Xport type take the action
  555. switch(IPCType) {
  556. case NP:
  557. IPC_Initialize = NMP_Initialize;
  558. IPC_PerClientInit = NMP_PerClientInit;
  559. IPC_Connect_To_Server = NMP_Connect_To_Server;
  560. IPC_Disconnect_From_Server = NMP_Disconnect_From_Server;
  561. IPC_Cleanup = NMP_Cleanup;
  562. IPC_Allocate_Memory = NMP_Allocate_Memory;
  563. IPC_DoHandshake = NMP_DoHandshake;
  564. IPC_ReadFromIPC = NMP_ReadFromIPC;
  565. IPC_WriteToIPC = NMP_WriteToIPC;
  566. IPC_XactIO = NMP_XactIO;
  567. IPC_Deallocate_Memory = NMP_Deallocate_Memory;
  568. IPC_ThreadCleanUp = NMP_ThreadCleanUp;
  569. break;
  570. case NB:
  571. IPC_Initialize = NB_Initialize;
  572. IPC_PerClientInit = NB_PerClientInit;
  573. IPC_Cleanup = NB_Cleanup;
  574. IPC_Connect_To_Server = NB_Connect_To_Server;
  575. IPC_Disconnect_From_Server = NB_Disconnect_From_Server;
  576. IPC_Allocate_Memory = NB_Allocate_Memory;
  577. IPC_DoHandshake = NB_DoHandshake;
  578. IPC_ReadFromIPC = NB_ReadFromIPC;
  579. IPC_WriteToIPC = NB_WriteToIPC;
  580. IPC_XactIO = NB_XactIO;
  581. IPC_Deallocate_Memory = NB_Deallocate_Memory;
  582. IPC_ThreadCleanUp = NB_ThreadCleanUp;
  583. break;
  584. case SCTCP:
  585. IPC_Initialize = SCTCP_Initialize;
  586. IPC_PerClientInit = SCTCP_PerClientInit;
  587. IPC_Cleanup = SCTCP_Cleanup;
  588. IPC_Connect_To_Server = SCTCP_Connect_To_Server;
  589. IPC_Disconnect_From_Server = SCTCP_Disconnect_From_Server;
  590. IPC_Allocate_Memory = SCTCP_Allocate_Memory;
  591. IPC_DoHandshake = SCTCP_DoHandshake;
  592. IPC_ReadFromIPC = SCTCP_ReadFromIPC;
  593. IPC_WriteToIPC = SCTCP_WriteToIPC;
  594. IPC_XactIO = SCTCP_XactIO;
  595. IPC_Deallocate_Memory = SCTCP_Deallocate_Memory;
  596. IPC_ThreadCleanUp = SCTCP_ThreadCleanUp;
  597. break;
  598. case SCXNS:
  599. IPC_Initialize = SCXNS_Initialize;
  600. IPC_PerClientInit = SCXNS_PerClientInit;
  601. IPC_Connect_To_Server = SCXNS_Connect_To_Server;
  602. IPC_Disconnect_From_Server = SCXNS_Disconnect_From_Server;
  603. IPC_Cleanup = SCXNS_Cleanup;
  604. IPC_Allocate_Memory = SCXNS_Allocate_Memory;
  605. IPC_DoHandshake = SCXNS_DoHandshake;
  606. IPC_ReadFromIPC = SCXNS_ReadFromIPC;
  607. IPC_WriteToIPC = SCXNS_WriteToIPC;
  608. IPC_XactIO = SCXNS_XactIO;
  609. IPC_Deallocate_Memory = SCXNS_Deallocate_Memory;
  610. IPC_ThreadCleanUp = SCXNS_ThreadCleanUp;
  611. break;
  612. case SCUDP:
  613. IPC_Initialize = SCUDP_Initialize;
  614. IPC_PerClientInit = SCUDP_PerClientInit;
  615. IPC_Connect_To_Server = SCUDP_Connect_To_Server;
  616. IPC_Disconnect_From_Server = SCUDP_Disconnect_From_Server;
  617. IPC_Cleanup = SCUDP_Cleanup;
  618. IPC_Allocate_Memory = SCUDP_Allocate_Memory;
  619. IPC_DoHandshake = SCUDP_DoHandshake;
  620. IPC_ReadFromIPC = SCUDP_ReadFromIPC;
  621. IPC_WriteToIPC = SCUDP_WriteToIPC;
  622. IPC_Deallocate_Memory = SCUDP_Deallocate_Memory;
  623. IPC_ThreadCleanUp = SCUDP_ThreadCleanUp;
  624. break;
  625. case SCIPX:
  626. IPC_Initialize = SCIPX_Initialize;
  627. IPC_PerClientInit = SCIPX_PerClientInit;
  628. IPC_PerClientInit = SCIPX_PerClientInit;
  629. IPC_Connect_To_Server = SCIPX_Connect_To_Server;
  630. IPC_Disconnect_From_Server = SCIPX_Disconnect_From_Server;
  631. IPC_Cleanup = SCIPX_Cleanup;
  632. IPC_Allocate_Memory = SCIPX_Allocate_Memory;
  633. IPC_DoHandshake = SCIPX_DoHandshake;
  634. IPC_ReadFromIPC = SCIPX_ReadFromIPC;
  635. IPC_WriteToIPC = SCIPX_WriteToIPC;
  636. IPC_Deallocate_Memory = SCIPX_Deallocate_Memory;
  637. IPC_ThreadCleanUp = SCIPX_ThreadCleanUp;
  638. break;
  639. case DGNB:
  640. IPC_Initialize = DGNB_Initialize;
  641. IPC_PerClientInit = DGNB_PerClientInit;
  642. IPC_Cleanup = DGNB_Cleanup;
  643. IPC_Connect_To_Server = DGNB_Connect_To_Server;
  644. IPC_Disconnect_From_Server = DGNB_Disconnect_From_Server;
  645. IPC_Allocate_Memory = DGNB_Allocate_Memory;
  646. IPC_DoHandshake = DGNB_DoHandshake;
  647. IPC_ReadFromIPC = DGNB_ReadFromIPC;
  648. IPC_WriteToIPC = DGNB_WriteToIPC;
  649. IPC_XactIO = DGNB_XactIO;
  650. IPC_Deallocate_Memory = DGNB_Deallocate_Memory;
  651. IPC_ThreadCleanUp = DGNB_ThreadCleanUp;
  652. break;
  653. default :
  654. // problem here
  655. printf("Incorrect Xport selection\n");
  656. }
  657. }
  658. /************************************************************************/
  659. /*++
  660. This routine makes the main thread wait for all the client threads to
  661. exit.
  662. --*/
  663. NTSTATUS
  664. Wait_For_Client_Threads(VOID)
  665. {
  666. NTSTATUS wstatus;
  667. // LARGE_INTEGER MTimeout;
  668. DWORD MTimeout;
  669. // printf("Main thread waiting for Client threads ");
  670. printf("..Wait");
  671. // MTimeout.LowPart = 0xFFFFFFFF;
  672. // MTimeout.HighPart = 0x7FFFFFFF; // -1L DIDN't work
  673. MTimeout = INFINITE;
  674. wstatus = WaitForMultipleObjectsEx( NClients,
  675. Threads,
  676. TRUE,
  677. MTimeout, // Default timeout
  678. TRUE); // Alertable
  679. printf("..Over..Results:\n");
  680. if (!NT_SUCCESS(wstatus)) {
  681. printf ("Failed on wait err=%lx\n",wstatus);
  682. }
  683. return wstatus;
  684. }
  685. /************************************************************************/
  686. VOID
  687. Cleanup(VOID)
  688. {
  689. USHORT Cindex = 0; // client index
  690. NTSTATUS exitstatus = 0;
  691. NTSTATUS cstatus;
  692. for (Cindex = 0; Cindex < NClients; Cindex++) {
  693. // terminate the thread
  694. cstatus = TerminateThread(Clients[Cindex].c_hThHandle, exitstatus);
  695. /*
  696. if (!NT_SUCCESS(cstatus)) {
  697. printf("Failed to terminate thread no:%d err=%lx\n",
  698. Cindex,cstatus);
  699. }
  700. */
  701. }
  702. // printf("Terminated All Threads\n");
  703. }
  704. /************************************************************************/