~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/torture/raw/mux.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 3 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, see <http://www.gnu.org/licenses/>.
 
18
*/
 
19
 
 
20
#include "includes.h"
 
21
#include "torture/torture.h"
 
22
#include "system/filesys.h"
 
23
#include "libcli/raw/libcliraw.h"
 
24
#include "libcli/raw/raw_proto.h"
 
25
#include "libcli/libcli.h"
 
26
#include "torture/util.h"
 
27
 
 
28
#define BASEDIR "\\test_mux"
 
29
 
 
30
#define CHECK_STATUS(status, correct) do { \
 
31
        if (!NT_STATUS_EQUAL(status, correct)) { \
 
32
                printf("(%s) Incorrect status %s - should be %s\n", \
 
33
                       __location__, nt_errstr(status), nt_errstr(correct)); \
 
34
                ret = false; \
 
35
                goto done; \
 
36
        }} while (0)
 
37
 
 
38
 
 
39
/*
 
40
  test the delayed reply to a open that leads to a sharing violation
 
41
*/
 
42
static bool test_mux_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 
43
{
 
44
        union smb_open io;
 
45
        NTSTATUS status;
 
46
        int fnum1, fnum2;
 
47
        bool ret = true;
 
48
        struct smbcli_request *req1, *req2;
 
49
        struct timeval tv;
 
50
        double d;
 
51
 
 
52
        printf("testing multiplexed open/open/close\n");
 
53
 
 
54
        printf("send first open\n");
 
55
        io.generic.level = RAW_OPEN_NTCREATEX;
 
56
        io.ntcreatex.in.root_fid = 0;
 
57
        io.ntcreatex.in.flags = 0;
 
58
        io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA;
 
59
        io.ntcreatex.in.create_options = 0;
 
60
        io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
 
61
        io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
 
62
        io.ntcreatex.in.alloc_size = 0;
 
63
        io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
 
64
        io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
 
65
        io.ntcreatex.in.security_flags = 0;
 
66
        io.ntcreatex.in.fname = BASEDIR "\\open.dat";
 
67
        status = smb_raw_open(cli->tree, mem_ctx, &io);
 
68
        CHECK_STATUS(status, NT_STATUS_OK);
 
69
        fnum1 = io.ntcreatex.out.file.fnum;
 
70
 
 
71
        printf("send 2nd open, non-conflicting\n");
 
72
        io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
 
73
        status = smb_raw_open(cli->tree, mem_ctx, &io);
 
74
        CHECK_STATUS(status, NT_STATUS_OK);
 
75
        fnum2 = io.ntcreatex.out.file.fnum;
 
76
 
 
77
        tv = timeval_current();
 
78
 
 
79
        printf("send 3rd open, conflicting\n");
 
80
        io.ntcreatex.in.share_access = 0;
 
81
        status = smb_raw_open(cli->tree, mem_ctx, &io);
 
82
        CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
 
83
 
 
84
        d = timeval_elapsed(&tv);
 
85
        if (d < 0.5 || d > 1.5) {
 
86
                printf("bad timeout for conflict - %.2f should be 1.0\n", d);
 
87
        } else {
 
88
                printf("open delay %.2f\n", d);
 
89
        }
 
90
 
 
91
        printf("send async open, conflicting\n");
 
92
        tv = timeval_current();
 
93
        req1 = smb_raw_open_send(cli->tree, &io);
 
94
 
 
95
        printf("send 2nd async open, conflicting\n");
 
96
        tv = timeval_current();
 
97
        req2 = smb_raw_open_send(cli->tree, &io);
 
98
        
 
99
        printf("close first sync open\n");
 
100
        smbcli_close(cli->tree, fnum1);
 
101
 
 
102
        printf("cancel 2nd async open (should be ignored)\n");
 
103
        smb_raw_ntcancel(req2);
 
104
 
 
105
        d = timeval_elapsed(&tv);
 
106
        if (d > 0.25) {
 
107
                printf("bad timeout after cancel - %.2f should be <0.25\n", d);
 
108
                ret = false;
 
109
        }
 
110
 
 
111
        printf("close the 2nd sync open\n");
 
112
        smbcli_close(cli->tree, fnum2);
 
113
 
 
114
        printf("see if the 1st async open now succeeded\n");
 
115
        status = smb_raw_open_recv(req1, mem_ctx, &io);
 
116
        CHECK_STATUS(status, NT_STATUS_OK);
 
117
 
 
118
        d = timeval_elapsed(&tv);
 
119
        if (d > 0.25) {
 
120
                printf("bad timeout for async conflict - %.2f should be <0.25\n", d);
 
121
                ret = false;
 
122
        } else {
 
123
                printf("async open delay %.2f\n", d);
 
124
        }
 
125
 
 
126
        printf("2nd async open should have timed out\n");
 
127
        status = smb_raw_open_recv(req2, mem_ctx, &io);
 
128
        CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
 
129
        d = timeval_elapsed(&tv);
 
130
        if (d < 0.8) {
 
131
                printf("bad timeout for async conflict - %.2f should be 1.0\n", d);
 
132
        }
 
133
 
 
134
        printf("close the 1st async open\n");
 
135
        smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
 
136
 
 
137
done:
 
138
        return ret;
 
139
}
 
