source: mainline/uspace/srv/net/udp/service.c@ 2f19103

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

TCP and UDP servers can make use of inet/endpoint.h types internally.

  • Property mode set to 100644
File size: 12.4 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 udp
30 * @{
31 */
32
33/**
34 * @file HelenOS service implementation
35 */
36
37#include <async.h>
38#include <errno.h>
39#include <inet/endpoint.h>
40#include <io/log.h>
41#include <ipc/services.h>
42#include <ipc/udp.h>
43#include <loc.h>
44#include <macros.h>
45#include <stdlib.h>
46
47#include "assoc.h"
48#include "msg.h"
49#include "service.h"
50#include "udp_type.h"
51
52#define NAME "udp"
53
54#define MAX_MSG_SIZE DATA_XFER_LIMIT
55
56static void udp_cassoc_recv_msg(void *, inet_ep2_t *, udp_msg_t *);
57
58static udp_assoc_cb_t udp_cassoc_cb = {
59 .recv_msg = udp_cassoc_recv_msg
60};
61
62static int udp_cassoc_queue_msg(udp_cassoc_t *cassoc, inet_ep2_t *epp,
63 udp_msg_t *msg)
64{
65 udp_crcv_queue_entry_t *rqe;
66
67 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_cassoc_queue_msg(%p, %p, %p)",
68 cassoc, epp, msg);
69
70 rqe = calloc(1, sizeof(udp_crcv_queue_entry_t));
71 if (rqe == NULL)
72 return ENOMEM;
73
74 link_initialize(&rqe->link);
75 rqe->epp = *epp;
76 rqe->msg = msg;
77 rqe->cassoc = cassoc;
78
79// fibril_mutex_lock(&assoc->lock);
80 list_append(&rqe->link, &cassoc->client->crcv_queue);
81// fibril_mutex_unlock(&assoc->lock);
82
83// fibril_condvar_broadcast(&assoc->rcv_queue_cv);
84
85 return EOK;
86}
87
88static void udp_ev_data(udp_client_t *client)
89{
90 async_exch_t *exch;
91
92 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_ev_data()");
93
94 exch = async_exchange_begin(client->sess);
95 aid_t req = async_send_0(exch, UDP_EV_DATA, NULL);
96 async_exchange_end(exch);
97
98 async_forget(req);
99}
100
101static int udp_cassoc_create(udp_client_t *client, udp_assoc_t *assoc,
102 udp_cassoc_t **rcassoc)
103{
104 udp_cassoc_t *cassoc;
105 sysarg_t id;
106
107 cassoc = calloc(1, sizeof(udp_cassoc_t));
108 if (cassoc == NULL)
109 return ENOMEM;
110
111 /* Allocate new ID */
112 id = 0;
113 list_foreach (client->cassoc, lclient, udp_cassoc_t, cassoc) {
114 if (cassoc->id >= id)
115 id = cassoc->id + 1;
116 }
117
118 cassoc->id = id;
119 cassoc->client = client;
120 cassoc->assoc = assoc;
121
122 list_append(&cassoc->lclient, &client->cassoc);
123 *rcassoc = cassoc;
124 return EOK;
125}
126
127static void udp_cassoc_destroy(udp_cassoc_t *cassoc)
128{
129 list_remove(&cassoc->lclient);
130 free(cassoc);
131}
132
133static int udp_cassoc_get(udp_client_t *client, sysarg_t id,
134 udp_cassoc_t **rcassoc)
135{
136 list_foreach (client->cassoc, lclient, udp_cassoc_t, cassoc) {
137 if (cassoc->id == id) {
138 *rcassoc = cassoc;
139 return EOK;
140 }
141 }
142
143 return ENOENT;
144}
145
146static void udp_cassoc_recv_msg(void *arg, inet_ep2_t *epp, udp_msg_t *msg)
147{
148 udp_cassoc_t *cassoc = (udp_cassoc_t *) arg;
149
150 udp_cassoc_queue_msg(cassoc, epp, msg);
151 udp_ev_data(cassoc->client);
152}
153
154static int udp_assoc_create_impl(udp_client_t *client, inet_ep2_t *epp,
155 sysarg_t *rassoc_id)
156{
157 udp_assoc_t *assoc;
158 udp_cassoc_t *cassoc;
159 int rc;
160
161 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_create_impl");
162
163 assoc = udp_assoc_new(epp, NULL, NULL);
164 if (assoc == NULL)
165 return EIO;
166
167 if (epp->local_link != 0)
168 udp_assoc_set_iplink(assoc, epp->local_link);
169
170 rc = udp_cassoc_create(client, assoc, &cassoc);
171 if (rc != EOK) {
172 assert(rc == ENOMEM);
173 udp_assoc_delete(assoc);
174 return ENOMEM;
175 }
176
177 assoc->cb = &udp_cassoc_cb;
178 assoc->cb_arg = cassoc;
179
180 udp_assoc_add(assoc);
181
182 *rassoc_id = cassoc->id;
183 return EOK;
184}
185
186static int udp_assoc_destroy_impl(udp_client_t *client, sysarg_t assoc_id)
187{
188 udp_cassoc_t *cassoc;
189 int rc;
190
191 rc = udp_cassoc_get(client, assoc_id, &cassoc);
192 if (rc != EOK) {
193 assert(rc == ENOENT);
194 return ENOENT;
195 }
196
197 udp_assoc_remove(cassoc->assoc);
198 udp_assoc_reset(cassoc->assoc);
199 udp_assoc_delete(cassoc->assoc);
200 udp_cassoc_destroy(cassoc);
201 return EOK;
202}
203
204static int udp_assoc_send_msg_impl(udp_client_t *client, sysarg_t assoc_id,
205 inet_ep_t *dest, void *data, size_t size)
206{
207 udp_msg_t msg;
208 udp_cassoc_t *cassoc;
209 int rc;
210
211 rc = udp_cassoc_get(client, assoc_id, &cassoc);
212 if (rc != EOK)
213 return rc;
214
215 msg.data = data;
216 msg.data_size = size;
217 rc = udp_assoc_send(cassoc->assoc, dest, &msg);
218 if (rc != EOK)
219 return rc;
220
221 return EOK;
222}
223
224static void udp_callback_create_srv(udp_client_t *client, ipc_callid_t iid,
225 ipc_call_t *icall)
226{
227 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_callback_create_srv()");
228
229 async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE);
230 if (sess == NULL) {
231 async_answer_0(iid, ENOMEM);
232 return;
233 }
234
235 client->sess = sess;
236 async_answer_0(iid, EOK);
237}
238
239static void udp_assoc_create_srv(udp_client_t *client, ipc_callid_t iid,
240 ipc_call_t *icall)
241{
242 ipc_callid_t callid;
243 size_t size;
244 inet_ep2_t epp;
245 sysarg_t assoc_id;
246 int rc;
247
248 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_create_srv()");
249
250 if (!async_data_write_receive(&callid, &size)) {
251 async_answer_0(callid, EREFUSED);
252 async_answer_0(iid, EREFUSED);
253 return;
254 }
255
256 if (size != sizeof(inet_ep2_t)) {
257 async_answer_0(callid, EINVAL);
258 async_answer_0(iid, EINVAL);
259 return;
260 }
261
262 rc = async_data_write_finalize(callid, &epp, size);
263 if (rc != EOK) {
264 async_answer_0(callid, rc);
265 async_answer_0(iid, rc);
266 return;
267 }
268
269 rc = udp_assoc_create_impl(client, &epp, &assoc_id);
270 if (rc != EOK) {
271 async_answer_0(iid, rc);
272 return;
273 }
274
275 async_answer_1(iid, EOK, assoc_id);
276}
277
278static void udp_assoc_destroy_srv(udp_client_t *client, ipc_callid_t iid,
279 ipc_call_t *icall)
280{
281 sysarg_t assoc_id;
282 int rc;
283
284 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_destroy_srv()");
285
286 assoc_id = IPC_GET_ARG1(*icall);
287 rc = udp_assoc_destroy_impl(client, assoc_id);
288 async_answer_0(iid, rc);
289}
290
291static void udp_assoc_send_msg_srv(udp_client_t *client, ipc_callid_t iid,
292 ipc_call_t *icall)
293{
294 ipc_callid_t callid;
295 size_t size;
296 inet_ep_t dest;
297 sysarg_t assoc_id;
298 void *data;
299 int rc;
300
301 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_send_msg_srv()");
302
303 /* Receive dest */
304
305 if (!async_data_write_receive(&callid, &size)) {
306 async_answer_0(callid, EREFUSED);
307 async_answer_0(iid, EREFUSED);
308 return;
309 }
310
311 if (size != sizeof(inet_ep_t)) {
312 async_answer_0(callid, EINVAL);
313 async_answer_0(iid, EINVAL);
314 return;
315 }
316
317 rc = async_data_write_finalize(callid, &dest, size);
318 if (rc != EOK) {
319 async_answer_0(callid, rc);
320 async_answer_0(iid, rc);
321 return;
322 }
323
324 /* Receive message data */
325
326 if (!async_data_write_receive(&callid, &size)) {
327 async_answer_0(callid, EREFUSED);
328 async_answer_0(iid, EREFUSED);
329 return;
330 }
331
332 if (size > MAX_MSG_SIZE) {
333 async_answer_0(callid, EINVAL);
334 async_answer_0(iid, EINVAL);
335 return;
336 }
337
338 data = malloc(size);
339 if (data == NULL) {
340 async_answer_0(callid, ENOMEM);
341 async_answer_0(iid, ENOMEM);
342 }
343
344 rc = async_data_write_finalize(callid, data, size);
345 if (rc != EOK) {
346 async_answer_0(callid, rc);
347 async_answer_0(iid, rc);
348 free(data);
349 return;
350 }
351
352 assoc_id = IPC_GET_ARG1(*icall);
353
354 rc = udp_assoc_send_msg_impl(client, assoc_id, &dest, data, size);
355 if (rc != EOK) {
356 async_answer_0(iid, rc);
357 free(data);
358 return;
359 }
360
361 async_answer_0(iid, EOK);
362 free(data);
363}
364
365static udp_crcv_queue_entry_t *udp_rmsg_get_next(udp_client_t *client)
366{
367 link_t *link;
368
369 link = list_first(&client->crcv_queue);
370 if (link == NULL)
371 return NULL;
372
373 return list_get_instance(link, udp_crcv_queue_entry_t, link);
374}
375
376static void udp_rmsg_info_srv(udp_client_t *client, ipc_callid_t iid,
377 ipc_call_t *icall)
378{
379 ipc_callid_t callid;
380 size_t size;
381 udp_crcv_queue_entry_t *enext;
382 sysarg_t assoc_id;
383 int rc;
384
385 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_rmsg_info_srv()");
386 enext = udp_rmsg_get_next(client);
387
388 if (!async_data_read_receive(&callid, &size)) {
389 async_answer_0(callid, EREFUSED);
390 async_answer_0(iid, EREFUSED);
391 return;
392 }
393
394 if (enext == NULL) {
395 async_answer_0(callid, ENOENT);
396 async_answer_0(iid, ENOENT);
397 return;
398 }
399
400 rc = async_data_read_finalize(callid, &enext->epp.remote,
401 max(size, (ssize_t)sizeof(inet_ep_t)));
402 if (rc != EOK) {
403 async_answer_0(iid, rc);
404 return;
405 }
406
407 assoc_id = enext->cassoc->id;
408 size = enext->msg->data_size;
409
410 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_rmsg_info_srv(): assoc_id=%zu, "
411 "size=%zu", assoc_id, size);
412 async_answer_2(iid, EOK, assoc_id, size);
413}
414
415static void udp_rmsg_read_srv(udp_client_t *client, ipc_callid_t iid,
416 ipc_call_t *icall)
417{
418 ipc_callid_t callid;
419 ssize_t msg_size;
420 udp_crcv_queue_entry_t *enext;
421 void *data;
422 size_t size;
423 ssize_t off;
424 int rc;
425
426 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_rmsg_read_srv()");
427 off = IPC_GET_ARG1(*icall);
428
429 enext = udp_rmsg_get_next(client);
430
431 if (!async_data_read_receive(&callid, &size)) {
432 async_answer_0(callid, EREFUSED);
433 async_answer_0(iid, EREFUSED);
434 return;
435 }
436
437 if (enext == NULL) {
438 async_answer_0(callid, ENOENT);
439 async_answer_0(iid, ENOENT);
440 return;
441 }
442
443 data = enext->msg->data + off;
444 msg_size = enext->msg->data_size;
445
446 rc = async_data_read_finalize(callid, data, max(msg_size - off,
447 (ssize_t)size));
448 if (rc != EOK) {
449 async_answer_0(iid, rc);
450 return;
451 }
452
453 async_answer_0(iid, EOK);
454 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_rmsg_read_srv(): OK");
455}
456
457static void udp_rmsg_discard_srv(udp_client_t *client, ipc_callid_t iid,
458 ipc_call_t *icall)
459{
460 udp_crcv_queue_entry_t *enext;
461
462 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_rmsg_discard_srv()");
463
464 enext = udp_rmsg_get_next(client);
465 if (enext == NULL) {
466 log_msg(LOG_DEFAULT, LVL_DEBUG, "usg_rmsg_discard_srv: enext==NULL");
467 async_answer_0(iid, ENOENT);
468 return;
469 }
470
471 list_remove(&enext->link);
472 udp_msg_delete(enext->msg);
473 free(enext);
474 async_answer_0(iid, EOK);
475}
476
477static void udp_client_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
478{
479 udp_client_t client;
480 size_t n;
481
482 /* Accept the connection */
483 async_answer_0(iid, EOK);
484
485 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_client_conn()");
486
487 list_initialize(&client.cassoc);
488 list_initialize(&client.crcv_queue);
489
490 while (true) {
491 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_client_conn: wait req");
492 ipc_call_t call;
493 ipc_callid_t callid = async_get_call(&call);
494 sysarg_t method = IPC_GET_IMETHOD(call);
495
496 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_client_conn: method=%d",
497 (int)method);
498 if (!method) {
499 /* The other side has hung up */
500 async_answer_0(callid, EOK);
501 break;
502 }
503
504 switch (method) {
505 case UDP_CALLBACK_CREATE:
506 udp_callback_create_srv(&client, callid, &call);
507 break;
508 case UDP_ASSOC_CREATE:
509 udp_assoc_create_srv(&client, callid, &call);
510 break;
511 case UDP_ASSOC_DESTROY:
512 udp_assoc_destroy_srv(&client, callid, &call);
513 break;
514 case UDP_ASSOC_SEND_MSG:
515 udp_assoc_send_msg_srv(&client, callid, &call);
516 break;
517 case UDP_RMSG_INFO:
518 udp_rmsg_info_srv(&client, callid, &call);
519 break;
520 case UDP_RMSG_READ:
521 udp_rmsg_read_srv(&client, callid, &call);
522 break;
523 case UDP_RMSG_DISCARD:
524 udp_rmsg_discard_srv(&client, callid, &call);
525 break;
526 default:
527 async_answer_0(callid, ENOTSUP);
528 break;
529 }
530 }
531
532 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_client_conn: terminated");
533
534 n = list_count(&client.cassoc);
535 if (n != 0) {
536 log_msg(LOG_DEFAULT, LVL_WARN, "udp_client_conn: "
537 "Client with %zu active associations closed session.", n);
538 /* XXX Clean up */
539 }
540
541 /* XXX Clean up client receive queue */
542}
543
544int udp_service_init(void)
545{
546 int rc;
547 service_id_t sid;
548
549 async_set_client_connection(udp_client_conn);
550
551 rc = loc_server_register(NAME);
552 if (rc != EOK) {
553 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering server.");
554 return EIO;
555 }
556
557 rc = loc_service_register(SERVICE_NAME_UDP, &sid);
558 if (rc != EOK) {
559 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service.");
560 return EIO;
561 }
562
563 return EOK;
564}
565
566/**
567 * @}
568 */
Note: See TracBrowser for help on using the repository browser.