s3:lib/events: add missing TEVENT_TRACE_BEFORE/AFTER_WAIT handling
[Samba.git] / source3 / libsmb / climessage.c
blob4e99761bf3a6ac120ed54e16a579dbbdaff32b4c
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;
101 status = cli_smb_recv(subreq, state, NULL, 0, &wct, &vwv,
102 NULL, NULL);
103 TALLOC_FREE(subreq);
104 if (!NT_STATUS_IS_OK(status)) {
105 TALLOC_FREE(subreq);
106 tevent_req_nterror(req, status);
107 return;
109 if (wct >= 1) {
110 state->grp = SVAL(vwv+0, 0);
111 } else {
112 state->grp = 0;
114 tevent_req_done(req);
117 static NTSTATUS cli_message_start_recv(struct tevent_req *req,
118 uint16_t *pgrp)
120 struct cli_message_start_state *state = tevent_req_data(
121 req, struct cli_message_start_state);
122 NTSTATUS status;
124 if (tevent_req_is_nterror(req, &status)) {
125 return status;
127 *pgrp = state->grp;
128 return NT_STATUS_OK;
131 struct cli_message_text_state {
132 uint16_t vwv;
135 static void cli_message_text_done(struct tevent_req *subreq);
137 static struct tevent_req *cli_message_text_send(TALLOC_CTX *mem_ctx,
138 struct tevent_context *ev,
139 struct cli_state *cli,
140 uint16_t grp,
141 const char *msg,
142 int msglen)
144 struct tevent_req *req, *subreq;
145 struct cli_message_text_state *state;
146 char *tmp;
147 size_t tmplen;
148 uint8_t *bytes;
150 req = tevent_req_create(mem_ctx, &state,
151 struct cli_message_text_state);
152 if (req == NULL) {
153 return NULL;
156 SSVAL(&state->vwv, 0, grp);
158 if (convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS, msg, msglen,
159 &tmp, &tmplen)) {
160 msg = tmp;
161 msglen = tmplen;
162 } else {
163 DEBUG(3, ("Conversion failed, sending message in UNIX "
164 "charset\n"));
165 tmp = NULL;
168 bytes = talloc_array(state, uint8_t, msglen+3);
169 if (tevent_req_nomem(bytes, req)) {
170 TALLOC_FREE(tmp);
171 return tevent_req_post(req, ev);
173 SCVAL(bytes, 0, 1); /* pad */
174 SSVAL(bytes+1, 0, msglen);
175 memcpy(bytes+3, msg, msglen);
176 TALLOC_FREE(tmp);
178 subreq = cli_smb_send(state, ev, cli, SMBsendtxt, 0, 1, &state->vwv,
179 talloc_get_size(bytes), bytes);
180 if (tevent_req_nomem(subreq, req)) {
181 return tevent_req_post(req, ev);
183 tevent_req_set_callback(subreq, cli_message_text_done, req);
184 return req;
187 static void cli_message_text_done(struct tevent_req *subreq)
189 struct tevent_req *req = tevent_req_callback_data(
190 subreq, struct tevent_req);
191 NTSTATUS status;
193 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
194 TALLOC_FREE(subreq);
195 if (!NT_STATUS_IS_OK(status)) {
196 tevent_req_nterror(req, status);
197 return;
199 tevent_req_done(req);
202 static NTSTATUS cli_message_text_recv(struct tevent_req *req)
204 return tevent_req_simple_recv_ntstatus(req);
207 struct cli_message_end_state {
208 uint16_t vwv;
211 static void cli_message_end_done(struct tevent_req *subreq);
213 static struct tevent_req *cli_message_end_send(TALLOC_CTX *mem_ctx,
214 struct tevent_context *ev,
215 struct cli_state *cli,
216 uint16_t grp)
218 struct tevent_req *req, *subreq;
219 struct cli_message_end_state *state;
221 req = tevent_req_create(mem_ctx, &state,
222 struct cli_message_end_state);
223 if (req == NULL) {
224 return NULL;
227 SSVAL(&state->vwv, 0, grp);
229 subreq = cli_smb_send(state, ev, cli, SMBsendend, 0, 1, &state->vwv,
230 0, NULL);
231 if (tevent_req_nomem(subreq, req)) {
232 return tevent_req_post(req, ev);
234 tevent_req_set_callback(subreq, cli_message_end_done, req);
235 return req;
238 static void cli_message_end_done(struct tevent_req *subreq)
240 struct tevent_req *req = tevent_req_callback_data(
241 subreq, struct tevent_req);
242 NTSTATUS status;
244 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
245 TALLOC_FREE(subreq);
246 if (!NT_STATUS_IS_OK(status)) {
247 tevent_req_nterror(req, status);
248 return;
250 tevent_req_done(req);
253 static NTSTATUS cli_message_end_recv(struct tevent_req *req)
255 return tevent_req_simple_recv_ntstatus(req);
258 struct cli_message_state {
259 struct tevent_context *ev;
260 struct cli_state *cli;
261 size_t sent;
262 const char *message;
263 uint16_t grp;
266 static void cli_message_started(struct tevent_req *subreq);
267 static void cli_message_sent(struct tevent_req *subreq);
268 static void cli_message_done(struct tevent_req *subreq);
270 struct tevent_req *cli_message_send(TALLOC_CTX *mem_ctx,
271 struct tevent_context *ev,
272 struct cli_state *cli,
273 const char *host, const char *username,
274 const char *message)
276 struct tevent_req *req, *subreq;
277 struct cli_message_state *state;
279 req = tevent_req_create(mem_ctx, &state, struct cli_message_state);
280 if (req == NULL) {
281 return NULL;
283 state->ev = ev;
284 state->cli = cli;
285 state->sent = 0;
286 state->message = message;
288 subreq = cli_message_start_send(state, ev, cli, host, username);
289 if (tevent_req_nomem(subreq, req)) {
290 return tevent_req_post(req, ev);
292 tevent_req_set_callback(subreq, cli_message_started, req);
293 return req;
296 static void cli_message_started(struct tevent_req *subreq)
298 struct tevent_req *req = tevent_req_callback_data(
299 subreq, struct tevent_req);
300 struct cli_message_state *state = tevent_req_data(
301 req, struct cli_message_state);
302 NTSTATUS status;
303 size_t thistime;
305 status = cli_message_start_recv(subreq, &state->grp);
306 TALLOC_FREE(subreq);
307 if (!NT_STATUS_IS_OK(status)) {
308 tevent_req_nterror(req, status);
309 return;
312 thistime = MIN(127, strlen(state->message));
314 subreq = cli_message_text_send(state, state->ev, state->cli,
315 state->grp, state->message, thistime);
316 if (tevent_req_nomem(subreq, req)) {
317 return;
319 state->sent += thistime;
320 tevent_req_set_callback(subreq, cli_message_sent, req);
323 static void cli_message_sent(struct tevent_req *subreq)
325 struct tevent_req *req = tevent_req_callback_data(
326 subreq, struct tevent_req);
327 struct cli_message_state *state = tevent_req_data(
328 req, struct cli_message_state);
329 NTSTATUS status;
330 size_t left, thistime;
332 status = cli_message_text_recv(subreq);
333 TALLOC_FREE(subreq);
334 if (!NT_STATUS_IS_OK(status)) {
335 tevent_req_nterror(req, status);
336 return;
339 if (state->sent >= strlen(state->message)) {
340 subreq = cli_message_end_send(state, state->ev, state->cli,
341 state->grp);
342 if (tevent_req_nomem(subreq, req)) {
343 return;
345 tevent_req_set_callback(subreq, cli_message_done, req);
346 return;
349 left = strlen(state->message) - state->sent;
350 thistime = MIN(127, left);
352 subreq = cli_message_text_send(state, state->ev, state->cli,
353 state->grp,
354 state->message + state->sent,
355 thistime);
356 if (tevent_req_nomem(subreq, req)) {
357 return;
359 state->sent += thistime;
360 tevent_req_set_callback(subreq, cli_message_sent, req);
363 static void cli_message_done(struct tevent_req *subreq)
365 struct tevent_req *req = tevent_req_callback_data(
366 subreq, struct tevent_req);
367 NTSTATUS status;
369 status = cli_message_end_recv(subreq);
370 TALLOC_FREE(subreq);
371 if (!NT_STATUS_IS_OK(status)) {
372 tevent_req_nterror(req, status);
373 return;
375 tevent_req_done(req);
378 NTSTATUS cli_message_recv(struct tevent_req *req)
380 return tevent_req_simple_recv_ntstatus(req);
383 NTSTATUS cli_message(struct cli_state *cli, const char *host,
384 const char *username, const char *message)
386 TALLOC_CTX *frame = talloc_stackframe();
387 struct event_context *ev;
388 struct tevent_req *req;
389 NTSTATUS status = NT_STATUS_OK;
391 if (smbXcli_conn_has_async_calls(cli->conn)) {
393 * Can't use sync call while an async call is in flight
395 status = NT_STATUS_INVALID_PARAMETER;
396 goto fail;
399 ev = event_context_init(frame);
400 if (ev == NULL) {
401 status = NT_STATUS_NO_MEMORY;
402 goto fail;
405 req = cli_message_send(frame, ev, cli, host, username, message);
406 if (req == NULL) {
407 status = NT_STATUS_NO_MEMORY;
408 goto fail;
411 if (!tevent_req_poll(req, ev)) {
412 status = map_nt_error_from_unix(errno);
413 goto fail;
416 status = cli_message_recv(req);
417 fail:
418 TALLOC_FREE(frame);
419 return status;