r5037: got rid of all of the TALLOC_DEPRECATED stuff. My apologies for the
[ira/wip.git] / source4 / torture / raw / mux.c
1 /* 
2    Unix SMB/CIFS implementation.
3    basic raw test suite for multiplexing
4    Copyright (C) Andrew Tridgell 2003
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22 #include "libcli/raw/libcliraw.h"
23 #include "librpc/gen_ndr/ndr_security.h"
24
25 #define BASEDIR "\\test_mux"
26
27 #define CHECK_STATUS(status, correct) do { \
28         if (!NT_STATUS_EQUAL(status, correct)) { \
29                 printf("(%s) Incorrect status %s - should be %s\n", \
30                        __location__, nt_errstr(status), nt_errstr(correct)); \
31                 ret = False; \
32                 goto done; \
33         }} while (0)
34
35
36 /*
37   test the delayed reply to a open that leads to a sharing violation
38 */
39 static BOOL test_mux_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
40 {
41         union smb_open io;
42         NTSTATUS status;
43         int fnum1, fnum2;
44         BOOL ret = True;
45         struct smbcli_request *req1, *req2;
46         struct timeval tv;
47         double d;
48
49         printf("testing multiplexed open/open/close\n");
50
51         printf("send first open\n");
52         io.generic.level = RAW_OPEN_NTCREATEX;
53         io.ntcreatex.in.root_fid = 0;
54         io.ntcreatex.in.flags = 0;
55         io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA;
56         io.ntcreatex.in.create_options = 0;
57         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
58         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
59         io.ntcreatex.in.alloc_size = 0;
60         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
61         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
62         io.ntcreatex.in.security_flags = 0;
63         io.ntcreatex.in.fname = BASEDIR "\\open.dat";
64         status = smb_raw_open(cli->tree, mem_ctx, &io);
65         CHECK_STATUS(status, NT_STATUS_OK);
66         fnum1 = io.ntcreatex.out.fnum;
67
68         printf("send 2nd open, non-conflicting\n");
69         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
70         status = smb_raw_open(cli->tree, mem_ctx, &io);
71         CHECK_STATUS(status, NT_STATUS_OK);
72         fnum2 = io.ntcreatex.out.fnum;
73
74         tv = timeval_current();
75
76         printf("send 3rd open, conflicting\n");
77         io.ntcreatex.in.share_access = 0;
78         status = smb_raw_open(cli->tree, mem_ctx, &io);
79         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
80
81         d = timeval_elapsed(&tv);
82         if (d < 0.5 || d > 1.5) {
83                 printf("bad timeout for conflict - %.2f should be 1.0\n", d);
84         } else {
85                 printf("open delay %.2f\n", d);
86         }
87
88         printf("send async open, conflicting\n");
89         tv = timeval_current();
90         req1 = smb_raw_open_send(cli->tree, &io);
91
92         printf("send 2nd async open, conflicting\n");
93         tv = timeval_current();
94         req2 = smb_raw_open_send(cli->tree, &io);
95         
96         printf("close first sync open\n");
97         smbcli_close(cli->tree, fnum1);
98
99         printf("cancel 2nd async open (should be ignored)\n");
100         smb_raw_ntcancel(req2);
101
102         d = timeval_elapsed(&tv);
103         if (d > 0.25) {
104                 printf("bad timeout after cancel - %.2f should be <0.25\n", d);
105                 ret = False;
106         }
107
108         printf("close the 2nd sync open\n");
109         smbcli_close(cli->tree, fnum2);
110
111         printf("see if the 1st async open now succeeded\n");
112         status = smb_raw_open_recv(req1, mem_ctx, &io);
113         CHECK_STATUS(status, NT_STATUS_OK);
114
115         d = timeval_elapsed(&tv);
116         if (d > 0.25) {
117                 printf("bad timeout for async conflict - %.2f should be <0.25\n", d);
118                 ret = False;
119         } else {
120                 printf("async open delay %.2f\n", d);
121         }
122
123         printf("2nd async open should have timed out\n");
124         status = smb_raw_open_recv(req2, mem_ctx, &io);
125         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
126         d = timeval_elapsed(&tv);
127         if (d < 0.8) {
128                 printf("bad timeout for async conflict - %.2f should be 1.0\n", d);
129         }
130
131         printf("close the 1st async open\n");
132         smbcli_close(cli->tree, io.ntcreatex.out.fnum);
133
134 done:
135         return ret;
136 }
137
138
139 /*
140   test a write that hits a byte range lock and send the close after the write
141 */
142 static BOOL test_mux_write(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
143 {
144         union smb_write io;
145         NTSTATUS status;
146         int fnum;
147         BOOL ret = True;
148         struct smbcli_request *req;
149
150         printf("testing multiplexed lock/write/close\n");
151
152         fnum = smbcli_open(cli->tree, BASEDIR "\\write.dat", O_RDWR | O_CREAT, DENY_NONE);
153         if (fnum == -1) {
154                 printf("open failed in mux_write - %s\n", smbcli_errstr(cli->tree));
155                 ret = False;
156                 goto done;
157         }
158
159         cli->session->pid = 1;
160
161         /* lock a range */
162         if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 0, 4, 0, WRITE_LOCK))) {
163                 printf("lock failed in mux_write - %s\n", smbcli_errstr(cli->tree));
164                 ret = False;
165                 goto done;
166         }
167
168         cli->session->pid = 2;
169
170         /* send an async write */
171         io.generic.level = RAW_WRITE_WRITEX;
172         io.writex.in.fnum = fnum;
173         io.writex.in.offset = 0;
174         io.writex.in.wmode = 0;
175         io.writex.in.remaining = 0;
176         io.writex.in.count = 4;
177         io.writex.in.data = (void *)&fnum;      
178         req = smb_raw_write_send(cli->tree, &io);
179
180         /* unlock the range */
181         cli->session->pid = 1;
182         smbcli_unlock(cli->tree, fnum, 0, 4);
183
184         /* and recv the async write reply */
185         status = smb_raw_write_recv(req, &io);
186         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
187
188         smbcli_close(cli->tree, fnum);
189
190 done:
191         return ret;
192 }
193
194
195 /*
196   test a lock that conflicts with an existing lock
197 */
198 static BOOL test_mux_lock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
199 {
200         union smb_lock io;
201         NTSTATUS status;
202         int fnum;
203         BOOL ret = True;
204         struct smbcli_request *req;
205         struct smb_lock_entry lock[1];
206
207         printf("TESTING MULTIPLEXED LOCK/LOCK/UNLOCK\n");
208
209         fnum = smbcli_open(cli->tree, BASEDIR "\\write.dat", O_RDWR | O_CREAT, DENY_NONE);
210         if (fnum == -1) {
211                 printf("open failed in mux_write - %s\n", smbcli_errstr(cli->tree));
212                 ret = False;
213                 goto done;
214         }
215
216         printf("establishing a lock\n");
217         io.lockx.level = RAW_LOCK_LOCKX;
218         io.lockx.in.fnum = fnum;
219         io.lockx.in.mode = 0;
220         io.lockx.in.timeout = 0;
221         io.lockx.in.lock_cnt = 1;
222         io.lockx.in.ulock_cnt = 0;
223         lock[0].pid = 1;
224         lock[0].offset = 0;
225         lock[0].count = 4;
226         io.lockx.in.locks = &lock[0];
227
228         status = smb_raw_lock(cli->tree, &io);
229         CHECK_STATUS(status, NT_STATUS_OK);
230
231         printf("the second lock will conflict with the first\n");
232         lock[0].pid = 2;
233         io.lockx.in.timeout = 1000;
234         status = smb_raw_lock(cli->tree, &io);
235         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
236
237         printf("this will too, but we'll unlock while waiting\n");
238         req = smb_raw_lock_send(cli->tree, &io);
239
240         printf("unlock the first range\n");
241         lock[0].pid = 1;
242         io.lockx.in.ulock_cnt = 1;
243         io.lockx.in.lock_cnt = 0;
244         io.lockx.in.timeout = 0;
245         status = smb_raw_lock(cli->tree, &io);
246         CHECK_STATUS(status, NT_STATUS_OK);
247
248         printf("recv the async reply\n");
249         status = smbcli_request_simple_recv(req);
250         CHECK_STATUS(status, NT_STATUS_OK);     
251
252         printf("reopening with an exit\n");
253         smb_raw_exit(cli->session);
254         fnum = smbcli_open(cli->tree, BASEDIR "\\write.dat", O_RDWR | O_CREAT, DENY_NONE);
255
256         printf("Now trying with a cancel\n");
257
258         io.lockx.level = RAW_LOCK_LOCKX;
259         io.lockx.in.fnum = fnum;
260         io.lockx.in.mode = 0;
261         io.lockx.in.timeout = 0;
262         io.lockx.in.lock_cnt = 1;
263         io.lockx.in.ulock_cnt = 0;
264         lock[0].pid = 1;
265         lock[0].offset = 0;
266         lock[0].count = 4;
267         io.lockx.in.locks = &lock[0];
268
269         status = smb_raw_lock(cli->tree, &io);
270         CHECK_STATUS(status, NT_STATUS_OK);
271
272         lock[0].pid = 2;
273         io.lockx.in.timeout = 1000;
274         status = smb_raw_lock(cli->tree, &io);
275         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
276
277         req = smb_raw_lock_send(cli->tree, &io);
278
279         /* cancel the blocking lock */
280         smb_raw_ntcancel(req);
281
282         /* the 2nd cancel is totally harmless, but tests the server trying to 
283            cancel an already cancelled request */
284         smb_raw_ntcancel(req);
285
286         lock[0].pid = 1;
287         io.lockx.in.ulock_cnt = 1;
288         io.lockx.in.lock_cnt = 0;
289         io.lockx.in.timeout = 0;
290         status = smb_raw_lock(cli->tree, &io);
291         CHECK_STATUS(status, NT_STATUS_OK);
292
293         status = smbcli_request_simple_recv(req);
294         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);     
295
296         smbcli_close(cli->tree, fnum);
297
298 done:
299         return ret;
300 }
301
302
303
304 /* 
305    basic testing of multiplexing notify
306 */
307 BOOL torture_raw_mux(void)
308 {
309         struct smbcli_state *cli;
310         BOOL ret = True;
311         TALLOC_CTX *mem_ctx;
312                 
313         if (!torture_open_connection(&cli)) {
314                 return False;
315         }
316
317         mem_ctx = talloc_init("torture_raw_mux");
318
319         if (!torture_setup_dir(cli, BASEDIR)) {
320                 return False;
321         }
322
323         if (!test_mux_open(cli, mem_ctx)) {
324                 ret = False;
325         }
326
327         if (!test_mux_write(cli, mem_ctx)) {
328                 ret = False;
329         }
330
331         if (!test_mux_lock(cli, mem_ctx)) {
332                 ret = False;
333         }
334
335         smb_raw_exit(cli->session);
336         smbcli_deltree(cli->tree, BASEDIR);
337         torture_close_connection(cli);
338         talloc_free(mem_ctx);
339         return ret;
340 }