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 : }
|