root/source4/torture/nbt/winsbench.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. generate_name
  2. register_handler
  3. generate_register
  4. release_handler
  5. generate_release
  6. query_handler
  7. generate_query
  8. generate_request
  9. bench_wins
  10. torture_bench_wins

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    WINS 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 "lib/events/events.h"
  24 #include "lib/socket/socket.h"
  25 #include "libcli/resolve/resolve.h"
  26 #include "system/network.h"
  27 #include "lib/socket/netif.h"
  28 #include "torture/torture.h"
  29 #include "torture/nbt/proto.h"
  30 #include "param/param.h"
  31 
  32 struct wins_state {
  33         int num_names;
  34         bool *registered;
  35         int pass_count;
  36         int fail_count;
  37         const char *wins_server;
  38         uint16_t wins_port;
  39         const char *my_ip;
  40         uint32_t ttl;
  41 };
  42 
  43 struct idx_state {
  44         int idx;
  45         struct wins_state *state;
  46 };
  47 
  48 static struct nbt_name generate_name(TALLOC_CTX *tctx, int idx)
     /* [<][>][^][v][top][bottom][index][help] */
  49 {
  50         struct nbt_name name;
  51         name.name       = talloc_asprintf(tctx, "WINSBench%6u", idx);
  52         name.type       = 0x4;
  53         name.scope      = NULL;
  54         return name;
  55 }
  56 
  57 static void register_handler(struct nbt_name_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
  58 {
  59         struct idx_state *istate = talloc_get_type(req->async.private_data, struct idx_state);
  60         struct wins_state *state = istate->state;
  61         struct nbt_name_register io;
  62         NTSTATUS status;
  63 
  64         status = nbt_name_register_recv(req, istate, &io);
  65         if (!NT_STATUS_IS_OK(status) || io.out.rcode != NBT_RCODE_OK) {
  66                 state->fail_count++;
  67         } else {
  68                 state->pass_count++;
  69                 state->registered[istate->idx] = true;
  70         }
  71         talloc_free(istate);    
  72 }
  73 
  74 /*
  75   generate a registration
  76 */
  77 static void generate_register(struct nbt_name_socket *nbtsock, struct wins_state *state, int idx)
     /* [<][>][^][v][top][bottom][index][help] */
  78 {
  79         struct nbt_name_register io;
  80         TALLOC_CTX *tmp_ctx = talloc_new(state);
  81         struct nbt_name_request *req;
  82         struct idx_state *istate;
  83 
  84         istate = talloc(nbtsock, struct idx_state);
  85         istate->idx = idx;
  86         istate->state = state;
  87 
  88         io.in.name            = generate_name(tmp_ctx, idx);
  89         io.in.dest_addr       = state->wins_server;
  90         io.in.dest_port       = state->wins_port;
  91         io.in.address         = state->my_ip;
  92         io.in.nb_flags        = NBT_NODE_H;
  93         io.in.register_demand = false;
  94         io.in.broadcast       = false;
  95         io.in.multi_homed     = false;
  96         io.in.ttl             = state->ttl;
  97         io.in.timeout         = 2;
  98         io.in.retries         = 1;
  99 
 100         req = nbt_name_register_send(nbtsock, &io);
 101 
 102         req->async.fn = register_handler;
 103         req->async.private_data = istate;
 104 
 105         talloc_free(tmp_ctx);
 106 }
 107 
 108 
 109 static void release_handler(struct nbt_name_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 110 {
 111         struct idx_state *istate = talloc_get_type(req->async.private_data, struct idx_state);
 112         struct wins_state *state = istate->state;
 113         struct nbt_name_release io;
 114         NTSTATUS status;
 115 
 116         status = nbt_name_release_recv(req, istate, &io);
 117         if (state->registered[istate->idx] && 
 118             (!NT_STATUS_IS_OK(status) || io.out.rcode != NBT_RCODE_OK)) {
 119                 state->fail_count++;
 120         } else {
 121                 state->pass_count++;
 122                 state->registered[istate->idx] = false;
 123         }
 124         talloc_free(istate);    
 125 }
 126 
 127 /*
 128   generate a name release
 129 */
 130 static void generate_release(struct nbt_name_socket *nbtsock, struct wins_state *state, int idx)
     /* [<][>][^][v][top][bottom][index][help] */
 131 {
 132         struct nbt_name_release io;
 133         TALLOC_CTX *tmp_ctx = talloc_new(state);
 134         struct nbt_name_request *req;
 135         struct idx_state *istate;
 136 
 137         istate = talloc(nbtsock, struct idx_state);
 138         istate->idx = idx;
 139         istate->state = state;
 140 
 141         io.in.name            = generate_name(tmp_ctx, idx);
 142         io.in.dest_port       = state->wins_port;
 143         io.in.dest_addr       = state->wins_server;
 144         io.in.address         = state->my_ip;
 145         io.in.nb_flags        = NBT_NODE_H;
 146         io.in.broadcast       = false;
 147         io.in.timeout         = 2;
 148         io.in.retries         = 1;
 149 
 150         req = nbt_name_release_send(nbtsock, &io);
 151 
 152         req->async.fn = release_handler;
 153         req->async.private_data = istate;
 154 
 155         talloc_free(tmp_ctx);
 156 }
 157 
 158 
 159 static void query_handler(struct nbt_name_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 160 {
 161         struct idx_state *istate = talloc_get_type(req->async.private_data, struct idx_state);
 162         struct wins_state *state = istate->state;
 163         struct nbt_name_query io;
 164         NTSTATUS status;
 165 
 166         status = nbt_name_query_recv(req, istate, &io);
 167         if (!NT_STATUS_IS_OK(status) && state->registered[istate->idx]) {
 168                 state->fail_count++;
 169         } else {
 170                 state->pass_count++;
 171         }
 172         talloc_free(istate);    
 173 }
 174 
 175 /*
 176   generate a name query
 177 */
 178 static void generate_query(struct nbt_name_socket *nbtsock, struct wins_state *state, int idx)
     /* [<][>][^][v][top][bottom][index][help] */
 179 {
 180         struct nbt_name_query io;
 181         TALLOC_CTX *tmp_ctx = talloc_new(state);
 182         struct nbt_name_request *req;
 183         struct idx_state *istate;
 184 
 185         istate = talloc(nbtsock, struct idx_state);
 186         istate->idx = idx;
 187         istate->state = state;
 188 
 189         io.in.name            = generate_name(tmp_ctx, idx);
 190         io.in.dest_addr       = state->wins_server;
 191         io.in.dest_port       = state->wins_port;
 192         io.in.broadcast       = false;
 193         io.in.wins_lookup     = true;
 194         io.in.timeout         = 2;
 195         io.in.retries         = 1;
 196 
 197         req = nbt_name_query_send(nbtsock, &io);
 198 
 199         req->async.fn = query_handler;
 200         req->async.private_data = istate;
 201 
 202         talloc_free(tmp_ctx);
 203 }
 204 
 205 /*
 206   generate one WINS request
 207 */
 208 static void generate_request(struct nbt_name_socket *nbtsock, struct wins_state *state, int idx)
     /* [<][>][^][v][top][bottom][index][help] */
 209 {
 210         if (random() % 5 == 0) {
 211                 generate_register(nbtsock, state, idx);
 212                 return;
 213         }
 214 
 215         if (random() % 20 == 0) {
 216                 generate_release(nbtsock, state, idx);
 217                 return;
 218         }
 219 
 220         generate_query(nbtsock, state, idx);
 221 }
 222 
 223 /*
 224   benchmark simple name queries
 225 */
 226 static bool bench_wins(struct torture_context *tctx)
     /* [<][>][^][v][top][bottom][index][help] */
 227 {
 228         struct nbt_name_socket *nbtsock = nbt_name_socket_init(tctx, tctx->ev, lp_iconv_convenience(tctx->lp_ctx));
 229         int num_sent=0;
 230         struct timeval tv = timeval_current();
 231         bool ret = true;
 232         int timelimit = torture_setting_int(tctx, "timelimit", 5);
 233         struct wins_state *state;
 234         extern int torture_entries;
 235         struct socket_address *my_ip;
 236         struct nbt_name name;
 237         const char *address;
 238         struct interface *ifaces;
 239 
 240         if (!torture_nbt_get_name(tctx, &name, &address))
 241                 return false;
 242 
 243         state = talloc_zero(nbtsock, struct wins_state);
 244 
 245         state->num_names = torture_entries;
 246         state->registered = talloc_zero_array(state, bool, state->num_names);
 247         state->wins_server = address;
 248         state->wins_port = lp_nbt_port(tctx->lp_ctx);
 249         load_interfaces(tctx, lp_interfaces(tctx->lp_ctx), &ifaces);
 250         state->my_ip = talloc_strdup(tctx, iface_best_ip(ifaces, address));
 251         state->ttl = timelimit;
 252 
 253         my_ip = socket_address_from_strings(nbtsock, nbtsock->sock->backend_name, 
 254                                             state->my_ip, 0);
 255 
 256         socket_listen(nbtsock->sock, my_ip, 0, 0);
 257 
 258         torture_comment(tctx, "Running for %d seconds\n", timelimit);
 259         while (timeval_elapsed(&tv) < timelimit) {
 260                 while (num_sent - (state->pass_count+state->fail_count) < 10) {
 261                         generate_request(nbtsock, state, num_sent % state->num_names);
 262                         num_sent++;
 263                         if (num_sent % 50 == 0) {
 264                                 if (torture_setting_bool(tctx, "progress", true)) {
 265                                         torture_comment(tctx, "%.1f queries per second (%d failures)  \r", 
 266                                                state->pass_count / timeval_elapsed(&tv),
 267                                                state->fail_count);
 268                                         fflush(stdout);
 269                                 }
 270                         }
 271                 }
 272 
 273                 event_loop_once(nbtsock->event_ctx);
 274         }
 275 
 276         while (num_sent != (state->pass_count + state->fail_count)) {
 277                 event_loop_once(nbtsock->event_ctx);
 278         }
 279 
 280         torture_comment(tctx, "%.1f queries per second (%d failures)  \n", 
 281                state->pass_count / timeval_elapsed(&tv),
 282                state->fail_count);
 283 
 284         talloc_free(nbtsock);
 285         return ret;
 286 }
 287 
 288 
 289 /*
 290   benchmark how fast a WINS server can respond to a mixture of
 291   registration/refresh/release and name query requests
 292 */
 293 struct torture_suite *torture_bench_wins(TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 294 {
 295         struct torture_suite *suite = torture_suite_create(mem_ctx, 
 296                                                            "BENCH-WINS");
 297 
 298         torture_suite_add_simple_test(suite, "wins", bench_wins);
 299 
 300         return suite;
 301 }

/* [<][>][^][v][top][bottom][index][help] */