This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
+#include "torture/torture.h"
+#include "system/filesys.h"
#include "libcli/raw/libcliraw.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
#define BASEDIR "\\test_mux"
#define CHECK_STATUS(status, correct) do { \
if (!NT_STATUS_EQUAL(status, correct)) { \
- printf("(%d) Incorrect status %s - should be %s\n", \
- __LINE__, nt_errstr(status), nt_errstr(correct)); \
+ printf("(%s) Incorrect status %s - should be %s\n", \
+ __location__, nt_errstr(status), nt_errstr(correct)); \
ret = False; \
goto done; \
}} while (0)
{
union smb_open io;
NTSTATUS status;
- int fnum;
+ int fnum1, fnum2;
BOOL ret = True;
- struct smbcli_request *req;
+ struct smbcli_request *req1, *req2;
+ struct timeval tv;
+ double d;
printf("testing multiplexed open/open/close\n");
- /*
- file open with no share access
- */
+ printf("send first open\n");
io.generic.level = RAW_OPEN_NTCREATEX;
io.ntcreatex.in.root_fid = 0;
io.ntcreatex.in.flags = 0;
- io.ntcreatex.in.access_mask = SEC_RIGHT_MAXIMUM_ALLOWED;
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA;
io.ntcreatex.in.create_options = 0;
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
- io.ntcreatex.in.share_access = 0;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
io.ntcreatex.in.alloc_size = 0;
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
io.ntcreatex.in.fname = BASEDIR "\\open.dat";
status = smb_raw_open(cli->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
- fnum = io.ntcreatex.out.fnum;
+ fnum1 = io.ntcreatex.out.file.fnum;
- /* send an open that will conflict */
+ printf("send 2nd open, non-conflicting\n");
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+
+ tv = timeval_current();
+
+ printf("send 3rd open, conflicting\n");
+ io.ntcreatex.in.share_access = 0;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
- /*
- same request, but async
- */
- req = smb_raw_open_send(cli->tree, &io);
+ d = timeval_elapsed(&tv);
+ if (d < 0.5 || d > 1.5) {
+ printf("bad timeout for conflict - %.2f should be 1.0\n", d);
+ } else {
+ printf("open delay %.2f\n", d);
+ }
+
+ printf("send async open, conflicting\n");
+ tv = timeval_current();
+ req1 = smb_raw_open_send(cli->tree, &io);
+
+ printf("send 2nd async open, conflicting\n");
+ tv = timeval_current();
+ req2 = smb_raw_open_send(cli->tree, &io);
- /* and close the file */
- smbcli_close(cli->tree, fnum);
+ printf("close first sync open\n");
+ smbcli_close(cli->tree, fnum1);
- /* see if the async open succeeded */
- status = smb_raw_open_recv(req, mem_ctx, &io);
+ printf("cancel 2nd async open (should be ignored)\n");
+ smb_raw_ntcancel(req2);
+
+ d = timeval_elapsed(&tv);
+ if (d > 0.25) {
+ printf("bad timeout after cancel - %.2f should be <0.25\n", d);
+ ret = False;
+ }
+
+ printf("close the 2nd sync open\n");
+ smbcli_close(cli->tree, fnum2);
+
+ printf("see if the 1st async open now succeeded\n");
+ status = smb_raw_open_recv(req1, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
- smbcli_close(cli->tree, io.ntcreatex.out.fnum);
+ d = timeval_elapsed(&tv);
+ if (d > 0.25) {
+ printf("bad timeout for async conflict - %.2f should be <0.25\n", d);
+ ret = False;
+ } else {
+ printf("async open delay %.2f\n", d);
+ }
+
+ printf("2nd async open should have timed out\n");
+ status = smb_raw_open_recv(req2, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+ d = timeval_elapsed(&tv);
+ if (d < 0.8) {
+ printf("bad timeout for async conflict - %.2f should be 1.0\n", d);
+ }
+
+ printf("close the 1st async open\n");
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
done:
return ret;
/* send an async write */
io.generic.level = RAW_WRITE_WRITEX;
- io.writex.in.fnum = fnum;
+ io.writex.in.file.fnum = fnum;
io.writex.in.offset = 0;
io.writex.in.wmode = 0;
io.writex.in.remaining = 0;
BOOL ret = True;
struct smbcli_request *req;
struct smb_lock_entry lock[1];
+ struct timeval t;
printf("TESTING MULTIPLEXED LOCK/LOCK/UNLOCK\n");
printf("establishing a lock\n");
io.lockx.level = RAW_LOCK_LOCKX;
- io.lockx.in.fnum = fnum;
+ io.lockx.in.file.fnum = fnum;
io.lockx.in.mode = 0;
io.lockx.in.timeout = 0;
io.lockx.in.lock_cnt = 1;
CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
printf("this will too, but we'll unlock while waiting\n");
+ t = timeval_current();
req = smb_raw_lock_send(cli->tree, &io);
printf("unlock the first range\n");
status = smbcli_request_simple_recv(req);
CHECK_STATUS(status, NT_STATUS_OK);
+ printf("async lock took %.2f msec\n", timeval_elapsed(&t) * 1000);
+ if (timeval_elapsed(&t) > 0.1) {
+ printf("failed to trigger early lock retry\n");
+ return False;
+ }
+
printf("reopening with an exit\n");
smb_raw_exit(cli->session);
fnum = smbcli_open(cli->tree, BASEDIR "\\write.dat", O_RDWR | O_CREAT, DENY_NONE);
printf("Now trying with a cancel\n");
io.lockx.level = RAW_LOCK_LOCKX;
- io.lockx.in.fnum = fnum;
+ io.lockx.in.file.fnum = fnum;
io.lockx.in.mode = 0;
io.lockx.in.timeout = 0;
io.lockx.in.lock_cnt = 1;
/* cancel the blocking lock */
smb_raw_ntcancel(req);
+ printf("sending 2nd cancel\n");
+ /* the 2nd cancel is totally harmless, but tests the server trying to
+ cancel an already cancelled request */
+ smb_raw_ntcancel(req);
+
+ printf("sent 2nd cancel\n");
+
lock[0].pid = 1;
io.lockx.in.ulock_cnt = 1;
io.lockx.in.lock_cnt = 0;
status = smbcli_request_simple_recv(req);
CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
- smbcli_close(cli->tree, fnum);
+ printf("cancel a lock using exit to close file\n");
+ lock[0].pid = 1;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.timeout = 1000;
+
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ t = timeval_current();
+ lock[0].pid = 2;
+ req = smb_raw_lock_send(cli->tree, &io);
+
+ smb_raw_exit(cli->session);
+ smb_raw_exit(cli->session);
+ smb_raw_exit(cli->session);
+ smb_raw_exit(cli->session);
+
+ printf("recv the async reply\n");
+ status = smbcli_request_simple_recv(req);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+ printf("async lock exit took %.2f msec\n", timeval_elapsed(&t) * 1000);
+ if (timeval_elapsed(&t) > 0.1) {
+ printf("failed to trigger early lock failure\n");
+ return False;
+ }
done:
return ret;
/*
basic testing of multiplexing notify
*/
-BOOL torture_raw_mux(void)
+BOOL torture_raw_mux(struct torture_context *torture)
{
struct smbcli_state *cli;
BOOL ret = True;
TALLOC_CTX *mem_ctx;
- if (!torture_open_connection(&cli)) {
+ if (!torture_open_connection(&cli, 0)) {
return False;
}
mem_ctx = talloc_init("torture_raw_mux");
- /* cleanup */
- if (smbcli_deltree(cli->tree, BASEDIR) == -1) {
- printf("Failed to cleanup " BASEDIR "\n");
- ret = False;
- goto done;
- }
-
-
- if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, BASEDIR))) {
- printf("Failed to create %s\n", BASEDIR);
- ret = False;
- goto done;
+ if (!torture_setup_dir(cli, BASEDIR)) {
+ return False;
}
if (!test_mux_open(cli, mem_ctx)) {
ret = False;
}
-done:
smb_raw_exit(cli->session);
smbcli_deltree(cli->tree, BASEDIR);
torture_close_connection(cli);
- talloc_destroy(mem_ctx);
+ talloc_free(mem_ctx);
return ret;
}