r23792: convert Samba4 to GPLv3
[kai/samba-autobuild/.git] / source4 / torture / raw / mux.c
index c184fb79a7adfe596e07620cdf0eb611240796f7..d61d037239b391b4a6d525c127893bf170a69aed 100644 (file)
@@ -5,7 +5,7 @@
    
    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)
@@ -39,22 +42,22 @@ static BOOL test_mux_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 {
        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;
@@ -62,26 +65,73 @@ static BOOL test_mux_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        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;
@@ -121,7 +171,7 @@ static BOOL test_mux_write(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 
        /* 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;
@@ -155,6 +205,7 @@ static BOOL test_mux_lock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        BOOL ret = True;
        struct smbcli_request *req;
        struct smb_lock_entry lock[1];
+       struct timeval t;
 
        printf("TESTING MULTIPLEXED LOCK/LOCK/UNLOCK\n");
 
@@ -167,7 +218,7 @@ static BOOL test_mux_lock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 
        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;
@@ -187,6 +238,7 @@ static BOOL test_mux_lock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        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");
@@ -201,6 +253,12 @@ static BOOL test_mux_lock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        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);
@@ -208,7 +266,7 @@ static BOOL test_mux_lock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        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;
@@ -231,6 +289,13 @@ static BOOL test_mux_lock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        /* 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;
@@ -241,7 +306,32 @@ static BOOL test_mux_lock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        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;
@@ -252,30 +342,20 @@ done:
 /* 
    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)) {
@@ -290,10 +370,9 @@ BOOL torture_raw_mux(void)
                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;
 }