36b319dec697261f3c0f8cc2937cb0524c4b1de1
[metze/samba/wip.git] / source4 / torture / ldap / cldapbench.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    CLDAP benchmark test
5
6    Copyright (C) Andrew Tridgell 2005
7    
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.
12    
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.
17    
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/>.
20 */
21
22 #include "includes.h"
23 #include "libcli/cldap/cldap.h"
24 #include "libcli/resolve/resolve.h"
25 #include "torture/torture.h"
26 #include "param/param.h"
27 #include "../lib/tsocket/tsocket.h"
28
29 #define CHECK_VAL(v, correct) torture_assert_int_equal(tctx, (v), (correct), "incorrect value");
30
31 struct bench_state {
32         struct torture_context *tctx;
33         int pass_count, fail_count;
34 };
35
36 static void request_netlogon_handler(struct tevent_req *req)
37 {
38         struct cldap_netlogon io;
39         struct bench_state *state = tevent_req_callback_data(req, struct bench_state);
40         NTSTATUS status;
41         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
42         io.in.version = 6;
43         status = cldap_netlogon_recv(req, tmp_ctx, &io);
44         talloc_free(req);
45         if (NT_STATUS_IS_OK(status)) {
46                 state->pass_count++;
47         } else {
48                 state->fail_count++;
49         }
50         talloc_free(tmp_ctx);
51 }
52
53 /*
54   benchmark cldap netlogon calls
55 */
56 static bool bench_cldap_netlogon(struct torture_context *tctx, const char *address)
57 {
58         struct cldap_socket *cldap;
59         int num_sent=0;
60         struct timeval tv = timeval_current();
61         int timelimit = torture_setting_int(tctx, "timelimit", 10);
62         struct cldap_netlogon search;
63         struct bench_state *state;
64         NTSTATUS status;
65         struct tsocket_address *dest_addr;
66         int ret;
67
68         ret = tsocket_address_inet_from_strings(tctx, "ip",
69                                                 address,
70                                                 lpcfg_cldap_port(tctx->lp_ctx),
71                                                 &dest_addr);
72         CHECK_VAL(ret, 0);
73
74         status = cldap_socket_init(tctx, NULL, dest_addr, &cldap);
75         torture_assert_ntstatus_ok(tctx, status, "cldap_socket_init");
76
77         state = talloc_zero(tctx, struct bench_state);
78         state->tctx = tctx;
79
80         ZERO_STRUCT(search);
81         search.in.dest_address = NULL;
82         search.in.dest_port = 0;
83         search.in.acct_control = -1;
84         search.in.version = 6;
85
86         printf("Running CLDAP/netlogon for %d seconds\n", timelimit);
87         while (timeval_elapsed(&tv) < timelimit) {
88                 while (num_sent - (state->pass_count+state->fail_count) < 10) {
89                         struct tevent_req *req;
90                         req = cldap_netlogon_send(state, tctx->ev,
91                                                   cldap, &search);
92
93                         tevent_req_set_callback(req, request_netlogon_handler, state);
94
95                         num_sent++;
96                         if (num_sent % 50 == 0) {
97                                 if (torture_setting_bool(tctx, "progress", true)) {
98                                         printf("%.1f queries per second (%d failures)  \r", 
99                                                state->pass_count / timeval_elapsed(&tv),
100                                                state->fail_count);
101                                         fflush(stdout);
102                                 }
103                         }
104                 }
105
106                 tevent_loop_once(tctx->ev);
107         }
108
109         while (num_sent != (state->pass_count + state->fail_count)) {
110                 tevent_loop_once(tctx->ev);
111         }
112
113         printf("%.1f queries per second (%d failures)  \n", 
114                state->pass_count / timeval_elapsed(&tv),
115                state->fail_count);
116
117         talloc_free(cldap);
118         return true;
119 }
120
121 static void request_rootdse_handler(struct tevent_req *req)
122 {
123         struct cldap_search io;
124         struct bench_state *state = tevent_req_callback_data(req, struct bench_state);
125         NTSTATUS status;
126         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
127         status = cldap_search_recv(req, tmp_ctx, &io);
128         talloc_free(req);
129         if (NT_STATUS_IS_OK(status)) {
130                 state->pass_count++;
131         } else {
132                 state->fail_count++;
133         }
134         talloc_free(tmp_ctx);
135 }
136
137 /*
138   benchmark cldap netlogon calls
139 */
140 static bool bench_cldap_rootdse(struct torture_context *tctx, const char *address)
141 {
142         struct cldap_socket *cldap;
143         int num_sent=0;
144         struct timeval tv = timeval_current();
145         int timelimit = torture_setting_int(tctx, "timelimit", 10);
146         struct cldap_search search;
147         struct bench_state *state;
148         NTSTATUS status;
149         struct tsocket_address *dest_addr;
150         int ret;
151
152         ret = tsocket_address_inet_from_strings(tctx, "ip",
153                                                 address,
154                                                 lpcfg_cldap_port(tctx->lp_ctx),
155                                                 &dest_addr);
156         CHECK_VAL(ret, 0);
157
158         /* cldap_socket_init should now know about the dest. address */
159         status = cldap_socket_init(tctx, NULL, dest_addr, &cldap);
160         torture_assert_ntstatus_ok(tctx, status, "cldap_socket_init");
161
162         state = talloc_zero(tctx, struct bench_state);
163
164         ZERO_STRUCT(search);
165         search.in.dest_address  = NULL;
166         search.in.dest_port     = 0;
167         search.in.filter        = "(objectClass=*)";
168         search.in.timeout       = 2;
169         search.in.retries       = 1;
170
171         printf("Running CLDAP/rootdse for %d seconds\n", timelimit);
172         while (timeval_elapsed(&tv) < timelimit) {
173                 while (num_sent - (state->pass_count+state->fail_count) < 10) {
174                         struct tevent_req *req;
175                         req = cldap_search_send(state, tctx->ev, cldap, &search);
176
177                         tevent_req_set_callback(req, request_rootdse_handler, state);
178
179                         num_sent++;
180                         if (num_sent % 50 == 0) {
181                                 if (torture_setting_bool(tctx, "progress", true)) {
182                                         printf("%.1f queries per second (%d failures)  \r",
183                                                state->pass_count / timeval_elapsed(&tv),
184                                                state->fail_count);
185                                         fflush(stdout);
186                                 }
187                         }
188                 }
189
190                 tevent_loop_once(tctx->ev);
191         }
192
193         while (num_sent != (state->pass_count + state->fail_count)) {
194                 tevent_loop_once(tctx->ev);
195         }
196
197         printf("%.1f queries per second (%d failures)  \n",
198                state->pass_count / timeval_elapsed(&tv),
199                state->fail_count);
200
201         talloc_free(cldap);
202         return true;
203 }
204
205 /*
206   benchmark how fast a CLDAP server can respond to a series of parallel
207   requests 
208 */
209 bool torture_bench_cldap(struct torture_context *torture)
210 {
211         const char *address;
212         struct nbt_name name;
213         NTSTATUS status;
214         bool ret = true;
215         
216         make_nbt_name_server(&name, torture_setting_string(torture, "host", NULL));
217
218         /* do an initial name resolution to find its IP */
219         status = resolve_name_ex(lpcfg_resolve_context(torture->lp_ctx),
220                                  0, 0, &name, torture, &address, torture->ev);
221         if (!NT_STATUS_IS_OK(status)) {
222                 printf("Failed to resolve %s - %s\n",
223                        name.name, nt_errstr(status));
224                 return false;
225         }
226
227         ret &= bench_cldap_netlogon(torture, address);
228         ret &= bench_cldap_rootdse(torture, address);
229
230         return ret;
231 }