tsocket: move tsocket_sendto_queue_send/recv() to tsocket_helpers.c
[samba.git] / lib / tsocket / tsocket_helpers.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 "system/filesys.h"
27 #include "tsocket.h"
28 #include "tsocket_internal.h"
29
30 int tsocket_simple_int_recv(struct tevent_req *req, int *perrno)
31 {
32         enum tevent_req_state state;
33         uint64_t error;
34
35         if (!tevent_req_is_error(req, &state, &error)) {
36                 return 0;
37         }
38
39         switch (state) {
40         case TEVENT_REQ_NO_MEMORY:
41                 *perrno = ENOMEM;
42                 return -1;
43         case TEVENT_REQ_TIMED_OUT:
44                 *perrno = ETIMEDOUT;
45                 return -1;
46         case TEVENT_REQ_USER_ERROR:
47                 *perrno = (int)error;
48                 return -1;
49         default:
50                 *perrno = EIO;
51                 return -1;
52         }
53
54         *perrno = EIO;
55         return -1;
56 }
57
58 struct tdgram_sendto_queue_state {
59         /* this structs are owned by the caller */
60         struct {
61                 struct tevent_context *ev;
62                 struct tdgram_context *dgram;
63                 const uint8_t *buf;
64                 size_t len;
65                 const struct tsocket_address *dst;
66         } caller;
67         ssize_t ret;
68 };
69
70 static void tdgram_sendto_queue_trigger(struct tevent_req *req,
71                                          void *private_data);
72 static void tdgram_sendto_queue_done(struct tevent_req *subreq);
73
74 /**
75  * @brief Queue a dgram blob for sending through the socket
76  * @param[in] mem_ctx   The memory context for the result
77  * @param[in] ev        The event context the operation should work on
78  * @param[in] dgram     The tdgram_context to send the message buffer
79  * @param[in] queue     The existing dgram queue
80  * @param[in] buf       The message buffer
81  * @param[in] len       The message length
82  * @param[in] dst       The destination socket address
83  * @retval              The async request handle
84  *
85  * This function queues a blob for sending to destination through an existing
86  * dgram socket. The async callback is triggered when the whole blob is
87  * delivered to the underlying system socket.
88  *
89  * The caller needs to make sure that all non-scalar input parameters hang
90  * arround for the whole lifetime of the request.
91  */
92 struct tevent_req *tdgram_sendto_queue_send(TALLOC_CTX *mem_ctx,
93                                             struct tevent_context *ev,
94                                             struct tdgram_context *dgram,
95                                             struct tevent_queue *queue,
96                                             const uint8_t *buf,
97                                             size_t len,
98                                             struct tsocket_address *dst)
99 {
100         struct tevent_req *req;
101         struct tdgram_sendto_queue_state *state;
102         bool ok;
103
104         req = tevent_req_create(mem_ctx, &state,
105                                 struct tdgram_sendto_queue_state);
106         if (!req) {
107                 return NULL;
108         }
109
110         state->caller.ev        = ev;
111         state->caller.dgram     = dgram;
112         state->caller.buf       = buf;
113         state->caller.len       = len;
114         state->caller.dst       = dst;
115         state->ret              = -1;
116
117         ok = tevent_queue_add(queue,
118                               ev,
119                               req,
120                               tdgram_sendto_queue_trigger,
121                               NULL);
122         if (!ok) {
123                 tevent_req_nomem(NULL, req);
124                 goto post;
125         }
126
127         return req;
128
129  post:
130         tevent_req_post(req, ev);
131         return req;
132 }
133
134 static void tdgram_sendto_queue_trigger(struct tevent_req *req,
135                                          void *private_data)
136 {
137         struct tdgram_sendto_queue_state *state = tevent_req_data(req,
138                                         struct tdgram_sendto_queue_state);
139         struct tevent_req *subreq;
140
141         subreq = tdgram_sendto_send(state,
142                                     state->caller.ev,
143                                     state->caller.dgram,
144                                     state->caller.buf,
145                                     state->caller.len,
146                                     state->caller.dst);
147         if (tevent_req_nomem(subreq, req)) {
148                 return;
149         }
150         tevent_req_set_callback(subreq, tdgram_sendto_queue_done, req);
151 }
152
153 static void tdgram_sendto_queue_done(struct tevent_req *subreq)
154 {
155         struct tevent_req *req = tevent_req_callback_data(subreq,
156                                  struct tevent_req);
157         struct tdgram_sendto_queue_state *state = tevent_req_data(req,
158                                         struct tdgram_sendto_queue_state);
159         ssize_t ret;
160         int sys_errno;
161
162         ret = tdgram_sendto_recv(subreq, &sys_errno);
163         talloc_free(subreq);
164         if (ret == -1) {
165                 tevent_req_error(req, sys_errno);
166                 return;
167         }
168         state->ret = ret;
169
170         tevent_req_done(req);
171 }
172
173 ssize_t tdgram_sendto_queue_recv(struct tevent_req *req, int *perrno)
174 {
175         struct tdgram_sendto_queue_state *state = tevent_req_data(req,
176                                         struct tdgram_sendto_queue_state);
177         ssize_t ret;
178
179         ret = tsocket_simple_int_recv(req, perrno);
180         if (ret == 0) {
181                 ret = state->ret;
182         }
183
184         tevent_req_received(req);
185         return ret;
186 }
187