source: mainline/uspace/lib/c/generic/inet/udp.c@ 496232e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 496232e was 1f2b07a, checked in by Jiri Svoboda <jiri@…>, 11 years ago

TCP and UDP client code needs to make sure callback connection handler has terminated before freeing session-related data.

  • Property mode set to 100644
File size: 7.5 KB
Line 
1/*
2 * Copyright (c) 2015 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libc
30 * @{
31 */
32/** @file UDP API
33 */
34
35#include <errno.h>
36#include <inet/endpoint.h>
37#include <inet/udp.h>
38#include <ipc/services.h>
39#include <ipc/udp.h>
40#include <loc.h>
41#include <stdlib.h>
42
43static void udp_cb_conn(ipc_callid_t, ipc_call_t *, void *);
44
45static int udp_callback_create(udp_t *udp)
46{
47 async_exch_t *exch = async_exchange_begin(udp->sess);
48
49 aid_t req = async_send_0(exch, UDP_CALLBACK_CREATE, NULL);
50 int rc = async_connect_to_me(exch, 0, 0, 0, udp_cb_conn, udp);
51 async_exchange_end(exch);
52
53 if (rc != EOK)
54 return rc;
55
56 sysarg_t retval;
57 async_wait_for(req, &retval);
58
59 return retval;
60}
61
62int udp_create(udp_t **rudp)
63{
64 udp_t *udp;
65 service_id_t udp_svcid;
66 int rc;
67
68 udp = calloc(1, sizeof(udp_t));
69 if (udp == NULL) {
70 rc = ENOMEM;
71 goto error;
72 }
73
74 list_initialize(&udp->assoc);
75 fibril_mutex_initialize(&udp->lock);
76 fibril_condvar_initialize(&udp->cv);
77
78 rc = loc_service_get_id(SERVICE_NAME_UDP, &udp_svcid,
79 IPC_FLAG_BLOCKING);
80 if (rc != EOK) {
81 rc = EIO;
82 goto error;
83 }
84
85 udp->sess = loc_service_connect(EXCHANGE_SERIALIZE, udp_svcid,
86 IPC_FLAG_BLOCKING);
87 if (udp->sess == NULL) {
88 rc = EIO;
89 goto error;
90 }
91
92 rc = udp_callback_create(udp);
93 if (rc != EOK) {
94 rc = EIO;
95 goto error;
96 }
97
98 *rudp = udp;
99 return EOK;
100error:
101 free(udp);
102 return rc;
103}
104
105void udp_destroy(udp_t *udp)
106{
107 if (udp == NULL)
108 return;
109
110 async_hangup(udp->sess);
111
112 fibril_mutex_lock(&udp->lock);
113 while (!udp->cb_done)
114 fibril_condvar_wait(&udp->cv, &udp->lock);
115 fibril_mutex_unlock(&udp->lock);
116
117 free(udp);
118}
119
120int udp_assoc_create(udp_t *udp, inet_ep2_t *ep2, udp_cb_t *cb, void *arg,
121 udp_assoc_t **rassoc)
122{
123 async_exch_t *exch;
124 udp_assoc_t *assoc;
125 ipc_call_t answer;
126
127 assoc = calloc(1, sizeof(udp_assoc_t));
128 if (assoc == NULL)
129 return ENOMEM;
130
131 exch = async_exchange_begin(udp->sess);
132 aid_t req = async_send_0(exch, UDP_ASSOC_CREATE, &answer);
133 sysarg_t rc = async_data_write_start(exch, (void *)ep2,
134 sizeof(inet_ep2_t));
135 async_exchange_end(exch);
136
137 if (rc != EOK) {
138 sysarg_t rc_orig;
139 async_wait_for(req, &rc_orig);
140 if (rc_orig != EOK)
141 rc = rc_orig;
142 goto error;
143 }
144
145 async_wait_for(req, &rc);
146 if (rc != EOK)
147 goto error;
148
149 assoc->udp = udp;
150 assoc->id = IPC_GET_ARG1(answer);
151 assoc->cb = cb;
152 assoc->cb_arg = arg;
153
154 list_append(&assoc->ludp, &udp->assoc);
155 *rassoc = assoc;
156
157 return EOK;
158error:
159 free(assoc);
160 return (int) rc;
161}
162
163void udp_assoc_destroy(udp_assoc_t *assoc)
164{
165 async_exch_t *exch;
166
167 if (assoc == NULL)
168 return;
169
170 list_remove(&assoc->ludp);
171
172 exch = async_exchange_begin(assoc->udp->sess);
173 sysarg_t rc = async_req_1_0(exch, UDP_ASSOC_DESTROY, assoc->id);
174 async_exchange_end(exch);
175
176 free(assoc);
177 (void) rc;
178}
179
180int udp_assoc_send_msg(udp_assoc_t *assoc, inet_ep_t *dest, void *data,
181 size_t bytes)
182{
183 async_exch_t *exch;
184
185 exch = async_exchange_begin(assoc->udp->sess);
186 aid_t req = async_send_1(exch, UDP_ASSOC_SEND_MSG, assoc->id, NULL);
187
188 sysarg_t rc = async_data_write_start(exch, (void *)dest,
189 sizeof(inet_ep_t));
190 if (rc != EOK) {
191 async_exchange_end(exch);
192 async_forget(req);
193 return rc;
194 }
195
196 rc = async_data_write_start(exch, data, bytes);
197 if (rc != EOK) {
198 async_forget(req);
199 return rc;
200 }
201
202 async_exchange_end(exch);
203
204 if (rc != EOK) {
205 async_forget(req);
206 return rc;
207 }
208
209 async_wait_for(req, &rc);
210 return rc;
211}
212
213void *udp_assoc_userptr(udp_assoc_t *assoc)
214{
215 return assoc->cb_arg;
216}
217
218size_t udp_rmsg_size(udp_rmsg_t *rmsg)
219{
220 return rmsg->size;
221}
222
223int udp_rmsg_read(udp_rmsg_t *rmsg, size_t off, void *buf, size_t bsize)
224{
225 async_exch_t *exch;
226 ipc_call_t answer;
227
228 exch = async_exchange_begin(rmsg->udp->sess);
229 aid_t req = async_send_1(exch, UDP_RMSG_READ, off, &answer);
230 int rc = async_data_read_start(exch, buf, bsize);
231 async_exchange_end(exch);
232
233 if (rc != EOK) {
234 async_forget(req);
235 return rc;
236 }
237
238 sysarg_t retval;
239 async_wait_for(req, &retval);
240 if (retval != EOK) {
241 return retval;
242 }
243
244 return EOK;
245}
246
247void udp_rmsg_remote_ep(udp_rmsg_t *rmsg, inet_ep_t *ep)
248{
249 *ep = rmsg->remote_ep;
250}
251
252uint8_t udp_rerr_type(udp_rerr_t *rerr)
253{
254 return 0;
255}
256
257uint8_t udp_rerr_code(udp_rerr_t *rerr)
258{
259 return 0;
260}
261
262static int udp_rmsg_info(udp_t *udp, udp_rmsg_t *rmsg)
263{
264 async_exch_t *exch;
265 inet_ep_t ep;
266 ipc_call_t answer;
267
268 exch = async_exchange_begin(udp->sess);
269 aid_t req = async_send_0(exch, UDP_RMSG_INFO, &answer);
270 int rc = async_data_read_start(exch, &ep, sizeof(inet_ep_t));
271 async_exchange_end(exch);
272
273 if (rc != EOK) {
274 async_forget(req);
275 return rc;
276 }
277
278 sysarg_t retval;
279 async_wait_for(req, &retval);
280 if (retval != EOK)
281 return retval;
282
283 rmsg->udp = udp;
284 rmsg->assoc_id = IPC_GET_ARG1(answer);
285 rmsg->size = IPC_GET_ARG2(answer);
286 rmsg->remote_ep = ep;
287 return EOK;
288}
289
290static int udp_rmsg_discard(udp_t *udp)
291{
292 async_exch_t *exch;
293
294 exch = async_exchange_begin(udp->sess);
295 sysarg_t rc = async_req_0_0(exch, UDP_RMSG_DISCARD);
296 async_exchange_end(exch);
297
298 return rc;
299}
300
301static int udp_assoc_get(udp_t *udp, sysarg_t id, udp_assoc_t **rassoc)
302{
303 list_foreach(udp->assoc, ludp, udp_assoc_t, assoc) {
304 if (assoc->id == id) {
305 *rassoc = assoc;
306 return EOK;
307 }
308 }
309
310 return EINVAL;
311}
312
313static void udp_ev_data(udp_t *udp, ipc_callid_t iid, ipc_call_t *icall)
314{
315 udp_rmsg_t rmsg;
316 udp_assoc_t *assoc;
317 int rc;
318
319 while (true) {
320 rc = udp_rmsg_info(udp, &rmsg);
321 if (rc != EOK) {
322 break;
323 }
324
325 rc = udp_assoc_get(udp, rmsg.assoc_id, &assoc);
326 if (rc != EOK) {
327 continue;
328 }
329
330 if (assoc->cb != NULL && assoc->cb->recv_msg != NULL)
331 assoc->cb->recv_msg(assoc, &rmsg);
332
333 rc = udp_rmsg_discard(udp);
334 if (rc != EOK) {
335 break;
336 }
337 }
338
339 async_answer_0(iid, EOK);
340}
341
342static void udp_cb_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
343{
344 udp_t *udp = (udp_t *)arg;
345
346 async_answer_0(iid, EOK);
347
348 while (true) {
349 ipc_call_t call;
350 ipc_callid_t callid = async_get_call(&call);
351
352 if (!IPC_GET_IMETHOD(call)) {
353 /* Hangup */
354 goto out;
355 }
356
357 switch (IPC_GET_IMETHOD(call)) {
358 case UDP_EV_DATA:
359 udp_ev_data(udp, callid, &call);
360 break;
361 default:
362 async_answer_0(callid, ENOTSUP);
363 break;
364 }
365 }
366out:
367 fibril_mutex_lock(&udp->lock);
368 udp->cb_done = true;
369 fibril_mutex_unlock(&udp->lock);
370 fibril_condvar_broadcast(&udp->cv);
371}
372
373/** @}
374 */
Note: See TracBrowser for help on using the repository browser.