s3:libsmb: get rid of cli_has_async_calls
[Samba/gebeck_regimport.git] / source3 / libsmb / climessage.c
blob6c562fa29033f1b17160b272c0a74b042abfc437
1 /*
2 Unix SMB/CIFS implementation.
3 client message handling routines
4 Copyright (C) Andrew Tridgell 1994-1998
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "../lib/util/tevent_ntstatus.h"
22 #include "async_smb.h"
23 #include "libsmb/libsmb.h"
24 #include "../libcli/smb/smbXcli_base.h"
26 struct cli_message_start_state {
27 uint16_t grp;
30 static void cli_message_start_done(struct tevent_req *subreq);
32 static struct tevent_req *cli_message_start_send(TALLOC_CTX *mem_ctx,
33 struct tevent_context *ev,
34 struct cli_state *cli,
35 const char *host,
36 const char *username)
38 struct tevent_req *req, *subreq;
39 struct cli_message_start_state *state;
40 char *htmp = NULL;
41 char *utmp = NULL;
42 size_t hlen, ulen;
43 uint8_t *bytes, *p;
45 req = tevent_req_create(mem_ctx, &state,
46 struct cli_message_start_state);
47 if (req == NULL) {
48 return NULL;
51 if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS,
52 username, strlen(username)+1,
53 &utmp, &ulen)) {
54 goto fail;
56 if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS,
57 host, strlen(host)+1,
58 &htmp, &hlen)) {
59 goto fail;
62 bytes = talloc_array(state, uint8_t, ulen+hlen+2);
63 if (bytes == NULL) {
64 goto fail;
66 p = bytes;
68 *p++ = 4;
69 memcpy(p, utmp, ulen);
70 p += ulen;
71 *p++ = 4;
72 memcpy(p, htmp, hlen);
73 p += hlen;
74 TALLOC_FREE(htmp);
75 TALLOC_FREE(utmp);
77 subreq = cli_smb_send(state, ev, cli, SMBsendstrt, 0, 0, NULL,
78 talloc_get_size(bytes), bytes);
79 if (tevent_req_nomem(subreq, req)) {
80 return tevent_req_post(req, ev);
82 tevent_req_set_callback(subreq, cli_message_start_done, req);
83 return req;
84 fail:
85 TALLOC_FREE(htmp);
86 TALLOC_FREE(utmp);
87 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
88 return tevent_req_post(req, ev);
91 static void cli_message_start_done(struct tevent_req *subreq)
93 struct tevent_req *req = tevent_req_callback_data(
94 subreq, struct tevent_req);
95 struct cli_message_start_state *state = tevent_req_data(
96 req, struct cli_message_start_state);
97 NTSTATUS status;
98 uint8_t wct;
99 uint16_t *vwv;
100 uint8_t *inbuf;
102 status = cli_smb_recv(subreq, state, &inbuf, 0, &wct, &vwv,
103 NULL, NULL);
104 TALLOC_FREE(subreq);
105 if (!NT_STATUS_IS_OK(status)) {
106 TALLOC_FREE(subreq);
107 tevent_req_nterror(req, status);
108 return;
110 if (wct >= 1) {
111 state->grp = SVAL(vwv+0, 0);
112 } else {
113 state->grp = 0;
115 tevent_req_done(req);
118 static NTSTATUS cli_message_start_recv(struct tevent_req *req,
119 uint16_t *pgrp)
121 struct cli_message_start_state *state = tevent_req_data(
122 req, struct cli_message_start_state);
123 NTSTATUS status;
125 if (tevent_req_is_nterror(req, &status)) {
126 return status;
128 *pgrp = state->grp;
129 return NT_STATUS_OK;
132 struct cli_message_text_state {
133 uint16_t vwv;
136 static void cli_message_text_done(struct tevent_req *subreq);
138 static struct tevent_req *cli_message_text_send(TALLOC_CTX *mem_ctx,
139 struct tevent_context *ev,
140 struct cli_state *cli,
141 uint16_t grp,
142 const char *msg,
143 int msglen)
145 struct tevent_req *req, *subreq;
146 struct cli_message_text_state *state;
147 char *tmp;
148 size_t tmplen;
149 uint8_t *bytes;
151 req = tevent_req_create(mem_ctx, &state,
152 struct cli_message_text_state);
153 if (req == NULL) {
154 return NULL;
157 SSVAL(&state->vwv, 0, grp);
159 if (convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS, msg, msglen,
160 &tmp, &tmplen)) {
161 msg = tmp;
162 msglen = tmplen;
163 } else {
164 DEBUG(3, ("Conversion failed, sending message in UNIX "
165 "charset\n"));
166 tmp = NULL;
169 bytes = talloc_array(state, uint8_t, msglen+3);
170 if (tevent_req_nomem(bytes, req)) {
171 TALLOC_FREE(tmp);
172 return tevent_req_post(req, ev);
174 SCVAL(bytes, 0, 1); /* pad */
175 SSVAL(bytes+1, 0, msglen);
176 memcpy(bytes+3, msg, msglen);
177 TALLOC_FREE(tmp);
179 subreq = cli_smb_send(state, ev, cli, SMBsendtxt, 0, 1, &state->vwv,
180 talloc_get_size(bytes), bytes);
181 if (tevent_req_nomem(subreq, req)) {
182 return tevent_req_post(req, ev);
184 tevent_req_set_callback(subreq, cli_message_text_done, req);
185 return req;
188 static void cli_message_text_done(struct tevent_req *subreq)
190 struct tevent_req *req = tevent_req_callback_data(
191 subreq, struct tevent_req);
192 NTSTATUS status;
194 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
195 TALLOC_FREE(subreq);
196 if (!NT_STATUS_IS_OK(status)) {
197 tevent_req_nterror(req, status);
198 return;
200 tevent_req_done(req);
203 static NTSTATUS cli_message_text_recv(struct tevent_req *req)
205 return tevent_req_simple_recv_ntstatus(req);
208 struct cli_message_end_state {
209 uint16_t vwv;
212 static void cli_message_end_done(struct tevent_req *subreq);
214 static struct tevent_req *cli_message_end_send(TALLOC_CTX *mem_ctx,
215 struct tevent_context *ev,
216 struct cli_state *cli,
217 uint16_t grp)
219 struct tevent_req *req, *subreq;
220 struct cli_message_end_state *state;
222 req = tevent_req_create(mem_ctx, &state,
223 struct cli_message_end_state);
224 if (req == NULL) {
225 return NULL;
228 SSVAL(&state->vwv, 0, grp);
230 subreq = cli_smb_send(state, ev, cli, SMBsendend, 0, 1, &state->vwv,
231 0, NULL);
232 if (tevent_req_nomem(subreq, req)) {
233 return tevent_req_post(req, ev);
235 tevent_req_set_callback(subreq, cli_message_end_done, req);
236 return req;
239 static void cli_message_end_done(struct tevent_req *subreq)
241 struct tevent_req *req = tevent_req_callback_data(
242 subreq, struct tevent_req);
243 NTSTATUS status;
245 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
246 TALLOC_FREE(subreq);
247 if (!NT_STATUS_IS_OK(status)) {
248 tevent_req_nterror(req, status);
249 return;
251 tevent_req_done(req);
254 static NTSTATUS cli_message_end_recv(struct tevent_req *req)
256 return tevent_req_simple_recv_ntstatus(req);
259 struct cli_message_state {
260 struct tevent_context *ev;
261 struct cli_state *cli;
262 size_t sent;
263 const char *message;
264 uint16_t grp;
267 static void cli_message_started(struct tevent_req *subreq);
268 static void cli_message_sent(struct tevent_req *subreq);
269 static void cli_message_done(struct tevent_req *subreq);
271 struct tevent_req *cli_message_send(TALLOC_CTX *mem_ctx,
272 struct tevent_context *ev,
273 struct cli_state *cli,
274 const char *host, const char *username,
275 const char *message)
277 struct tevent_req *req, *subreq;
278 struct cli_message_state *state;
280 req = tevent_req_create(mem_ctx, &state, struct cli_message_state);
281 if (req == NULL) {
282 return NULL;
284 state->ev = ev;
285 state->cli = cli;
286 state->sent = 0;
287 state->message = message;
289 subreq = cli_message_start_send(state, ev, cli, host, username);
290 if (tevent_req_nomem(subreq, req)) {
291 return tevent_req_post(req, ev);
293 tevent_req_set_callback(subreq, cli_message_started, req);
294 return req;
297 static void cli_message_started(struct tevent_req *subreq)
299 struct tevent_req *req = tevent_req_callback_data(
300 subreq, struct tevent_req);
301 struct cli_message_state *state = tevent_req_data(
302 req, struct cli_message_state);
303 NTSTATUS status;
304 size_t thistime;
306 status = cli_message_start_recv(subreq, &state->grp);
307 TALLOC_FREE(subreq);
308 if (!NT_STATUS_IS_OK(status)) {
309 tevent_req_nterror(req, status);
310 return;
313 thistime = MIN(127, strlen(state->message));
315 subreq = cli_message_text_send(state, state->ev, state->cli,
316 state->grp, state->message, thistime);
317 if (tevent_req_nomem(subreq, req)) {
318 return;
320 state->sent += thistime;
321 tevent_req_set_callback(subreq, cli_message_sent, req);
324 static void cli_message_sent(struct tevent_req *subreq)
326 struct tevent_req *req = tevent_req_callback_data(
327 subreq, struct tevent_req);
328 struct cli_message_state *state = tevent_req_data(
329 req, struct cli_message_state);
330 NTSTATUS status;
331 size_t left, thistime;
333 status = cli_message_text_recv(subreq);
334 TALLOC_FREE(subreq);
335 if (!NT_STATUS_IS_OK(status)) {
336 tevent_req_nterror(req, status);
337 return;
340 if (state->sent >= strlen(state->message)) {
341 subreq = cli_message_end_send(state, state->ev, state->cli,
342 state->grp);
343 if (tevent_req_nomem(subreq, req)) {
344 return;
346 tevent_req_set_callback(subreq, cli_message_done, req);
347 return;
350 left = strlen(state->message) - state->sent;
351 thistime = MIN(127, left);
353 subreq = cli_message_text_send(state, state->ev, state->cli,
354 state->grp,
355 state->message + state->sent,
356 thistime);
357 if (tevent_req_nomem(subreq, req)) {
358 return;
360 state->sent += thistime;
361 tevent_req_set_callback(subreq, cli_message_sent, req);
364 static void cli_message_done(struct tevent_req *subreq)
366 struct tevent_req *req = tevent_req_callback_data(
367 subreq, struct tevent_req);
368 NTSTATUS status;
370 status = cli_message_end_recv(subreq);
371 TALLOC_FREE(subreq);
372 if (!NT_STATUS_IS_OK(status)) {
373 tevent_req_nterror(req, status);
374 return;
376 tevent_req_done(req);
379 NTSTATUS cli_message_recv(struct tevent_req *req)
381 return tevent_req_simple_recv_ntstatus(req);
384 NTSTATUS cli_message(struct cli_state *cli, const char *host,
385 const char *username, const char *message)
387 TALLOC_CTX *frame = talloc_stackframe();
388 struct event_context *ev;
389 struct tevent_req *req;
390 NTSTATUS status = NT_STATUS_OK;
392 if (smbXcli_conn_has_async_calls(cli->conn)) {
394 * Can't use sync call while an async call is in flight
396 status = NT_STATUS_INVALID_PARAMETER;
397 goto fail;
400 ev = event_context_init(frame);
401 if (ev == NULL) {
402 status = NT_STATUS_NO_MEMORY;
403 goto fail;
406 req = cli_message_send(frame, ev, cli, host, username, message);
407 if (req == NULL) {
408 status = NT_STATUS_NO_MEMORY;
409 goto fail;
412 if (!tevent_req_poll(req, ev)) {
413 status = map_nt_error_from_unix(errno);
414 goto fail;
417 status = cli_message_recv(req);
418 fail:
419 TALLOC_FREE(frame);
420 return status;