14
14
#include < httpext.h>
15
15
#include < stdio.h>
16
16
#include < stdlib.h>
17
+ #include " getopt.h"
17
18
18
19
// These are things that go out in the Response Header
19
20
//
29
30
//
30
31
// The mandatory exports from the ISAPI DLL
31
32
//
32
- #define NUM_THREADS 10
33
- #define ITERATIONS 1
33
+ DWORD numThreads = 1 ;
34
+ DWORD iterations = 1 ;
35
+
34
36
HANDLE StartNow;
35
37
// quick and dirty environment
36
38
typedef CMapStringToString TEnvironment;
@@ -53,6 +55,7 @@ typedef struct _TIsapiContext {
53
55
HANDLE out;
54
56
DWORD tid;
55
57
TEnvironment env;
58
+ HANDLE waitEvent;
56
59
} TIsapiContext;
57
60
58
61
//
@@ -62,13 +65,15 @@ extern "C" {
62
65
HINSTANCE hDll;
63
66
typedef BOOL (WINAPI *VersionProc)(HSE_VERSION_INFO *) ;
64
67
typedef DWORD (WINAPI *HttpExtProc)(EXTENSION_CONTROL_BLOCK *);
68
+ typedef BOOL (WINAPI *TerminateProc) (DWORD);
65
69
BOOL WINAPI FillExtensionControlBlock (EXTENSION_CONTROL_BLOCK *, TIsapiContext *) ;
66
70
BOOL WINAPI GetServerVariable (HCONN, LPSTR, LPVOID, LPDWORD );
67
71
BOOL WINAPI ReadClient (HCONN, LPVOID, LPDWORD);
68
72
BOOL WINAPI WriteClient (HCONN, LPVOID, LPDWORD, DWORD);
69
73
BOOL WINAPI ServerSupportFunction (HCONN, DWORD, LPVOID, LPDWORD, LPDWORD);
70
74
VersionProc IsapiGetExtensionVersion;
71
75
HttpExtProc IsapiHttpExtensionProc;
76
+ TerminateProc TerminateExtensionProc;
72
77
HSE_VERSION_INFO version_info;
73
78
}
74
79
@@ -153,8 +158,9 @@ BOOL CompareStringWithFile(const char *filename, const char *str, unsigned int s
153
158
bool retval;
154
159
char buf[COMPARE_BUF_SIZE];
155
160
unsigned int offset=0 , readbytes;
156
-
157
- if ((fp=fopen (filename, " r" ))==NULL ) {
161
+ fprintf (stderr, " test %s\n " ,filename);
162
+ if ((fp=fopen (filename, " rb" ))==NULL ) {
163
+ fprintf (stderr, " Error opening %s\n " ,filename);
158
164
return FALSE ;
159
165
}
160
166
@@ -163,15 +169,17 @@ BOOL CompareStringWithFile(const char *filename, const char *str, unsigned int s
163
169
readbytes = fread (buf, 1 , sizeof (buf), fp);
164
170
165
171
// check for end of file
166
- if (feof (fp)) {
167
- break ;
168
- }
169
172
170
173
if (offset+readbytes > str_length
171
174
|| memcmp (buf, str+offset, readbytes)!=NULL ) {
175
+ fprintf (stderr, " File missmatch %s\n " ,filename);
172
176
retval = FALSE ;
173
177
break ;
174
178
}
179
+ if (feof (fp)) {
180
+ if (!retval) fprintf (stderr, " File zero length %s\n " ,filename);
181
+ break ;
182
+ }
175
183
}
176
184
fclose (fp);
177
185
@@ -250,15 +258,20 @@ void DoThreads() {
250
258
printf (" Starting Threads...\n " );
251
259
// loop creating threads
252
260
DWORD tid;
253
- HANDLE threads[NUM_THREADS];
254
- for (DWORD i=0 ; i< NUM_THREADS; i++) {
261
+ HANDLE *threads = new HANDLE[numThreads];
262
+ DWORD i;
263
+ for (i=0 ; i< numThreads; i++) {
255
264
threads[i]=CreateThread (NULL , 0 , IsapiThread, NULL , CREATE_SUSPENDED, &tid);
256
265
}
257
- for (i=0 ; i< NUM_THREADS ; i++) {
266
+ for (i=0 ; i< numThreads ; i++) {
258
267
if (threads[i]) ResumeThread (threads[i]);
259
268
}
260
269
// wait for threads to finish
261
- WaitForMultipleObjects (NUM_THREADS, threads, TRUE , INFINITE);
270
+ WaitForMultipleObjects (numThreads, threads, TRUE , INFINITE);
271
+ for (i=0 ; i< numThreads; i++) {
272
+ CloseHandle (threads[i]);
273
+ }
274
+ delete threads;
262
275
}
263
276
264
277
void DoFileList (const char *filelist, const char *environment)
@@ -292,11 +305,11 @@ BOOL ParseTestFile(const char *path, const char *fn)
292
305
293
306
enum state {none, test, skipif, post, get, file, expect} parsestate = none;
294
307
295
- FILE *fp = fopen (filename, " r " );
308
+ FILE *fp = fopen (filename, " rb " );
296
309
char *tn = _tempnam (temppath," pht." );
297
310
char *en = _tempnam (temppath," exp." );
298
- FILE *ft = fopen (tn, " w +" );
299
- FILE *fe = fopen (en, " w +" );
311
+ FILE *ft = fopen (tn, " wb +" );
312
+ FILE *fe = fopen (en, " wb +" );
300
313
if (fp && ft && fe) {
301
314
while (fgets (line, sizeof (line)-1 , fp)) {
302
315
if (line[0 ]==' -' ) {
@@ -353,9 +366,13 @@ BOOL ParseTestFile(const char *path, const char *fn)
353
366
IsapiGetData.Add (cGet);
354
367
IsapiPostData.Add (cPost);
355
368
IsapiMatchData.Add (en);
369
+ free (tn);
370
+ free (en);
356
371
return TRUE ;
357
372
}
358
373
}
374
+ free (tn);
375
+ free (en);
359
376
return FALSE ;
360
377
}
361
378
@@ -441,23 +458,66 @@ void DoTestFiles(const char *filelist, const char *environment)
441
458
printf (" Done\r\n " );
442
459
}
443
460
444
- int main (int argc, char * argv[])
461
+ #define OPTSTRING " m:f:d:h:t:i:"
462
+ static void _usage (char *argv0)
445
463
{
446
- LPVOID lpMsgBuf;
447
- char *filelist=NULL , *environment=NULL ;
464
+ char *prog;
448
465
449
- if (argc < 3 ) {
450
- // look for phpt files in tests
451
- printf (" USAGE: stresstest [L|T] filelist [environment]\r\n " );
452
- return 0 ;
466
+ prog = strrchr (argv0, ' /' );
467
+ if (prog) {
468
+ prog++;
453
469
} else {
454
- if (argv[1 ][0 ]==' T' ) bUseTestFiles = TRUE ;
455
- if (argc > 1 ) filelist = argv[2 ];
456
- if (argc > 2 ) environment = argv[3 ];
470
+ prog = " stresstest" ;
471
+ }
472
+
473
+ printf (" Usage: %s -m <isapi.dll> -d|-l <file> [-t <numthreads>] [-i <numiterations>]\n "
474
+ " -m path to isapi dll\n "
475
+ " -d <directory> php directory (to run php test files).\n "
476
+ " -f <file> file containing list of files to run\n "
477
+ " -t number of threads to use (default=1)\n "
478
+ " -i number of iterations per thread (default=1)\n "
479
+ " -h This help\n " , prog);
480
+ }
481
+ int main (int argc, char * argv[])
482
+ {
483
+ LPVOID lpMsgBuf;
484
+ char *filelist=NULL , *environment=NULL , *module =NULL ;
485
+ int c = NULL ;
486
+ while ((c=ap_getopt (argc, argv, OPTSTRING))!=-1 ) {
487
+ switch (c) {
488
+ case ' d' :
489
+ bUseTestFiles = TRUE ;
490
+ filelist = strdup (ap_optarg);
491
+ break ;
492
+ case ' f' :
493
+ bUseTestFiles = FALSE ;
494
+ filelist = strdup (ap_optarg);
495
+ break ;
496
+ case ' e' :
497
+ environment = strdup (ap_optarg);
498
+ break ;
499
+ case ' t' :
500
+ numThreads = atoi (ap_optarg);
501
+ break ;
502
+ case ' i' :
503
+ iterations = atoi (ap_optarg);
504
+ break ;
505
+ case ' m' :
506
+ module = strdup (ap_optarg);
507
+ break ;
508
+ case ' h' :
509
+ _usage (argv[0 ]);
510
+ exit (0 );
511
+ break ;
512
+ }
513
+ }
514
+ if (!module || !filelist) {
515
+ _usage (argv[0 ]);
516
+ exit (0 );
457
517
}
458
518
459
519
GetTempPath (sizeof (temppath), temppath);
460
- hDll = LoadLibrary (" php4isapi.dll " ); // Load our DLL
520
+ hDll = LoadLibrary (module ); // Load our DLL
461
521
462
522
if (!hDll) {
463
523
FormatMessage (
@@ -470,6 +530,8 @@ int main(int argc, char* argv[])
470
530
NULL
471
531
);
472
532
fprintf (stderr," Error: Dll 'php4isapi.dll' not found -%d\n %s\n " , GetLastError (), lpMsgBuf);
533
+ free (module );
534
+ free (filelist);
473
535
LocalFree ( lpMsgBuf );
474
536
return -1 ;
475
537
}
@@ -480,19 +542,27 @@ int main(int argc, char* argv[])
480
542
IsapiGetExtensionVersion = (VersionProc)GetProcAddress (hDll," GetExtensionVersion" );
481
543
if (!IsapiGetExtensionVersion) {
482
544
fprintf (stderr," Can't Get Extension Version %d\n " , GetLastError ());
545
+ free (module );
546
+ free (filelist);
483
547
return -1 ;
484
548
}
485
549
IsapiHttpExtensionProc = (HttpExtProc)GetProcAddress (hDll," HttpExtensionProc" );
486
550
if (!IsapiHttpExtensionProc) {
487
551
fprintf (stderr," Can't Get Extension proc %d\n " , GetLastError ());
552
+ free (module );
553
+ free (filelist);
488
554
return -1 ;
489
555
}
556
+ TerminateExtensionProc = (TerminateProc) GetProcAddress (hDll,
557
+ " TerminateExtension" );
490
558
491
559
// This should really check if the version information matches what we
492
560
// expect.
493
561
//
494
562
if (!IsapiGetExtensionVersion (&version_info) ) {
495
563
fprintf (stderr," Fatal: GetExtensionVersion failed\n " );
564
+ free (module );
565
+ free (filelist);
496
566
return -1 ;
497
567
}
498
568
@@ -507,12 +577,14 @@ int main(int argc, char* argv[])
507
577
}
508
578
509
579
// cleanup
510
-
580
+ if (TerminateExtensionProc) TerminateExtensionProc ( 0 );
511
581
512
582
// We should really free memory (e.g., from GetEnv), but we'll be dead
513
583
// soon enough
514
584
515
585
FreeLibrary (hDll);
586
+ free (module );
587
+ free (filelist);
516
588
return 0 ;
517
589
}
518
590
@@ -521,7 +593,7 @@ DWORD CALLBACK IsapiThread(void *p)
521
593
{
522
594
DWORD filecount = IsapiFileList.GetSize ();
523
595
524
- for (DWORD j=0 ; j<ITERATIONS ; j++) {
596
+ for (DWORD j=0 ; j<iterations ; j++) {
525
597
for (DWORD i=0 ; i<filecount; i++) {
526
598
// execute each file
527
599
CString testname = TestNames.GetAt (i);
@@ -572,7 +644,7 @@ BOOL stress_main(const char *filename,
572
644
CString fname;
573
645
fname.Format (" %08X.out" , context.tid );
574
646
575
- context.out = CreateFile (fname, GENERIC_WRITE, FILE_SHARE_READ, NULL , CREATE_ALWAYS, 0 , NULL );
647
+ context.out = CreateFile (fname, GENERIC_WRITE, FILE_SHARE_READ, NULL , CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH , NULL );
576
648
if (context.out ==INVALID_HANDLE_VALUE) {
577
649
printf (" failed to open output file %s\n " , fname);
578
650
return 0 ;
@@ -600,7 +672,8 @@ BOOL stress_main(const char *filename,
600
672
context.env [" CONTENT_LENGTH" ]= " " ;
601
673
context.env [" QUERY_STRING" ]= arg;
602
674
context.env [" METHOD" ]=" GET" ;
603
-
675
+ context.env [" PATH_INFO" ] = " " ;
676
+ context.waitEvent = CreateEvent (NULL , FALSE , FALSE , NULL );
604
677
char buf[MAX_PATH];
605
678
if (postdata && *postdata !=0 ) {
606
679
ECB.cbAvailable = strlen (postdata);
@@ -613,28 +686,36 @@ BOOL stress_main(const char *filename,
613
686
614
687
context.env [" CONTENT_TYPE" ]=" application/x-www-form-urlencoded" ;
615
688
}
689
+ ECB.lpszMethod = strdup (context.env [" METHOD" ]);
616
690
ECB.lpszPathTranslated = strdup (filename);
617
691
ECB.lpszQueryString = strdup (arg);
692
+ ECB.lpszPathInfo = strdup (context.env [" PATH_INFO" ]);
693
+
618
694
619
695
// Call the DLL
620
696
//
621
697
rc = IsapiHttpExtensionProc (&ECB);
622
-
698
+ if (rc == HSE_STATUS_PENDING) {
699
+ // We will exit in ServerSupportFunction
700
+ WaitForSingleObject (context.waitEvent , INFINITE);
701
+ }
702
+ CloseHandle (context.waitEvent );
703
+ // Sleep(75);
623
704
free (ECB.lpszPathTranslated );
624
705
free (ECB.lpszQueryString );
706
+ free (ECB.lpszMethod );
707
+ free (ECB.lpszPathInfo );
625
708
626
709
BOOL ok = TRUE ;
627
710
628
711
if (context.out != INVALID_HANDLE_VALUE) CloseHandle (context.out );
629
712
630
713
// compare the output with the EXPECT section
631
714
if (matchdata && *matchdata != 0 ) {
632
- ok = CompareStringWithFile (fname, matchdata, strlen (matchdata) );
715
+ ok = CompareFiles (fname, matchdata);
633
716
}
634
717
635
718
DeleteFile (fname);
636
- // if (rc == HSE_STATUS_PENDING) // We will exit in ServerSupportFunction
637
- // Sleep(INFINITE);
638
719
639
720
return ok;
640
721
@@ -696,9 +777,8 @@ BOOL WINAPI WriteClient(HCONN hConn, LPVOID lpBuffer, LPDWORD lpdwSize,
696
777
TIsapiContext *c = (TIsapiContext *)hConn;
697
778
if (!c) return FALSE ;
698
779
699
- if (c->out != INVALID_HANDLE_VALUE)
780
+ if (c->out != INVALID_HANDLE_VALUE)
700
781
return WriteFile (c->out , lpBuffer, *lpdwSize, lpdwSize, NULL );
701
-
702
782
return FALSE ;
703
783
}
704
784
//
@@ -708,10 +788,11 @@ BOOL WINAPI WriteClient(HCONN hConn, LPVOID lpBuffer, LPDWORD lpdwSize,
708
788
BOOL WINAPI ServerSupportFunction (HCONN hConn, DWORD dwHSERequest,
709
789
LPVOID lpvBuffer, LPDWORD lpdwSize, LPDWORD lpdwDataType){
710
790
791
+ TIsapiContext *c = (TIsapiContext *)hConn;
711
792
char *lpszRespBuf;
712
793
char * temp = NULL ;
713
794
DWORD dwBytes;
714
- BOOL bRet;
795
+ BOOL bRet = TRUE ;
715
796
716
797
switch (dwHSERequest) {
717
798
case (HSE_REQ_SEND_RESPONSE_HEADER) :
@@ -744,6 +825,7 @@ BOOL WINAPI ServerSupportFunction(HCONN hConn, DWORD dwHSERequest,
744
825
//
745
826
// A real server would do cleanup here
746
827
case (HSE_REQ_DONE_WITH_SESSION):
828
+ SetEvent (c->waitEvent );
747
829
// ExitThread(0);
748
830
break ;
749
831
0 commit comments