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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since eed4139 was eed4139, checked in by Jakub Jermar <jakub@…>, 7 years ago

Fix some comments mentioning 'call IDs'

  • Property mode set to 100644
File size: 18.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 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
[b10460a]54/** Maximum message size */
[fab2746]55#define MAX_MSG_SIZE DATA_XFER_LIMIT
56
[2f19103]57static void udp_cassoc_recv_msg(void *, inet_ep2_t *, udp_msg_t *);
[fab2746]58
[b10460a]59/** Callbacks to tie us to association layer */
[fab2746]60static udp_assoc_cb_t udp_cassoc_cb = {
61 .recv_msg = udp_cassoc_recv_msg
62};
63
[b10460a]64/** Add message to client receive queue.
65 *
66 * @param cassoc Client association
67 * @param epp Endpoint pair on which message was received
68 * @param msg Message
69 *
70 * @return EOK on success, ENOMEM if out of memory
71 */
[b7fd2a0]72static errno_t udp_cassoc_queue_msg(udp_cassoc_t *cassoc, inet_ep2_t *epp,
[fab2746]73 udp_msg_t *msg)
74{
75 udp_crcv_queue_entry_t *rqe;
76
[99ea91b2]77 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_cassoc_queue_msg(%p, %p, %p)",
[2f19103]78 cassoc, epp, msg);
[fab2746]79
80 rqe = calloc(1, sizeof(udp_crcv_queue_entry_t));
81 if (rqe == NULL)
82 return ENOMEM;
83
84 link_initialize(&rqe->link);
[2f19103]85 rqe->epp = *epp;
[fab2746]86 rqe->msg = msg;
87 rqe->cassoc = cassoc;
88
89// fibril_mutex_lock(&assoc->lock);
90 list_append(&rqe->link, &cassoc->client->crcv_queue);
91// fibril_mutex_unlock(&assoc->lock);
92
93// fibril_condvar_broadcast(&assoc->rcv_queue_cv);
94
95 return EOK;
96}
97
[b10460a]98/** Send 'data' event to client.
99 *
100 * @param client Client
101 */
[99ea91b2]102static void udp_ev_data(udp_client_t *client)
[fab2746]103{
104 async_exch_t *exch;
105
[99ea91b2]106 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_ev_data()");
[fab2746]107
108 exch = async_exchange_begin(client->sess);
[99ea91b2]109 aid_t req = async_send_0(exch, UDP_EV_DATA, NULL);
[fab2746]110 async_exchange_end(exch);
111
[99ea91b2]112 async_forget(req);
[fab2746]113}
114
[b10460a]115/** Create client association.
116 *
117 * This effectively adds an association into a client's namespace.
118 *
119 * @param client Client
120 * @param assoc Association
121 * @param rcassoc Place to store pointer to new client association
122 *
123 * @return EOK on soccess, ENOMEM if out of memory
124 */
[b7fd2a0]125static errno_t udp_cassoc_create(udp_client_t *client, udp_assoc_t *assoc,
[fab2746]126 udp_cassoc_t **rcassoc)
127{
128 udp_cassoc_t *cassoc;
129 sysarg_t id;
130
131 cassoc = calloc(1, sizeof(udp_cassoc_t));
132 if (cassoc == NULL)
133 return ENOMEM;
134
135 /* Allocate new ID */
136 id = 0;
137 list_foreach (client->cassoc, lclient, udp_cassoc_t, cassoc) {
138 if (cassoc->id >= id)
139 id = cassoc->id + 1;
140 }
141
142 cassoc->id = id;
143 cassoc->client = client;
144 cassoc->assoc = assoc;
145
146 list_append(&cassoc->lclient, &client->cassoc);
147 *rcassoc = cassoc;
148 return EOK;
149}
150
[b10460a]151/** Destroy client association.
152 *
153 * @param cassoc Client association
154 */
[fab2746]155static void udp_cassoc_destroy(udp_cassoc_t *cassoc)
156{
157 list_remove(&cassoc->lclient);
158 free(cassoc);
159}
160
[b10460a]161/** Get client association by ID.
162 *
163 * @param client Client
164 * @param id Client association ID
165 * @param rcassoc Place to store pointer to client association
166 *
167 * @return EOK on success, ENOENT if no client association with the given ID
168 * is found.
169 */
[b7fd2a0]170static errno_t udp_cassoc_get(udp_client_t *client, sysarg_t id,
[fab2746]171 udp_cassoc_t **rcassoc)
172{
173 list_foreach (client->cassoc, lclient, udp_cassoc_t, cassoc) {
174 if (cassoc->id == id) {
175 *rcassoc = cassoc;
176 return EOK;
177 }
178 }
179
180 return ENOENT;
181}
182
[b10460a]183/** Message received on client association.
184 *
185 * Used as udp_assoc_cb.recv_msg callback.
186 *
187 * @param arg Callback argument, client association
188 * @param epp Endpoint pair where message was received
189 * @param msg Message
190 */
[2f19103]191static void udp_cassoc_recv_msg(void *arg, inet_ep2_t *epp, udp_msg_t *msg)
[fab2746]192{
193 udp_cassoc_t *cassoc = (udp_cassoc_t *) arg;
194
[2f19103]195 udp_cassoc_queue_msg(cassoc, epp, msg);
[fab2746]196 udp_ev_data(cassoc->client);
197}
198
[b10460a]199/** Create association.
200 *
201 * Handle client request to create association (with parameters unmarshalled).
202 *
203 * @param client UDP client
204 * @param epp Endpoint pair
205 * @param rassoc_id Place to store ID of new association
206 *
[cde999a]207 * @return EOK on success or an error code
[b10460a]208 */
[b7fd2a0]209static errno_t udp_assoc_create_impl(udp_client_t *client, inet_ep2_t *epp,
[fab2746]210 sysarg_t *rassoc_id)
211{
212 udp_assoc_t *assoc;
213 udp_cassoc_t *cassoc;
[b7fd2a0]214 errno_t rc;
[779541b]215
216 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_create_impl");
[fab2746]217
[2f19103]218 assoc = udp_assoc_new(epp, NULL, NULL);
[fab2746]219 if (assoc == NULL)
220 return EIO;
221
222 if (epp->local_link != 0)
223 udp_assoc_set_iplink(assoc, epp->local_link);
224
225 rc = udp_cassoc_create(client, assoc, &cassoc);
226 if (rc != EOK) {
227 assert(rc == ENOMEM);
228 udp_assoc_delete(assoc);
229 return ENOMEM;
230 }
231
232 assoc->cb = &udp_cassoc_cb;
233 assoc->cb_arg = cassoc;
234
[2989c7e]235 rc = udp_assoc_add(assoc);
236 if (rc != EOK) {
237 udp_cassoc_destroy(cassoc);
238 udp_assoc_delete(assoc);
239 return rc;
240 }
[fab2746]241
242 *rassoc_id = cassoc->id;
243 return EOK;
244}
245
[b10460a]246/** Destroy association.
247 *
248 * Handle client request to destroy association (with parameters unmarshalled).
249 *
250 * @param client UDP client
251 * @param assoc_id Association ID
252 * @return EOK on success, ENOENT if no such association is found
253 */
[b7fd2a0]254static errno_t udp_assoc_destroy_impl(udp_client_t *client, sysarg_t assoc_id)
[fab2746]255{
256 udp_cassoc_t *cassoc;
[b7fd2a0]257 errno_t rc;
[fab2746]258
259 rc = udp_cassoc_get(client, assoc_id, &cassoc);
260 if (rc != EOK) {
261 assert(rc == ENOENT);
262 return ENOENT;
263 }
264
265 udp_assoc_remove(cassoc->assoc);
266 udp_assoc_reset(cassoc->assoc);
267 udp_assoc_delete(cassoc->assoc);
268 udp_cassoc_destroy(cassoc);
269 return EOK;
270}
271
[58e8646]272/** Set association sending messages with no local address.
273 *
274 * Handle client request to set nolocal flag (with parameters unmarshalled).
275 *
276 * @param client UDP client
277 * @param assoc_id Association ID
278 * @return EOK on success, ENOENT if no such association is found
279 */
[b7fd2a0]280static errno_t udp_assoc_set_nolocal_impl(udp_client_t *client, sysarg_t assoc_id)
[58e8646]281{
282 udp_cassoc_t *cassoc;
[b7fd2a0]283 errno_t rc;
[58e8646]284
285 rc = udp_cassoc_get(client, assoc_id, &cassoc);
286 if (rc != EOK) {
287 assert(rc == ENOENT);
288 return ENOENT;
289 }
290
291 log_msg(LOG_DEFAULT, LVL_NOTE, "Setting nolocal to true");
292 cassoc->assoc->nolocal = true;
293 return EOK;
294}
295
[b10460a]296/** Send message via association.
297 *
298 * Handle client request to send message (with parameters unmarshalled).
299 *
300 * @param client UDP client
301 * @param assoc_id Association ID
302 * @param dest Destination endpoint or @c NULL to use the default from
303 * association
304 * @param data Message data
305 * @param size Message size
306 *
[cde999a]307 * @return EOK on success or an error code
[b10460a]308 */
[b7fd2a0]309static errno_t udp_assoc_send_msg_impl(udp_client_t *client, sysarg_t assoc_id,
[fab2746]310 inet_ep_t *dest, void *data, size_t size)
311{
312 udp_msg_t msg;
313 udp_cassoc_t *cassoc;
[b7fd2a0]314 errno_t rc;
[fab2746]315
316 rc = udp_cassoc_get(client, assoc_id, &cassoc);
317 if (rc != EOK)
318 return rc;
319
320 msg.data = data;
321 msg.data_size = size;
[2f19103]322 rc = udp_assoc_send(cassoc->assoc, dest, &msg);
[fab2746]323 if (rc != EOK)
324 return rc;
325
326 return EOK;
327}
328
[b10460a]329/** Create callback session.
330 *
331 * Handle client request to create callback session.
332 *
333 * @param client UDP client
334 * @param iid Async request ID
335 * @param icall Async request data
336 */
[a46e56b]337static void udp_callback_create_srv(udp_client_t *client, cap_call_handle_t icall_handle,
[fab2746]338 ipc_call_t *icall)
339{
340 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_callback_create_srv()");
341
342 async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE);
343 if (sess == NULL) {
[a46e56b]344 async_answer_0(icall_handle, ENOMEM);
[fab2746]345 return;
346 }
347
348 client->sess = sess;
[a46e56b]349 async_answer_0(icall_handle, EOK);
[fab2746]350}
351
[b10460a]352/** Create association.
353 *
354 * Handle client request to create association.
355 *
356 * @param client UDP client
357 * @param iid Async request ID
358 * @param icall Async request data
359 */
[a46e56b]360static void udp_assoc_create_srv(udp_client_t *client, cap_call_handle_t icall_handle,
[fab2746]361 ipc_call_t *icall)
362{
[a46e56b]363 cap_call_handle_t chandle;
[fab2746]364 size_t size;
365 inet_ep2_t epp;
366 sysarg_t assoc_id;
[b7fd2a0]367 errno_t rc;
[fab2746]368
369 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_create_srv()");
370
[a46e56b]371 if (!async_data_write_receive(&chandle, &size)) {
372 async_answer_0(chandle, EREFUSED);
373 async_answer_0(icall_handle, EREFUSED);
[fab2746]374 return;
375 }
376
377 if (size != sizeof(inet_ep2_t)) {
[a46e56b]378 async_answer_0(chandle, EINVAL);
379 async_answer_0(icall_handle, EINVAL);
[fab2746]380 return;
381 }
382
[a46e56b]383 rc = async_data_write_finalize(chandle, &epp, size);
[fab2746]384 if (rc != EOK) {
[a46e56b]385 async_answer_0(chandle, rc);
386 async_answer_0(icall_handle, rc);
[fab2746]387 return;
388 }
389
390 rc = udp_assoc_create_impl(client, &epp, &assoc_id);
391 if (rc != EOK) {
[a46e56b]392 async_answer_0(icall_handle, rc);
[fab2746]393 return;
394 }
395
[a46e56b]396 async_answer_1(icall_handle, EOK, assoc_id);
[fab2746]397}
398
[b10460a]399/** Destroy association.
400 *
401 * Handle client request to destroy association.
402 *
403 * @param client UDP client
404 * @param iid Async request ID
405 * @param icall Async request data
406 */
[a46e56b]407static void udp_assoc_destroy_srv(udp_client_t *client, cap_call_handle_t icall_handle,
[fab2746]408 ipc_call_t *icall)
409{
410 sysarg_t assoc_id;
[b7fd2a0]411 errno_t rc;
[fab2746]412
413 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_destroy_srv()");
414
415 assoc_id = IPC_GET_ARG1(*icall);
416 rc = udp_assoc_destroy_impl(client, assoc_id);
[a46e56b]417 async_answer_0(icall_handle, rc);
[fab2746]418}
419
[58e8646]420/** Set association with no local address.
421 *
422 * Handle client request to set no local address flag.
423 *
424 * @param client UDP client
425 * @param iid Async request ID
426 * @param icall Async request data
427 */
[a46e56b]428static void udp_assoc_set_nolocal_srv(udp_client_t *client, cap_call_handle_t icall_handle,
[58e8646]429 ipc_call_t *icall)
430{
431 sysarg_t assoc_id;
[b7fd2a0]432 errno_t rc;
[58e8646]433
434 log_msg(LOG_DEFAULT, LVL_NOTE, "udp_assoc_set_nolocal_srv()");
435
436 assoc_id = IPC_GET_ARG1(*icall);
437 rc = udp_assoc_set_nolocal_impl(client, assoc_id);
[a46e56b]438 async_answer_0(icall_handle, rc);
[58e8646]439}
440
[b10460a]441/** Send message via association.
442 *
443 * Handle client request to send message.
444 *
445 * @param client UDP client
446 * @param iid Async request ID
447 * @param icall Async request data
448 */
[a46e56b]449static void udp_assoc_send_msg_srv(udp_client_t *client, cap_call_handle_t icall_handle,
[fab2746]450 ipc_call_t *icall)
451{
[a46e56b]452 cap_call_handle_t chandle;
[fab2746]453 size_t size;
454 inet_ep_t dest;
455 sysarg_t assoc_id;
456 void *data;
[b7fd2a0]457 errno_t rc;
[fab2746]458
459 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_assoc_send_msg_srv()");
460
461 /* Receive dest */
462
[a46e56b]463 if (!async_data_write_receive(&chandle, &size)) {
464 async_answer_0(chandle, EREFUSED);
465 async_answer_0(icall_handle, EREFUSED);
[fab2746]466 return;
467 }
468
469 if (size != sizeof(inet_ep_t)) {
[a46e56b]470 async_answer_0(chandle, EINVAL);
471 async_answer_0(icall_handle, EINVAL);
[fab2746]472 return;
473 }
474
[a46e56b]475 rc = async_data_write_finalize(chandle, &dest, size);
[fab2746]476 if (rc != EOK) {
[a46e56b]477 async_answer_0(chandle, rc);
478 async_answer_0(icall_handle, rc);
[fab2746]479 return;
480 }
481
482 /* Receive message data */
483
[a46e56b]484 if (!async_data_write_receive(&chandle, &size)) {
485 async_answer_0(chandle, EREFUSED);
486 async_answer_0(icall_handle, EREFUSED);
[fab2746]487 return;
488 }
489
490 if (size > MAX_MSG_SIZE) {
[a46e56b]491 async_answer_0(chandle, EINVAL);
492 async_answer_0(icall_handle, EINVAL);
[fab2746]493 return;
494 }
495
496 data = malloc(size);
497 if (data == NULL) {
[a46e56b]498 async_answer_0(chandle, ENOMEM);
499 async_answer_0(icall_handle, ENOMEM);
[fab2746]500 }
501
[a46e56b]502 rc = async_data_write_finalize(chandle, data, size);
[fab2746]503 if (rc != EOK) {
[a46e56b]504 async_answer_0(chandle, rc);
505 async_answer_0(icall_handle, rc);
[fab2746]506 free(data);
507 return;
508 }
509
510 assoc_id = IPC_GET_ARG1(*icall);
511
512 rc = udp_assoc_send_msg_impl(client, assoc_id, &dest, data, size);
513 if (rc != EOK) {
[a46e56b]514 async_answer_0(icall_handle, rc);
[fab2746]515 free(data);
516 return;
517 }
518
[a46e56b]519 async_answer_0(icall_handle, EOK);
[fab2746]520 free(data);
521}
522
[b10460a]523/** Get next received message.
524 *
525 * @param client UDP Client
526 * @return Pointer to queue entry for next received message
527 */
[fab2746]528static udp_crcv_queue_entry_t *udp_rmsg_get_next(udp_client_t *client)
529{
530 link_t *link;
531
532 link = list_first(&client->crcv_queue);
533 if (link == NULL)
534 return NULL;
535
536 return list_get_instance(link, udp_crcv_queue_entry_t, link);
537}
538
[b10460a]539/** Get info on first received message.
540 *
541 * Handle client request to get information on received message.
542 *
543 * @param client UDP client
544 * @param iid Async request ID
545 * @param icall Async request data
546 */
[a46e56b]547static void udp_rmsg_info_srv(udp_client_t *client, cap_call_handle_t icall_handle,
[fab2746]548 ipc_call_t *icall)
549{
[a46e56b]550 cap_call_handle_t chandle;
[fab2746]551 size_t size;
552 udp_crcv_queue_entry_t *enext;
553 sysarg_t assoc_id;
[b7fd2a0]554 errno_t rc;
[fab2746]555
556 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_rmsg_info_srv()");
557 enext = udp_rmsg_get_next(client);
558
[a46e56b]559 if (!async_data_read_receive(&chandle, &size)) {
560 async_answer_0(chandle, EREFUSED);
561 async_answer_0(icall_handle, EREFUSED);
[fab2746]562 return;
563 }
564
565 if (enext == NULL) {
[a46e56b]566 async_answer_0(chandle, ENOENT);
567 async_answer_0(icall_handle, ENOENT);
[fab2746]568 return;
569 }
570
[a46e56b]571 rc = async_data_read_finalize(chandle, &enext->epp.remote,
[bde5c04]572 max(size, (size_t)sizeof(inet_ep_t)));
[fab2746]573 if (rc != EOK) {
[a46e56b]574 async_answer_0(icall_handle, rc);
[fab2746]575 return;
576 }
577
578 assoc_id = enext->cassoc->id;
579 size = enext->msg->data_size;
580
581 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_rmsg_info_srv(): assoc_id=%zu, "
582 "size=%zu", assoc_id, size);
[a46e56b]583 async_answer_2(icall_handle, EOK, assoc_id, size);
[fab2746]584}
585
[b10460a]586/** Read data from first received message.
587 *
588 * Handle client request to read data from first received message.
589 *
590 * @param client UDP client
591 * @param iid Async request ID
592 * @param icall Async request data
593 */
[a46e56b]594static void udp_rmsg_read_srv(udp_client_t *client, cap_call_handle_t icall_handle,
[fab2746]595 ipc_call_t *icall)
596{
[a46e56b]597 cap_call_handle_t chandle;
[bde5c04]598 size_t msg_size;
[fab2746]599 udp_crcv_queue_entry_t *enext;
600 void *data;
601 size_t size;
[bde5c04]602 size_t off;
[b7fd2a0]603 errno_t rc;
[fab2746]604
605 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_rmsg_read_srv()");
606 off = IPC_GET_ARG1(*icall);
607
608 enext = udp_rmsg_get_next(client);
609
[a46e56b]610 if (!async_data_read_receive(&chandle, &size)) {
611 async_answer_0(chandle, EREFUSED);
612 async_answer_0(icall_handle, EREFUSED);
[fab2746]613 return;
614 }
615
616 if (enext == NULL) {
[a46e56b]617 async_answer_0(chandle, ENOENT);
618 async_answer_0(icall_handle, ENOENT);
[fab2746]619 return;
620 }
621
622 data = enext->msg->data + off;
623 msg_size = enext->msg->data_size;
624
[bde5c04]625 if (off > msg_size) {
[a46e56b]626 async_answer_0(chandle, EINVAL);
627 async_answer_0(icall_handle, EINVAL);
[bde5c04]628 return;
629 }
630
[a46e56b]631 rc = async_data_read_finalize(chandle, data, min(msg_size - off, size));
[fab2746]632 if (rc != EOK) {
[a46e56b]633 async_answer_0(icall_handle, rc);
[fab2746]634 return;
635 }
636
[a46e56b]637 async_answer_0(icall_handle, EOK);
[fab2746]638 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_rmsg_read_srv(): OK");
639}
640
[b10460a]641/** Discard first received message.
642 *
643 * Handle client request to discard first received message, advancing
644 * to the next one.
645 *
646 * @param client UDP client
647 * @param iid Async request ID
648 * @param icall Async request data
649 */
[a46e56b]650static void udp_rmsg_discard_srv(udp_client_t *client, cap_call_handle_t icall_handle,
[fab2746]651 ipc_call_t *icall)
652{
653 udp_crcv_queue_entry_t *enext;
654
655 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_rmsg_discard_srv()");
656
657 enext = udp_rmsg_get_next(client);
658 if (enext == NULL) {
[99ea91b2]659 log_msg(LOG_DEFAULT, LVL_DEBUG, "usg_rmsg_discard_srv: enext==NULL");
[a46e56b]660 async_answer_0(icall_handle, ENOENT);
[fab2746]661 return;
662 }
663
664 list_remove(&enext->link);
665 udp_msg_delete(enext->msg);
[99ea91b2]666 free(enext);
[a46e56b]667 async_answer_0(icall_handle, EOK);
[fab2746]668}
669
[b10460a]670/** Handle UDP client connection.
671 *
[eed4139]672 * @param icall_handle Connect call handle
673 * @param icall Connect call data
674 * @param arg Connection argument
[b10460a]675 */
[eed4139]676static void udp_client_conn(cap_call_handle_t icall_handle, ipc_call_t *icall,
677 void *arg)
[fab2746]678{
679 udp_client_t client;
[be12474]680 unsigned long n;
[fab2746]681
682 /* Accept the connection */
[a46e56b]683 async_answer_0(icall_handle, EOK);
[fab2746]684
685 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_client_conn()");
686
[1f2b07a]687 client.sess = NULL;
[fab2746]688 list_initialize(&client.cassoc);
689 list_initialize(&client.crcv_queue);
690
691 while (true) {
[99ea91b2]692 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_client_conn: wait req");
[fab2746]693 ipc_call_t call;
[a46e56b]694 cap_call_handle_t chandle = async_get_call(&call);
[fab2746]695 sysarg_t method = IPC_GET_IMETHOD(call);
696
[99ea91b2]697 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_client_conn: method=%d",
[fab2746]698 (int)method);
699 if (!method) {
700 /* The other side has hung up */
[a46e56b]701 async_answer_0(chandle, EOK);
[309469de]702 break;
[fab2746]703 }
704
705 switch (method) {
706 case UDP_CALLBACK_CREATE:
[a46e56b]707 udp_callback_create_srv(&client, chandle, &call);
[fab2746]708 break;
709 case UDP_ASSOC_CREATE:
[a46e56b]710 udp_assoc_create_srv(&client, chandle, &call);
[fab2746]711 break;
712 case UDP_ASSOC_DESTROY:
[a46e56b]713 udp_assoc_destroy_srv(&client, chandle, &call);
[fab2746]714 break;
[58e8646]715 case UDP_ASSOC_SET_NOLOCAL:
[a46e56b]716 udp_assoc_set_nolocal_srv(&client, chandle, &call);
[58e8646]717 break;
[fab2746]718 case UDP_ASSOC_SEND_MSG:
[a46e56b]719 udp_assoc_send_msg_srv(&client, chandle, &call);
[fab2746]720 break;
721 case UDP_RMSG_INFO:
[a46e56b]722 udp_rmsg_info_srv(&client, chandle, &call);
[fab2746]723 break;
724 case UDP_RMSG_READ:
[a46e56b]725 udp_rmsg_read_srv(&client, chandle, &call);
[fab2746]726 break;
727 case UDP_RMSG_DISCARD:
[a46e56b]728 udp_rmsg_discard_srv(&client, chandle, &call);
[fab2746]729 break;
730 default:
[a46e56b]731 async_answer_0(chandle, ENOTSUP);
[fab2746]732 break;
733 }
734 }
[309469de]735
736 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_client_conn: terminated");
737
738 n = list_count(&client.cassoc);
739 if (n != 0) {
740 log_msg(LOG_DEFAULT, LVL_WARN, "udp_client_conn: "
[1d03e86]741 "Client with %lu active associations closed session.", n);
[309469de]742 /* XXX Clean up */
743 }
744
745 /* XXX Clean up client receive queue */
[1f2b07a]746
747 if (client.sess != NULL)
748 async_hangup(client.sess);
[fab2746]749}
750
[b10460a]751/** Initialize UDP service.
752 *
[cde999a]753 * @return EOK on success or an error code.
[b10460a]754 */
[b7fd2a0]755errno_t udp_service_init(void)
[fab2746]756{
[b7fd2a0]757 errno_t rc;
[fab2746]758 service_id_t sid;
759
[b688fd8]760 async_set_fallback_port_handler(udp_client_conn, NULL);
[fab2746]761
762 rc = loc_server_register(NAME);
763 if (rc != EOK) {
764 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering server.");
765 return EIO;
766 }
767
768 rc = loc_service_register(SERVICE_NAME_UDP, &sid);
769 if (rc != EOK) {
770 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service.");
771 return EIO;
772 }
773
774 return EOK;
775}
776
777/**
778 * @}
779 */
Note: See TracBrowser for help on using the repository browser.