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