tmocon.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  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. ** Name: tmocon.c
  8. **
  9. ** Description: test client socket connection.
  10. **
  11. ** Modification History:
  12. ** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
  13. ** The debug mode will print all of the printfs associated with this test.
  14. ** The regress mode will be the default mode. Since the regress tool limits
  15. ** the output to a one line status:PASS or FAIL,all of the printf statements
  16. ** have been handled with an if (debug_mode) statement.
  17. ***********************************************************************/
  18. /***********************************************************************
  19. ** Includes
  20. ***********************************************************************/
  21. /* Used to get the command line option */
  22. #include "plgetopt.h"
  23. #include "nspr.h"
  24. #include "pprio.h"
  25. #include "plerror.h"
  26. #include "plgetopt.h"
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. /* for getcwd */
  31. #if defined(XP_UNIX) || defined (XP_OS2)
  32. #include <unistd.h>
  33. #elif defined(XP_PC)
  34. #include <direct.h>
  35. #endif
  36. #ifdef WINCE
  37. #include <windows.h>
  38. char *getcwd(char *buf, size_t size)
  39. {
  40. wchar_t wpath[MAX_PATH];
  41. _wgetcwd(wpath, MAX_PATH);
  42. WideCharToMultiByte(CP_ACP, 0, wpath, -1, buf, size, 0, 0);
  43. }
  44. #endif
  45. #ifdef DEBUG
  46. #define PORT_INC_DO +100
  47. #else
  48. #define PORT_INC_DO
  49. #endif
  50. #ifdef IS_64
  51. #define PORT_INC_3264 +200
  52. #else
  53. #define PORT_INC_3264
  54. #endif
  55. #define BASE_PORT 9867 PORT_INC_DO PORT_INC_3264
  56. #define DEFAULT_DALLY 1
  57. #define DEFAULT_THREADS 1
  58. #define DEFAULT_TIMEOUT 10
  59. #define DEFAULT_MESSAGES 100
  60. #define DEFAULT_MESSAGESIZE 100
  61. static PRFileDesc *debug_out = NULL;
  62. typedef struct Shared
  63. {
  64. PRBool random;
  65. PRBool failed;
  66. PRBool intermittant;
  67. PRIntn debug;
  68. PRInt32 messages;
  69. PRIntervalTime dally;
  70. PRIntervalTime timeout;
  71. PRInt32 message_length;
  72. PRNetAddr serverAddress;
  73. } Shared;
  74. static PRIntervalTime Timeout(const Shared *shared)
  75. {
  76. PRIntervalTime timeout = shared->timeout;
  77. if (shared->random)
  78. {
  79. PRIntervalTime quarter = timeout >> 2; /* one quarter of the interval */
  80. PRUint32 random = rand() % quarter; /* something in[0..timeout / 4) */
  81. timeout = (((3 * quarter) + random) >> 2) + quarter; /* [75..125)% */
  82. }
  83. return timeout;
  84. } /* Timeout */
  85. static void CauseTimeout(const Shared *shared)
  86. {
  87. if (shared->intermittant) {
  88. PR_Sleep(Timeout(shared));
  89. }
  90. } /* CauseTimeout */
  91. static PRStatus MakeReceiver(Shared *shared)
  92. {
  93. PRStatus rv = PR_FAILURE;
  94. if (PR_IsNetAddrType(&shared->serverAddress, PR_IpAddrLoopback))
  95. {
  96. char *argv[3];
  97. char path[1024 + sizeof("/tmoacc")];
  98. getcwd(path, sizeof(path));
  99. (void)strcat(path, "/tmoacc");
  100. #ifdef XP_PC
  101. (void)strcat(path, ".exe");
  102. #endif
  103. argv[0] = path;
  104. if (shared->debug > 0)
  105. {
  106. argv[1] = "-d";
  107. argv[2] = NULL;
  108. }
  109. else {
  110. argv[1] = NULL;
  111. }
  112. if (shared->debug > 1) {
  113. PR_fprintf(debug_out, " creating accept process %s ...", path);
  114. }
  115. fflush(stdout);
  116. rv = PR_CreateProcessDetached(path, argv, NULL, NULL);
  117. if (PR_SUCCESS == rv)
  118. {
  119. if (shared->debug > 1) {
  120. PR_fprintf(debug_out, " wait 5 seconds");
  121. }
  122. if (shared->debug > 1) {
  123. PR_fprintf(debug_out, " before connecting to accept process ...");
  124. }
  125. fflush(stdout);
  126. PR_Sleep(PR_SecondsToInterval(5));
  127. return rv;
  128. }
  129. shared->failed = PR_TRUE;
  130. if (shared->debug > 0) {
  131. PL_FPrintError(debug_out, "PR_CreateProcessDetached failed");
  132. }
  133. }
  134. return rv;
  135. } /* MakeReceiver */
  136. static void Connect(void *arg)
  137. {
  138. PRStatus rv;
  139. char *buffer = NULL;
  140. PRFileDesc *clientSock;
  141. Shared *shared = (Shared*)arg;
  142. PRInt32 loop, bytes, flags = 0;
  143. struct Descriptor {
  144. PRInt32 length;
  145. PRUint32 checksum;
  146. } descriptor;
  147. debug_out = (0 == shared->debug) ? NULL : PR_GetSpecialFD(PR_StandardError);
  148. buffer = (char*)PR_MALLOC(shared->message_length);
  149. for (bytes = 0; bytes < shared->message_length; ++bytes) {
  150. buffer[bytes] = (char)bytes;
  151. }
  152. descriptor.checksum = 0;
  153. for (bytes = 0; bytes < shared->message_length; ++bytes)
  154. {
  155. PRUint32 overflow = descriptor.checksum & 0x80000000;
  156. descriptor.checksum = (descriptor.checksum << 1);
  157. if (0x00000000 != overflow) {
  158. descriptor.checksum += 1;
  159. }
  160. descriptor.checksum += buffer[bytes];
  161. }
  162. descriptor.checksum = PR_htonl(descriptor.checksum);
  163. for (loop = 0; loop < shared->messages; ++loop)
  164. {
  165. if (shared->debug > 1) {
  166. PR_fprintf(debug_out, "[%d]socket ... ", loop);
  167. }
  168. clientSock = PR_NewTCPSocket();
  169. if (clientSock)
  170. {
  171. /*
  172. * We need to slow down the rate of generating connect requests,
  173. * otherwise the listen backlog queue on the accept side may
  174. * become full and we will get connection refused or timeout
  175. * error.
  176. */
  177. PR_Sleep(shared->dally);
  178. if (shared->debug > 1)
  179. {
  180. char buf[128];
  181. PR_NetAddrToString(&shared->serverAddress, buf, sizeof(buf));
  182. PR_fprintf(debug_out, "connecting to %s ... ", buf);
  183. }
  184. rv = PR_Connect(
  185. clientSock, &shared->serverAddress, Timeout(shared));
  186. if (PR_SUCCESS == rv)
  187. {
  188. PRInt32 descriptor_length = (loop < (shared->messages - 1)) ?
  189. shared->message_length : 0;
  190. descriptor.length = PR_htonl(descriptor_length);
  191. if (shared->debug > 1)
  192. PR_fprintf(
  193. debug_out, "sending %d bytes ... ", descriptor_length);
  194. CauseTimeout(shared); /* might cause server to timeout */
  195. bytes = PR_Send(
  196. clientSock, &descriptor, sizeof(descriptor),
  197. flags, Timeout(shared));
  198. if (bytes != sizeof(descriptor))
  199. {
  200. shared->failed = PR_TRUE;
  201. if (shared->debug > 0) {
  202. PL_FPrintError(debug_out, "PR_Send failed");
  203. }
  204. }
  205. if (0 != descriptor_length)
  206. {
  207. CauseTimeout(shared);
  208. bytes = PR_Send(
  209. clientSock, buffer, descriptor_length,
  210. flags, Timeout(shared));
  211. if (bytes != descriptor_length)
  212. {
  213. shared->failed = PR_TRUE;
  214. if (shared->debug > 0) {
  215. PL_FPrintError(debug_out, "PR_Send failed");
  216. }
  217. }
  218. }
  219. if (shared->debug > 1) {
  220. PR_fprintf(debug_out, "closing ... ");
  221. }
  222. rv = PR_Shutdown(clientSock, PR_SHUTDOWN_BOTH);
  223. rv = PR_Close(clientSock);
  224. if (shared->debug > 1)
  225. {
  226. if (PR_SUCCESS == rv) {
  227. PR_fprintf(debug_out, "\n");
  228. }
  229. else {
  230. PL_FPrintError(debug_out, "shutdown failed");
  231. }
  232. }
  233. }
  234. else
  235. {
  236. if (shared->debug > 1) {
  237. PL_FPrintError(debug_out, "connect failed");
  238. }
  239. PR_Close(clientSock);
  240. if ((loop == 0) && (PR_GetError() == PR_CONNECT_REFUSED_ERROR))
  241. {
  242. if (MakeReceiver(shared) == PR_FAILURE) {
  243. break;
  244. }
  245. }
  246. else
  247. {
  248. if (shared->debug > 1) {
  249. PR_fprintf(debug_out, " exiting\n");
  250. }
  251. break;
  252. }
  253. }
  254. }
  255. else
  256. {
  257. shared->failed = PR_TRUE;
  258. if (shared->debug > 0) {
  259. PL_FPrintError(debug_out, "create socket");
  260. }
  261. break;
  262. }
  263. }
  264. PR_DELETE(buffer);
  265. } /* Connect */
  266. int Tmocon(int argc, char **argv)
  267. {
  268. /*
  269. * USAGE
  270. * -d turn on debugging output (default = off)
  271. * -v turn on verbose output (default = off)
  272. * -h <n> dns name of host serving the connection (default = self)
  273. * -i dally intermittantly to cause timeouts (default = off)
  274. * -m <n> number of messages to send (default = 100)
  275. * -s <n> size of each message (default = 100)
  276. * -t <n> number of threads sending (default = 1)
  277. * -G use global threads (default = local)
  278. * -T <n> timeout on I/O operations (seconds) (default = 10)
  279. * -D <n> dally between connect requests (seconds)(default = 0)
  280. * -R randomize the dally types around 'T' (default = no)
  281. */
  282. PRStatus rv;
  283. int exitStatus;
  284. PLOptStatus os;
  285. Shared *shared = NULL;
  286. PRThread **thread = NULL;
  287. PRIntn index, threads = DEFAULT_THREADS;
  288. PRThreadScope thread_scope = PR_LOCAL_THREAD;
  289. PRInt32 dally = DEFAULT_DALLY, timeout = DEFAULT_TIMEOUT;
  290. PLOptState *opt = PL_CreateOptState(argc, argv, "divGRh:m:s:t:T:D:");
  291. shared = PR_NEWZAP(Shared);
  292. shared->debug = 0;
  293. shared->failed = PR_FALSE;
  294. shared->random = PR_FALSE;
  295. shared->messages = DEFAULT_MESSAGES;
  296. shared->message_length = DEFAULT_MESSAGESIZE;
  297. PR_STDIO_INIT();
  298. memset(&shared->serverAddress, 0, sizeof(shared->serverAddress));
  299. rv = PR_InitializeNetAddr(PR_IpAddrLoopback, BASE_PORT, &shared->serverAddress);
  300. PR_ASSERT(PR_SUCCESS == rv);
  301. while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
  302. {
  303. if (PL_OPT_BAD == os) {
  304. continue;
  305. }
  306. switch (opt->option)
  307. {
  308. case 'd':
  309. if (0 == shared->debug) {
  310. shared->debug = 1;
  311. }
  312. break;
  313. case 'v':
  314. if (0 == shared->debug) {
  315. shared->debug = 2;
  316. }
  317. break;
  318. case 'i':
  319. shared->intermittant = PR_TRUE;
  320. break;
  321. case 'R':
  322. shared->random = PR_TRUE;
  323. break;
  324. case 'G':
  325. thread_scope = PR_GLOBAL_THREAD;
  326. break;
  327. case 'h': /* the value for backlock */
  328. {
  329. PRIntn es = 0;
  330. PRHostEnt host;
  331. char buffer[1024];
  332. (void)PR_GetHostByName(
  333. opt->value, buffer, sizeof(buffer), &host);
  334. es = PR_EnumerateHostEnt(
  335. es, &host, BASE_PORT, &shared->serverAddress);
  336. PR_ASSERT(es > 0);
  337. }
  338. break;
  339. case 'm': /* number of messages to send */
  340. shared->messages = atoi(opt->value);
  341. break;
  342. case 't': /* number of threads sending */
  343. threads = atoi(opt->value);
  344. break;
  345. case 'D': /* dally time between transmissions */
  346. dally = atoi(opt->value);
  347. break;
  348. case 'T': /* timeout on I/O operations */
  349. timeout = atoi(opt->value);
  350. break;
  351. case 's': /* total size of each message */
  352. shared->message_length = atoi(opt->value);
  353. break;
  354. default:
  355. break;
  356. }
  357. }
  358. PL_DestroyOptState(opt);
  359. if (0 == timeout) {
  360. timeout = DEFAULT_TIMEOUT;
  361. }
  362. if (0 == threads) {
  363. threads = DEFAULT_THREADS;
  364. }
  365. if (0 == shared->messages) {
  366. shared->messages = DEFAULT_MESSAGES;
  367. }
  368. if (0 == shared->message_length) {
  369. shared->message_length = DEFAULT_MESSAGESIZE;
  370. }
  371. shared->dally = PR_SecondsToInterval(dally);
  372. shared->timeout = PR_SecondsToInterval(timeout);
  373. thread = (PRThread**)PR_CALLOC(threads * sizeof(PRThread*));
  374. for (index = 0; index < threads; ++index)
  375. thread[index] = PR_CreateThread(
  376. PR_USER_THREAD, Connect, shared,
  377. PR_PRIORITY_NORMAL, thread_scope,
  378. PR_JOINABLE_THREAD, 0);
  379. for (index = 0; index < threads; ++index) {
  380. rv = PR_JoinThread(thread[index]);
  381. }
  382. PR_DELETE(thread);
  383. PR_fprintf(
  384. PR_GetSpecialFD(PR_StandardError), "%s\n",
  385. ((shared->failed) ? "FAILED" : "PASSED"));
  386. exitStatus = (shared->failed) ? 1 : 0;
  387. PR_DELETE(shared);
  388. return exitStatus;
  389. }
  390. int main(int argc, char **argv)
  391. {
  392. return (PR_VersionCheck(PR_VERSION)) ?
  393. PR_Initialize(Tmocon, argc, argv, 4) : -1;
  394. } /* main */
  395. /* tmocon.c */