LCOV - code coverage report
Current view: top level - source4/torture/smb2 - oplock_break_handler.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 55 68 80.9 %
Date: 2024-04-21 15:09:00 Functions: 4 5 80.0 %

          Line data    Source code
       1             : /*
       2             :  * Unix SMB/CIFS implementation.
       3             :  *
       4             :  * test suite for SMB2 replay
       5             :  *
       6             :  * Copyright (C) Anubhav Rakshit 2014
       7             :  * Copyright (C) Stefan Metzmacher 2014
       8             :  *
       9             :  * This program is free software; you can redistribute it and/or modify
      10             :  * it under the terms of the GNU General Public License as published by
      11             :  * the Free Software Foundation; either version 3 of the License, or
      12             :  * (at your option) any later version.
      13             :  *
      14             :  * This program is distributed in the hope that it will be useful,
      15             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :  * GNU General Public License for more details.
      18             :  *
      19             :  * You should have received a copy of the GNU General Public License
      20             :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      21             :  */
      22             : 
      23             : #include "includes.h"
      24             : #include "libcli/smb2/smb2.h"
      25             : #include "libcli/smb2/smb2_calls.h"
      26             : #include "torture/torture.h"
      27             : #include "torture/smb2/proto.h"
      28             : #include "../libcli/smb/smbXcli_base.h"
      29             : #include "oplock_break_handler.h"
      30             : #include "lib/events/events.h"
      31             : 
      32             : struct break_info break_info;
      33             : 
      34          30 : static void torture_oplock_ack_callback(struct smb2_request *req)
      35             : {
      36           0 :         NTSTATUS status;
      37             : 
      38          30 :         status = smb2_break_recv(req, &break_info.br);
      39          30 :         if (!NT_STATUS_IS_OK(status)) {
      40           2 :                 break_info.failures++;
      41           2 :                 break_info.failure_status = status;
      42             :         }
      43          30 : }
      44             : 
      45             : /**
      46             :  * A general oplock break notification handler.  This should be used when a
      47             :  * test expects to break from batch or exclusive to a lower level.
      48             :  */
      49             : 
      50         222 : bool torture_oplock_ack_handler(struct smb2_transport *transport,
      51             :                                 const struct smb2_handle *handle,
      52             :                                 uint8_t level,
      53             :                                 void *private_data)
      54             : {
      55         222 :         struct smb2_tree *tree = private_data;
      56           0 :         const char *name;
      57           0 :         struct smb2_request *req;
      58             : 
      59         222 :         ZERO_STRUCT(break_info.br);
      60             : 
      61         222 :         break_info.handle       = *handle;
      62         222 :         break_info.level        = level;
      63         222 :         break_info.count++;
      64             : 
      65         222 :         switch (level) {
      66         220 :         case SMB2_OPLOCK_LEVEL_II:
      67         220 :                 name = "level II";
      68         220 :                 break;
      69           2 :         case SMB2_OPLOCK_LEVEL_NONE:
      70           2 :                 name = "none";
      71           2 :                 break;
      72           0 :         default:
      73           0 :                 name = "unknown";
      74           0 :                 break_info.failures++;
      75             :         }
      76             : 
      77         222 :         break_info.br.in.file.handle    = *handle;
      78         222 :         break_info.br.in.oplock_level   = level;
      79         222 :         break_info.br.in.reserved       = 0;
      80         222 :         break_info.br.in.reserved2      = 0;
      81         222 :         break_info.received_transport = tree->session->transport;
      82         222 :         SMB_ASSERT(tree->session->transport == transport);
      83             : 
      84         222 :         if (break_info.oplock_skip_ack) {
      85         192 :                 torture_comment(break_info.tctx,
      86             :                                 "transport[%p] skip acking to %s [0x%02X] in oplock handler\n",
      87             :                                 transport, name, level);
      88         192 :                 return true;
      89             :         }
      90             : 
      91          30 :         torture_comment(break_info.tctx,
      92             :                         "transport[%p] Acking to %s [0x%02X] in oplock handler\n",
      93             :                         transport, name, level);
      94             : 
      95          30 :         req = smb2_break_send(tree, &break_info.br);
      96          30 :         req->async.fn = torture_oplock_ack_callback;
      97          30 :         req->async.private_data = NULL;
      98             : 
      99          30 :         return true;
     100             : }
     101             : 
     102             : /**
     103             :  * A oplock break handler designed to ignore incoming break requests.
     104             :  * This is used when incoming oplock break requests need to be ignored
     105             :  */
     106           0 : bool torture_oplock_ignore_handler(struct smb2_transport *transport,
     107             :                                    const struct smb2_handle *handle,
     108             :                                    uint8_t level, void *private_data)
     109             : {
     110           0 :         return true;
     111             : }
     112             : 
     113             : /*
     114             :  * Timer handler function notifies the registering function that time is up
     115             :  */
     116         480 : static void timeout_cb(struct tevent_context *ev,
     117             :                        struct tevent_timer *te,
     118             :                        struct timeval current_time,
     119             :                        void *private_data)
     120             : {
     121         480 :         bool *timesup = (bool *)private_data;
     122         480 :         *timesup = true;
     123         480 : }
     124             : 
     125             : /*
     126             :  * Wait a short period of time to receive a single oplock break request
     127             :  */
     128         544 : void torture_wait_for_oplock_break(struct torture_context *tctx)
     129             : {
     130         544 :         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
     131         544 :         struct tevent_timer *te = NULL;
     132           0 :         struct timeval ne;
     133         544 :         bool timesup = false;
     134         544 :         int old_count = break_info.count;
     135             : 
     136             :         /* Wait 1 second for an oplock break */
     137         544 :         ne = tevent_timeval_current_ofs(0, 1000000);
     138             : 
     139         544 :         te = tevent_add_timer(tctx->ev, tmp_ctx, ne, timeout_cb, &timesup);
     140         544 :         if (te == NULL) {
     141           0 :                 torture_comment(tctx, "Failed to wait for an oplock break. "
     142             :                                       "test results may not be accurate.\n");
     143           0 :                 goto done;
     144             :         }
     145             : 
     146         544 :         torture_comment(tctx, "Waiting for a potential oplock break...\n");
     147        1368 :         while (!timesup && break_info.count < old_count + 1) {
     148         824 :                 if (tevent_loop_once(tctx->ev) != 0) {
     149           0 :                         torture_comment(tctx, "Failed to wait for an oplock "
     150             :                                               "break. test results may not be "
     151             :                                               "accurate\n.");
     152           0 :                         goto done;
     153             :                 }
     154             :         }
     155         544 :         if (timesup) {
     156         480 :                 torture_comment(tctx, "... waiting for an oplock break timed out\n");
     157             :         } else {
     158          64 :                 torture_comment(tctx, "Got %u oplock breaks\n",
     159          64 :                                 break_info.count - old_count);
     160             :         }
     161             : 
     162         544 : done:
     163             :         /* We don't know if the timed event fired and was freed, we received
     164             :          * our oplock break, or some other event triggered the loop.  Thus,
     165             :          * we create a tmp_ctx to be able to safely free/remove the timed
     166             :          * event in all 3 cases.
     167             :          */
     168         544 :         talloc_free(tmp_ctx);
     169         544 : }

Generated by: LCOV version 1.14