LCOV - code coverage report
Current view: top level - source4/libcli/composite - composite.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 65 74 87.8 %
Date: 2024-04-21 15:09:00 Functions: 11 12 91.7 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Copyright (C) Volker Lendecke 2005
       5             :    Copyright (C) Andrew Tridgell 2005
       6             :    
       7             :    This program is free software; you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation; either version 3 of the License, or
      10             :    (at your option) any later version.
      11             :    
      12             :    This program is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             :    
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : /*
      21             :   composite API helper functions
      22             : */
      23             : 
      24             : #include "includes.h"
      25             : #include "lib/events/events.h"
      26             : #include "libcli/smb2/smb2.h"
      27             : #include "libcli/composite/composite.h"
      28             : #include "../libcli/nbt/libnbt.h"
      29             : 
      30             : /*
      31             :  create a new composite_context structure
      32             :  and initialize it
      33             : */
      34      825669 : _PUBLIC_ struct composite_context *composite_create(TALLOC_CTX *mem_ctx,
      35             :                                                     struct tevent_context *ev)
      36             : {
      37       12835 :         struct composite_context *c;
      38             : 
      39      825669 :         c = talloc_zero(mem_ctx, struct composite_context);
      40      825669 :         if (!c) return NULL;
      41      825669 :         c->state = COMPOSITE_STATE_IN_PROGRESS;
      42      825669 :         c->event_ctx = ev;
      43             : 
      44      825669 :         return c;
      45             : }
      46             : 
      47             : /*
      48             :   block until a composite function has completed, then return the status
      49             : */
      50      916904 : _PUBLIC_ NTSTATUS composite_wait(struct composite_context *c)
      51             : {
      52      916904 :         if (c == NULL) return NT_STATUS_NO_MEMORY;
      53             : 
      54      916904 :         c->used_wait = true;
      55             : 
      56     3911044 :         while (c->state < COMPOSITE_STATE_DONE) {
      57     2994140 :                 if (tevent_loop_once(c->event_ctx) != 0) {
      58           0 :                         return NT_STATUS_UNSUCCESSFUL;
      59             :                 }
      60             :         }
      61             : 
      62      916904 :         return c->status;
      63             : }
      64             : 
      65             : /*
      66             :   block until a composite function has completed, then return the status. 
      67             :   Free the composite context before returning
      68             : */
      69      361666 : _PUBLIC_ NTSTATUS composite_wait_free(struct composite_context *c)
      70             : {
      71      361666 :         NTSTATUS status = composite_wait(c);
      72      361666 :         talloc_free(c);
      73      361666 :         return status;
      74             : }
      75             : 
      76             : /* 
      77             :    callback from composite_done() and composite_error()
      78             : 
      79             :    this is used to allow for a composite function to complete without
      80             :    going through any state transitions. When that happens the caller
      81             :    has had no opportunity to fill in the async callback fields
      82             :    (ctx->async.fn and ctx->async.private_data) which means the usual way of
      83             :    dealing with composite functions doesn't work. To cope with this,
      84             :    we trigger a timer event that will happen then the event loop is
      85             :    re-entered. This gives the caller a chance to setup the callback,
      86             :    and allows the caller to ignore the fact that the composite
      87             :    function completed early
      88             : */
      89       92930 : static void composite_trigger(struct tevent_context *ev, struct tevent_timer *te,
      90             :                               struct timeval t, void *ptr)
      91             : {
      92       92930 :         struct composite_context *c = talloc_get_type(ptr, struct composite_context);
      93       92930 :         if (c->async.fn) {
      94       92913 :                 c->async.fn(c);
      95             :         }
      96       92930 : }
      97             : 
      98             : 
      99      466575 : _PUBLIC_ void composite_error(struct composite_context *ctx, NTSTATUS status)
     100             : {
     101             :         /* you are allowed to pass NT_STATUS_OK to composite_error(), in which
     102             :            case it is equivalent to composite_done() */
     103      466575 :         if (NT_STATUS_IS_OK(status)) {
     104      200564 :                 composite_done(ctx);
     105      200564 :                 return;
     106             :         }
     107      266011 :         if (!ctx->used_wait && !ctx->async.fn) {
     108       66763 :                 tevent_add_timer(ctx->event_ctx, ctx, timeval_zero(), composite_trigger, ctx);
     109             :         }
     110      266011 :         ctx->status = status;
     111      266011 :         ctx->state = COMPOSITE_STATE_ERROR;
     112      266011 :         if (ctx->async.fn != NULL) {
     113       36367 :                 ctx->async.fn(ctx);
     114             :         }
     115             : }
     116             : 
     117     2991439 : _PUBLIC_ bool composite_nomem(const void *p, struct composite_context *ctx)
     118             : {
     119     2991439 :         if (p != NULL) {
     120     2923263 :                 return false;
     121             :         }
     122           0 :         composite_error(ctx, NT_STATUS_NO_MEMORY);
     123           0 :         return true;
     124             : }
     125             : 
     126     1229105 : _PUBLIC_ bool composite_is_ok(struct composite_context *ctx)
     127             : {
     128     1229105 :         if (NT_STATUS_IS_OK(ctx->status)) {
     129     1121837 :                 return true;
     130             :         }
     131       86042 :         composite_error(ctx, ctx->status);
     132       86042 :         return false;
     133             : }
     134             : 
     135     1037412 : _PUBLIC_ void composite_done(struct composite_context *ctx)
     136             : {
     137     1037412 :         if (!ctx->used_wait && !ctx->async.fn) {
     138       27202 :                 tevent_add_timer(ctx->event_ctx, ctx, timeval_zero(), composite_trigger, ctx);
     139             :         }
     140     1037412 :         ctx->state = COMPOSITE_STATE_DONE;
     141     1037412 :         if (ctx->async.fn != NULL) {
     142      275551 :                 ctx->async.fn(ctx);
     143             :         }
     144     1037412 : }
     145             : 
     146      263266 : _PUBLIC_ void composite_continue(struct composite_context *ctx,
     147             :                                  struct composite_context *new_ctx,
     148             :                                  void (*continuation)(struct composite_context *),
     149             :                                  void *private_data)
     150             : {
     151      263266 :         if (composite_nomem(new_ctx, ctx)) return;
     152      263266 :         new_ctx->async.fn = continuation;
     153      263266 :         new_ctx->async.private_data = private_data;
     154             : 
     155             :         /* if we are setting up a continuation, and the context has
     156             :            already finished, then we should run the callback with an
     157             :            immediate event, otherwise we can be stuck forever */
     158      263266 :         if (new_ctx->state >= COMPOSITE_STATE_DONE && continuation) {
     159       24850 :                 tevent_add_timer(new_ctx->event_ctx, new_ctx, timeval_zero(), composite_trigger, new_ctx);
     160             :         }
     161             : }
     162             : 
     163        6669 : _PUBLIC_ void composite_continue_smb(struct composite_context *ctx,
     164             :                                      struct smbcli_request *new_req,
     165             :                                      void (*continuation)(struct smbcli_request *),
     166             :                                      void *private_data)
     167             : {
     168        6669 :         if (composite_nomem(new_req, ctx)) return;
     169        6669 :         if (new_req->state > SMBCLI_REQUEST_RECV) {
     170           0 :                 composite_error(ctx, new_req->status);
     171           0 :                 return;
     172             :         }
     173        6669 :         new_req->async.fn = continuation;
     174        6669 :         new_req->async.private_data = private_data;
     175             : }
     176             : 
     177      562225 : _PUBLIC_ void composite_continue_smb2(struct composite_context *ctx,
     178             :                                       struct smb2_request *new_req,
     179             :                                       void (*continuation)(struct smb2_request *),
     180             :                                       void *private_data)
     181             : {
     182      562225 :         if (composite_nomem(new_req, ctx)) return;
     183      562225 :         if (new_req->state > SMB2_REQUEST_RECV) {
     184          10 :                 composite_error(ctx, new_req->status);
     185          10 :                 return;
     186             :         }
     187      562215 :         new_req->async.fn = continuation;
     188      562215 :         new_req->async.private_data = private_data;
     189             : }
     190             : 
     191           0 : _PUBLIC_ void composite_continue_nbt(struct composite_context *ctx,
     192             :                                      struct nbt_name_request *new_req,
     193             :                                      void (*continuation)(struct nbt_name_request *),
     194             :                                      void *private_data)
     195             : {
     196           0 :         if (composite_nomem(new_req, ctx)) return;
     197           0 :         new_req->async.fn = continuation;
     198           0 :         new_req->async.private_data = private_data;
     199             : }

Generated by: LCOV version 1.14