2 Unix SMB/CIFS implementation.
4 Copyright (C) Stefan Metzmacher 2009
6 ** NOTE! The following LGPL license applies to the tevent
7 ** library. This does NOT imply that all of Samba is released
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 3 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, see <http://www.gnu.org/licenses/>.
25 #include "system/network.h"
27 #include "tsocket_internal.h"
29 struct tsocket_writev_state {
30 /* this structs are owned by the caller */
32 struct tsocket_context *sock;
33 const struct iovec *vector;
42 static int tsocket_writev_state_destructor(struct tsocket_writev_state *state)
44 if (state->caller.sock) {
45 tsocket_set_writeable_handler(state->caller.sock, NULL, NULL);
47 ZERO_STRUCT(state->caller);
52 static void tsocket_writev_handler(struct tsocket_context *sock,
55 struct tevent_req *tsocket_writev_send(struct tsocket_context *sock,
57 const struct iovec *vector,
60 struct tevent_req *req;
61 struct tsocket_writev_state *state;
68 req = tevent_req_create(mem_ctx, &state,
69 struct tsocket_writev_state);
74 state->caller.sock = sock;
75 state->caller.vector = vector;
76 state->caller.count = count;
80 state->total_written = 0;
82 state->iov = talloc_array(state, struct iovec, count);
83 if (tevent_req_nomem(state->iov, req)) {
86 memcpy(state->iov, vector, sizeof(struct iovec) * count);
88 for (i=0; i < count; i++) {
91 tmp += state->iov[i].iov_len;
94 tevent_req_error(req, EMSGSIZE);
102 tevent_req_done(req);
106 talloc_set_destructor(state, tsocket_writev_state_destructor);
108 ret = tsocket_set_writeable_handler(sock,
109 tsocket_writev_handler,
111 err = tsocket_error_from_errno(ret, errno, &dummy);
112 if (tevent_req_error(req, err)) {
119 return tevent_req_post(req, sock->event.ctx);
122 static void tsocket_writev_handler(struct tsocket_context *sock,
125 struct tevent_req *req = talloc_get_type(private_data,
127 struct tsocket_writev_state *state = tevent_req_data(req,
128 struct tsocket_writev_state);
133 ret = tsocket_writev(state->caller.sock,
136 err = tsocket_error_from_errno(ret, errno, &retry);
141 if (tevent_req_error(req, err)) {
145 state->total_written += ret;
148 * we have not written everything yet, so we need to truncate
149 * the already written bytes from our iov copy
152 if (ret < state->iov[0].iov_len) {
154 base = (uint8_t *)state->iov[0].iov_base;
156 state->iov[0].iov_base = base;
157 state->iov[0].iov_len -= ret;
160 ret -= state->iov[0].iov_len;
165 if (state->count > 0) {
170 tevent_req_done(req);
173 int tsocket_writev_recv(struct tevent_req *req, int *perrno)
175 struct tsocket_writev_state *state = tevent_req_data(req,
176 struct tsocket_writev_state);
179 ret = tsocket_simple_int_recv(req, perrno);
181 ret = state->total_written;
184 tevent_req_received(req);
188 struct tsocket_writev_queue_state {
189 /* this structs are owned by the caller */
191 struct tsocket_context *sock;
192 const struct iovec *vector;
198 static void tsocket_writev_queue_trigger(struct tevent_req *req,
200 static void tsocket_writev_queue_done(struct tevent_req *subreq);
203 * @brief Queue a dgram blob for sending through the socket
204 * @param[in] mem_ctx The memory context for the result
205 * @param[in] sock The socket to send data through
206 * @param[in] queue The existing send queue
207 * @param[in] vector The iovec vector so write
208 * @param[in] count The size of the vector
209 * @retval The async request handle
211 * This function queues a blob for sending to destination through an existing
212 * dgram socket. The async callback is triggered when the whole blob is
213 * delivered to the underlying system socket.
215 * The caller needs to make sure that all non-scalar input parameters hang
216 * arround for the whole lifetime of the request.
218 struct tevent_req *tsocket_writev_queue_send(TALLOC_CTX *mem_ctx,
219 struct tsocket_context *sock,
220 struct tevent_queue *queue,
221 const struct iovec *vector,
224 struct tevent_req *req;
225 struct tsocket_writev_queue_state *state;
228 req = tevent_req_create(mem_ctx, &state,
229 struct tsocket_writev_queue_state);
234 state->caller.sock = sock;
235 state->caller.vector = vector;
236 state->caller.count = count;
239 ok = tevent_queue_add(queue,
242 tsocket_writev_queue_trigger,
245 tevent_req_nomem(NULL, req);
252 return tevent_req_post(req, sock->event.ctx);
255 static void tsocket_writev_queue_trigger(struct tevent_req *req,
258 struct tsocket_writev_queue_state *state = tevent_req_data(req,
259 struct tsocket_writev_queue_state);
260 struct tevent_req *subreq;
262 subreq = tsocket_writev_send(state->caller.sock,
264 state->caller.vector,
265 state->caller.count);
266 if (tevent_req_nomem(subreq, req)) {
269 tevent_req_set_callback(subreq, tsocket_writev_queue_done ,req);
272 static void tsocket_writev_queue_done(struct tevent_req *subreq)
274 struct tevent_req *req = tevent_req_callback_data(subreq,
276 struct tsocket_writev_queue_state *state = tevent_req_data(req,
277 struct tsocket_writev_queue_state);
281 ret = tsocket_writev_recv(subreq, &sys_errno);
284 tevent_req_error(req, sys_errno);
289 tevent_req_done(req);
292 int tsocket_writev_queue_recv(struct tevent_req *req, int *perrno)
294 struct tsocket_writev_queue_state *state = tevent_req_data(req,
295 struct tsocket_writev_queue_state);
298 ret = tsocket_simple_int_recv(req, perrno);
303 tevent_req_received(req);