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.

579 lines
18 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1994 - 1999
  6. //
  7. // File: server.c
  8. //
  9. //--------------------------------------------------------------------------
  10. /////////////////////////////////////////////////////////////////////////
  11. //
  12. // Filename: server.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 "server.h"
  25. /************************************************************************/
  26. // Global variables
  27. /************************************************************************/
  28. struct client Clients[MAXCLIENTS]; // all the client data
  29. HANDLE Threads[MAXCLIENTS];
  30. USHORT NClients = 1; // number of clients
  31. USHORT IPCType = NP; // IPC type
  32. LARGE_INTEGER Timeout; // for the main thread
  33. CHAR Xport[9]; // Xport type Name
  34. USHORT ThreadError = 0;
  35. BOOLEAN Failure = FALSE;
  36. // function pointers for redirecting calls according to Xport types
  37. NTSTATUS (* IPC_Initialize)();
  38. NTSTATUS (* IPC_PerClientInit)();
  39. NTSTATUS (* IPC_Wait_For_Client)();
  40. NTSTATUS (* IPC_Disconnect_Client)();
  41. NTSTATUS (* IPC_Cleanup)();
  42. NTSTATUS (* IPC_Allocate_Memory)();
  43. NTSTATUS (* IPC_DoHandshake)();
  44. NTSTATUS (* IPC_ReadFromIPC)();
  45. NTSTATUS (* IPC_WriteToIPC)();
  46. NTSTATUS (* IPC_XactIO)();
  47. NTSTATUS (* IPC_Deallocate_Memory)();
  48. NTSTATUS (* IPC_ThreadCleanUp)();
  49. // Later all of this should move under an union
  50. // Globals for NamedPipe
  51. //OBJECT_ATTRIBUTES objectAttributes;
  52. //UNICODE_STRING unicodePipeName;
  53. char *pipeName;
  54. ULONG Quotas = 32768; // read/write quota
  55. ULONG PipeType = PIPE_TYPE_MESSAGE; // pipe type
  56. ULONG PipeMode = PIPE_READMODE_MESSAGE; // read mode
  57. ULONG BlockorNot = PIPE_NOWAIT; // non blocking
  58. // Globals for NetBIOS
  59. USHORT LanaCount = 1;
  60. USHORT LanaBase = 0;
  61. USHORT MachineNumber = 1;
  62. UCHAR NameNumber = 1;
  63. CHAR LocalName[NCBNAMSZ];
  64. CHAR RemoteName[NCBNAMSZ];
  65. // GLobals for Sockets
  66. PCHAR ServerName = NULL; // local host ip address
  67. PCHAR HostName = NULL; // local host ip address
  68. int AddrFly;
  69. /************************************************************************/
  70. NTSTATUS
  71. __cdecl main (
  72. IN USHORT argc,
  73. IN PSZ argv[],
  74. IN PSZ envp[])
  75. {
  76. NTSTATUS mstatus;
  77. USHORT Cindex = 0; // client index
  78. //UCHAR NBretcode; // NetBIOS call return code
  79. //USHORT LanaNumber;
  80. // argc, argv, envp; // Shut up the compiler
  81. mstatus = Parse_Cmd_Line(argc, argv);
  82. if (!NT_SUCCESS(mstatus)) {
  83. return(1);
  84. }
  85. // based on the Xport type set up all the function pointers
  86. Setup_Function_Pointers();
  87. // do IPC dependent initializing
  88. mstatus = IPC_Initialize(NClients, HostName, SRV);
  89. if (!NT_SUCCESS(mstatus)) {
  90. return(1);
  91. }
  92. // now create worker threads for handling NetBIOS I/O requests
  93. printf("Creating %s Server threads...", Xport);
  94. for (Cindex = 0; Cindex < NClients; Cindex++) {
  95. // do appropriate per client initialization
  96. mstatus = IPC_PerClientInit(Cindex,SRV);
  97. // use win32 API instead of NT native so that NetBIOS works fine
  98. Clients[Cindex].c_hThHandle = CreateThread(
  99. NULL,
  100. 0,
  101. (LPTHREAD_START_ROUTINE)&SrvService,
  102. (PUSHORT)&(Clients[Cindex].c_client_num),
  103. 0,
  104. (LPDWORD)&(Clients[Cindex].c_ThClientID));
  105. Threads[Cindex] = Clients[Cindex].c_hThHandle; //*get rid of one handle
  106. printf("%d..",Cindex+1);
  107. }
  108. printf("\n");
  109. //The main thread should now wait for all the other threads
  110. if (!mstatus) { // if no error then wait for everyone to sync
  111. mstatus = Wait_For_Client_Threads();
  112. if (!NT_SUCCESS(mstatus)) {
  113. printf ("Failed on wait err=%lx\n",mstatus);
  114. }
  115. }
  116. // now do the cleanup. i.e. clear all memory and close all handles
  117. IPC_Cleanup(NClients);
  118. exit(0);
  119. } // main
  120. /************************************************************************/
  121. /*++
  122. This routine sets up all the function pointers based on Xport type
  123. I could just set one pointer to a function table supporting all the
  124. functions and move all tis initialization in individual init routines.
  125. Will be done in future.
  126. --*/
  127. VOID
  128. Setup_Function_Pointers()
  129. {
  130. // based on Xport type take the action
  131. switch(IPCType) {
  132. case NP:
  133. IPC_Initialize = NMP_Initialize;
  134. IPC_PerClientInit = NMP_PerClientInit;
  135. IPC_Wait_For_Client = NMP_Wait_For_Client;
  136. IPC_Disconnect_Client = NMP_Disconnect_Client;
  137. IPC_Cleanup = NMP_Cleanup;
  138. IPC_Allocate_Memory = NMP_Allocate_Memory;
  139. IPC_DoHandshake = NMP_DoHandshake;
  140. IPC_ReadFromIPC = NMP_ReadFromIPC;
  141. IPC_WriteToIPC = NMP_WriteToIPC;
  142. IPC_XactIO = NMP_XactIO;
  143. IPC_Deallocate_Memory = NMP_Deallocate_Memory;
  144. IPC_ThreadCleanUp = NMP_ThreadCleanUp;
  145. break;
  146. case NB:
  147. IPC_Initialize = NB_Initialize;
  148. IPC_PerClientInit = NB_PerClientInit;
  149. IPC_Cleanup = NB_Cleanup;
  150. IPC_Wait_For_Client = NB_Wait_For_Client;
  151. IPC_Disconnect_Client = NB_Disconnect_Client;
  152. IPC_Allocate_Memory = NB_Allocate_Memory;
  153. IPC_DoHandshake = NB_DoHandshake;
  154. IPC_ReadFromIPC = NB_ReadFromIPC;
  155. IPC_WriteToIPC = NB_WriteToIPC;
  156. IPC_XactIO = NB_XactIO;
  157. IPC_Deallocate_Memory = NB_Deallocate_Memory;
  158. IPC_ThreadCleanUp = NB_ThreadCleanUp;
  159. break;
  160. case SCTCP:
  161. IPC_Initialize = SCTCP_Initialize;
  162. IPC_PerClientInit = SCTCP_PerClientInit;
  163. IPC_Cleanup = SCTCP_Cleanup;
  164. IPC_Wait_For_Client = SCTCP_Wait_For_Client;
  165. IPC_Disconnect_Client = SCTCP_Disconnect_Client;
  166. IPC_Allocate_Memory = SCTCP_Allocate_Memory;
  167. IPC_DoHandshake = SCTCP_DoHandshake;
  168. IPC_ReadFromIPC = SCTCP_ReadFromIPC;
  169. IPC_WriteToIPC = SCTCP_WriteToIPC;
  170. IPC_XactIO = SCTCP_XactIO;
  171. IPC_Deallocate_Memory = SCTCP_Deallocate_Memory;
  172. IPC_ThreadCleanUp = SCTCP_ThreadCleanUp;
  173. break;
  174. case SCXNS:
  175. IPC_Initialize = SCXNS_Initialize;
  176. IPC_PerClientInit = SCXNS_PerClientInit;
  177. IPC_Wait_For_Client = SCXNS_Wait_For_Client;
  178. IPC_Disconnect_Client = SCXNS_Disconnect_Client;
  179. IPC_Cleanup = SCXNS_Cleanup;
  180. IPC_Allocate_Memory = SCXNS_Allocate_Memory;
  181. IPC_DoHandshake = SCXNS_DoHandshake;
  182. IPC_ReadFromIPC = SCXNS_ReadFromIPC;
  183. IPC_WriteToIPC = SCXNS_WriteToIPC;
  184. IPC_XactIO = SCXNS_XactIO;
  185. IPC_Deallocate_Memory = SCXNS_Deallocate_Memory;
  186. IPC_ThreadCleanUp = SCXNS_ThreadCleanUp;
  187. break;
  188. case SCUDP:
  189. IPC_Initialize = SCUDP_Initialize;
  190. IPC_PerClientInit = SCUDP_PerClientInit;
  191. IPC_Wait_For_Client = SCUDP_Wait_For_Client;
  192. IPC_Disconnect_Client = SCUDP_Disconnect_Client;
  193. IPC_Cleanup = SCUDP_Cleanup;
  194. IPC_Allocate_Memory = SCUDP_Allocate_Memory;
  195. IPC_DoHandshake = SCUDP_DoHandshake;
  196. IPC_ReadFromIPC = SCUDP_ReadFromIPC;
  197. IPC_WriteToIPC = SCUDP_WriteToIPC;
  198. IPC_Deallocate_Memory = SCUDP_Deallocate_Memory;
  199. IPC_ThreadCleanUp = SCUDP_ThreadCleanUp;
  200. break;
  201. case SCIPX:
  202. IPC_Initialize = SCIPX_Initialize;
  203. IPC_PerClientInit = SCIPX_PerClientInit;
  204. IPC_Wait_For_Client = SCIPX_Wait_For_Client;
  205. IPC_Disconnect_Client = SCIPX_Disconnect_Client;
  206. IPC_Cleanup = SCIPX_Cleanup;
  207. IPC_Allocate_Memory = SCIPX_Allocate_Memory;
  208. IPC_DoHandshake = SCIPX_DoHandshake;
  209. IPC_ReadFromIPC = SCIPX_ReadFromIPC;
  210. IPC_WriteToIPC = SCIPX_WriteToIPC;
  211. IPC_Deallocate_Memory = SCIPX_Deallocate_Memory;
  212. IPC_ThreadCleanUp = SCIPX_ThreadCleanUp;
  213. break;
  214. case DGNB:
  215. IPC_Initialize = DGNB_Initialize;
  216. IPC_PerClientInit = DGNB_PerClientInit;
  217. IPC_Cleanup = DGNB_Cleanup;
  218. IPC_Wait_For_Client = DGNB_Wait_For_Client;
  219. IPC_Disconnect_Client = DGNB_Disconnect_Client;
  220. IPC_Allocate_Memory = DGNB_Allocate_Memory;
  221. IPC_DoHandshake = DGNB_DoHandshake;
  222. IPC_ReadFromIPC = DGNB_ReadFromIPC;
  223. IPC_WriteToIPC = DGNB_WriteToIPC;
  224. IPC_XactIO = DGNB_XactIO;
  225. IPC_Deallocate_Memory = DGNB_Deallocate_Memory;
  226. IPC_ThreadCleanUp = DGNB_ThreadCleanUp;
  227. break;
  228. default :
  229. // problem here
  230. printf("Incorrect Xport selection\n");
  231. }
  232. }
  233. /************************************************************************/
  234. /*++
  235. This routine makes the main thread wait for all the client threads to
  236. exit.
  237. --*/
  238. NTSTATUS
  239. Wait_For_Client_Threads(VOID)
  240. {
  241. NTSTATUS wstatus;
  242. DWORD MTimeout = INFINITE;
  243. printf("Main thread waiting for Client threads ");
  244. wstatus = WaitForMultipleObjectsEx(NClients,
  245. Threads,
  246. TRUE, // Wait for all objects
  247. MTimeout, // Default timeout
  248. TRUE); // Alertable
  249. printf(".. Wait over with status:%lx\n",wstatus);
  250. if (!NT_SUCCESS(wstatus)) {
  251. printf ("Failed on wait err=%lx\n",wstatus);
  252. }
  253. if (ThreadError) {
  254. printf("Thread Error: %d \n", ThreadError);
  255. }
  256. return wstatus;
  257. }
  258. /************************************************************************/
  259. /*++
  260. This routine is the thread service routine. It first waits for clients to
  261. connect. Then it does a handshake to gather all the test info. Then it
  262. services all requests.
  263. --*/
  264. VOID
  265. SrvService( // provides server service
  266. IN PUSHORT pTindex)
  267. {
  268. NTSTATUS tstatus;
  269. USHORT tCindex;
  270. //UCHAR RetCode;
  271. BOOLEAN keepdoing;
  272. BOOLEAN Terminate;
  273. ULONG RecvLen = 0;
  274. ULONG SendLen = 0;
  275. ULONG Iterations = 0;
  276. BOOLEAN First = TRUE;
  277. tCindex = *pTindex;
  278. keepdoing = TRUE;
  279. ThreadError = 0;
  280. Failure = FALSE;
  281. do { // keep doing the work till it receives 'E' from client
  282. //DbgPrint("Srv:Waiting for a client %d\n",tCindex);
  283. // First post listen for a client's connection request
  284. tstatus = IPC_Wait_For_Client(tCindex);
  285. ThreadError = 1;
  286. FAIL_CHECK(PERFSRV, " Wait for Client" , tstatus);
  287. // now the thread has been connected
  288. // now do the handshake to read the request message
  289. tstatus = IPC_DoHandshake(tCindex,SRV);
  290. ThreadError = 2;
  291. FAIL_CHECK(PERFSRV, " Doing Handshake" , tstatus);
  292. // allocate memory for data buffers and start the I/O
  293. tstatus = IPC_Allocate_Memory(tCindex);
  294. ThreadError = 3;
  295. FAIL_CHECK(PERFSRV, " Memory Allocation" , tstatus);
  296. // check if the client wants to quit.
  297. // Set up number of iterations
  298. Iterations = Clients[tCindex].c_reqbuf.Iterations;
  299. Terminate = FALSE;
  300. First = TRUE;
  301. while (Iterations--) {
  302. if (Clients[tCindex].c_reqbuf.TestCmd = 'P') {
  303. // now the server has to first receive X messages and then
  304. // send Y messages.
  305. MyDbgPrint("Srv:Reading \n");
  306. tstatus = IPC_ReadFromIPC( tCindex, &RecvLen,SRV);
  307. ThreadError = 4;
  308. FAIL_CHECK(PERFSRV, " Read from IPC" , tstatus);
  309. // We can check for recv length and data integrity out here
  310. MyDbgPrint("Srv:Writing \n");
  311. tstatus = IPC_WriteToIPC( tCindex, &SendLen, SRV);
  312. ThreadError = 5;
  313. FAIL_CHECK(PERFSRV, " Read from IPC" , tstatus);
  314. }
  315. else { // for 'U' or 'T' do transct I/O
  316. // We have to do something different for NetBIOS as
  317. // it sould first post a receive and then do RecvSend for
  318. // Other iterations. for Client this works fine as it always
  319. // does send/Recv.
  320. tstatus = IPC_XactIO( tCindex, &SendLen, &RecvLen, SRV,First);
  321. // FAIL_CHECK(PERFSRV, " Xact IPC" , tstatus);
  322. ThreadError = 6;
  323. if (!NT_SUCCESS(tstatus)) {
  324. if ((tstatus != STATUS_PIPE_BROKEN) &&
  325. (tstatus != STATUS_INVALID_PIPE_STATE)) {
  326. //DbgPrint("Error in XactIO: %lx \n", tstatus);
  327. }
  328. break;
  329. }
  330. First = FALSE;
  331. }
  332. }
  333. // now we are done with the current tests so do the cleanup and
  334. // start all over again
  335. tstatus = IPC_Disconnect_Client(tCindex);
  336. ThreadError = 7;
  337. FAIL_CHECK(PERFSRV, " Disconnect Client " , tstatus);
  338. tstatus = IPC_Deallocate_Memory(tCindex);
  339. ThreadError = 8;
  340. FAIL_CHECK(PERFSRV, " Memory Deallocation" , tstatus);
  341. ThreadError = 0;
  342. } while (keepdoing); // till we receive 'E' or bad status
  343. // we should check if we have to deallocate all the buffers.
  344. // Do all the thread cleanup work
  345. tstatus = IPC_ThreadCleanUp(tCindex);
  346. }
  347. /************************************************************************/
  348. VOID
  349. Cleanup(VOID)
  350. {
  351. USHORT Cindex = 0; // client index
  352. NTSTATUS cstatus;
  353. NTSTATUS exitstatus = 0;
  354. for (Cindex = 0; Cindex < NClients; Cindex++) {
  355. // terminate the thread
  356. cstatus = TerminateThread(Clients[Cindex].c_hThHandle, exitstatus);
  357. if (!NT_SUCCESS(cstatus)) {
  358. printf("Failed to terminate thread no:%d err=%lx\n", Cindex,cstatus);
  359. }
  360. }
  361. printf("Terminated All Threads\n");
  362. }
  363. /************************************************************************/
  364. NTSTATUS
  365. Parse_Cmd_Line(USHORT argc, CHAR *argv[])
  366. {
  367. USHORT i;
  368. PCHAR s;
  369. NTSTATUS pstatus = 0L;
  370. BOOLEAN doingok = TRUE;
  371. if (argc > 5) {
  372. printf("Too many arguments \n");
  373. pstatus = -1L;
  374. }
  375. // copy default Xport name : Nmp
  376. strncpy(Xport, NamePipe, 8);
  377. for (i=1; (doingok) && (i< argc); i++) {
  378. s = argv[i];
  379. if ((*s == '/') &&(*(s+2) == ':'))
  380. {
  381. s++;
  382. switch(*s) {
  383. case 'b' :
  384. case 'B' :
  385. LanaBase = (USHORT)atoi(s+2);
  386. break;
  387. case 'c' : // number of Clients
  388. case 'C' :
  389. NClients = (USHORT)atoi(s+2);
  390. break;
  391. case 'h' :
  392. case 'H' :
  393. HostName = (PCHAR) malloc(strlen(s+2)+1);
  394. strcpy(HostName,s+2);
  395. // check for the validity of the address
  396. break;
  397. case 'l' :
  398. case 'L' :
  399. LanaCount = (USHORT)atoi(s+2);
  400. break;
  401. case 'p' : // NamedPipe mode
  402. case 'P' :
  403. switch(*(s+2)) {
  404. case 'm':
  405. case 'M':
  406. PipeType = PIPE_TYPE_MESSAGE;
  407. PipeMode = PIPE_READMODE_MESSAGE;
  408. break;
  409. case 's':
  410. case 'S':
  411. PipeType = PIPE_TYPE_BYTE;
  412. PipeMode = PIPE_READMODE_BYTE;
  413. break;
  414. default:
  415. doingok = FALSE;
  416. break;
  417. }
  418. case 'x' : // Xport Type
  419. case 'X' :
  420. strncpy(Xport, (PUCHAR) (s+2), 8);
  421. if (!_stricmp(Xport,NamePipe)) {
  422. IPCType = NP;
  423. break;
  424. }
  425. if (!_stricmp(Xport,NetBIOS)) {
  426. IPCType = NB;
  427. break;
  428. }
  429. if (!_stricmp(Xport,SocketXNS)) {
  430. IPCType = SCXNS;
  431. AddrFly = AF_NS;
  432. break;
  433. }
  434. if (!_stricmp(Xport,SocketTCP)) {
  435. IPCType = SCTCP;
  436. AddrFly = AF_INET;
  437. break;
  438. }
  439. if (!_stricmp(Xport,UDP)) {
  440. IPCType = SCUDP;
  441. AddrFly = AF_INET;
  442. break;
  443. }
  444. if (!_stricmp(Xport,IPX)) {
  445. IPCType = SCIPX;
  446. AddrFly = AF_NS;
  447. break;
  448. }
  449. if (!_stricmp(Xport,DGNetBIOS)) {
  450. IPCType = DGNB;
  451. break;
  452. }
  453. // bad choice of Xport
  454. doingok = FALSE;
  455. break;
  456. default :
  457. doingok = FALSE;
  458. }
  459. }
  460. else {
  461. doingok = FALSE;
  462. }
  463. }
  464. if (!doingok) {
  465. Usage(argv[0]);
  466. pstatus = -1L;
  467. }
  468. else {
  469. if (((IPCType == SCTCP)|| (IPCType == SCXNS)) && (HostName == NULL)) {
  470. printf("Please enter Host address \n");
  471. pstatus = -1L;
  472. }
  473. }
  474. return(pstatus);
  475. }
  476. /************************************************************************/
  477. VOID Usage(char * PrgName)
  478. {
  479. fprintf(stderr, "Usage: %s [/c: ] [/x: ] \n", PrgName);
  480. fprintf(stderr, " Opt Default Defines\n");
  481. fprintf(stderr, " === ======= =======\n");
  482. fprintf(stderr, " /c: 1 Number of clients\n");
  483. fprintf(stderr, " /x: Nmp Xport(IPC)type\n");
  484. fprintf(stderr, " Nmp/NetB/SockTCP/\n");
  485. fprintf(stderr, " SockXNS/UDP/IPX/DGNetB\n");
  486. fprintf(stderr, " /p: m Nmp : Pip Type m/s\n");
  487. fprintf(stderr, " /l: 0 NetB: lana count\n");
  488. fprintf(stderr, " /b: 0 NetB: lana base\n");
  489. fprintf(stderr, " /h: NULL Server Name/Host IP addr.\n");
  490. }
  491. /************************************************************************/