lib/tsocket: add tsocket_sendto_queue_send/recv()
[Samba/gbeck.git] / lib / tsocket / tsocket_sendto.c
blob4531c403212976af202e08f13415a5e9b838e250
1 /*
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
8 ** under the LGPL
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/>.
24 #include "replace.h"
25 #include "system/network.h"
26 #include "tsocket.h"
27 #include "tsocket_internal.h"
29 struct tsocket_sendto_state {
30 /* this structs are owned by the caller */
31 struct {
32 struct tsocket_context *sock;
33 const uint8_t *buf;
34 size_t len;
35 const struct tsocket_address *dst;
36 } caller;
38 ssize_t ret;
41 static int tsocket_sendto_state_destructor(struct tsocket_sendto_state *state)
43 if (state->caller.sock) {
44 tsocket_set_writeable_handler(state->caller.sock, NULL, NULL);
46 ZERO_STRUCT(state->caller);
48 return 0;
51 static void tsocket_sendto_handler(struct tsocket_context *sock,
52 void *private_data);
54 struct tevent_req *tsocket_sendto_send(struct tsocket_context *sock,
55 TALLOC_CTX *mem_ctx,
56 const uint8_t *buf,
57 size_t len,
58 const struct tsocket_address *dst)
60 struct tevent_req *req;
61 struct tsocket_sendto_state *state;
62 int ret;
63 int err;
64 bool dummy;
66 req = tevent_req_create(mem_ctx, &state,
67 struct tsocket_sendto_state);
68 if (!req) {
69 return NULL;
72 state->caller.sock = sock;
73 state->caller.buf = buf;
74 state->caller.len = len;
75 state->caller.dst = dst;
76 state->ret = -1;
78 talloc_set_destructor(state, tsocket_sendto_state_destructor);
80 ret = tsocket_set_writeable_handler(sock,
81 tsocket_sendto_handler,
82 req);
83 err = tsocket_error_from_errno(ret, errno, &dummy);
84 if (tevent_req_error(req, err)) {
85 goto post;
88 return req;
90 post:
91 return tevent_req_post(req, sock->event.ctx);
94 static void tsocket_sendto_handler(struct tsocket_context *sock,
95 void *private_data)
97 struct tevent_req *req = talloc_get_type(private_data,
98 struct tevent_req);
99 struct tsocket_sendto_state *state = tevent_req_data(req,
100 struct tsocket_sendto_state);
101 ssize_t ret;
102 int err;
103 bool retry;
105 ret = tsocket_sendto(state->caller.sock,
106 state->caller.buf,
107 state->caller.len,
108 state->caller.dst);
109 err = tsocket_error_from_errno(ret, errno, &retry);
110 if (retry) {
111 /* retry later */
112 return;
114 if (tevent_req_error(req, err)) {
115 return;
118 state->ret = ret;
120 tevent_req_done(req);
123 ssize_t tsocket_sendto_recv(struct tevent_req *req, int *perrno)
125 struct tsocket_sendto_state *state = tevent_req_data(req,
126 struct tsocket_sendto_state);
127 ssize_t ret;
129 ret = tsocket_simple_int_recv(req, perrno);
130 if (ret == 0) {
131 ret = state->ret;
134 tevent_req_received(req);
135 return ret;
138 struct tsocket_sendto_queue_state {
139 /* this structs are owned by the caller */
140 struct {
141 struct tsocket_context *sock;
142 const uint8_t *buf;
143 size_t len;
144 const struct tsocket_address *dst;
145 } caller;
146 ssize_t ret;
149 static void tsocket_sendto_queue_trigger(struct tevent_req *req,
150 void *private_data);
151 static void tsocket_sendto_queue_done(struct tevent_req *subreq);
154 * @brief Queue a dgram blob for sending through the socket
155 * @param[in] mem_ctx The memory context for the result
156 * @param[in] sock The socket to send the message buffer
157 * @param[in] queue The existing dgram queue
158 * @param[in] buf The message buffer
159 * @param[in] len The message length
160 * @param[in] dst The destination socket address
161 * @retval The async request handle
163 * This function queues a blob for sending to destination through an existing
164 * dgram socket. The async callback is triggered when the whole blob is
165 * delivered to the underlying system socket.
167 * The caller needs to make sure that all non-scalar input parameters hang
168 * arround for the whole lifetime of the request.
170 struct tevent_req *tsocket_sendto_queue_send(TALLOC_CTX *mem_ctx,
171 struct tsocket_context *sock,
172 struct tevent_queue *queue,
173 const uint8_t *buf,
174 size_t len,
175 struct tsocket_address *dst)
177 struct tevent_req *req;
178 struct tsocket_sendto_queue_state *state;
179 bool ok;
181 req = tevent_req_create(mem_ctx, &state,
182 struct tsocket_sendto_queue_state);
183 if (!req) {
184 return NULL;
187 state->caller.sock = sock;
188 state->caller.buf = buf;
189 state->caller.len = len;
190 state->caller.dst = dst;
191 state->ret = -1;
193 ok = tevent_queue_add(queue,
194 sock->event.ctx,
195 req,
196 tsocket_sendto_queue_trigger,
197 NULL);
198 if (!ok) {
199 tevent_req_nomem(NULL, req);
200 goto post;
203 return req;
205 post:
206 return tevent_req_post(req, sock->event.ctx);
209 static void tsocket_sendto_queue_trigger(struct tevent_req *req,
210 void *private_data)
212 struct tsocket_sendto_queue_state *state = tevent_req_data(req,
213 struct tsocket_sendto_queue_state);
214 struct tevent_req *subreq;
216 subreq = tsocket_sendto_send(state->caller.sock,
217 state,
218 state->caller.buf,
219 state->caller.len,
220 state->caller.dst);
221 if (tevent_req_nomem(subreq, req)) {
222 return;
224 tevent_req_set_callback(subreq, tsocket_sendto_queue_done ,req);
227 static void tsocket_sendto_queue_done(struct tevent_req *subreq)
229 struct tevent_req *req = tevent_req_callback_data(subreq,
230 struct tevent_req);
231 struct tsocket_sendto_queue_state *state = tevent_req_data(req,
232 struct tsocket_sendto_queue_state);
233 ssize_t ret;
234 int sys_errno;
236 ret = tsocket_sendto_recv(subreq, &sys_errno);
237 talloc_free(subreq);
238 if (ret == -1) {
239 tevent_req_error(req, sys_errno);
240 return;
242 state->ret = ret;
244 tevent_req_done(req);
247 ssize_t tsocket_sendto_queue_recv(struct tevent_req *req, int *perrno)
249 struct tsocket_sendto_queue_state *state = tevent_req_data(req,
250 struct tsocket_sendto_queue_state);
251 ssize_t ret;
253 ret = tsocket_simple_int_recv(req, perrno);
254 if (ret == 0) {
255 ret = state->ret;
258 tevent_req_received(req);
259 return ret;