rsearch.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2006 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. /*
  42. * XP port of dboreham's NT tool "repeated_search"
  43. * robey, march 1998
  44. */
  45. #ifdef LINUX
  46. #include <sys/param.h>
  47. #include <sys/sysinfo.h>
  48. #include <getopt.h>
  49. #endif
  50. #include <stdio.h>
  51. #include <stdlib.h>
  52. #ifdef XP_UNIX
  53. #include <unistd.h>
  54. #endif
  55. #include "nspr.h"
  56. #include "rsearch.h"
  57. #include "nametable.h"
  58. #include "searchthread.h"
  59. #include "ldap.h"
  60. #define DEFAULT_HOSTNAME "localhost"
  61. #define DEFAULT_PORT 389
  62. #define DEFAULT_THREADS 1
  63. #define DEFAULT_INTERVAL 10000
  64. void usage()
  65. {
  66. printf("\nUsage: rsearch -D binddn -w bindpw -s suffix -f filter [options]\n"
  67. "-\\? -- print Usage (this message)\n"
  68. "-H -- print Usage (this message)\n"
  69. "-h host -- ldap server host (default: %s)\n"
  70. "-p port -- ldap server port (default: %d)\n"
  71. "-S scope -- search SCOPE [%d,%d,or %d] (default: %d)\n"
  72. "-b -- bind before every operation\n"
  73. "-u -- don't unbind -- just close the connection\n"
  74. "-L -- set linger -- connection discarded when closed\n"
  75. "-N -- No operation -- just bind (ignore mdc)\n"
  76. "-v -- verbose\n"
  77. "-y -- nodelay\n"
  78. "-q -- quiet\n"
  79. #ifndef NDSRK
  80. "-l -- logging\n"
  81. #endif /* NDSRK */
  82. "-m -- operaton: modify non-indexed attr (description). -B required\n"
  83. "-M -- operaton: modify indexed attr (telephonenumber). -B required\n"
  84. "-d -- operaton: delete. -B required\n"
  85. "-c -- operaton: compare. -B required\n"
  86. "-i file -- name file; used for the search filter\n"
  87. "-B file -- [DN and] UID file (use '-B \\?' to see the format)\n"
  88. "-A attrs -- list of attributes for search request\n"
  89. "-a file -- list of attributes for search request in a file\n"
  90. " -- (use '-a \\?' to see the format ; -a & -A are mutually exclusive)\n"
  91. "-n number -- (reserved for future use)\n"
  92. "-o number -- Search time limit, in seconds; (default: 30; no time limit: 0)\n"
  93. "-j number -- sample interval, in seconds (default: %u)\n"
  94. "-t number -- threads (default: %d)\n"
  95. "-T number -- Time limit, in seconds; cmd stops when exceeds <number>\n"
  96. "-V -- show running average\n"
  97. "-C num -- take num samples, then stop\n"
  98. "-R num -- drop connection & reconnect every num searches\n"
  99. "-x -- Use -B file for binding; ignored if -B is not given\n"
  100. "\n",
  101. DEFAULT_HOSTNAME, DEFAULT_PORT,
  102. LDAP_SCOPE_BASE, LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE,
  103. LDAP_SCOPE_SUBTREE,
  104. (DEFAULT_INTERVAL/1000), DEFAULT_THREADS);
  105. exit(1);
  106. }
  107. void usage_B()
  108. {
  109. printf("\nFormat of the file for the '-B <file>' option:\n"
  110. "(Assuming each passwd is identical to its corresponding UID.)\n"
  111. "\n"
  112. "Format 1.\n"
  113. "=========\n"
  114. "UID: <uid>\n"
  115. "...\n"
  116. "\n"
  117. "Format 2.\n"
  118. "=========\n"
  119. "DN: <dn>\n"
  120. "UID: <uid>\n"
  121. "...\n"
  122. "\n");
  123. }
  124. void usage_A()
  125. {
  126. printf("\nNote: -A and -a are mutually exclusive options\n");
  127. printf("\nFormat of the file for the '-a <file>' option:\n"
  128. "\n"
  129. "Format :\n"
  130. "=========\n"
  131. "<attr>\n"
  132. "<attr>\n"
  133. "...\n"
  134. "\n");
  135. }
  136. /*
  137. * Convert a string of the form "foo bar baz"
  138. * into an array of strings. Returns a pointer
  139. * to allocated memory. Array contains pointers
  140. * to the string passed in. So the array needs freed,
  141. * but the pointers don't.
  142. */
  143. char **string_to_list(char* s)
  144. {
  145. int string_count = 0;
  146. int in_space = 1;
  147. char *p;
  148. for (p = s; *p != '\0'; p++) {
  149. if (in_space) {
  150. if (' ' != *p) {
  151. /* We just found the beginning of a string */
  152. string_count++;
  153. in_space = 0;
  154. }
  155. }
  156. else if (' ' == *p) {
  157. /* Back in space again */
  158. in_space = 1;
  159. }
  160. }
  161. /* Now we have the suckers counted */
  162. if (string_count > 0) {
  163. char **return_array = (char **)malloc((string_count+1)*sizeof(char *));
  164. int index = 0;
  165. in_space = 1;
  166. for (p = s; *p != '\0'; p++) {
  167. if (in_space) {
  168. if (' ' != *p) {
  169. /* We just found the beginning of a string */
  170. return_array[index++] = p;
  171. in_space = 0;
  172. }
  173. }
  174. else if (' ' == *p) {
  175. /* Back in space again */
  176. in_space = 1;
  177. *p = '\0';
  178. }
  179. }
  180. return_array[index] = 0;
  181. return return_array;
  182. }
  183. else return 0;
  184. }
  185. /* global data for the threads to share */
  186. char *hostname = DEFAULT_HOSTNAME;
  187. int port = DEFAULT_PORT;
  188. int numeric = 0;
  189. int searchTimelimit = 30;
  190. int threadCount = DEFAULT_THREADS;
  191. int verbose = 0;
  192. int logging = 0;
  193. int doBind = 0;
  194. int cool = 0;
  195. int quiet = 0;
  196. int noDelay = 0;
  197. int noUnBind = 0;
  198. int noOp = 0;
  199. int showRunningAvg = 0;
  200. int countLimit = 0;
  201. int reconnect = 0;
  202. char *suffix = NULL;
  203. char *filter = NULL;
  204. char *nameFile = 0;
  205. char *searchDatFile = 0;
  206. char *attrFile = 0;
  207. char *bindDN = NULL;
  208. char *bindPW = NULL;
  209. char **attrToReturn = 0;
  210. char *attrList = 0;
  211. Operation opType = op_search;
  212. NameTable *ntable = NULL;
  213. NameTable *attrTable = NULL;
  214. SDatTable *sdattable = NULL;
  215. int sampleInterval = DEFAULT_INTERVAL;
  216. int timeLimit = 0;
  217. int setLinger = 0;
  218. int useBFile = 0;
  219. int myScope = LDAP_SCOPE_SUBTREE;
  220. int main(int argc, char** argv)
  221. {
  222. int index = 0, numThreads, numDead = 0;
  223. int ch;
  224. int lifeTime;
  225. SearchThread **threads;
  226. PRUint32 total;
  227. double rate, val, cumrate;
  228. double sumVal;
  229. int counter;
  230. if (argc == 1) {
  231. usage();
  232. exit(1);
  233. }
  234. while ((ch = getopt(argc, argv,
  235. "B:a:j:i:h:s:f:p:o:t:T:D:w:n:A:S:C:R:bvlyqmMcduNLHx?V"))
  236. != EOF)
  237. switch (ch) {
  238. case 'h':
  239. hostname = optarg;
  240. break;
  241. case 's':
  242. suffix = optarg;
  243. break;
  244. case 'f':
  245. filter = optarg;
  246. break;
  247. case 'i':
  248. nameFile = optarg;
  249. break;
  250. case 'B':
  251. if (optarg[0] == '?') {
  252. usage_B();
  253. exit(1);
  254. }
  255. searchDatFile = optarg;
  256. break;
  257. case 'D':
  258. bindDN = optarg;
  259. break;
  260. case 'w':
  261. bindPW = optarg;
  262. break;
  263. case 'A':
  264. if (!attrFile)
  265. attrList = optarg;
  266. else
  267. usage();
  268. break;
  269. case 'p':
  270. port = atoi(optarg);
  271. break;
  272. case 'S':
  273. myScope = atoi(optarg);
  274. if (myScope < LDAP_SCOPE_BASE || myScope > LDAP_SCOPE_SUBTREE)
  275. myScope = LDAP_SCOPE_SUBTREE;
  276. break;
  277. case 'C':
  278. countLimit = atoi(optarg);
  279. break;
  280. case 'b':
  281. doBind = 1;
  282. break;
  283. case 'u':
  284. noUnBind = 1;
  285. break;
  286. case 'L':
  287. setLinger = 1;
  288. break;
  289. case 'n':
  290. numeric = atoi(optarg);
  291. break;
  292. case 'o':
  293. searchTimelimit = atoi(optarg);
  294. break;
  295. case 't':
  296. threadCount = atoi(optarg);
  297. break;
  298. case 'j':
  299. sampleInterval = atoi(optarg) * 1000;
  300. break;
  301. case 'v':
  302. verbose = 1;
  303. break;
  304. case 'q':
  305. quiet = 1;
  306. break;
  307. case 'l':
  308. logging = 1;
  309. break;
  310. case 'y':
  311. noDelay = 1;
  312. break;
  313. case 'm':
  314. opType = op_modify;
  315. break;
  316. case 'M':
  317. opType = op_idxmodify;
  318. break;
  319. case 'd':
  320. opType = op_delete;
  321. break;
  322. case 'c':
  323. opType = op_compare;
  324. break;
  325. case 'N':
  326. noOp = 1;
  327. doBind = 1; /* no use w/o this */
  328. break;
  329. case 'T':
  330. timeLimit = atoi(optarg);
  331. break;
  332. case 'V':
  333. showRunningAvg = 1;
  334. break;
  335. case 'R':
  336. reconnect = atoi(optarg);
  337. break;
  338. case 'x':
  339. useBFile = 1;
  340. break;
  341. case 'a':
  342. if (optarg[0] == '?') {
  343. usage_A();
  344. exit(1);
  345. }
  346. if (!attrList)
  347. attrFile = optarg;
  348. else
  349. usage();
  350. break;
  351. case '?':
  352. case 'H':
  353. default :
  354. usage();
  355. }
  356. if ( !suffix || !filter || !bindDN || !bindPW ) {
  357. printf("rsearch: missing option\n");
  358. usage();
  359. }
  360. if ( timeLimit < 0 || threadCount <= 0 || sampleInterval <= 0 ) {
  361. printf("rsearch: invalid option value\n");
  362. usage();
  363. }
  364. argc -= optind;
  365. argv += optind;
  366. PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 0);
  367. ntable = nt_new(0);
  368. if (nameFile) {
  369. if (!nt_load(ntable, nameFile)) {
  370. printf("Failed to read name table\n");
  371. exit(1);
  372. }
  373. }
  374. attrTable = nt_new(0);
  375. if (attrFile)
  376. {
  377. if (!nt_load(attrTable , attrFile))
  378. {
  379. printf ("Failed to read attr name table\n");
  380. exit(1);
  381. }
  382. }
  383. sdattable = sdt_new(0);
  384. if (searchDatFile) {
  385. if (!sdt_load(sdattable, searchDatFile)) {
  386. printf("Failed to read search data table: %s\n", searchDatFile);
  387. exit(1);
  388. }
  389. }
  390. if (attrList)
  391. attrToReturn = string_to_list(attrList);
  392. /* a "vector" */
  393. threads = (SearchThread **)malloc(threadCount * sizeof(SearchThread *));
  394. while (threadCount--) {
  395. SearchThread *st;
  396. PRThread *thr;
  397. st = st_new();
  398. thr = PR_CreateThread(PR_SYSTEM_THREAD, search_start,
  399. (void *)st, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
  400. PR_JOINABLE_THREAD, 0);
  401. st_setThread(st, thr, index+1);
  402. threads[index++] = st;
  403. }
  404. numThreads = index;
  405. printf("rsearch: %d threads launched.\n\n", numThreads);
  406. lifeTime = 0;
  407. counter = 0;
  408. sumVal = 0;
  409. cumrate = 0.0;
  410. while (numThreads) {
  411. int x, alive;
  412. PR_Sleep(PR_MillisecondsToInterval(sampleInterval));
  413. counter++;
  414. lifeTime += sampleInterval/1000;
  415. /* now check for deadies */
  416. for (x = 0; x < numThreads; x++) {
  417. alive = st_alive(threads[x]);
  418. if (alive < 1) {
  419. int limit = -1 * (searchTimelimit>timeLimit?searchTimelimit:timeLimit + 40) * 1000 / sampleInterval;
  420. int y;
  421. PRThread *tid;
  422. printf("T%d no heartbeat", st_getThread(threads[x], &tid));
  423. if (alive <= limit) {
  424. printf(" -- Dead thread being reaped.\n");
  425. PR_JoinThread(tid);
  426. for (y = x+1; y < numThreads; y++)
  427. threads[y-1] = threads[y];
  428. numThreads--;
  429. numDead++;
  430. x--;
  431. }
  432. else
  433. printf(" (waiting)\n");
  434. }
  435. }
  436. /* print out stats */
  437. total = 0;
  438. for (x = 0; x < numThreads; x++) {
  439. PRUint32 count, min, max;
  440. st_getCountMinMax(threads[x], &count, &min, &max);
  441. total += count;
  442. if (!quiet && verbose)
  443. printf("T%d min=%4ums, max=%4ums, count = %u\n",
  444. st_getThread(threads[x], NULL), min, max, count);
  445. }
  446. rate = (double)total / (double)numThreads;
  447. val = 1000.0 * (double)total / (double)sampleInterval;
  448. cumrate += rate;
  449. if ((numThreads > 1) || (!verbose)) {
  450. if (!quiet) {
  451. if (showRunningAvg)
  452. printf("Rate: %7.2f/thr (cumul rate: %7.2f/thr)\n",
  453. rate, cumrate/(double)counter);
  454. else
  455. printf("Rate: %7.2f/thr (%6.2f/sec =%7.4fms/op), "
  456. "total:%6u (%d thr)\n",
  457. rate, val, (double)1000.0/val, total, numThreads);
  458. }
  459. }
  460. if (countLimit && (counter >= countLimit)) {
  461. printf("Thank you, and good night.\n");
  462. exit(0);
  463. }
  464. if (timeLimit && (lifeTime >= timeLimit)) {
  465. double tmpv = (val + sumVal)/counter;
  466. if (verbose)
  467. printf("%d sec >= %d\n", lifeTime, timeLimit);
  468. printf("Final Average rate: "
  469. "%6.2f/sec = %6.4fmsec/op, total:%6u\n",
  470. tmpv,
  471. (double)1000.0/tmpv,
  472. total);
  473. exit(0);
  474. }
  475. sumVal += val;
  476. /* watchdogs were reset when we fetched the min/max counters */
  477. }
  478. printf("All threads died. (?)\n");
  479. exit(1);
  480. }