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