ldb: comment for ldb_dn_compare_base
[Samba.git] / nsswitch / stress-nss-libwbclient.c
blobd9dc3b53869ed2cfa8a8554093ea471c380cd005
1 /*
2 Unix SMB/CIFS implementation.
4 Stress test for parallel NSS & libwbclient calls.
6 Copyright (C) Ralph Wuerthner 2018
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include <stdio.h>
23 #include <stdint.h>
24 #include <stdbool.h>
25 #include <pthread.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <time.h>
29 #include <stdlib.h>
30 #include <sys/types.h>
31 #include <pwd.h>
32 #include <wbclient.h>
33 #include <sys/socket.h>
34 #include <errno.h>
35 #include <assert.h>
37 #define RUNTIME 10
39 struct thread_state {
40 const char *username;
41 time_t timeout;
42 pthread_mutex_t lock;
43 bool fail;
44 int nss_loop_count;
45 int wbc_loop_count;
48 static void *query_nss_thread(void *ptr)
50 struct thread_state *state = ptr;
51 char buf[1024];
52 ssize_t nread, nwritten;
53 int p[2];
54 int rc;
55 struct passwd pwd, *result;
56 pid_t pid;
58 while (time(NULL) < state->timeout) {
59 rc = getpwnam_r(state->username,
60 &pwd,
61 buf,
62 sizeof(buf),
63 &result);
64 if (rc != 0 || result == NULL) {
65 pthread_mutex_lock(&state->lock);
66 state->fail = true;
67 pthread_mutex_unlock(&state->lock);
68 fprintf(stderr,
69 "getpwnam_r failed with rc='%s' result=%p\n",
70 strerror(rc),
71 result);
72 break;
74 state->nss_loop_count++;
75 pthread_mutex_lock(&state->lock);
76 if (state->fail) {
77 pthread_mutex_unlock(&state->lock);
78 break;
80 pthread_mutex_unlock(&state->lock);
83 rc = socketpair(AF_UNIX, SOCK_STREAM, 0, p);
84 if (rc != 0) {
85 state->fail = true;
86 return NULL;
90 * Check getpwnam_r() still works after a fork,
91 * both in parent and child.
94 pid = fork();
95 if (pid == -1) {
96 return NULL;
98 if (pid == 0) {
99 /* Child */
100 rc = getpwnam_r(state->username,
101 &pwd,
102 buf,
103 sizeof(buf),
104 &result);
105 if (rc != 0 || result == NULL) {
106 fprintf(stderr,
107 "getpwnam_r failed with rc='%s' result=%p\n",
108 strerror(rc),
109 result);
110 rc = 1;
111 nwritten = write(p[0], &rc, sizeof(int));
112 assert(nwritten == sizeof(int));
113 exit(1);
115 printf("child: getpwnam_r in child succeeded\n");
116 rc = 0;
117 nwritten = write(p[0], &rc, sizeof(int));
118 assert(nwritten == sizeof(int));
119 exit(1);
122 /* Parent */
124 /* Check result from child */
125 nread = read(p[1], &rc, sizeof(int));
126 if (nread != sizeof(int)) {
127 fprintf(stderr,
128 "read from child failed with errno='%s' nread=%zd\n",
129 strerror(errno),
130 nread);
131 state->fail = true;
132 return NULL;
135 if (rc != 0) {
136 fprintf(stderr,
137 "getpwnam_r failed in the child\n");
138 state->fail = true;
139 return NULL;
141 printf("parent: getpwnam_r in child succeeded\n");
143 /* Verify getpwnam_r() in parent after fork */
144 rc = getpwnam_r(state->username,
145 &pwd,
146 buf,
147 sizeof(buf),
148 &result);
149 if (rc != 0 || result == NULL) {
150 fprintf(stderr,
151 "getpwnam_r failed with rc='%s' result=%p\n",
152 strerror(rc),
153 result);
154 state->fail = true;
155 return NULL;
157 printf("parent: getpwnam_r in parent succeeded\n");
158 return NULL;
161 static void *query_wbc_thread(void *ptr)
163 struct thread_state *state = ptr;
164 struct passwd *ppwd;
165 wbcErr wbc_status;
166 pid_t pid;
167 ssize_t nread, nwritten;
168 int p[2];
169 int rc;
171 while (time(NULL) < state->timeout) {
172 wbc_status = wbcGetpwnam(state->username, &ppwd);
173 if (!WBC_ERROR_IS_OK(wbc_status)) {
174 pthread_mutex_lock(&state->lock);
175 state->fail = true;
176 pthread_mutex_unlock(&state->lock);
177 fprintf(stderr,
178 "wbcGetpwnam failed with %s\n",
179 wbcErrorString(wbc_status));
180 break;
182 wbcFreeMemory(ppwd);
183 state->wbc_loop_count++;
184 pthread_mutex_lock(&state->lock);
185 if (state->fail) {
186 pthread_mutex_unlock(&state->lock);
187 break;
189 pthread_mutex_unlock(&state->lock);
192 rc = socketpair(AF_UNIX, SOCK_STREAM, 0, p);
193 if (rc != 0) {
194 state->fail = true;
195 return NULL;
199 * Check wbcGetpwnam() still works after a fork,
200 * both in parent and child.
203 pid = fork();
204 if (pid == -1) {
205 return NULL;
207 if (pid == 0) {
208 /* Child */
209 wbc_status = wbcGetpwnam(state->username, &ppwd);
210 if (!WBC_ERROR_IS_OK(wbc_status)) {
211 fprintf(stderr,
212 "wbcGetpwnam failed with %s\n",
213 wbcErrorString(wbc_status));
214 rc = 1;
215 nwritten = write(p[0], &rc, sizeof(int));
216 assert(nwritten == sizeof(int));
217 exit(1);
219 wbcFreeMemory(ppwd);
220 printf("child: wbcGetpwnam in child succeeded\n");
221 rc = 0;
222 nwritten = write(p[0], &rc, sizeof(int));
223 assert(nwritten == sizeof(int));
224 exit(1);
227 /* Parent */
229 /* Check result from child */
230 nread = read(p[1], &rc, sizeof(int));
231 if (nread != sizeof(int)) {
232 fprintf(stderr,
233 "read from child failed with errno='%s' nread=%zd\n",
234 strerror(errno),
235 nread);
236 state->fail = true;
237 return NULL;
240 if (rc != 0) {
241 fprintf(stderr,
242 "wbcGetpwnam failed in the child\n");
243 state->fail = true;
244 return NULL;
246 printf("parent: wbcGetpwnam in child succeeded\n");
248 /* Verify wbcGetpwnam() in parent after fork */
249 wbc_status = wbcGetpwnam(state->username, &ppwd);
250 if (!WBC_ERROR_IS_OK(wbc_status)) {
251 fprintf(stderr,
252 "wbcGetpwnam failed with %s\n",
253 wbcErrorString(wbc_status));
254 state->fail = true;
255 return NULL;
257 wbcFreeMemory(ppwd);
258 printf("parent: wbcGetpwnam in parent succeeded\n");
259 return NULL;
262 int main(int argc, char *argv[])
264 int rc, n;
265 struct thread_state state;
266 pthread_t threads[2];
268 if (argc < 2 ) {
269 fprintf(stderr,"%s: missing domain user\n", argv[0]);
270 return 1;
273 state.username = argv[1];
274 state.timeout = time(NULL) + RUNTIME;
275 rc = pthread_mutex_init(&state.lock, NULL);
276 if (rc != 0) {
277 fprintf(stderr,
278 "pthread_mutex_init failed: %s\n",
279 strerror(rc));
280 exit(1);
282 state.fail = false;
283 state.nss_loop_count = 0;
284 state.wbc_loop_count = 0;
286 printf("query domain user '%s'\n", state.username);
288 /* create query threads */
289 rc = pthread_create(&threads[0], NULL, query_nss_thread, &state);
290 if (rc != 0) {
291 fprintf(stderr,
292 "creating NSS thread failed: %s\n",
293 strerror(rc));
294 exit(1);
296 rc = pthread_create(&threads[1], NULL, query_wbc_thread, &state);
297 if (rc != 0) {
298 fprintf(stderr,
299 "creating libwbclient thread failed: %s\n",
300 strerror(rc));
301 exit(1);
304 /* wait for query threads to terminate */
305 for (n = 0; n < 2; n++) {
306 rc = pthread_join(threads[n], NULL);
307 if (rc != 0) {
308 fprintf(stderr,
309 "joining query thread %i failed: %s\n",
311 strerror(rc));
312 exit(1);
316 fprintf(state.fail ? stderr: stdout,
317 "test %s with %i NSS and %i libwbclient calls\n",
318 state.fail ? "failed" : "passed",
319 state.nss_loop_count,
320 state.wbc_loop_count);
322 return state.fail;