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

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

New transport layer API. Only UDP implemented.

  • Property mode set to 100644
File size: 8.3 KB
RevLine 
[fab2746]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 <io/log.h>
39#include <ipc/services.h>
40#include <ipc/udp.h>
41#include <loc.h>
42#include <stdlib.h>
43
44#include <stdio.h>
45
46static void udp_cb_conn(ipc_callid_t, ipc_call_t *, void *);
47
48static int udp_callback_create(udp_t *udp)
49{
50 async_exch_t *exch = async_exchange_begin(udp->sess);
51
52 log_msg(LOG_DEFAULT, LVL_NOTE, "udp_callback_create()\n");
53
54 aid_t req = async_send_0(exch, UDP_CALLBACK_CREATE, NULL);
55 int rc = async_connect_to_me(exch, 0, 0, 0, udp_cb_conn, udp);
56 async_exchange_end(exch);
57
58 if (rc != EOK)
59 return rc;
60
61 sysarg_t retval;
62 async_wait_for(req, &retval);
63
64 return retval;
65}
66
67int udp_create(udp_t **rudp)
68{
69 udp_t *udp;
70 service_id_t udp_svcid;
71 int rc;
72
73 log_msg(LOG_DEFAULT, LVL_NOTE, "udp_create()\n");
74
75 udp = calloc(1, sizeof(udp_t));
76 if (udp == NULL) {
77 rc = ENOMEM;
78 goto error;
79 }
80
81 list_initialize(&udp->assoc);
82
83 rc = loc_service_get_id(SERVICE_NAME_UDP, &udp_svcid,
84 IPC_FLAG_BLOCKING);
85 if (rc != EOK) {
86 rc = EIO;
87 goto error;
88 }
89
90 udp->sess = loc_service_connect(EXCHANGE_SERIALIZE, udp_svcid,
91 IPC_FLAG_BLOCKING);
92 if (udp->sess == NULL) {
93 rc = EIO;
94 goto error;
95 }
96
97 rc = udp_callback_create(udp);
98 if (rc != EOK) {
99 rc = EIO;
100 goto error;
101 }
102
103 *rudp = udp;
104 return EOK;
105error:
106 free(udp);
107 return rc;
108}
109
110void udp_destroy(udp_t *udp)
111{
112 if (udp == NULL)
113 return;
114
115 async_hangup(udp->sess);
116 free(udp);
117}
118
119int udp_assoc_create(udp_t *udp, inet_ep2_t *ep2, udp_cb_t *cb, void *arg,
120 udp_assoc_t **rassoc)
121{
122 async_exch_t *exch;
123 udp_assoc_t *assoc;
124 ipc_call_t answer;
125
126 log_msg(LOG_DEFAULT, LVL_NOTE, "udp_assoc_create()\n");
127
128 assoc = calloc(1, sizeof(udp_assoc_t));
129 if (assoc == NULL)
130 return ENOMEM;
131
132 exch = async_exchange_begin(udp->sess);
133 aid_t req = async_send_0(exch, UDP_ASSOC_CREATE, &answer);
134 sysarg_t rc = async_data_write_start(exch, (void *)ep2,
135 sizeof(inet_ep2_t));
136 async_exchange_end(exch);
137
138 if (rc != EOK) {
139 sysarg_t rc_orig;
140 async_wait_for(req, &rc_orig);
141 if (rc_orig != EOK)
142 rc = rc_orig;
143 goto error;
144 }
145
146 async_wait_for(req, &rc);
147 if (rc != EOK)
148 goto error;
149
150 assoc->udp = udp;
151 assoc->id = IPC_GET_ARG1(answer);
152 assoc->cb = cb;
153 assoc->cb_arg = arg;
154
155 list_append(&assoc->ludp, &udp->assoc);
156 *rassoc = assoc;
157
158 return EOK;
159error:
160 free(assoc);
161 return (int) rc;
162}
163
164void udp_assoc_destroy(udp_assoc_t *assoc)
165{
166 async_exch_t *exch;
167
168 log_msg(LOG_DEFAULT, LVL_NOTE, "udp_assoc_destroy()\n");
169
170 if (assoc == NULL)
171 return;
172
173 list_remove(&assoc->ludp);
174
175 exch = async_exchange_begin(assoc->udp->sess);
176 sysarg_t rc = async_req_1_0(exch, UDP_ASSOC_DESTROY, assoc->id);
177 async_exchange_end(exch);
178
179 free(assoc);
180 (void) rc;
181}
182
183int udp_assoc_send_msg(udp_assoc_t *assoc, inet_ep_t *dest, void *data,
184 size_t bytes)
185{
186 async_exch_t *exch;
187
188 log_msg(LOG_DEFAULT, LVL_NOTE, "udp_assoc_send_msg()\n");
189
190 exch = async_exchange_begin(assoc->udp->sess);
191 aid_t req = async_send_1(exch, UDP_ASSOC_SEND_MSG, assoc->id, NULL);
192
193 sysarg_t rc = async_data_write_start(exch, (void *)dest,
194 sizeof(inet_ep_t));
195 if (rc != EOK) {
196 async_exchange_end(exch);
197 async_forget(req);
198 return rc;
199 }
200
201 rc = async_data_write_start(exch, data, bytes);
202 if (rc != EOK) {
203 async_forget(req);
204 return rc;
205 }
206
207 async_exchange_end(exch);
208
209 if (rc != EOK) {
210 async_forget(req);
211 return rc;
212 }
213
214 async_wait_for(req, &rc);
215 return rc;
216}
217
218void *udp_assoc_userptr(udp_assoc_t *assoc)
219{
220 return assoc->cb_arg;
221}
222
223size_t udp_rmsg_size(udp_rmsg_t *rmsg)
224{
225 return rmsg->size;
226}
227
228int udp_rmsg_read(udp_rmsg_t *rmsg, size_t off, void *buf, size_t bsize)
229{
230 async_exch_t *exch;
231 ipc_call_t answer;
232
233 log_msg(LOG_DEFAULT, LVL_NOTE, "udp_rmsg_read()");
234
235 exch = async_exchange_begin(rmsg->udp->sess);
236 aid_t req = async_send_1(exch, UDP_RMSG_READ, off, &answer);
237 int rc = async_data_read_start(exch, buf, bsize);
238 async_exchange_end(exch);
239
240 if (rc != EOK) {
241 log_msg(LOG_DEFAULT, LVL_NOTE, "udp_rmsg_read() - rc != EOK");
242 async_forget(req);
243 return rc;
244 }
245
246 log_msg(LOG_DEFAULT, LVL_NOTE, "udp_rmsg_read() - wait for req");
247 sysarg_t retval;
248 async_wait_for(req, &retval);
249 if (retval != EOK) {
250 log_msg(LOG_DEFAULT, LVL_NOTE, "udp_rmsg_read() - retval != EOK");
251 return retval;
252 }
253
254 log_msg(LOG_DEFAULT, LVL_NOTE, "udp_rmsg_read() - OK");
255 return EOK;
256}
257
258void udp_rmsg_remote_ep(udp_rmsg_t *rmsg, inet_ep_t *ep)
259{
260 *ep = rmsg->remote_ep;
261}
262
263uint8_t udp_rerr_type(udp_rerr_t *rerr)
264{
265 return 0;
266}
267
268uint8_t udp_rerr_code(udp_rerr_t *rerr)
269{
270 return 0;
271}
272
273static int udp_rmsg_info(udp_t *udp, udp_rmsg_t *rmsg)
274{
275 async_exch_t *exch;
276 inet_ep_t ep;
277 ipc_call_t answer;
278
279 log_msg(LOG_DEFAULT, LVL_NOTE, "udp_rmsg_info()\n");
280
281 exch = async_exchange_begin(udp->sess);
282 aid_t req = async_send_0(exch, UDP_RMSG_INFO, &answer);
283 int rc = async_data_read_start(exch, &ep, sizeof(inet_ep_t));
284 async_exchange_end(exch);
285
286 if (rc != EOK) {
287 async_forget(req);
288 return rc;
289 }
290
291 sysarg_t retval;
292 async_wait_for(req, &retval);
293 if (retval != EOK)
294 return retval;
295
296 rmsg->udp = udp;
297 rmsg->assoc_id = IPC_GET_ARG1(answer);
298 rmsg->size = IPC_GET_ARG2(answer);
299 rmsg->remote_ep = ep;
300 return EOK;
301}
302
303static int udp_rmsg_discard(udp_t *udp)
304{
305 async_exch_t *exch;
306
307 log_msg(LOG_DEFAULT, LVL_NOTE, "udp_rmsg_discard()\n");
308
309 exch = async_exchange_begin(udp->sess);
310 sysarg_t rc = async_req_0_0(exch, UDP_RMSG_DISCARD);
311 async_exchange_end(exch);
312
313 return rc;
314}
315
316static int udp_assoc_get(udp_t *udp, sysarg_t id, udp_assoc_t **rassoc)
317{
318 list_foreach(udp->assoc, ludp, udp_assoc_t, assoc) {
319 if (assoc->id == id) {
320 *rassoc = assoc;
321 return EOK;
322 }
323 }
324
325 return EINVAL;
326}
327
328static void udp_ev_data(udp_t *udp, ipc_callid_t iid, ipc_call_t *icall)
329{
330 udp_rmsg_t rmsg;
331 udp_assoc_t *assoc;
332 int rc;
333
334 log_msg(LOG_DEFAULT, LVL_NOTE, "udp_ev_data()\n");
335
336 while (true) {
337 rc = udp_rmsg_info(udp, &rmsg);
338 if (rc != EOK) {
339 log_msg(LOG_DEFAULT, LVL_NOTE, "Error getting message info\n");
340 break;
341 }
342
343 rc = udp_assoc_get(udp, rmsg.assoc_id, &assoc);
344 if (rc != EOK) {
345 log_msg(LOG_DEFAULT, LVL_NOTE, "assoc ID %zu not found\n",
346 rmsg.assoc_id);
347 continue;
348 }
349
350 if (assoc->cb != NULL && assoc->cb->recv_msg != NULL)
351 assoc->cb->recv_msg(assoc, &rmsg);
352
353 rc = udp_rmsg_discard(udp);
354 if (rc != EOK) {
355 log_msg(LOG_DEFAULT, LVL_NOTE, "Error discarding message\n");
356 break;
357 }
358 }
359
360 async_answer_0(iid, EOK);
361}
362
363static void udp_cb_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
364{
365 udp_t *udp = (udp_t *)arg;
366
367 async_answer_0(iid, EOK);
368
369 log_msg(LOG_DEFAULT, LVL_NOTE, "udp_cb_conn()\n");
370
371 while (true) {
372 ipc_call_t call;
373 ipc_callid_t callid = async_get_call(&call);
374
375 log_msg(LOG_DEFAULT, LVL_NOTE, "udp_cb_conn() - msg %d\n",
376 (int)IPC_GET_IMETHOD(call));
377 if (!IPC_GET_IMETHOD(call)) {
378 /* TODO: Handle hangup */
379 return;
380 }
381
382 switch (IPC_GET_IMETHOD(call)) {
383 case UDP_EV_DATA:
384 udp_ev_data(udp, callid, &call);
385 break;
386 default:
387 async_answer_0(callid, ENOTSUP);
388 break;
389 }
390 }
391}
392
393/** @}
394 */
Note: See TracBrowser for help on using the repository browser.