2
Unix SMB/CIFS implementation.
3
basic raw test suite for multiplexing
4
Copyright (C) Andrew Tridgell 2003
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.
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.
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/>.
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"
28
#define BASEDIR "\\test_mux"
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)); \
40
test the delayed reply to a open that leads to a sharing violation
42
static bool test_mux_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
48
struct smbcli_request *req1, *req2;
52
printf("testing multiplexed open/open/close\n");
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;
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;
77
tv = timeval_current();
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);
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);
88
printf("open delay %.2f\n", d);
91
printf("send async open, conflicting\n");
92
tv = timeval_current();
93
req1 = smb_raw_open_send(cli->tree, &io);
95
printf("send 2nd async open, conflicting\n");
96
tv = timeval_current();
97
req2 = smb_raw_open_send(cli->tree, &io);
99
printf("close first sync open\n");
100
smbcli_close(cli->tree, fnum1);
102
printf("cancel 2nd async open (should be ignored)\n");
103
smb_raw_ntcancel(req2);
105
d = timeval_elapsed(&tv);
107
printf("bad timeout after cancel - %.2f should be <0.25\n", d);
111
printf("close the 2nd sync open\n");
112
smbcli_close(cli->tree, fnum2);
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);
118
d = timeval_elapsed(&tv);
120
printf("bad timeout for async conflict - %.2f should be <0.25\n", d);
123
printf("async open delay %.2f\n", d);
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);
131
printf("bad timeout for async conflict - %.2f should be 1.0\n", d);
134
printf("close the 1st async open\n");
135
smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
143
test a write that hits a byte range lock and send the close after the write
145
static bool test_mux_write(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
151
struct smbcli_request *req;
153
printf("testing multiplexed lock/write/close\n");
155
fnum = smbcli_open(cli->tree, BASEDIR "\\write.dat", O_RDWR | O_CREAT, DENY_NONE);
157
printf("open failed in mux_write - %s\n", smbcli_errstr(cli->tree));
162
cli->session->pid = 1;
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));
171
cli->session->pid = 2;
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);
183
/* unlock the range */
184
cli->session->pid = 1;
185
smbcli_unlock(cli->tree, fnum, 0, 4);
187
/* and recv the async write reply */
188
status = smb_raw_write_recv(req, &io);
189
CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
191
smbcli_close(cli->tree, fnum);
199
test a lock that conflicts with an existing lock
201
static bool test_mux_lock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
207
struct smbcli_request *req;
208
struct smb_lock_entry lock[1];
211
printf("TESTING MULTIPLEXED LOCK/LOCK/UNLOCK\n");
213
fnum = smbcli_open(cli->tree, BASEDIR "\\write.dat", O_RDWR | O_CREAT, DENY_NONE);
215
printf("open failed in mux_write - %s\n", smbcli_errstr(cli->tree));
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;
230
io.lockx.in.locks = &lock[0];
232
status = smb_raw_lock(cli->tree, &io);
233
CHECK_STATUS(status, NT_STATUS_OK);
235
printf("the second lock will conflict with the first\n");
237
io.lockx.in.timeout = 1000;
238
status = smb_raw_lock(cli->tree, &io);
239
CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
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);
245
printf("unlock the first range\n");
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);
253
printf("recv the async reply\n");
254
status = smbcli_request_simple_recv(req);
255
CHECK_STATUS(status, NT_STATUS_OK);
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");
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);
267
printf("Now trying with a cancel\n");
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;
278
io.lockx.in.locks = &lock[0];
280
status = smb_raw_lock(cli->tree, &io);
281
CHECK_STATUS(status, NT_STATUS_OK);
284
io.lockx.in.timeout = 1000;
285
status = smb_raw_lock(cli->tree, &io);
286
CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
288
req = smb_raw_lock_send(cli->tree, &io);
290
/* cancel the blocking lock */
291
smb_raw_ntcancel(req);
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);
298
printf("sent 2nd cancel\n");
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);
307
status = smbcli_request_simple_recv(req);
308
CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
310
printf("cancel a lock using exit to close file\n");
312
io.lockx.in.ulock_cnt = 0;
313
io.lockx.in.lock_cnt = 1;
314
io.lockx.in.timeout = 1000;
316
status = smb_raw_lock(cli->tree, &io);
317
CHECK_STATUS(status, NT_STATUS_OK);
319
t = timeval_current();
321
req = smb_raw_lock_send(cli->tree, &io);
323
smb_raw_exit(cli->session);
324
smb_raw_exit(cli->session);
325
smb_raw_exit(cli->session);
326
smb_raw_exit(cli->session);
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");
344
basic testing of multiplexing notify
346
bool torture_raw_mux(struct torture_context *torture, struct smbcli_state *cli)
350
if (!torture_setup_dir(cli, BASEDIR)) {
354
ret &= test_mux_open(cli, torture);
355
ret &= test_mux_write(cli, torture);
356
ret &= test_mux_lock(cli, torture);
358
smb_raw_exit(cli->session);
359
smbcli_deltree(cli->tree, BASEDIR);