1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 *
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
8 *
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
13 *
14 * The Original Code is Mozilla Communicator client code, released
15 * March 31, 1998.
16 *
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998-1999
20 * the Initial Developer. All Rights Reserved.
21 *
22 * Contributor(s):
23 *
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
35 *
36 * ***** END LICENSE BLOCK ***** */
37 #include <nspr.h>
38 #include <stdio.h>
39 #include <ldap.h>
40
41 #define NAME "cn=Directory Manager"
42 #define PASSWORD "secret99"
43 #define BASE "dc=example,dc=com"
44
45 static int simplebind(LDAP* ld, char* msg, int tries);
46 static void search_thread(void*);
47 static void modify_thread(void*);
48 static void add_thread(void*);
49 static void delete_thread(void*);
50 static void set_ld_error();
51 static int get_ld_error();
52 static void set_errno();
53 static int get_errno();
54 static void tsd_setup();
55 static void* my_mutex_alloc(void);
56 static void my_mutex_free(void*);
57 static int my_mutex_lock(void*);
58 static int my_mutex_unlock(void*);
59 static LDAPHostEnt* my_gethostbyname(const char* name, LDAPHostEnt* result,
60 char* buffer, int buflen, int* statusp,
61 void* extradata);
62 static LDAPHostEnt* my_gethostbyaddr(const char* addr, int length, int type,
63 LDAPHostEnt* result, char* buffer,
64 int buflen, int* statusp, void* extradata);
65 static LDAPHostEnt* copyPRHostEnt2LDAPHostEnt(LDAPHostEnt* ldhp,
66 PRHostEnt* prhp);
67
68 typedef struct ldapmsgwrapper {
69 LDAPMessage* lmw_messagep;
70 struct ldapmsgwrapper* lmw_next;
71 } ldapmsgwrapper;
72
73 #define CONNECTION_ERROR(lderr) \
74 ((lderr) == LDAP_SERVER_DOWN || (lderr) == LDAP_CONNECT_ERROR)
75
76 LDAP* ld;
77 PRUintn tsdindex;
78 #ifdef LDAP_MEMCACHE
79 LDAPMemCache* memcache = NULL;
80 # define MEMCACHE_SIZE (256 * 1024) /* 256K bytes */
81 # define MEMCACHE_TTL (15 * 60) /* 15 minutes */
82 #endif
83
main(int argc,char ** argv)84 main(int argc, char** argv) {
85 PRThread *search_tid, *search_tid2, *search_tid3;
86 PRThread *search_tid4, *modify_tid, *add_tid;
87 PRThread* delete_tid;
88 struct ldap_thread_fns tfns;
89 struct ldap_dns_fns dnsfns;
90 int rc;
91
92 if (argc != 3) {
93 fprintf(stderr, "usage: %s host port\n", argv[0]);
94 exit(1);
95 }
96
97 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
98 if (PR_NewThreadPrivateIndex(&tsdindex, NULL) != PR_SUCCESS) {
99 perror("PR_NewThreadPrivateIndex");
100 exit(1);
101 }
102 tsd_setup(); /* for main thread */
103
104 if ((ld = ldap_init(argv[1], atoi(argv[2]))) == NULL) {
105 perror("ldap_open");
106 exit(1);
107 }
108
109 /* set thread function pointers */
110 memset(&tfns, '\0', sizeof(struct ldap_thread_fns));
111 tfns.ltf_mutex_alloc = my_mutex_alloc;
112 tfns.ltf_mutex_free = my_mutex_free;
113 tfns.ltf_mutex_lock = my_mutex_lock;
114 tfns.ltf_mutex_unlock = my_mutex_unlock;
115 tfns.ltf_get_errno = get_errno;
116 tfns.ltf_set_errno = set_errno;
117 tfns.ltf_get_lderrno = get_ld_error;
118 tfns.ltf_set_lderrno = set_ld_error;
119 tfns.ltf_lderrno_arg = NULL;
120 if (ldap_set_option(ld, LDAP_OPT_THREAD_FN_PTRS, (void*)&tfns) != 0) {
121 ldap_perror(ld, "ldap_set_option: thread functions");
122 exit(1);
123 }
124
125 /* set DNS function pointers */
126 memset(&dnsfns, '\0', sizeof(struct ldap_dns_fns));
127 dnsfns.lddnsfn_bufsize = PR_NETDB_BUF_SIZE;
128 dnsfns.lddnsfn_gethostbyname = my_gethostbyname;
129 dnsfns.lddnsfn_gethostbyaddr = my_gethostbyaddr;
130 if (ldap_set_option(ld, LDAP_OPT_DNS_FN_PTRS, (void*)&dnsfns) != 0) {
131 ldap_perror(ld, "ldap_set_option: DNS functions");
132 exit(1);
133 }
134
135 #ifdef LDAP_MEMCACHE
136 /* create the in-memory cache */
137 if ((rc = ldap_memcache_init(MEMCACHE_TTL, MEMCACHE_SIZE, NULL, &tfns,
138 &memcache)) != LDAP_SUCCESS) {
139 fprintf(stderr, "ldap_memcache_init failed - %s\n", ldap_err2string(rc));
140 exit(1);
141 }
142 if ((rc = ldap_memcache_set(ld, memcache)) != LDAP_SUCCESS) {
143 fprintf(stderr, "ldap_memcache_set failed - %s\n", ldap_err2string(rc));
144 exit(1);
145 }
146 #endif
147
148 /*
149 * set option so that the next call to ldap_simple_bind_s() after
150 * the server connection is lost will attempt to reconnect.
151 */
152 if (ldap_set_option(ld, LDAP_OPT_RECONNECT, LDAP_OPT_ON) != 0) {
153 ldap_perror(ld, "ldap_set_option: reconnect");
154 exit(1);
155 }
156
157 /* initial bind */
158 if (simplebind(ld, "ldap_simple_bind_s/main", 1) != LDAP_SUCCESS) {
159 exit(1);
160 }
161
162 /* create the operation threads */
163 if ((search_tid = PR_CreateThread(PR_USER_THREAD, search_thread, "1",
164 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
165 PR_UNJOINABLE_THREAD, 0)) == NULL) {
166 perror("PR_CreateThread search_thread");
167 exit(1);
168 }
169 if ((modify_tid = PR_CreateThread(PR_USER_THREAD, modify_thread, "2",
170 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
171 PR_UNJOINABLE_THREAD, 0)) == NULL) {
172 perror("PR_CreateThread modify_thread");
173 exit(1);
174 }
175 if ((search_tid2 = PR_CreateThread(PR_USER_THREAD, search_thread, "3",
176 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
177 PR_UNJOINABLE_THREAD, 0)) == NULL) {
178 perror("PR_CreateThread search_thread 2");
179 exit(1);
180 }
181 if ((add_tid = PR_CreateThread(PR_USER_THREAD, add_thread, "4",
182 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
183 PR_UNJOINABLE_THREAD, 0)) == NULL) {
184 perror("PR_CreateThread add_thread");
185 exit(1);
186 }
187 if ((search_tid3 = PR_CreateThread(PR_USER_THREAD, search_thread, "5",
188 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
189 PR_UNJOINABLE_THREAD, 0)) == NULL) {
190 perror("PR_CreateThread search_thread 3");
191 exit(1);
192 }
193 if ((delete_tid = PR_CreateThread(PR_USER_THREAD, delete_thread, "6",
194 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
195 PR_UNJOINABLE_THREAD, 0)) == NULL) {
196 perror("PR_CreateThread delete_thread");
197 exit(1);
198 }
199 if ((search_tid4 = PR_CreateThread(PR_USER_THREAD, search_thread, "7",
200 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
201 PR_UNJOINABLE_THREAD, 0)) == NULL) {
202 perror("PR_CreateThread search_thread 4");
203 exit(1);
204 }
205
206 PR_Cleanup();
207 return (0);
208 }
209
simplebind(LDAP * ld,char * msg,int tries)210 static int simplebind(LDAP* ld, char* msg, int tries) {
211 int rc;
212
213 while (tries-- > 0) {
214 rc = ldap_simple_bind_s(ld, NAME, PASSWORD);
215 if (rc != LDAP_SUCCESS) {
216 ldap_perror(ld, msg);
217 }
218 if (tries == 0 || !CONNECTION_ERROR(rc)) {
219 return (rc);
220 }
221 fprintf(stderr, "%s: sleeping for 5 secs - will try %d more time(s)...\n",
222 msg, tries);
223 sleep(5);
224 }
225
226 return (rc);
227 }
228
search_thread(void * arg1)229 static void search_thread(void* arg1) {
230 LDAPMessage* res;
231 LDAPMessage* e;
232 char* a;
233 char** v;
234 char* dn;
235 BerElement* ber;
236 int i, rc, msgid;
237 void* tsd;
238 char* id = arg1;
239
240 printf("search_thread\n");
241 tsd_setup();
242 for (;;) {
243 printf("%sSearching...\n", id);
244 if ((msgid = ldap_search(ld, BASE, LDAP_SCOPE_SUBTREE, "(objectclass=*)",
245 NULL, 0)) == -1) {
246 ldap_perror(ld, "ldap_search_s");
247 rc = ldap_get_lderrno(ld, NULL, NULL);
248 if (CONNECTION_ERROR(rc) &&
249 simplebind(ld, "bind-search_thread", 5) != LDAP_SUCCESS) {
250 return;
251 }
252 continue;
253 }
254 while ((rc = ldap_result(ld, msgid, 0, NULL, &res)) ==
255 LDAP_RES_SEARCH_ENTRY) {
256 for (e = ldap_first_entry(ld, res); e != NULL;
257 e = ldap_next_entry(ld, e)) {
258 dn = ldap_get_dn(ld, e);
259 /* printf( "%sdn: %s\n", id, dn ); */
260 free(dn);
261 for (a = ldap_first_attribute(ld, e, &ber); a != NULL;
262 a = ldap_next_attribute(ld, e, ber)) {
263 v = ldap_get_values(ld, e, a);
264 for (i = 0; v && v[i] != 0; i++) {
265 /*
266 printf( "%s%s: %s\n", id, a,
267 v[i] );
268 */
269 }
270 ldap_value_free(v);
271 ldap_memfree(a);
272 }
273 if (ber != NULL) {
274 ber_free(ber, 0);
275 }
276 }
277 ldap_msgfree(res);
278 /* printf( "%s\n", id ); */
279 }
280
281 if (rc == -1 || ldap_result2error(ld, res, 0) != LDAP_SUCCESS) {
282 ldap_perror(ld, "ldap_search");
283 } else {
284 printf("%sDone with one round\n", id);
285 }
286
287 if (rc == -1) {
288 rc = ldap_get_lderrno(ld, NULL, NULL);
289 if (CONNECTION_ERROR(rc) &&
290 simplebind(ld, "bind-search_thread", 5) != LDAP_SUCCESS) {
291 return;
292 }
293 }
294 }
295 }
296
modify_thread(void * arg1)297 static void modify_thread(void* arg1) {
298 LDAPMessage* res;
299 LDAPMessage* e;
300 int i, modentry, entries, msgid, rc;
301 LDAPMod mod;
302 LDAPMod* mods[2];
303 char* vals[2];
304 char* dn;
305 char* id = arg1;
306 ldapmsgwrapper *list, *lmwp, *lastlmwp;
307
308 printf("modify_thread\n");
309 tsd_setup();
310 if ((msgid = ldap_search(ld, BASE, LDAP_SCOPE_SUBTREE, "(objectclass=*)",
311 NULL, 0)) == -1) {
312 ldap_perror(ld, "ldap_search_s");
313 exit(1);
314 }
315 entries = 0;
316 list = lastlmwp = NULL;
317 while ((rc = ldap_result(ld, msgid, 0, NULL, &res)) ==
318 LDAP_RES_SEARCH_ENTRY) {
319 entries++;
320 if ((lmwp = (ldapmsgwrapper*)malloc(sizeof(ldapmsgwrapper))) == NULL) {
321 perror("modify_thread: malloc");
322 exit(1);
323 }
324 lmwp->lmw_messagep = res;
325 lmwp->lmw_next = NULL;
326 if (lastlmwp == NULL) {
327 list = lastlmwp = lmwp;
328 } else {
329 lastlmwp->lmw_next = lmwp;
330 }
331 lastlmwp = lmwp;
332 }
333 if (rc == -1 || ldap_result2error(ld, res, 0) != LDAP_SUCCESS) {
334 ldap_perror(ld, "modify_thread: ldap_search");
335 exit(1);
336 } else {
337 entries++;
338 printf("%sModify got %d entries\n", id, entries);
339 }
340
341 mods[0] = &mod;
342 mods[1] = NULL;
343 vals[0] = "bar";
344 vals[1] = NULL;
345 for (;;) {
346 modentry = rand() % entries;
347 for (i = 0, lmwp = list; lmwp != NULL && i < modentry;
348 i++, lmwp = lmwp->lmw_next) {
349 /* NULL */
350 }
351
352 if (lmwp == NULL) {
353 fprintf(stderr, "%sModify could not find entry %d of %d\n", id, modentry,
354 entries);
355 continue;
356 }
357 e = lmwp->lmw_messagep;
358 printf("%sPicked entry %d of %d\n", id, i, entries);
359 dn = ldap_get_dn(ld, e);
360 mod.mod_op = LDAP_MOD_REPLACE;
361 mod.mod_type = "description";
362 mod.mod_values = vals;
363 printf("%sModifying (%s)\n", id, dn);
364 if ((rc = ldap_modify_s(ld, dn, mods)) != LDAP_SUCCESS) {
365 ldap_perror(ld, "ldap_modify_s");
366 if (CONNECTION_ERROR(rc) &&
367 simplebind(ld, "bind-modify_thread", 5) != LDAP_SUCCESS) {
368 return;
369 }
370 }
371 free(dn);
372 }
373 }
374
add_thread(void * arg1)375 static void add_thread(void* arg1) {
376 LDAPMod mod[5];
377 LDAPMod* mods[6];
378 char dn[BUFSIZ], name[40];
379 char *cnvals[2], *snvals[2], *ocvals[2];
380 int i, rc;
381 char* id = arg1;
382
383 printf("add_thread\n");
384 tsd_setup();
385 for (i = 0; i < 5; i++) {
386 mods[i] = &mod[i];
387 }
388 mods[5] = NULL;
389 mod[0].mod_op = 0;
390 mod[0].mod_type = "cn";
391 mod[0].mod_values = cnvals;
392 cnvals[1] = NULL;
393 mod[1].mod_op = 0;
394 mod[1].mod_type = "sn";
395 mod[1].mod_values = snvals;
396 snvals[1] = NULL;
397 mod[2].mod_op = 0;
398 mod[2].mod_type = "objectclass";
399 mod[2].mod_values = ocvals;
400 ocvals[0] = "person";
401 ocvals[1] = NULL;
402 mods[3] = NULL;
403
404 for (;;) {
405 sprintf(name, "%d", rand());
406 sprintf(dn, "cn=%s, " BASE, name);
407 cnvals[0] = name;
408 snvals[0] = name;
409
410 printf("%sAdding entry (%s)\n", id, dn);
411 if ((rc = ldap_add_s(ld, dn, mods)) != LDAP_SUCCESS) {
412 ldap_perror(ld, "ldap_add_s");
413 if (CONNECTION_ERROR(rc) &&
414 simplebind(ld, "bind-add_thread", 5) != LDAP_SUCCESS) {
415 return;
416 }
417 }
418 }
419 }
420
delete_thread(void * arg1)421 static void delete_thread(void* arg1) {
422 LDAPMessage* res;
423 char dn[BUFSIZ], name[40];
424 int entries, msgid, rc;
425 char* id = arg1;
426
427 printf("delete_thread\n");
428 tsd_setup();
429 if ((msgid = ldap_search(ld, BASE, LDAP_SCOPE_SUBTREE, "(objectclass=*)",
430 NULL, 0)) == -1) {
431 ldap_perror(ld, "delete_thread: ldap_search_s");
432 exit(1);
433 }
434 entries = 0;
435 while ((rc = ldap_result(ld, msgid, 0, NULL, &res)) ==
436 LDAP_RES_SEARCH_ENTRY) {
437 entries++;
438 ldap_msgfree(res);
439 }
440 entries++;
441 if (rc == -1 || ldap_result2error(ld, res, 1) != LDAP_SUCCESS) {
442 ldap_perror(ld, "delete_thread: ldap_search");
443 } else {
444 printf("%sDelete got %d entries\n", id, entries);
445 }
446
447 for (;;) {
448 sprintf(name, "%d", rand());
449 sprintf(dn, "cn=%s, " BASE, name);
450
451 printf("%sDeleting entry (%s)\n", id, dn);
452 if ((rc = ldap_delete_s(ld, dn)) != LDAP_SUCCESS) {
453 ldap_perror(ld, "ldap_delete_s");
454 if (CONNECTION_ERROR(rc) &&
455 simplebind(ld, "bind-delete_thread", 5) != LDAP_SUCCESS) {
456 return;
457 }
458 }
459 }
460 }
461
462 struct ldap_error {
463 int le_errno;
464 char* le_matched;
465 char* le_errmsg;
466 };
467
tsd_setup()468 static void tsd_setup() {
469 void* tsd;
470
471 tsd = (void*)PR_GetThreadPrivate(tsdindex);
472 if (tsd != NULL) {
473 fprintf(stderr, "tsd non-null!\n");
474 exit(1);
475 }
476 tsd = (void*)calloc(1, sizeof(struct ldap_error));
477 if (PR_SetThreadPrivate(tsdindex, tsd) != 0) {
478 perror("PR_SetThreadPrivate");
479 exit(1);
480 }
481 }
482
set_ld_error(int err,char * matched,char * errmsg,void * dummy)483 static void set_ld_error(int err, char* matched, char* errmsg, void* dummy) {
484 struct ldap_error* le;
485
486 le = (void*)PR_GetThreadPrivate(tsdindex);
487 le->le_errno = err;
488 if (le->le_matched != NULL) {
489 ldap_memfree(le->le_matched);
490 }
491 le->le_matched = matched;
492 if (le->le_errmsg != NULL) {
493 ldap_memfree(le->le_errmsg);
494 }
495 le->le_errmsg = errmsg;
496 }
497
get_ld_error(char ** matchedp,char ** errmsgp,void * dummy)498 static int get_ld_error(char** matchedp, char** errmsgp, void* dummy) {
499 struct ldap_error* le;
500
501 le = PR_GetThreadPrivate(tsdindex);
502 if (matchedp != NULL) {
503 *matchedp = le->le_matched;
504 }
505 if (errmsgp != NULL) {
506 *errmsgp = le->le_errmsg;
507 }
508 return (le->le_errno);
509 }
510
set_errno(int oserrno)511 static void set_errno(int oserrno) {
512 /* XXXmcs: should this be PR_SetError( oserrno, 0 )? */
513 PR_SetError(PR_UNKNOWN_ERROR, oserrno);
514 }
515
get_errno(void)516 static int get_errno(void) {
517 /* XXXmcs: should this be PR_GetError()? */
518 return (PR_GetOSError());
519 }
520
my_mutex_alloc(void)521 static void* my_mutex_alloc(void) { return ((void*)PR_NewLock()); }
522
my_mutex_free(void * mutex)523 static void my_mutex_free(void* mutex) { PR_DestroyLock((PRLock*)mutex); }
524
my_mutex_lock(void * mutex)525 static int my_mutex_lock(void* mutex) {
526 PR_Lock((PRLock*)mutex);
527 return (0);
528 }
529
my_mutex_unlock(void * mutex)530 static int my_mutex_unlock(void* mutex) {
531 if (PR_Unlock((PRLock*)mutex) == PR_FAILURE) {
532 return (-1);
533 }
534
535 return (0);
536 }
537
my_gethostbyname(const char * name,LDAPHostEnt * result,char * buffer,int buflen,int * statusp,void * extradata)538 static LDAPHostEnt* my_gethostbyname(const char* name, LDAPHostEnt* result,
539 char* buffer, int buflen, int* statusp,
540 void* extradata) {
541 PRHostEnt prhent;
542
543 if (PR_GetHostByName(name, buffer, buflen, &prhent) != PR_SUCCESS) {
544 return (NULL);
545 }
546
547 return (copyPRHostEnt2LDAPHostEnt(result, &prhent));
548 }
549
my_gethostbyaddr(const char * addr,int length,int type,LDAPHostEnt * result,char * buffer,int buflen,int * statusp,void * extradata)550 static LDAPHostEnt* my_gethostbyaddr(const char* addr, int length, int type,
551 LDAPHostEnt* result, char* buffer,
552 int buflen, int* statusp,
553 void* extradata) {
554 PRHostEnt prhent;
555
556 if (PR_GetHostByAddr((PRNetAddr*)addr, buffer, buflen, &prhent) !=
557 PR_SUCCESS) {
558 return (NULL);
559 }
560
561 return (copyPRHostEnt2LDAPHostEnt(result, &prhent));
562 }
563
copyPRHostEnt2LDAPHostEnt(LDAPHostEnt * ldhp,PRHostEnt * prhp)564 static LDAPHostEnt* copyPRHostEnt2LDAPHostEnt(LDAPHostEnt* ldhp,
565 PRHostEnt* prhp) {
566 ldhp->ldaphe_name = prhp->h_name;
567 ldhp->ldaphe_aliases = prhp->h_aliases;
568 ldhp->ldaphe_addrtype = prhp->h_addrtype;
569 ldhp->ldaphe_length = prhp->h_length;
570 ldhp->ldaphe_addr_list = prhp->h_addr_list;
571 return (ldhp);
572 }
573