2 Unix SMB/CIFS implementation.
6 Copyright (C) Andrew Tridgell 2005
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 2 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, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "lib/events/events.h"
25 #include "libcli/nbt/libnbt.h"
26 #include "librpc/gen_ndr/ndr_nbt.h"
27 #include "lib/socket/socket.h"
34 const char *wins_server;
41 struct wins_state *state;
44 struct nbt_name generate_name(TALLOC_CTX *mem_ctx, int idx)
47 name.name = talloc_asprintf(mem_ctx, "WINSBench%6u", idx);
53 static void register_handler(struct nbt_name_request *req)
55 struct idx_state *istate = talloc_get_type(req->async.private, struct idx_state);
56 struct wins_state *state = istate->state;
57 struct nbt_name_register io;
60 status = nbt_name_register_recv(req, istate, &io);
61 if (!NT_STATUS_IS_OK(status) || io.out.rcode != NBT_RCODE_OK) {
65 state->registered[istate->idx] = True;
71 generate a registration
73 static void generate_register(struct nbt_name_socket *nbtsock, struct wins_state *state, int idx)
75 struct nbt_name_register io;
76 TALLOC_CTX *tmp_ctx = talloc_new(state);
77 struct nbt_name_request *req;
78 struct idx_state *istate;
80 istate = talloc(nbtsock, struct idx_state);
82 istate->state = state;
84 io.in.name = generate_name(tmp_ctx, idx);
85 io.in.dest_addr = state->wins_server;
86 io.in.address = state->my_ip;
87 io.in.nb_flags = NBT_NODE_H;
88 io.in.register_demand = False;
89 io.in.broadcast = False;
90 io.in.multi_homed = False;
91 io.in.ttl = state->ttl;
95 req = nbt_name_register_send(nbtsock, &io);
97 req->async.fn = register_handler;
98 req->async.private = istate;
100 talloc_free(tmp_ctx);
104 static void release_handler(struct nbt_name_request *req)
106 struct idx_state *istate = talloc_get_type(req->async.private, struct idx_state);
107 struct wins_state *state = istate->state;
108 struct nbt_name_release io;
111 status = nbt_name_release_recv(req, istate, &io);
112 if (state->registered[istate->idx] &&
113 (!NT_STATUS_IS_OK(status) || io.out.rcode != NBT_RCODE_OK)) {
117 state->registered[istate->idx] = False;
123 generate a name release
125 static void generate_release(struct nbt_name_socket *nbtsock, struct wins_state *state, int idx)
127 struct nbt_name_release io;
128 TALLOC_CTX *tmp_ctx = talloc_new(state);
129 struct nbt_name_request *req;
130 struct idx_state *istate;
132 istate = talloc(nbtsock, struct idx_state);
134 istate->state = state;
136 io.in.name = generate_name(tmp_ctx, idx);
137 io.in.dest_addr = state->wins_server;
138 io.in.address = state->my_ip;
139 io.in.nb_flags = NBT_NODE_H;
140 io.in.broadcast = False;
144 req = nbt_name_release_send(nbtsock, &io);
146 req->async.fn = release_handler;
147 req->async.private = istate;
149 talloc_free(tmp_ctx);
153 static void query_handler(struct nbt_name_request *req)
155 struct idx_state *istate = talloc_get_type(req->async.private, struct idx_state);
156 struct wins_state *state = istate->state;
157 struct nbt_name_query io;
160 status = nbt_name_query_recv(req, istate, &io);
161 if (!NT_STATUS_IS_OK(status) && state->registered[istate->idx]) {
170 generate a name query
172 static void generate_query(struct nbt_name_socket *nbtsock, struct wins_state *state, int idx)
174 struct nbt_name_query io;
175 TALLOC_CTX *tmp_ctx = talloc_new(state);
176 struct nbt_name_request *req;
177 struct idx_state *istate;
179 istate = talloc(nbtsock, struct idx_state);
181 istate->state = state;
183 io.in.name = generate_name(tmp_ctx, idx);
184 io.in.dest_addr = state->wins_server;
185 io.in.broadcast = False;
186 io.in.wins_lookup = True;
190 req = nbt_name_query_send(nbtsock, &io);
192 req->async.fn = query_handler;
193 req->async.private = istate;
195 talloc_free(tmp_ctx);
199 generate one WINS request
201 static void generate_request(struct nbt_name_socket *nbtsock, struct wins_state *state, int idx)
203 if (random() % 5 == 0) {
204 generate_register(nbtsock, state, idx);
208 if (random() % 20 == 0) {
209 generate_release(nbtsock, state, idx);
213 generate_query(nbtsock, state, idx);
217 benchmark simple name queries
219 static BOOL bench_wins(TALLOC_CTX *mem_ctx, struct nbt_name *name, const char *address)
221 struct nbt_name_socket *nbtsock = nbt_name_socket_init(mem_ctx, NULL);
223 struct timeval tv = timeval_current();
225 int timelimit = lp_parm_int(-1, "torture", "timelimit", 10);
226 struct wins_state *state;
227 extern int torture_entries;
229 state = talloc_zero(nbtsock, struct wins_state);
231 state->num_names = torture_entries;
232 state->registered = talloc_zero_array(state, BOOL, state->num_names);
233 state->wins_server = address;
234 state->my_ip = talloc_strdup(mem_ctx, iface_best_ip(address));
235 state->ttl = timelimit;
237 socket_listen(nbtsock->sock, state->my_ip, 0, 0, 0);
239 printf("Running for %d seconds\n", timelimit);
240 while (timeval_elapsed(&tv) < timelimit) {
241 while (num_sent - (state->pass_count+state->fail_count) < 10) {
242 generate_request(nbtsock, state, num_sent % state->num_names);
244 if (num_sent % 50 == 0) {
245 printf("%.1f queries per second (%d failures) \r",
246 state->pass_count / timeval_elapsed(&tv),
251 event_loop_once(nbtsock->event_ctx);
254 while (num_sent != (state->pass_count + state->fail_count)) {
255 event_loop_once(nbtsock->event_ctx);
258 printf("%.1f queries per second (%d failures) \n",
259 state->pass_count / timeval_elapsed(&tv),
262 talloc_free(nbtsock);
268 benchmark how fast a WINS server can respond to a mixture of
269 registration/refresh/release and name query requests
271 BOOL torture_bench_wins(void)
274 struct nbt_name name;
275 TALLOC_CTX *mem_ctx = talloc_new(NULL);
279 make_nbt_name_server(&name, lp_parm_string(-1, "torture", "host"));
281 /* do an initial name resolution to find its IP */
282 status = resolve_name(&name, mem_ctx, &address, event_context_find(mem_ctx));
283 if (!NT_STATUS_IS_OK(status)) {
284 printf("Failed to resolve %s - %s\n",
285 name.name, nt_errstr(status));
286 talloc_free(mem_ctx);
290 ret &= bench_wins(mem_ctx, &name, address);
292 talloc_free(mem_ctx);