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);
107 * this is a fast path, not waiting for the
108 * socket to become explicit writeable gains
109 * about 10%-20% performance in benchmark tests.
111 tsocket_writev_handler(sock, req);
112 if (!tevent_req_is_in_progress(req)) {
116 talloc_set_destructor(state, tsocket_writev_state_destructor);
118 ret = tsocket_set_writeable_handler(sock,
119 tsocket_writev_handler,
121 err = tsocket_error_from_errno(ret, errno, &dummy);
122 if (tevent_req_error(req, err)) {
129 return tevent_req_post(req, sock->event.ctx);
132 static void tsocket_writev_handler(struct tsocket_context *sock,
135 struct tevent_req *req = talloc_get_type(private_data,
137 struct tsocket_writev_state *state = tevent_req_data(req,
138 struct tsocket_writev_state);
143 ret = tsocket_writev(state->caller.sock,
146 err = tsocket_error_from_errno(ret, errno, &retry);
151 if (tevent_req_error(req, err)) {
155 state->total_written += ret;
158 * we have not written everything yet, so we need to truncate
159 * the already written bytes from our iov copy
162 if (ret < state->iov[0].iov_len) {
164 base = (uint8_t *)state->iov[0].iov_base;
166 state->iov[0].iov_base = base;
167 state->iov[0].iov_len -= ret;
170 ret -= state->iov[0].iov_len;
175 if (state->count > 0) {
180 tevent_req_done(req);
183 int tsocket_writev_recv(struct tevent_req *req, int *perrno)
185 struct tsocket_writev_state *state = tevent_req_data(req,
186 struct tsocket_writev_state);
189 ret = tsocket_simple_int_recv(req, perrno);
191 ret = state->total_written;
194 tevent_req_received(req);
198 struct tsocket_writev_queue_state {
199 /* this structs are owned by the caller */
201 struct tsocket_context *sock;
202 const struct iovec *vector;
208 static void tsocket_writev_queue_trigger(struct tevent_req *req,
210 static void tsocket_writev_queue_done(struct tevent_req *subreq);
213 * @brief Queue a dgram blob for sending through the socket
214 * @param[in] mem_ctx The memory context for the result
215 * @param[in] sock The socket to send data through
216 * @param[in] queue The existing send queue
217 * @param[in] vector The iovec vector so write
218 * @param[in] count The size of the vector
219 * @retval The async request handle
221 * This function queues a blob for sending to destination through an existing
222 * dgram socket. The async callback is triggered when the whole blob is
223 * delivered to the underlying system socket.
225 * The caller needs to make sure that all non-scalar input parameters hang
226 * arround for the whole lifetime of the request.
228 struct tevent_req *tsocket_writev_queue_send(TALLOC_CTX *mem_ctx,
229 struct tsocket_context *sock,
230 struct tevent_queue *queue,
231 const struct iovec *vector,
234 struct tevent_req *req;
235 struct tsocket_writev_queue_state *state;
238 req = tevent_req_create(mem_ctx, &state,
239 struct tsocket_writev_queue_state);
244 state->caller.sock = sock;
245 state->caller.vector = vector;
246 state->caller.count = count;
249 ok = tevent_queue_add(queue,
252 tsocket_writev_queue_trigger,
255 tevent_req_nomem(NULL, req);
262 return tevent_req_post(req, sock->event.ctx);
265 static void tsocket_writev_queue_trigger(struct tevent_req *req,
268 struct tsocket_writev_queue_state *state = tevent_req_data(req,
269 struct tsocket_writev_queue_state);
270 struct tevent_req *subreq;
272 subreq = tsocket_writev_send(state->caller.sock,
274 state->caller.vector,
275 state->caller.count);
276 if (tevent_req_nomem(subreq, req)) {
279 tevent_req_set_callback(subreq, tsocket_writev_queue_done ,req);
282 static void tsocket_writev_queue_done(struct tevent_req *subreq)
284 struct tevent_req *req = tevent_req_callback_data(subreq,
286 struct tsocket_writev_queue_state *state = tevent_req_data(req,
287 struct tsocket_writev_queue_state);
291 ret = tsocket_writev_recv(subreq, &sys_errno);
294 tevent_req_error(req, sys_errno);
299 tevent_req_done(req);
302 int tsocket_writev_queue_recv(struct tevent_req *req, int *perrno)
304 struct tsocket_writev_queue_state *state = tevent_req_data(req,
305 struct tsocket_writev_queue_state);
308 ret = tsocket_simple_int_recv(req, perrno);
313 tevent_req_received(req);