140
 
 
141
 
 
142
/*
 
143
  test a write that hits a byte range lock and send the close after the write
 
144
*/
 
145
static bool test_mux_write(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 
146
{
 
147
        union smb_write io;
 
148
        NTSTATUS status;
 
149
        int fnum;
 
150
        bool ret = true;
 
151
        struct smbcli_request *req;
 
152
 
 
153
        printf("testing multiplexed lock/write/close\n");
 
154
 
 
155
        fnum = smbcli_open(cli->tree, BASEDIR "\\write.dat", O_RDWR | O_CREAT, DENY_NONE);
 
156
        if (fnum == -1) {
 
157
                printf("open failed in mux_write - %s\n", smbcli_errstr(cli->tree));
 
158
                ret = false;
 
159
                goto done;
 
160
        }
 
161
 
 
162
        cli->session->pid = 1;
 
163
 
 
164
        /* lock a range */
 
165
        if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 0, 4, 0, WRITE_LOCK))) {
 
166
                printf("lock failed in mux_write - %s\n", smbcli_errstr(cli->tree));
 
167
                ret = false;
 
168
                goto done;
 
169
        }
 
170
 
 
171
        cli->session->pid = 2;
 
172
 
 
173
        /* send an async write */
 
174
        io.generic.level = RAW_WRITE_WRITEX;
 
175
        io.writex.in.file.fnum = fnum;
 
176
        io.writex.in.offset = 0;
 
177
        io.writex.in.wmode = 0;
 
178
        io.writex.in.remaining = 0;
 
179
        io.writex.in.count = 4;
 
180
        io.writex.in.data = (const uint8_t *)&fnum;     
 
181
        req = smb_raw_write_send(cli->tree, &io);
 
182
 
 
183
        /* unlock the range */
 
184
        cli->session->pid = 1;
 
185
        smbcli_unlock(cli->tree, fnum, 0, 4);
 
186
 
 
187
        /* and recv the async write reply */
 
188
        status = smb_raw_write_recv(req, &io);
 
189
        CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
 
190
 
 
191
        smbcli_close(cli->tree, fnum);
 
192
 
 
193
done:
 
194
        return ret;
 
195
}
 
196
 
 
197
 
 
198
/*
 
199
  test a lock that conflicts with an existing lock
 
200
*/
 
