libcli/cldap: convert to tsocket_* function to tdgram_*
[ira/wip.git] / lib / tsocket / tsocket_sendto.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Stefan Metzmacher 2009
5
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
9
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.
14
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.
19
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/>.
22 */
23
24 #include "replace.h"
25 #include "system/network.h"
26 #include "tsocket.h"
27 #include "tsocket_internal.h"
28
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;
37
38         ssize_t ret;
39 };
40
41 static int tsocket_sendto_state_destructor(struct tsocket_sendto_state *state)
42 {
43         if (state->caller.sock) {
44                 tsocket_set_writeable_handler(state->caller.sock, NULL, NULL);
45         }
46         ZERO_STRUCT(state->caller);
47
48         return 0;
49 }
50
51 static void tsocket_sendto_handler(struct tsocket_context *sock,
52                                    void *private_data);
53
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)
59 {
60         struct tevent_req *req;
61         struct tsocket_sendto_state *state;
62         int ret;
63         int err;
64         bool dummy;
65
66         req = tevent_req_create(mem_ctx, &state,
67                                 struct tsocket_sendto_state);
68         if (!req) {
69                 return NULL;
70         }
71
72         state->caller.sock      = sock;
73         state->caller.buf       = buf;
74         state->caller.len       = len;
75         state->caller.dst       = dst;
76         state->ret              = -1;
77
78         /*
79          * this is a fast path, not waiting for the
80          * socket to become explicit writeable gains
81          * about 10%-20% performance in benchmark tests.
82          */
83         tsocket_sendto_handler(sock, req);
84         if (!tevent_req_is_in_progress(req)) {
85                 goto post;
86         }
87
88         talloc_set_destructor(state, tsocket_sendto_state_destructor);
89
90         ret = tsocket_set_writeable_handler(sock,
91                                             tsocket_sendto_handler,
92                                             req);
93         err = tsocket_error_from_errno(ret, errno, &dummy);
94         if (tevent_req_error(req, err)) {
95                 goto post;
96         }
97
98         return req;
99
100  post:
101         return tevent_req_post(req, sock->event.ctx);
102 }
103
104 static void tsocket_sendto_handler(struct tsocket_context *sock,
105                                    void *private_data)
106 {
107         struct tevent_req *req = talloc_get_type(private_data,
108                                  struct tevent_req);
109         struct tsocket_sendto_state *state = tevent_req_data(req,
110                                              struct tsocket_sendto_state);
111         ssize_t ret;
112         int err;
113         bool retry;
114
115         ret = tsocket_sendto(state->caller.sock,
116                              state->caller.buf,
117                              state->caller.len,
118                              state->caller.dst);
119         err = tsocket_error_from_errno(ret, errno, &retry);
120         if (retry) {
121                 /* retry later */
122                 return;
123         }
124         if (tevent_req_error(req, err)) {
125                 return;
126         }
127
128         state->ret = ret;
129
130         tevent_req_done(req);
131 }
132
133 ssize_t tsocket_sendto_recv(struct tevent_req *req, int *perrno)
134 {
135         struct tsocket_sendto_state *state = tevent_req_data(req,
136                                              struct tsocket_sendto_state);
137         ssize_t ret;
138
139         ret = tsocket_simple_int_recv(req, perrno);
140         if (ret == 0) {
141                 ret = state->ret;
142         }
143
144         tevent_req_received(req);
145         return ret;
146 }
147
148 struct tsocket_sendto_queue_state {
149         /* this structs are owned by the caller */
150         struct {
151                 struct tsocket_context *sock;
152                 const uint8_t *buf;
153                 size_t len;
154                 const struct tsocket_address *dst;
155         } caller;
156         ssize_t ret;
157 };
158
159 static void tsocket_sendto_queue_trigger(struct tevent_req *req,
160                                          void *private_data);
161 static void tsocket_sendto_queue_done(struct tevent_req *subreq);
162
163 /**
164  * @brief Queue a dgram blob for sending through the socket
165  * @param[in] mem_ctx   The memory context for the result
166  * @param[in] sock      The socket to send the message buffer
167  * @param[in] queue     The existing dgram queue
168  * @param[in] buf       The message buffer
169  * @param[in] len       The message length
170  * @param[in] dst       The destination socket address
171  * @retval              The async request handle
172  *
173  * This function queues a blob for sending to destination through an existing
174  * dgram socket. The async callback is triggered when the whole blob is
175  * delivered to the underlying system socket.
176  *
177  * The caller needs to make sure that all non-scalar input parameters hang
178  * arround for the whole lifetime of the request.
179  */
180 struct tevent_req *tsocket_sendto_queue_send(TALLOC_CTX *mem_ctx,
181                                              struct tsocket_context *sock,
182                                              struct tevent_queue *queue,
183                                              const uint8_t *buf,
184                                              size_t len,
185                                              struct tsocket_address *dst)
186 {
187         struct tevent_req *req;
188         struct tsocket_sendto_queue_state *state;
189         bool ok;
190
191         req = tevent_req_create(mem_ctx, &state,
192                                 struct tsocket_sendto_queue_state);
193         if (!req) {
194                 return NULL;
195         }
196
197         state->caller.sock      = sock;
198         state->caller.buf       = buf;
199         state->caller.len       = len;
200         state->caller.dst       = dst;
201         state->ret              = -1;
202
203         ok = tevent_queue_add(queue,
204                               sock->event.ctx,
205                               req,
206                               tsocket_sendto_queue_trigger,
207                               NULL);
208         if (!ok) {
209                 tevent_req_nomem(NULL, req);
210                 goto post;
211         }
212
213         return req;
214
215  post:
216         return tevent_req_post(req, sock->event.ctx);
217 }
218
219 static void tsocket_sendto_queue_trigger(struct tevent_req *req,
220                                          void *private_data)
221 {
222         struct tsocket_sendto_queue_state *state = tevent_req_data(req,
223                                         struct tsocket_sendto_queue_state);
224         struct tevent_req *subreq;
225
226         subreq = tsocket_sendto_send(state->caller.sock,
227                                      state,
228                                      state->caller.buf,
229                                      state->caller.len,
230                                      state->caller.dst);
231         if (tevent_req_nomem(subreq, req)) {
232                 return;
233         }
234         tevent_req_set_callback(subreq, tsocket_sendto_queue_done ,req);
235 }
236
237 static void tsocket_sendto_queue_done(struct tevent_req *subreq)
238 {
239         struct tevent_req *req = tevent_req_callback_data(subreq,
240                                  struct tevent_req);
241         struct tsocket_sendto_queue_state *state = tevent_req_data(req,
242                                         struct tsocket_sendto_queue_state);
243         ssize_t ret;
244         int sys_errno;
245
246         ret = tsocket_sendto_recv(subreq, &sys_errno);
247         talloc_free(subreq);
248         if (ret == -1) {
249                 tevent_req_error(req, sys_errno);
250                 return;
251         }
252         state->ret = ret;
253
254         tevent_req_done(req);
255 }
256
257 ssize_t tsocket_sendto_queue_recv(struct tevent_req *req, int *perrno)
258 {
259         struct tsocket_sendto_queue_state *state = tevent_req_data(req,
260                                         struct tsocket_sendto_queue_state);
261         ssize_t ret;
262
263         ret = tsocket_simple_int_recv(req, perrno);
264         if (ret == 0) {
265                 ret = state->ret;
266         }
267
268         tevent_req_received(req);
269         return ret;
270 }
271