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 3 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, see <http://www.gnu.org/licenses/>.
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"
37 const char *wins_server
;
45 struct wins_state
*state
;
48 static struct nbt_name
generate_name(TALLOC_CTX
*tctx
, int idx
)
51 name
.name
= talloc_asprintf(tctx
, "WINSBench%6u", idx
);
57 static void register_handler(struct nbt_name_request
*req
)
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
;
64 status
= nbt_name_register_recv(req
, istate
, &io
);
65 if (!NT_STATUS_IS_OK(status
) || io
.out
.rcode
!= NBT_RCODE_OK
) {
69 state
->registered
[istate
->idx
] = true;
75 generate a registration
77 static void generate_register(struct nbt_name_socket
*nbtsock
, struct wins_state
*state
, int idx
)
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
;
84 istate
= talloc(nbtsock
, struct idx_state
);
86 istate
->state
= state
;
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
;
100 req
= nbt_name_register_send(nbtsock
, &io
);
102 req
->async
.fn
= register_handler
;
103 req
->async
.private_data
= istate
;
105 talloc_free(tmp_ctx
);
109 static void release_handler(struct nbt_name_request
*req
)
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
;
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
)) {
122 state
->registered
[istate
->idx
] = false;
128 generate a name release
130 static void generate_release(struct nbt_name_socket
*nbtsock
, struct wins_state
*state
, int idx
)
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
;
137 istate
= talloc(nbtsock
, struct idx_state
);
139 istate
->state
= state
;
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;
150 req
= nbt_name_release_send(nbtsock
, &io
);
152 req
->async
.fn
= release_handler
;
153 req
->async
.private_data
= istate
;
155 talloc_free(tmp_ctx
);
159 static void query_handler(struct nbt_name_request
*req
)
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
;
166 status
= nbt_name_query_recv(req
, istate
, &io
);
167 if (!NT_STATUS_IS_OK(status
) && state
->registered
[istate
->idx
]) {
176 generate a name query
178 static void generate_query(struct nbt_name_socket
*nbtsock
, struct wins_state
*state
, int idx
)
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
;
185 istate
= talloc(nbtsock
, struct idx_state
);
187 istate
->state
= state
;
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;
197 req
= nbt_name_query_send(nbtsock
, &io
);
199 req
->async
.fn
= query_handler
;
200 req
->async
.private_data
= istate
;
202 talloc_free(tmp_ctx
);
206 generate one WINS request
208 static void generate_request(struct nbt_name_socket
*nbtsock
, struct wins_state
*state
, int idx
)
210 if (random() % 5 == 0) {
211 generate_register(nbtsock
, state
, idx
);
215 if (random() % 20 == 0) {
216 generate_release(nbtsock
, state
, idx
);
220 generate_query(nbtsock
, state
, idx
);
224 benchmark simple name queries
226 static bool bench_wins(struct torture_context
*tctx
)
228 struct nbt_name_socket
*nbtsock
= nbt_name_socket_init(tctx
, tctx
->ev
);
230 struct timeval tv
= timeval_current();
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
;
238 struct interface
*ifaces
;
240 if (!torture_nbt_get_name(tctx
, &name
, &address
))
243 state
= talloc_zero(nbtsock
, struct wins_state
);
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
= lpcfg_nbt_port(tctx
->lp_ctx
);
249 load_interface_list(tctx
, tctx
->lp_ctx
, &ifaces
);
250 state
->my_ip
= talloc_strdup(tctx
, iface_list_best_ip(ifaces
, address
));
251 state
->ttl
= timelimit
;
253 my_ip
= socket_address_from_strings(nbtsock
, nbtsock
->sock
->backend_name
,
256 socket_listen(nbtsock
->sock
, my_ip
, 0, 0);
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
);
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
),
273 tevent_loop_once(nbtsock
->event_ctx
);
276 while (num_sent
!= (state
->pass_count
+ state
->fail_count
)) {
277 tevent_loop_once(nbtsock
->event_ctx
);
280 torture_comment(tctx
, "%.1f queries per second (%d failures) \n",
281 state
->pass_count
/ timeval_elapsed(&tv
),
284 talloc_free(nbtsock
);
290 benchmark how fast a WINS server can respond to a mixture of
291 registration/refresh/release and name query requests
293 struct torture_suite
*torture_bench_wins(TALLOC_CTX
*mem_ctx
)
295 struct torture_suite
*suite
= torture_suite_create(mem_ctx
, "bench-wins");
297 torture_suite_add_simple_test(suite
, "wins", bench_wins
);