• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src/router/samba-3.5.8/source4/torture/nbt/
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
32struct 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
43struct idx_state {
44	int idx;
45	struct wins_state *state;
46};
47
48static struct nbt_name generate_name(TALLOC_CTX *tctx, int idx)
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
57static void register_handler(struct nbt_name_request *req)
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*/
77static void generate_register(struct nbt_name_socket *nbtsock, struct wins_state *state, int idx)
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
109static void release_handler(struct nbt_name_request *req)
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*/
130static void generate_release(struct nbt_name_socket *nbtsock, struct wins_state *state, int idx)
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
159static void query_handler(struct nbt_name_request *req)
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*/
178static void generate_query(struct nbt_name_socket *nbtsock, struct wins_state *state, int idx)
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*/
208static void generate_request(struct nbt_name_socket *nbtsock, struct wins_state *state, int idx)
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*/
226static bool bench_wins(struct torture_context *tctx)
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*/
293struct torture_suite *torture_bench_wins(TALLOC_CTX *mem_ctx)
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}
302