201
static bool test_mux_lock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 
202
{
 
203
        union smb_lock io;
 
204
        NTSTATUS status;
 
205
        int fnum;
 
206
        bool ret = true;
 
207
        struct smbcli_request *req;
 
208
        struct smb_lock_entry lock[1];
 
209
        struct timeval t;
 
210
 
 
211
        printf("TESTING MULTIPLEXED LOCK/LOCK/UNLOCK\n");
 
212
 
 
213
        fnum = smbcli_open(cli->tree, BASEDIR "\\write.dat", O_RDWR | O_CREAT, DENY_NONE);
 
214
        if (fnum == -1) {
 
215
                printf("open failed in mux_write - %s\n", smbcli_errstr(cli->tree));
 
216
                ret = false;
 
217
                goto done;
 
218
        }
 
219
 
 
220
        printf("establishing a lock\n");
 
221
        io.lockx.level = RAW_LOCK_LOCKX;
 
222
        io.lockx.in.file.fnum = fnum;
 
223
        io.lockx.in.mode = 0;
 
224
        io.lockx.in.timeout = 0;
 
225
        io.lockx.in.lock_cnt = 1;
 
226
        io.lockx.in.ulock_cnt = 0;
 
227
        lock[0].pid = 1;
 
228
        lock[0].offset = 0;
 
229
        lock[0].count = 4;
 
230
        io.lockx.in.locks = &lock[0];
 
231
 
 
232
        status = smb_raw_lock(cli->tree, &io);
 
233
        CHECK_STATUS(status, NT_STATUS_OK);
 
234
 
 
235
        printf("the second lock will conflict with the first\n");
 
236
        lock[0].pid = 2;
 
237
        io.lockx.in.timeout = 1000;
 
238
        status = smb_raw_lock(cli->tree, &io);
 
239
        CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
 
240
 
 
241
        printf("this will too, but we'll unlock while waiting\n");
 
242
        t = timeval_current();
 
243
        req = smb_raw_lock_send(cli->tree, &io);
 
244
 
 
245
        printf("unlock the first range\n");
 
246
        lock[0].pid = 1;
 
247
        io.lockx.in.ulock_cnt = 1;
 
248
        io.lockx.in.lock_cnt = 0;
 
249
        io.lockx.in.timeout = 0;
 
250
        status = smb_raw_lock(cli->tree, &io);
 
251
        CHECK_STATUS(status, NT_STATUS_OK);
 
252
 
 
253
        printf("recv the async reply\n");
 
254
        status = smbcli_request_simple_recv(req);
 
255
        CHECK_STATUS(status, NT_STATUS_OK);     
 
256
 
 
257
        printf("async lock took %.2f msec\n", timeval_elapsed(&t) * 1000);
 
258
        if (timeval_elapsed(&t) > 0.1) {
 
259
                printf("failed to trigger early lock retry\n");
 
260
                return false;           
 
261
        }
 
262
 
 
263
        printf("reopening with an exit\n");
 
264
        smb_raw_exit(cli->session);
 
265
        fnum = smbcli_open(cli->tree, BASEDIR "\\write.dat", O_RDWR | O_CREAT, DENY_NONE);
 
266
 
 
267
        printf("Now trying with a cancel\n");
 
268
 
 
269
        io.lockx.level = RAW_LOCK_LOCKX;
 
270
        io.lockx.in.file.fnum = fnum;
 
271
        io.lockx.in.mode = 0;
 
272
        io.lockx.in.timeout = 0;
 
273
        io.lockx.in.lock_cnt = 1;
 
274
        io.lockx.in.ulock_cnt = 0;
 
275
        lock[0].pid = 1;
 
276
        lock[0].offset = 0;
 
277
        lock[0].count = 4;
 
278
        io.lockx.in.locks = &lock[0];
 
279
 
 
280
        status = smb_raw_lock(cli->tree, &io);
 
281
        CHECK_STATUS(status, NT_STATUS_OK);
 
282
 
 
283
        lock[0].pid = 2;
 
284
        io.lockx.in.timeout = 1000;
 
285
        status = smb_raw_lock(cli->tree, &io);
 
286
        CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
 
287
 
 
288
        req = smb_raw_lock_send(cli->tree, &io);
 
289
 
 
290
        /* cancel the blocking lock */
 
291
        smb_raw_ntcancel(req);
 
292
 
 
293
        printf("sending 2nd cancel\n");
 
294
        /* the 2nd cancel is totally harmless, but tests the server trying to 
 
295
           cancel an already cancelled request */
 
296
        smb_raw_ntcancel(req);
 
297
 
 
298
        printf("sent 2nd cancel\n");
 
299
 
 
300
        lock[0].pid = 1;
 
301
        io.lockx.in.ulock_cnt = 1;
 
302
        io.lockx.in.lock_cnt = 0;
 
303
        io.lockx.in.timeout = 0;
 
304
        status = smb_raw_lock(cli->tree, &io);
 
305
        CHECK_STATUS(status, NT_STATUS_OK);
 
306
 
 
307
        status = smbcli_request_simple_recv(req);
 
308
        CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);     
 
309
 
 
310
        printf("cancel a lock using exit to close file\n");
 
311
        lock[0].pid = 1;
 
312
        io.lockx.in.ulock_cnt = 0;
 
313
        io.lockx.in.lock_cnt = 1;
 
314
        io.lockx.in.timeout = 1000;
 
315
 
 
316
        status = smb_raw_lock(cli->tree, &io);
 
317
        CHECK_STATUS(status, NT_STATUS_OK);
 
318
 
 
319
        t = timeval_current();
 
320
        lock[0].pid = 2;
 
321
        req = smb_raw_lock_send(cli->tree, &io);
 
322
 
 
323
        smb_raw_exit(cli->session);
 
324
        smb_raw_exit(cli->session);
 
325
        smb_raw_exit(cli->session);
 
326
        smb_raw_exit(cli->session);
 
327
 
 
328
        printf("recv the async reply\n");
 
329
        status = smbcli_request_simple_recv(req);
 
330
        CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
 
331
        printf("async lock exit took %.2f msec\n", timeval_elapsed(&t) * 1000);
 
332
        if (timeval_elapsed(&t) > 0.1) {
 
333
                printf("failed to trigger early lock failure\n");
 
334
                return false;           
 
335
        }
 
336
 
 
337
done:
 
338
        return ret;
 
339
}
 
340
 
 
341
 
 
342
 
 
343
/* 
 
344
   basic testing of multiplexing notify
 
345
*/
 
346
bool torture_raw_mux(struct torture_context *torture, struct smbcli_state *cli)
 
347
{
 
348
        bool ret = true;
 
349
                
 
350
        if (!torture_setup_dir(cli, BASEDIR)) {
 
351
                return false;
 
352
        }
 
353
 
 
354
        ret &= test_mux_open(cli, torture);
 
355
        ret &= test_mux_write(cli, torture);
 
356
        ret &= test_mux_lock(cli, torture);
 
357
 
 
358
        smb_raw_exit(cli->session);
 
359
        smbcli_deltree(cli->tree, BASEDIR);
 
360
        return ret;
 
361
}