provider.c 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413
  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. /*
  6. *
  7. * Notes:
  8. * [1] lth. The call to Sleep() is a hack to get the test case to run
  9. * on Windows 95. Without it, the test case fails with an error
  10. * WSAECONNRESET following a recv() call. The error is caused by the
  11. * server side thread termination without a shutdown() or closesocket()
  12. * call. Windows docmunentation suggests that this is predicted
  13. * behavior; that other platforms get away with it is ... serindipity.
  14. * The test case should shutdown() or closesocket() before
  15. * thread termination. I didn't have time to figure out where or how
  16. * to do it. The Sleep() call inserts enough delay to allow the
  17. * client side to recv() all his data before the server side thread
  18. * terminates. Whew! ...
  19. *
  20. ** Modification History:
  21. * 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
  22. * The debug mode will print all of the printfs associated with this test.
  23. * The regress mode will be the default mode. Since the regress tool limits
  24. * the output to a one line status:PASS or FAIL,all of the printf statements
  25. * have been handled with an if (debug_mode) statement.
  26. */
  27. #include "prclist.h"
  28. #include "prcvar.h"
  29. #include "prerror.h"
  30. #include "prinit.h"
  31. #include "prinrval.h"
  32. #include "prio.h"
  33. #include "prlock.h"
  34. #include "prlog.h"
  35. #include "prtime.h"
  36. #include "prmem.h"
  37. #include "prnetdb.h"
  38. #include "prprf.h"
  39. #include "prthread.h"
  40. #include "pprio.h"
  41. #include "primpl.h"
  42. #include "plstr.h"
  43. #include "plerror.h"
  44. #include "plgetopt.h"
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #if defined(XP_UNIX)
  48. #include <math.h>
  49. #endif
  50. /*
  51. ** This is the beginning of the test
  52. */
  53. #ifdef DEBUG
  54. #define PORT_INC_DO +100
  55. #else
  56. #define PORT_INC_DO
  57. #endif
  58. #ifdef IS_64
  59. #define PORT_INC_3264 +200
  60. #else
  61. #define PORT_INC_3264
  62. #endif
  63. #define RECV_FLAGS 0
  64. #define SEND_FLAGS 0
  65. #define BUFFER_SIZE 1024
  66. #define DEFAULT_BACKLOG 5
  67. #define DEFAULT_PORT 13000 PORT_INC_DO PORT_INC_3264
  68. #define DEFAULT_CLIENTS 1
  69. #define ALLOWED_IN_ACCEPT 1
  70. #define DEFAULT_CLIPPING 1000
  71. #define DEFAULT_WORKERS_MIN 1
  72. #define DEFAULT_WORKERS_MAX 1
  73. #define DEFAULT_SERVER "localhost"
  74. #define DEFAULT_EXECUTION_TIME 10
  75. #define DEFAULT_CLIENT_TIMEOUT 4000
  76. #define DEFAULT_SERVER_TIMEOUT 4000
  77. #define DEFAULT_SERVER_PRIORITY PR_PRIORITY_HIGH
  78. typedef enum CSState_e {cs_init, cs_run, cs_stop, cs_exit} CSState_t;
  79. static void PR_CALLBACK Worker(void *arg);
  80. typedef struct CSPool_s CSPool_t;
  81. typedef struct CSWorker_s CSWorker_t;
  82. typedef struct CSServer_s CSServer_t;
  83. typedef enum Verbosity
  84. {
  85. TEST_LOG_ALWAYS,
  86. TEST_LOG_ERROR,
  87. TEST_LOG_WARNING,
  88. TEST_LOG_NOTICE,
  89. TEST_LOG_INFO,
  90. TEST_LOG_STATUS,
  91. TEST_LOG_VERBOSE
  92. } Verbosity;
  93. static enum {
  94. thread_nspr, thread_pthread, thread_sproc, thread_win32
  95. } thread_provider;
  96. static PRInt32 domain = AF_INET;
  97. static PRInt32 protocol = 6; /* TCP */
  98. static PRFileDesc *debug_out = NULL;
  99. static PRBool debug_mode = PR_FALSE;
  100. static PRBool pthread_stats = PR_FALSE;
  101. static Verbosity verbosity = TEST_LOG_ALWAYS;
  102. static PRThreadScope thread_scope = PR_LOCAL_THREAD;
  103. struct CSWorker_s
  104. {
  105. PRCList element; /* list of the server's workers */
  106. PRThread *thread; /* this worker objects thread */
  107. CSServer_t *server; /* back pointer to server structure */
  108. };
  109. struct CSPool_s
  110. {
  111. PRCondVar *exiting;
  112. PRCondVar *acceptComplete;
  113. PRUint32 accepting, active, workers;
  114. };
  115. struct CSServer_s
  116. {
  117. PRCList list; /* head of worker list */
  118. PRLock *ml;
  119. PRThread *thread; /* the main server thread */
  120. PRCondVar *stateChange;
  121. PRUint16 port; /* port we're listening on */
  122. PRUint32 backlog; /* size of our listener backlog */
  123. PRFileDesc *listener; /* the fd accepting connections */
  124. CSPool_t pool; /* statistics on worker threads */
  125. CSState_t state; /* the server's state */
  126. struct /* controlling worker counts */
  127. {
  128. PRUint32 minimum, maximum, accepting;
  129. } workers;
  130. /* statistics */
  131. PRIntervalTime started, stopped;
  132. PRUint32 operations, bytesTransferred;
  133. };
  134. typedef struct CSDescriptor_s
  135. {
  136. PRInt32 size; /* size of transfer */
  137. char filename[60]; /* filename, null padded */
  138. } CSDescriptor_t;
  139. typedef struct CSClient_s
  140. {
  141. PRLock *ml;
  142. PRThread *thread;
  143. PRCondVar *stateChange;
  144. PRNetAddr serverAddress;
  145. CSState_t state;
  146. /* statistics */
  147. PRIntervalTime started, stopped;
  148. PRUint32 operations, bytesTransferred;
  149. } CSClient_t;
  150. #define TEST_LOG(l, p, a) \
  151. do { \
  152. if (debug_mode || (p <= verbosity)) printf a; \
  153. } while (0)
  154. PRLogModuleInfo *cltsrv_log_file = NULL;
  155. #define MY_ASSERT(_expr) \
  156. ((_expr)?((void)0):_MY_Assert(# _expr,__FILE__,__LINE__))
  157. #define TEST_ASSERT(_expr) \
  158. ((_expr)?((void)0):_MY_Assert(# _expr,__FILE__,__LINE__))
  159. static void _MY_Assert(const char *s, const char *file, PRIntn ln)
  160. {
  161. PL_PrintError(NULL);
  162. PR_Assert(s, file, ln);
  163. } /* _MY_Assert */
  164. static PRBool Aborted(PRStatus rv)
  165. {
  166. return ((PR_FAILURE == rv) && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) ?
  167. PR_TRUE : PR_FALSE;
  168. }
  169. static void TimeOfDayMessage(const char *msg, PRThread* me)
  170. {
  171. char buffer[100];
  172. PRExplodedTime tod;
  173. PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &tod);
  174. (void)PR_FormatTime(buffer, sizeof(buffer), "%H:%M:%S", &tod);
  175. TEST_LOG(
  176. cltsrv_log_file, TEST_LOG_ALWAYS,
  177. ("%s(0x%p): %s\n", msg, me, buffer));
  178. } /* TimeOfDayMessage */
  179. static void PR_CALLBACK Client(void *arg)
  180. {
  181. PRStatus rv;
  182. PRIntn index;
  183. char buffer[1024];
  184. PRFileDesc *fd = NULL;
  185. PRUintn clipping = DEFAULT_CLIPPING;
  186. CSClient_t *client = (CSClient_t*)arg;
  187. PRThread *me = client->thread = PR_GetCurrentThread();
  188. CSDescriptor_t *descriptor = PR_NEW(CSDescriptor_t);
  189. PRIntervalTime timeout = PR_MillisecondsToInterval(DEFAULT_CLIENT_TIMEOUT);
  190. for (index = 0; index < sizeof(buffer); ++index) {
  191. buffer[index] = (char)index;
  192. }
  193. client->started = PR_IntervalNow();
  194. PR_Lock(client->ml);
  195. client->state = cs_run;
  196. PR_NotifyCondVar(client->stateChange);
  197. PR_Unlock(client->ml);
  198. TimeOfDayMessage("Client started at", me);
  199. while (cs_run == client->state)
  200. {
  201. PRInt32 bytes, descbytes, filebytes, netbytes;
  202. (void)PR_NetAddrToString(&client->serverAddress, buffer, sizeof(buffer));
  203. TEST_LOG(cltsrv_log_file, TEST_LOG_INFO,
  204. ("\tClient(0x%p): connecting to server at %s\n", me, buffer));
  205. fd = PR_Socket(domain, SOCK_STREAM, protocol);
  206. TEST_ASSERT(NULL != fd);
  207. rv = PR_Connect(fd, &client->serverAddress, timeout);
  208. if (PR_FAILURE == rv)
  209. {
  210. TEST_LOG(
  211. cltsrv_log_file, TEST_LOG_ERROR,
  212. ("\tClient(0x%p): conection failed\n", me));
  213. goto aborted;
  214. }
  215. memset(descriptor, 0, sizeof(*descriptor));
  216. descriptor->size = PR_htonl(descbytes = rand() % clipping);
  217. PR_snprintf(
  218. descriptor->filename, sizeof(descriptor->filename),
  219. "CS%p%p-%p.dat", client->started, me, client->operations);
  220. TEST_LOG(
  221. cltsrv_log_file, TEST_LOG_VERBOSE,
  222. ("\tClient(0x%p): sending descriptor for %u bytes\n", me, descbytes));
  223. bytes = PR_Send(
  224. fd, descriptor, sizeof(*descriptor), SEND_FLAGS, timeout);
  225. if (sizeof(CSDescriptor_t) != bytes)
  226. {
  227. if (Aborted(PR_FAILURE)) {
  228. goto aborted;
  229. }
  230. if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  231. {
  232. TEST_LOG(
  233. cltsrv_log_file, TEST_LOG_ERROR,
  234. ("\tClient(0x%p): send descriptor timeout\n", me));
  235. goto retry;
  236. }
  237. }
  238. TEST_ASSERT(sizeof(*descriptor) == bytes);
  239. netbytes = 0;
  240. while (netbytes < descbytes)
  241. {
  242. filebytes = sizeof(buffer);
  243. if ((descbytes - netbytes) < filebytes) {
  244. filebytes = descbytes - netbytes;
  245. }
  246. TEST_LOG(
  247. cltsrv_log_file, TEST_LOG_VERBOSE,
  248. ("\tClient(0x%p): sending %d bytes\n", me, filebytes));
  249. bytes = PR_Send(fd, buffer, filebytes, SEND_FLAGS, timeout);
  250. if (filebytes != bytes)
  251. {
  252. if (Aborted(PR_FAILURE)) {
  253. goto aborted;
  254. }
  255. if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  256. {
  257. TEST_LOG(
  258. cltsrv_log_file, TEST_LOG_ERROR,
  259. ("\tClient(0x%p): send data timeout\n", me));
  260. goto retry;
  261. }
  262. }
  263. TEST_ASSERT(bytes == filebytes);
  264. netbytes += bytes;
  265. }
  266. filebytes = 0;
  267. while (filebytes < descbytes)
  268. {
  269. netbytes = sizeof(buffer);
  270. if ((descbytes - filebytes) < netbytes) {
  271. netbytes = descbytes - filebytes;
  272. }
  273. TEST_LOG(
  274. cltsrv_log_file, TEST_LOG_VERBOSE,
  275. ("\tClient(0x%p): receiving %d bytes\n", me, netbytes));
  276. bytes = PR_Recv(fd, buffer, netbytes, RECV_FLAGS, timeout);
  277. if (-1 == bytes)
  278. {
  279. if (Aborted(PR_FAILURE))
  280. {
  281. TEST_LOG(
  282. cltsrv_log_file, TEST_LOG_ERROR,
  283. ("\tClient(0x%p): receive data aborted\n", me));
  284. goto aborted;
  285. }
  286. else if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  287. TEST_LOG(
  288. cltsrv_log_file, TEST_LOG_ERROR,
  289. ("\tClient(0x%p): receive data timeout\n", me));
  290. else
  291. TEST_LOG(
  292. cltsrv_log_file, TEST_LOG_ERROR,
  293. ("\tClient(0x%p): receive error (%d, %d)\n",
  294. me, PR_GetError(), PR_GetOSError()));
  295. goto retry;
  296. }
  297. if (0 == bytes)
  298. {
  299. TEST_LOG(
  300. cltsrv_log_file, TEST_LOG_ERROR,
  301. ("\t\tClient(0x%p): unexpected end of stream\n",
  302. PR_GetCurrentThread()));
  303. break;
  304. }
  305. filebytes += bytes;
  306. }
  307. rv = PR_Shutdown(fd, PR_SHUTDOWN_BOTH);
  308. if (Aborted(rv)) {
  309. goto aborted;
  310. }
  311. TEST_ASSERT(PR_SUCCESS == rv);
  312. retry:
  313. (void)PR_Close(fd); fd = NULL;
  314. TEST_LOG(
  315. cltsrv_log_file, TEST_LOG_INFO,
  316. ("\tClient(0x%p): disconnected from server\n", me));
  317. PR_Lock(client->ml);
  318. client->operations += 1;
  319. client->bytesTransferred += 2 * descbytes;
  320. rv = PR_WaitCondVar(client->stateChange, rand() % clipping);
  321. PR_Unlock(client->ml);
  322. if (Aborted(rv)) {
  323. break;
  324. }
  325. }
  326. aborted:
  327. client->stopped = PR_IntervalNow();
  328. PR_ClearInterrupt();
  329. if (NULL != fd) {
  330. rv = PR_Close(fd);
  331. }
  332. PR_Lock(client->ml);
  333. client->state = cs_exit;
  334. PR_NotifyCondVar(client->stateChange);
  335. PR_Unlock(client->ml);
  336. PR_DELETE(descriptor);
  337. TEST_LOG(
  338. cltsrv_log_file, TEST_LOG_ALWAYS,
  339. ("\tClient(0x%p): stopped after %u operations and %u bytes\n",
  340. PR_GetCurrentThread(), client->operations, client->bytesTransferred));
  341. } /* Client */
  342. static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server)
  343. {
  344. PRStatus drv, rv;
  345. char buffer[1024];
  346. PRFileDesc *file = NULL;
  347. PRThread * me = PR_GetCurrentThread();
  348. PRInt32 bytes, descbytes, netbytes, filebytes = 0;
  349. CSDescriptor_t *descriptor = PR_NEW(CSDescriptor_t);
  350. PRIntervalTime timeout = PR_MillisecondsToInterval(DEFAULT_SERVER_TIMEOUT);
  351. TEST_LOG(
  352. cltsrv_log_file, TEST_LOG_VERBOSE,
  353. ("\tProcessRequest(0x%p): receiving desciptor\n", me));
  354. bytes = PR_Recv(
  355. fd, descriptor, sizeof(*descriptor), RECV_FLAGS, timeout);
  356. if (-1 == bytes)
  357. {
  358. rv = PR_FAILURE;
  359. if (Aborted(rv)) {
  360. goto exit;
  361. }
  362. if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  363. {
  364. TEST_LOG(
  365. cltsrv_log_file, TEST_LOG_ERROR,
  366. ("\tProcessRequest(0x%p): receive timeout\n", me));
  367. }
  368. goto exit;
  369. }
  370. if (0 == bytes)
  371. {
  372. rv = PR_FAILURE;
  373. TEST_LOG(
  374. cltsrv_log_file, TEST_LOG_ERROR,
  375. ("\tProcessRequest(0x%p): unexpected end of file\n", me));
  376. goto exit;
  377. }
  378. descbytes = PR_ntohl(descriptor->size);
  379. TEST_ASSERT(sizeof(*descriptor) == bytes);
  380. TEST_LOG(
  381. cltsrv_log_file, TEST_LOG_VERBOSE,
  382. ("\t\tProcessRequest(0x%p): read descriptor {%d, %s}\n",
  383. me, descbytes, descriptor->filename));
  384. file = PR_Open(
  385. descriptor->filename, (PR_CREATE_FILE | PR_WRONLY), 0666);
  386. if (NULL == file)
  387. {
  388. rv = PR_FAILURE;
  389. if (Aborted(rv)) {
  390. goto aborted;
  391. }
  392. if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  393. {
  394. TEST_LOG(
  395. cltsrv_log_file, TEST_LOG_ERROR,
  396. ("\tProcessRequest(0x%p): open file timeout\n", me));
  397. goto aborted;
  398. }
  399. }
  400. TEST_ASSERT(NULL != file);
  401. filebytes = 0;
  402. while (filebytes < descbytes)
  403. {
  404. netbytes = sizeof(buffer);
  405. if ((descbytes - filebytes) < netbytes) {
  406. netbytes = descbytes - filebytes;
  407. }
  408. TEST_LOG(
  409. cltsrv_log_file, TEST_LOG_VERBOSE,
  410. ("\tProcessRequest(0x%p): receive %d bytes\n", me, netbytes));
  411. bytes = PR_Recv(fd, buffer, netbytes, RECV_FLAGS, timeout);
  412. if (-1 == bytes)
  413. {
  414. rv = PR_FAILURE;
  415. if (Aborted(rv)) {
  416. goto aborted;
  417. }
  418. if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  419. {
  420. TEST_LOG(
  421. cltsrv_log_file, TEST_LOG_ERROR,
  422. ("\t\tProcessRequest(0x%p): receive data timeout\n", me));
  423. goto aborted;
  424. }
  425. /*
  426. * XXX: I got (PR_CONNECT_RESET_ERROR, ERROR_NETNAME_DELETED)
  427. * on NT here. This is equivalent to ECONNRESET on Unix.
  428. * -wtc
  429. */
  430. TEST_LOG(
  431. cltsrv_log_file, TEST_LOG_WARNING,
  432. ("\t\tProcessRequest(0x%p): unexpected error (%d, %d)\n",
  433. me, PR_GetError(), PR_GetOSError()));
  434. goto aborted;
  435. }
  436. if(0 == bytes)
  437. {
  438. TEST_LOG(
  439. cltsrv_log_file, TEST_LOG_WARNING,
  440. ("\t\tProcessRequest(0x%p): unexpected end of stream\n", me));
  441. rv = PR_FAILURE;
  442. goto aborted;
  443. }
  444. filebytes += bytes;
  445. netbytes = bytes;
  446. /* The byte count for PR_Write should be positive */
  447. MY_ASSERT(netbytes > 0);
  448. TEST_LOG(
  449. cltsrv_log_file, TEST_LOG_VERBOSE,
  450. ("\tProcessRequest(0x%p): write %d bytes to file\n", me, netbytes));
  451. bytes = PR_Write(file, buffer, netbytes);
  452. if (netbytes != bytes)
  453. {
  454. rv = PR_FAILURE;
  455. if (Aborted(rv)) {
  456. goto aborted;
  457. }
  458. if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  459. {
  460. TEST_LOG(
  461. cltsrv_log_file, TEST_LOG_ERROR,
  462. ("\t\tProcessRequest(0x%p): write file timeout\n", me));
  463. goto aborted;
  464. }
  465. }
  466. TEST_ASSERT(bytes > 0);
  467. }
  468. PR_Lock(server->ml);
  469. server->operations += 1;
  470. server->bytesTransferred += filebytes;
  471. PR_Unlock(server->ml);
  472. rv = PR_Close(file); file = NULL;
  473. if (Aborted(rv)) {
  474. goto aborted;
  475. }
  476. TEST_ASSERT(PR_SUCCESS == rv);
  477. TEST_LOG(
  478. cltsrv_log_file, TEST_LOG_VERBOSE,
  479. ("\t\tProcessRequest(0x%p): opening %s\n", me, descriptor->filename));
  480. file = PR_Open(descriptor->filename, PR_RDONLY, 0);
  481. if (NULL == file)
  482. {
  483. rv = PR_FAILURE;
  484. if (Aborted(rv)) {
  485. goto aborted;
  486. }
  487. if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  488. {
  489. TEST_LOG(
  490. cltsrv_log_file, TEST_LOG_ERROR,
  491. ("\t\tProcessRequest(0x%p): open file timeout\n",
  492. PR_GetCurrentThread()));
  493. goto aborted;
  494. }
  495. TEST_LOG(
  496. cltsrv_log_file, TEST_LOG_ERROR,
  497. ("\t\tProcessRequest(0x%p): other file open error (%u, %u)\n",
  498. me, PR_GetError(), PR_GetOSError()));
  499. goto aborted;
  500. }
  501. TEST_ASSERT(NULL != file);
  502. netbytes = 0;
  503. while (netbytes < descbytes)
  504. {
  505. filebytes = sizeof(buffer);
  506. if ((descbytes - netbytes) < filebytes) {
  507. filebytes = descbytes - netbytes;
  508. }
  509. TEST_LOG(
  510. cltsrv_log_file, TEST_LOG_VERBOSE,
  511. ("\tProcessRequest(0x%p): read %d bytes from file\n", me, filebytes));
  512. bytes = PR_Read(file, buffer, filebytes);
  513. if (filebytes != bytes)
  514. {
  515. rv = PR_FAILURE;
  516. if (Aborted(rv)) {
  517. goto aborted;
  518. }
  519. if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  520. TEST_LOG(
  521. cltsrv_log_file, TEST_LOG_ERROR,
  522. ("\t\tProcessRequest(0x%p): read file timeout\n", me));
  523. else
  524. TEST_LOG(
  525. cltsrv_log_file, TEST_LOG_ERROR,
  526. ("\t\tProcessRequest(0x%p): other file error (%d, %d)\n",
  527. me, PR_GetError(), PR_GetOSError()));
  528. goto aborted;
  529. }
  530. TEST_ASSERT(bytes > 0);
  531. netbytes += bytes;
  532. filebytes = bytes;
  533. TEST_LOG(
  534. cltsrv_log_file, TEST_LOG_VERBOSE,
  535. ("\t\tProcessRequest(0x%p): sending %d bytes\n", me, filebytes));
  536. bytes = PR_Send(fd, buffer, filebytes, SEND_FLAGS, timeout);
  537. if (filebytes != bytes)
  538. {
  539. rv = PR_FAILURE;
  540. if (Aborted(rv)) {
  541. goto aborted;
  542. }
  543. if (PR_IO_TIMEOUT_ERROR == PR_GetError())
  544. {
  545. TEST_LOG(
  546. cltsrv_log_file, TEST_LOG_ERROR,
  547. ("\t\tProcessRequest(0x%p): send data timeout\n", me));
  548. goto aborted;
  549. }
  550. break;
  551. }
  552. TEST_ASSERT(bytes > 0);
  553. }
  554. PR_Lock(server->ml);
  555. server->bytesTransferred += filebytes;
  556. PR_Unlock(server->ml);
  557. rv = PR_Shutdown(fd, PR_SHUTDOWN_BOTH);
  558. if (Aborted(rv)) {
  559. goto aborted;
  560. }
  561. rv = PR_Close(file); file = NULL;
  562. if (Aborted(rv)) {
  563. goto aborted;
  564. }
  565. TEST_ASSERT(PR_SUCCESS == rv);
  566. aborted:
  567. PR_ClearInterrupt();
  568. if (NULL != file) {
  569. PR_Close(file);
  570. }
  571. drv = PR_Delete(descriptor->filename);
  572. TEST_ASSERT(PR_SUCCESS == drv);
  573. exit:
  574. TEST_LOG(
  575. cltsrv_log_file, TEST_LOG_VERBOSE,
  576. ("\t\tProcessRequest(0x%p): Finished\n", me));
  577. PR_DELETE(descriptor);
  578. #if defined(WIN95)
  579. PR_Sleep(PR_MillisecondsToInterval(200)); /* lth. see note [1] */
  580. #endif
  581. return rv;
  582. } /* ProcessRequest */
  583. typedef void (*StartFn)(void*);
  584. typedef struct StartObject
  585. {
  586. StartFn start;
  587. void *arg;
  588. } StartObject;
  589. #if defined(_PR_PTHREADS)
  590. #include "md/_pth.h"
  591. #include <pthread.h>
  592. static void *pthread_start(void *arg)
  593. {
  594. StartObject *so = (StartObject*)arg;
  595. StartFn start = so->start;
  596. void *data = so->arg;
  597. PR_Free(so);
  598. start(data);
  599. return NULL;
  600. } /* pthread_start */
  601. #endif /* defined(_PR_PTHREADS) */
  602. #if defined(WIN32)
  603. #include <process.h> /* for _beginthreadex() */
  604. static PRUintn __stdcall windows_start(void *arg)
  605. {
  606. StartObject *so = (StartObject*)arg;
  607. StartFn start = so->start;
  608. void *data = so->arg;
  609. PR_Free(so);
  610. start(data);
  611. return 0;
  612. } /* windows_start */
  613. #endif /* defined(WIN32) */
  614. static PRStatus JoinThread(PRThread *thread)
  615. {
  616. PRStatus rv;
  617. switch (thread_provider)
  618. {
  619. case thread_nspr:
  620. rv = PR_JoinThread(thread);
  621. break;
  622. case thread_pthread:
  623. #if defined(_PR_PTHREADS)
  624. rv = PR_SUCCESS;
  625. break;
  626. #endif /* defined(_PR_PTHREADS) */
  627. case thread_win32:
  628. #if defined(WIN32)
  629. rv = PR_SUCCESS;
  630. break;
  631. #endif
  632. default:
  633. rv = PR_FAILURE;
  634. break;
  635. }
  636. return rv;
  637. } /* JoinThread */
  638. static PRStatus NewThread(
  639. StartFn start, void *arg, PRThreadPriority prio, PRThreadState state)
  640. {
  641. PRStatus rv;
  642. switch (thread_provider)
  643. {
  644. case thread_nspr:
  645. {
  646. PRThread *thread = PR_CreateThread(
  647. PR_USER_THREAD, start, arg,
  648. PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
  649. PR_JOINABLE_THREAD, 0);
  650. rv = (NULL == thread) ? PR_FAILURE : PR_SUCCESS;
  651. }
  652. break;
  653. case thread_pthread:
  654. #if defined(_PR_PTHREADS)
  655. {
  656. int rv;
  657. pthread_t id;
  658. pthread_attr_t tattr;
  659. StartObject *start_object;
  660. start_object = PR_NEW(StartObject);
  661. PR_ASSERT(NULL != start_object);
  662. start_object->start = start;
  663. start_object->arg = arg;
  664. rv = _PT_PTHREAD_ATTR_INIT(&tattr);
  665. PR_ASSERT(0 == rv);
  666. rv = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
  667. PR_ASSERT(0 == rv);
  668. rv = pthread_attr_setstacksize(&tattr, 64 * 1024);
  669. PR_ASSERT(0 == rv);
  670. rv = _PT_PTHREAD_CREATE(&id, tattr, pthread_start, start_object);
  671. (void)_PT_PTHREAD_ATTR_DESTROY(&tattr);
  672. return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
  673. }
  674. #else
  675. PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
  676. rv = PR_FAILURE;
  677. #endif /* defined(_PR_PTHREADS) */
  678. break;
  679. case thread_sproc:
  680. PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
  681. rv = PR_FAILURE;
  682. break;
  683. case thread_win32:
  684. #if defined(WIN32)
  685. {
  686. void *th;
  687. PRUintn id;
  688. StartObject *start_object;
  689. start_object = PR_NEW(StartObject);
  690. PR_ASSERT(NULL != start_object);
  691. start_object->start = start;
  692. start_object->arg = arg;
  693. th = (void*)_beginthreadex(
  694. NULL, /* LPSECURITY_ATTRIBUTES - pointer to thread security attributes */
  695. 0U, /* DWORD - initial thread stack size, in bytes */
  696. windows_start, /* LPTHREAD_START_ROUTINE - pointer to thread function */
  697. start_object, /* LPVOID - argument for new thread */
  698. STACK_SIZE_PARAM_IS_A_RESERVATION, /*DWORD dwCreationFlags - creation flags */
  699. &id /* LPDWORD - pointer to returned thread identifier */ );
  700. rv = (NULL == th) ? PR_FAILURE : PR_SUCCESS;
  701. }
  702. #else
  703. PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
  704. rv = PR_FAILURE;
  705. #endif
  706. break;
  707. default:
  708. PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
  709. rv = PR_FAILURE;
  710. }
  711. return rv;
  712. } /* NewThread */
  713. static PRStatus CreateWorker(CSServer_t *server, CSPool_t *pool)
  714. {
  715. PRStatus rv;
  716. CSWorker_t *worker = PR_NEWZAP(CSWorker_t);
  717. worker->server = server;
  718. PR_INIT_CLIST(&worker->element);
  719. rv = NewThread(
  720. Worker, worker, DEFAULT_SERVER_PRIORITY, PR_UNJOINABLE_THREAD);
  721. if (PR_FAILURE == rv) {
  722. PR_DELETE(worker);
  723. }
  724. TEST_LOG(cltsrv_log_file, TEST_LOG_STATUS,
  725. ("\tCreateWorker(0x%p): create new worker (0x%p)\n",
  726. PR_GetCurrentThread(), worker->thread));
  727. return rv;
  728. } /* CreateWorker */
  729. static void PR_CALLBACK Worker(void *arg)
  730. {
  731. PRStatus rv;
  732. PRNetAddr from;
  733. PRFileDesc *fd = NULL;
  734. CSWorker_t *worker = (CSWorker_t*)arg;
  735. CSServer_t *server = worker->server;
  736. CSPool_t *pool = &server->pool;
  737. PRThread *me = worker->thread = PR_GetCurrentThread();
  738. TEST_LOG(
  739. cltsrv_log_file, TEST_LOG_NOTICE,
  740. ("\t\tWorker(0x%p): started [%u]\n", me, pool->workers + 1));
  741. PR_Lock(server->ml);
  742. PR_APPEND_LINK(&worker->element, &server->list);
  743. pool->workers += 1; /* define our existance */
  744. while (cs_run == server->state)
  745. {
  746. while (pool->accepting >= server->workers.accepting)
  747. {
  748. TEST_LOG(
  749. cltsrv_log_file, TEST_LOG_VERBOSE,
  750. ("\t\tWorker(0x%p): waiting for accept slot[%d]\n",
  751. me, pool->accepting));
  752. rv = PR_WaitCondVar(pool->acceptComplete, PR_INTERVAL_NO_TIMEOUT);
  753. if (Aborted(rv) || (cs_run != server->state))
  754. {
  755. TEST_LOG(
  756. cltsrv_log_file, TEST_LOG_NOTICE,
  757. ("\tWorker(0x%p): has been %s\n",
  758. me, (Aborted(rv) ? "interrupted" : "stopped")));
  759. goto exit;
  760. }
  761. }
  762. pool->accepting += 1; /* how many are really in accept */
  763. PR_Unlock(server->ml);
  764. TEST_LOG(
  765. cltsrv_log_file, TEST_LOG_VERBOSE,
  766. ("\t\tWorker(0x%p): calling accept\n", me));
  767. fd = PR_Accept(server->listener, &from, PR_INTERVAL_NO_TIMEOUT);
  768. PR_Lock(server->ml);
  769. pool->accepting -= 1;
  770. PR_NotifyCondVar(pool->acceptComplete);
  771. if ((NULL == fd) && Aborted(PR_FAILURE))
  772. {
  773. if (NULL != server->listener)
  774. {
  775. PR_Close(server->listener);
  776. server->listener = NULL;
  777. }
  778. goto exit;
  779. }
  780. if (NULL != fd)
  781. {
  782. /*
  783. ** Create another worker of the total number of workers is
  784. ** less than the minimum specified or we have none left in
  785. ** accept() AND we're not over the maximum.
  786. ** This sort of presumes that the number allowed in accept
  787. ** is at least as many as the minimum. Otherwise we'll keep
  788. ** creating new threads and deleting them soon after.
  789. */
  790. PRBool another =
  791. ((pool->workers < server->workers.minimum) ||
  792. ((0 == pool->accepting)
  793. && (pool->workers < server->workers.maximum))) ?
  794. PR_TRUE : PR_FALSE;
  795. pool->active += 1;
  796. PR_Unlock(server->ml);
  797. if (another) {
  798. (void)CreateWorker(server, pool);
  799. }
  800. rv = ProcessRequest(fd, server);
  801. if (PR_SUCCESS != rv)
  802. TEST_LOG(
  803. cltsrv_log_file, TEST_LOG_ERROR,
  804. ("\t\tWorker(0x%p): server process ended abnormally\n", me));
  805. (void)PR_Close(fd); fd = NULL;
  806. PR_Lock(server->ml);
  807. pool->active -= 1;
  808. }
  809. }
  810. exit:
  811. PR_ClearInterrupt();
  812. PR_Unlock(server->ml);
  813. if (NULL != fd)
  814. {
  815. (void)PR_Shutdown(fd, PR_SHUTDOWN_BOTH);
  816. (void)PR_Close(fd);
  817. }
  818. TEST_LOG(
  819. cltsrv_log_file, TEST_LOG_NOTICE,
  820. ("\t\tWorker(0x%p): exiting [%u]\n", PR_GetCurrentThread(), pool->workers));
  821. PR_Lock(server->ml);
  822. pool->workers -= 1; /* undefine our existance */
  823. PR_REMOVE_AND_INIT_LINK(&worker->element);
  824. PR_NotifyCondVar(pool->exiting);
  825. PR_Unlock(server->ml);
  826. PR_DELETE(worker); /* destruction of the "worker" object */
  827. } /* Worker */
  828. static void PR_CALLBACK Server(void *arg)
  829. {
  830. PRStatus rv;
  831. PRNetAddr serverAddress;
  832. CSServer_t *server = (CSServer_t*)arg;
  833. PRThread *me = server->thread = PR_GetCurrentThread();
  834. PRSocketOptionData sockOpt;
  835. server->listener = PR_Socket(domain, SOCK_STREAM, protocol);
  836. sockOpt.option = PR_SockOpt_Reuseaddr;
  837. sockOpt.value.reuse_addr = PR_TRUE;
  838. rv = PR_SetSocketOption(server->listener, &sockOpt);
  839. TEST_ASSERT(PR_SUCCESS == rv);
  840. memset(&serverAddress, 0, sizeof(serverAddress));
  841. rv = PR_InitializeNetAddr(PR_IpAddrAny, DEFAULT_PORT, &serverAddress);
  842. rv = PR_Bind(server->listener, &serverAddress);
  843. TEST_ASSERT(PR_SUCCESS == rv);
  844. rv = PR_Listen(server->listener, server->backlog);
  845. TEST_ASSERT(PR_SUCCESS == rv);
  846. server->started = PR_IntervalNow();
  847. TimeOfDayMessage("Server started at", me);
  848. PR_Lock(server->ml);
  849. server->state = cs_run;
  850. PR_NotifyCondVar(server->stateChange);
  851. PR_Unlock(server->ml);
  852. /*
  853. ** Create the first worker (actually, a thread that accepts
  854. ** connections and then processes the work load as needed).
  855. ** From this point on, additional worker threads are created
  856. ** as they are needed by existing worker threads.
  857. */
  858. rv = CreateWorker(server, &server->pool);
  859. TEST_ASSERT(PR_SUCCESS == rv);
  860. /*
  861. ** From here on this thread is merely hanging around as the contact
  862. ** point for the main test driver. It's just waiting for the driver
  863. ** to declare the test complete.
  864. */
  865. TEST_LOG(
  866. cltsrv_log_file, TEST_LOG_VERBOSE,
  867. ("\tServer(0x%p): waiting for state change\n", me));
  868. PR_Lock(server->ml);
  869. while ((cs_run == server->state) && !Aborted(rv))
  870. {
  871. rv = PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT);
  872. }
  873. PR_Unlock(server->ml);
  874. PR_ClearInterrupt();
  875. TEST_LOG(
  876. cltsrv_log_file, TEST_LOG_INFO,
  877. ("\tServer(0x%p): shutting down workers\n", me));
  878. /*
  879. ** Get all the worker threads to exit. They know how to
  880. ** clean up after themselves, so this is just a matter of
  881. ** waiting for clorine in the pool to take effect. During
  882. ** this stage we're ignoring interrupts.
  883. */
  884. server->workers.minimum = server->workers.maximum = 0;
  885. PR_Lock(server->ml);
  886. while (!PR_CLIST_IS_EMPTY(&server->list))
  887. {
  888. PRCList *head = PR_LIST_HEAD(&server->list);
  889. CSWorker_t *worker = (CSWorker_t*)head;
  890. TEST_LOG(
  891. cltsrv_log_file, TEST_LOG_VERBOSE,
  892. ("\tServer(0x%p): interrupting worker(0x%p)\n", me, worker));
  893. rv = PR_Interrupt(worker->thread);
  894. TEST_ASSERT(PR_SUCCESS == rv);
  895. PR_REMOVE_AND_INIT_LINK(head);
  896. }
  897. while (server->pool.workers > 0)
  898. {
  899. TEST_LOG(
  900. cltsrv_log_file, TEST_LOG_NOTICE,
  901. ("\tServer(0x%p): waiting for %u workers to exit\n",
  902. me, server->pool.workers));
  903. (void)PR_WaitCondVar(server->pool.exiting, PR_INTERVAL_NO_TIMEOUT);
  904. }
  905. server->state = cs_exit;
  906. PR_NotifyCondVar(server->stateChange);
  907. PR_Unlock(server->ml);
  908. TEST_LOG(
  909. cltsrv_log_file, TEST_LOG_ALWAYS,
  910. ("\tServer(0x%p): stopped after %u operations and %u bytes\n",
  911. me, server->operations, server->bytesTransferred));
  912. if (NULL != server->listener) {
  913. PR_Close(server->listener);
  914. }
  915. server->stopped = PR_IntervalNow();
  916. } /* Server */
  917. static void WaitForCompletion(PRIntn execution)
  918. {
  919. while (execution > 0)
  920. {
  921. PRIntn dally = (execution > 30) ? 30 : execution;
  922. PR_Sleep(PR_SecondsToInterval(dally));
  923. if (pthread_stats) {
  924. PT_FPrintStats(debug_out, "\nPThread Statistics\n");
  925. }
  926. execution -= dally;
  927. }
  928. } /* WaitForCompletion */
  929. static void Help(void)
  930. {
  931. PR_fprintf(debug_out, "cltsrv test program usage:\n");
  932. PR_fprintf(debug_out, "\t-a <n> threads allowed in accept (5)\n");
  933. PR_fprintf(debug_out, "\t-b <n> backlock for listen (5)\n");
  934. PR_fprintf(debug_out, "\t-c <threads> number of clients to create (1)\n");
  935. PR_fprintf(debug_out, "\t-w <threads> minimal number of server threads (1)\n");
  936. PR_fprintf(debug_out, "\t-W <threads> maximum number of server threads (1)\n");
  937. PR_fprintf(debug_out, "\t-e <seconds> duration of the test in seconds (10)\n");
  938. PR_fprintf(debug_out, "\t-s <string> dsn name of server (localhost)\n");
  939. PR_fprintf(debug_out, "\t-G use GLOBAL threads (LOCAL)\n");
  940. PR_fprintf(debug_out, "\t-T <string> thread provider ('n' | 'p' | 'w')(n)\n");
  941. PR_fprintf(debug_out, "\t-X use XTP as transport (TCP)\n");
  942. PR_fprintf(debug_out, "\t-6 Use IPv6 (IPv4)\n");
  943. PR_fprintf(debug_out, "\t-v verbosity (accumulative) (0)\n");
  944. PR_fprintf(debug_out, "\t-p pthread statistics (FALSE)\n");
  945. PR_fprintf(debug_out, "\t-d debug mode (FALSE)\n");
  946. PR_fprintf(debug_out, "\t-h this message\n");
  947. } /* Help */
  948. static Verbosity IncrementVerbosity(void)
  949. {
  950. PRIntn verboge = (PRIntn)verbosity + 1;
  951. return (Verbosity)verboge;
  952. } /* IncrementVerbosity */
  953. int main(int argc, char **argv)
  954. {
  955. PRUintn index;
  956. PRBool boolean;
  957. CSClient_t *client;
  958. PRStatus rv, joinStatus;
  959. CSServer_t *server = NULL;
  960. char *thread_type;
  961. PRUintn backlog = DEFAULT_BACKLOG;
  962. PRUintn clients = DEFAULT_CLIENTS;
  963. const char *serverName = DEFAULT_SERVER;
  964. PRBool serverIsLocal = PR_TRUE;
  965. PRUintn accepting = ALLOWED_IN_ACCEPT;
  966. PRUintn workersMin = DEFAULT_WORKERS_MIN;
  967. PRUintn workersMax = DEFAULT_WORKERS_MAX;
  968. PRIntn execution = DEFAULT_EXECUTION_TIME;
  969. /*
  970. * -G use global threads
  971. * -a <n> threads allowed in accept
  972. * -b <n> backlock for listen
  973. * -c <threads> number of clients to create
  974. * -w <threads> minimal number of server threads
  975. * -W <threads> maximum number of server threads
  976. * -e <seconds> duration of the test in seconds
  977. * -s <string> dsn name of server (implies no server here)
  978. * -v verbosity
  979. */
  980. PLOptStatus os;
  981. PLOptState *opt = PL_CreateOptState(argc, argv, "GX6b:a:c:w:W:e:s:T:vdhp");
  982. #if defined(WIN32)
  983. thread_provider = thread_win32;
  984. #elif defined(_PR_PTHREADS)
  985. thread_provider = thread_pthread;
  986. #else
  987. thread_provider = thread_nspr;
  988. #endif
  989. debug_out = PR_GetSpecialFD(PR_StandardError);
  990. while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
  991. {
  992. if (PL_OPT_BAD == os) {
  993. continue;
  994. }
  995. switch (opt->option)
  996. {
  997. case 'G': /* use global threads */
  998. thread_scope = PR_GLOBAL_THREAD;
  999. break;
  1000. case 'X': /* use XTP as transport */
  1001. protocol = 36;
  1002. break;
  1003. case '6': /* Use IPv6 */
  1004. domain = PR_AF_INET6;
  1005. break;
  1006. case 'a': /* the value for accepting */
  1007. accepting = atoi(opt->value);
  1008. break;
  1009. case 'b': /* the value for backlock */
  1010. backlog = atoi(opt->value);
  1011. break;
  1012. case 'T': /* the thread provider */
  1013. if ('n' == *opt->value) {
  1014. thread_provider = thread_nspr;
  1015. }
  1016. else if ('p' == *opt->value) {
  1017. thread_provider = thread_pthread;
  1018. }
  1019. else if ('w' == *opt->value) {
  1020. thread_provider = thread_win32;
  1021. }
  1022. else {
  1023. Help();
  1024. return 2;
  1025. }
  1026. break;
  1027. case 'c': /* number of client threads */
  1028. clients = atoi(opt->value);
  1029. break;
  1030. case 'w': /* minimum server worker threads */
  1031. workersMin = atoi(opt->value);
  1032. break;
  1033. case 'W': /* maximum server worker threads */
  1034. workersMax = atoi(opt->value);
  1035. break;
  1036. case 'e': /* program execution time in seconds */
  1037. execution = atoi(opt->value);
  1038. break;
  1039. case 's': /* server's address */
  1040. serverName = opt->value;
  1041. break;
  1042. case 'v': /* verbosity */
  1043. verbosity = IncrementVerbosity();
  1044. break;
  1045. case 'd': /* debug mode */
  1046. debug_mode = PR_TRUE;
  1047. break;
  1048. case 'p': /* pthread mode */
  1049. pthread_stats = PR_TRUE;
  1050. break;
  1051. case 'h':
  1052. default:
  1053. Help();
  1054. return 2;
  1055. }
  1056. }
  1057. PL_DestroyOptState(opt);
  1058. if (0 != PL_strcmp(serverName, DEFAULT_SERVER)) {
  1059. serverIsLocal = PR_FALSE;
  1060. }
  1061. if (0 == execution) {
  1062. execution = DEFAULT_EXECUTION_TIME;
  1063. }
  1064. if (0 == workersMax) {
  1065. workersMax = DEFAULT_WORKERS_MAX;
  1066. }
  1067. if (0 == workersMin) {
  1068. workersMin = DEFAULT_WORKERS_MIN;
  1069. }
  1070. if (0 == accepting) {
  1071. accepting = ALLOWED_IN_ACCEPT;
  1072. }
  1073. if (0 == backlog) {
  1074. backlog = DEFAULT_BACKLOG;
  1075. }
  1076. if (workersMin > accepting) {
  1077. accepting = workersMin;
  1078. }
  1079. PR_STDIO_INIT();
  1080. TimeOfDayMessage("Client/Server started at", PR_GetCurrentThread());
  1081. cltsrv_log_file = PR_NewLogModule("cltsrv_log");
  1082. MY_ASSERT(NULL != cltsrv_log_file);
  1083. boolean = PR_SetLogFile("cltsrv.log");
  1084. MY_ASSERT(boolean);
  1085. if (serverIsLocal)
  1086. {
  1087. /* Establish the server */
  1088. TEST_LOG(
  1089. cltsrv_log_file, TEST_LOG_INFO,
  1090. ("main(0x%p): starting server\n", PR_GetCurrentThread()));
  1091. server = PR_NEWZAP(CSServer_t);
  1092. PR_INIT_CLIST(&server->list);
  1093. server->state = cs_init;
  1094. server->ml = PR_NewLock();
  1095. server->backlog = backlog;
  1096. server->port = DEFAULT_PORT;
  1097. server->workers.minimum = workersMin;
  1098. server->workers.maximum = workersMax;
  1099. server->workers.accepting = accepting;
  1100. server->stateChange = PR_NewCondVar(server->ml);
  1101. server->pool.exiting = PR_NewCondVar(server->ml);
  1102. server->pool.acceptComplete = PR_NewCondVar(server->ml);
  1103. TEST_LOG(
  1104. cltsrv_log_file, TEST_LOG_NOTICE,
  1105. ("main(0x%p): creating server thread\n", PR_GetCurrentThread()));
  1106. rv = NewThread(
  1107. Server, server, PR_PRIORITY_HIGH, PR_JOINABLE_THREAD);
  1108. TEST_ASSERT(PR_SUCCESS == rv);
  1109. TEST_LOG(
  1110. cltsrv_log_file, TEST_LOG_VERBOSE,
  1111. ("main(0x%p): waiting for server init\n", PR_GetCurrentThread()));
  1112. PR_Lock(server->ml);
  1113. while (server->state == cs_init) {
  1114. PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT);
  1115. }
  1116. PR_Unlock(server->ml);
  1117. TEST_LOG(
  1118. cltsrv_log_file, TEST_LOG_VERBOSE,
  1119. ("main(0x%p): server init complete (port #%d)\n",
  1120. PR_GetCurrentThread(), server->port));
  1121. }
  1122. if (clients != 0)
  1123. {
  1124. /* Create all of the clients */
  1125. PRHostEnt host;
  1126. char buffer[BUFFER_SIZE];
  1127. client = (CSClient_t*)PR_CALLOC(clients * sizeof(CSClient_t));
  1128. TEST_LOG(
  1129. cltsrv_log_file, TEST_LOG_VERBOSE,
  1130. ("main(0x%p): creating %d client threads\n",
  1131. PR_GetCurrentThread(), clients));
  1132. if (!serverIsLocal)
  1133. {
  1134. rv = PR_GetHostByName(serverName, buffer, BUFFER_SIZE, &host);
  1135. if (PR_SUCCESS != rv)
  1136. {
  1137. PL_FPrintError(PR_STDERR, "PR_GetHostByName");
  1138. return 2;
  1139. }
  1140. }
  1141. for (index = 0; index < clients; ++index)
  1142. {
  1143. client[index].state = cs_init;
  1144. client[index].ml = PR_NewLock();
  1145. if (serverIsLocal)
  1146. {
  1147. (void)PR_InitializeNetAddr(
  1148. PR_IpAddrLoopback, DEFAULT_PORT,
  1149. &client[index].serverAddress);
  1150. }
  1151. else
  1152. {
  1153. (void)PR_EnumerateHostEnt(
  1154. 0, &host, DEFAULT_PORT, &client[index].serverAddress);
  1155. }
  1156. client[index].stateChange = PR_NewCondVar(client[index].ml);
  1157. TEST_LOG(
  1158. cltsrv_log_file, TEST_LOG_INFO,
  1159. ("main(0x%p): creating client threads\n", PR_GetCurrentThread()));
  1160. rv = NewThread(
  1161. Client, &client[index], PR_PRIORITY_NORMAL, PR_JOINABLE_THREAD);
  1162. TEST_ASSERT(PR_SUCCESS == rv);
  1163. PR_Lock(client[index].ml);
  1164. while (cs_init == client[index].state) {
  1165. PR_WaitCondVar(client[index].stateChange, PR_INTERVAL_NO_TIMEOUT);
  1166. }
  1167. PR_Unlock(client[index].ml);
  1168. }
  1169. }
  1170. /* Then just let them go at it for a bit */
  1171. TEST_LOG(
  1172. cltsrv_log_file, TEST_LOG_ALWAYS,
  1173. ("main(0x%p): waiting for execution interval (%d seconds)\n",
  1174. PR_GetCurrentThread(), execution));
  1175. WaitForCompletion(execution);
  1176. TimeOfDayMessage("Shutting down", PR_GetCurrentThread());
  1177. if (clients != 0)
  1178. {
  1179. for (index = 0; index < clients; ++index)
  1180. {
  1181. TEST_LOG(cltsrv_log_file, TEST_LOG_STATUS,
  1182. ("main(0x%p): notifying client(0x%p) to stop\n",
  1183. PR_GetCurrentThread(), client[index].thread));
  1184. PR_Lock(client[index].ml);
  1185. if (cs_run == client[index].state)
  1186. {
  1187. client[index].state = cs_stop;
  1188. PR_Interrupt(client[index].thread);
  1189. while (cs_stop == client[index].state)
  1190. PR_WaitCondVar(
  1191. client[index].stateChange, PR_INTERVAL_NO_TIMEOUT);
  1192. }
  1193. PR_Unlock(client[index].ml);
  1194. TEST_LOG(cltsrv_log_file, TEST_LOG_VERBOSE,
  1195. ("main(0x%p): joining client(0x%p)\n",
  1196. PR_GetCurrentThread(), client[index].thread));
  1197. joinStatus = JoinThread(client[index].thread);
  1198. TEST_ASSERT(PR_SUCCESS == joinStatus);
  1199. PR_DestroyCondVar(client[index].stateChange);
  1200. PR_DestroyLock(client[index].ml);
  1201. }
  1202. PR_DELETE(client);
  1203. }
  1204. if (NULL != server)
  1205. {
  1206. /* All clients joined - retrieve the server */
  1207. TEST_LOG(
  1208. cltsrv_log_file, TEST_LOG_NOTICE,
  1209. ("main(0x%p): notifying server(0x%p) to stop\n",
  1210. PR_GetCurrentThread(), server->thread));
  1211. PR_Lock(server->ml);
  1212. server->state = cs_stop;
  1213. PR_Interrupt(server->thread);
  1214. while (cs_exit != server->state) {
  1215. PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT);
  1216. }
  1217. PR_Unlock(server->ml);
  1218. TEST_LOG(
  1219. cltsrv_log_file, TEST_LOG_NOTICE,
  1220. ("main(0x%p): joining server(0x%p)\n",
  1221. PR_GetCurrentThread(), server->thread));
  1222. joinStatus = JoinThread(server->thread);
  1223. TEST_ASSERT(PR_SUCCESS == joinStatus);
  1224. PR_DestroyCondVar(server->stateChange);
  1225. PR_DestroyCondVar(server->pool.exiting);
  1226. PR_DestroyCondVar(server->pool.acceptComplete);
  1227. PR_DestroyLock(server->ml);
  1228. PR_DELETE(server);
  1229. }
  1230. TEST_LOG(
  1231. cltsrv_log_file, TEST_LOG_ALWAYS,
  1232. ("main(0x%p): test complete\n", PR_GetCurrentThread()));
  1233. if (thread_provider == thread_win32) {
  1234. thread_type = "\nWin32 Thread Statistics\n";
  1235. }
  1236. else if (thread_provider == thread_pthread) {
  1237. thread_type = "\npthread Statistics\n";
  1238. }
  1239. else if (thread_provider == thread_sproc) {
  1240. thread_type = "\nsproc Statistics\n";
  1241. }
  1242. else {
  1243. PR_ASSERT(thread_provider == thread_nspr);
  1244. thread_type = "\nPRThread Statistics\nn";
  1245. }
  1246. PT_FPrintStats(debug_out, thread_type);
  1247. TimeOfDayMessage("Test exiting at", PR_GetCurrentThread());
  1248. PR_Cleanup();
  1249. return 0;
  1250. } /* main */
  1251. /* cltsrv.c */