LCOV - code coverage report
Current view: top level - source4/libcli/composite - composite.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 64 73 87.7 %
Date: 2021-09-23 10:06:22 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      822190 : _PUBLIC_ struct composite_context *composite_create(TALLOC_CTX *mem_ctx,
      35             :                                                     struct tevent_context *ev)
      36             : {
      37             :         struct composite_context *c;
      38             : 
      39      822190 :         c = talloc_zero(mem_ctx, struct composite_context);
      40      822190 :         if (!c) return NULL;
      41      822190 :         c->state = COMPOSITE_STATE_IN_PROGRESS;
      42      822190 :         c->event_ctx = ev;
      43             : 
      44      822190 :         return c;
      45             : }
      46             : 
      47             : /*
      48             :   block until a composite function has completed, then return the status
      49             : */
      50      893917 : _PUBLIC_ NTSTATUS composite_wait(struct composite_context *c)
      51             : {
      52      893917 :         if (c == NULL) return NT_STATUS_NO_MEMORY;
      53             : 
      54      893917 :         c->used_wait = true;
      55             : 
      56     4735702 :         while (c->state < COMPOSITE_STATE_DONE) {
      57     3063499 :                 if (tevent_loop_once(c->event_ctx) != 0) {
      58           0 :                         return NT_STATUS_UNSUCCESSFUL;
      59             :                 }
      60             :         }
      61             : 
      62      893899 :         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      374893 : _PUBLIC_ NTSTATUS composite_wait_free(struct composite_context *c)
      70             : {
      71      374893 :         NTSTATUS status = composite_wait(c);
      72      374893 :         talloc_free(c);
      73      374893 :         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       86556 : static void composite_trigger(struct tevent_context *ev, struct tevent_timer *te,
      90             :                               struct timeval t, void *ptr)
      91             : {
      92       86556 :         struct composite_context *c = talloc_get_type(ptr, struct composite_context);
      93       86556 :         if (c->async.fn) {
      94       86539 :                 c->async.fn(c);
      95             :         }
      96       86537 : }
      97             : 
      98             : 
      99      481212 : _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      481212 :         if (NT_STATUS_IS_OK(status)) {
     104      215678 :                 composite_done(ctx);
     105      215678 :                 return;
     106             :         }
     107      265534 :         if (!ctx->used_wait && !ctx->async.fn) {
     108       60667 :                 tevent_add_timer(ctx->event_ctx, ctx, timeval_zero(), composite_trigger, ctx);
     109             :         }
     110      265534 :         ctx->status = status;
     111      265534 :         ctx->state = COMPOSITE_STATE_ERROR;
     112      265534 :         if (ctx->async.fn != NULL) {
     113       44459 :                 ctx->async.fn(ctx);
     114             :         }
     115             : }
     116             : 
     117     2803717 : _PUBLIC_ bool composite_nomem(const void *p, struct composite_context *ctx)
     118             : {
     119     2803717 :         if (p != NULL) {
     120     2746663 :                 return false;
     121             :         }
     122           0 :         composite_error(ctx, NT_STATUS_NO_MEMORY);
     123           0 :         return true;
     124             : }
     125             : 
     126      906126 : _PUBLIC_ bool composite_is_ok(struct composite_context *ctx)
     127             : {
     128      906126 :         if (NT_STATUS_IS_OK(ctx->status)) {
     129      804382 :                 return true;
     130             :         }
     131       82735 :         composite_error(ctx, ctx->status);
     132       82735 :         return false;
     133             : }
     134             : 
     135      752326 : _PUBLIC_ void composite_done(struct composite_context *ctx)
     136             : {
     137      752326 :         if (!ctx->used_wait && !ctx->async.fn) {
     138       26815 :                 tevent_add_timer(ctx->event_ctx, ctx, timeval_zero(), composite_trigger, ctx);
     139             :         }
     140      752326 :         ctx->state = COMPOSITE_STATE_DONE;
     141      752326 :         if (ctx->async.fn != NULL) {
     142      229912 :                 ctx->async.fn(ctx);
     143             :         }
     144      752326 : }
     145             : 
     146      237777 : _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      237777 :         if (composite_nomem(new_ctx, ctx)) return;
     152      237777 :         new_ctx->async.fn = continuation;
     153      237777 :         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      237777 :         if (new_ctx->state >= COMPOSITE_STATE_DONE && continuation) {
     159       24777 :                 tevent_add_timer(new_ctx->event_ctx, new_ctx, timeval_zero(), composite_trigger, new_ctx);
     160             :         }
     161             : }
     162             : 
     163        5708 : _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        5708 :         if (composite_nomem(new_req, ctx)) return;
     169        5708 :         if (new_req->state > SMBCLI_REQUEST_RECV) {
     170           0 :                 composite_error(ctx, new_req->status);
     171           0 :                 return;
     172             :         }
     173        5708 :         new_req->async.fn = continuation;
     174        5708 :         new_req->async.private_data = private_data;
     175             : }
     176             : 
     177      590567 : _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      590567 :         if (composite_nomem(new_req, ctx)) return;
     183      590567 :         if (new_req->state > SMB2_REQUEST_RECV) {
     184          10 :                 composite_error(ctx, new_req->status);
     185          10 :                 return;
     186             :         }
     187      590557 :         new_req->async.fn = continuation;
     188      590557 :         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.13