source: mainline/uspace/srv/net/udp/sock.c@ 57c8fc9

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

Crude DHCP client prototype.

  • Property mode set to 100644
File size: 21.4 KB
RevLine 
[66a272f8]1/*
[e33bceb]2 * Copyright (c) 2008 Lukas Mejdrech
[695b6ff]3 * Copyright (c) 2013 Jiri Svoboda
[66a272f8]4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup udp
31 * @{
32 */
33
34/**
35 * @file Socket provider
36 */
37
[e33bceb]38#include <async.h>
39#include <byteorder.h>
[66a272f8]40#include <errno.h>
[e33bceb]41#include <inet/inet.h>
42#include <io/log.h>
43#include <ipc/services.h>
44#include <ipc/socket.h>
45#include <net/socket.h>
46#include <ns.h>
[66a272f8]47
48#include "sock.h"
[e33bceb]49#include "std.h"
50#include "udp_type.h"
51#include "ucall.h"
52
53/** Free ports pool start. */
54#define UDP_FREE_PORTS_START 1025
55
56/** Free ports pool end. */
57#define UDP_FREE_PORTS_END 65535
58
59static int last_used_port = UDP_FREE_PORTS_START - 1;
60static socket_ports_t gsock;
61
62static void udp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg);
[32d19f7]63static int udp_sock_recv_fibril(void *arg);
[66a272f8]64
65int udp_sock_init(void)
66{
[e33bceb]67 socket_ports_initialize(&gsock);
[1038a9c]68
[e33bceb]69 async_set_client_connection(udp_sock_connection);
[1038a9c]70
71 int rc = service_register(SERVICE_UDP);
[e33bceb]72 if (rc != EOK)
73 return EEXIST;
[1038a9c]74
[66a272f8]75 return EOK;
76}
77
[e33bceb]78static void udp_free_sock_data(socket_core_t *sock_core)
79{
80 udp_sockdata_t *socket;
81
82 socket = (udp_sockdata_t *)sock_core->specific_data;
[32d19f7]83 (void)socket;
84
85 /* XXX We need to force the receive fibril to quit */
[e33bceb]86}
87
88static void udp_sock_notify_data(socket_core_t *sock_core)
89{
[a1a101d]90 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_notify_data(%d)", sock_core->socket_id);
[e33bceb]91 async_exch_t *exch = async_exchange_begin(sock_core->sess);
[42fd4d2]92 async_msg_5(exch, NET_SOCKET_RECEIVED, (sysarg_t) sock_core->socket_id,
[32d19f7]93 UDP_FRAGMENT_SIZE, 0, 0, 1);
[e33bceb]94 async_exchange_end(exch);
95}
96
97static void udp_sock_socket(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
98{
99 udp_sockdata_t *sock;
100 socket_core_t *sock_core;
101 int sock_id;
102 int rc;
103 ipc_call_t answer;
104
[a1a101d]105 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_socket()");
[db81577]106 sock = calloc(1, sizeof(udp_sockdata_t));
[e33bceb]107 if (sock == NULL) {
108 async_answer_0(callid, ENOMEM);
109 return;
110 }
111
112 fibril_mutex_initialize(&sock->lock);
113 sock->client = client;
114
[32d19f7]115 sock->recv_buffer_used = 0;
116 sock->recv_error = UDP_EOK;
117 fibril_mutex_initialize(&sock->recv_buffer_lock);
118 fibril_condvar_initialize(&sock->recv_buffer_cv);
119
[e33bceb]120 rc = udp_uc_create(&sock->assoc);
121 if (rc != EOK) {
122 free(sock);
123 async_answer_0(callid, rc);
124 return;
125 }
126
[32d19f7]127 sock->recv_fibril = fibril_create(udp_sock_recv_fibril, sock);
128 if (sock->recv_fibril == 0) {
129 udp_uc_destroy(sock->assoc);
130 free(sock);
131 async_answer_0(callid, ENOMEM);
132 return;
133 }
134
[e33bceb]135 sock_id = SOCKET_GET_SOCKET_ID(call);
136 rc = socket_create(&client->sockets, client->sess, sock, &sock_id);
137 if (rc != EOK) {
[32d19f7]138 fibril_destroy(sock->recv_fibril);
139 udp_uc_destroy(sock->assoc);
140 free(sock);
[e33bceb]141 async_answer_0(callid, rc);
142 return;
143 }
144
[32d19f7]145 fibril_add_ready(sock->recv_fibril);
146
[e33bceb]147 sock_core = socket_cores_find(&client->sockets, sock_id);
148 assert(sock_core != NULL);
149 sock->sock_core = sock_core;
[b1bd89ea]150
[e33bceb]151 SOCKET_SET_SOCKET_ID(answer, sock_id);
152
[32d19f7]153 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, UDP_FRAGMENT_SIZE);
[e33bceb]154 SOCKET_SET_HEADER_SIZE(answer, sizeof(udp_header_t));
[b1bd89ea]155 async_answer_3(callid, EOK, IPC_GET_ARG1(answer),
156 IPC_GET_ARG2(answer), IPC_GET_ARG3(answer));
[e33bceb]157}
158
159static void udp_sock_bind(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
160{
[a1a101d]161 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_bind()");
162 log_msg(LOG_DEFAULT, LVL_DEBUG, " - async_data_write_accept");
[02a09ed]163
164 struct sockaddr_in6 *addr6 = NULL;
165 size_t addr_len;
166 int rc = async_data_write_accept((void **) &addr6, false, 0, 0, 0, &addr_len);
[e33bceb]167 if (rc != EOK) {
168 async_answer_0(callid, rc);
[02a09ed]169 return;
[e33bceb]170 }
[8fc8969]171
[02a09ed]172 if ((addr_len != sizeof(struct sockaddr_in)) &&
173 (addr_len != sizeof(struct sockaddr_in6))) {
[8fc8969]174 async_answer_0(callid, EINVAL);
175 goto out;
176 }
177
[02a09ed]178 struct sockaddr_in *addr = (struct sockaddr_in *) addr6;
179
[a1a101d]180 log_msg(LOG_DEFAULT, LVL_DEBUG, " - call socket_bind");
[02a09ed]181
[e33bceb]182 rc = socket_bind(&client->sockets, &gsock, SOCKET_GET_SOCKET_ID(call),
[02a09ed]183 addr6, addr_len, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END,
[e33bceb]184 last_used_port);
185 if (rc != EOK) {
186 async_answer_0(callid, rc);
187 goto out;
188 }
[8fc8969]189
[a1a101d]190 log_msg(LOG_DEFAULT, LVL_DEBUG, " - call socket_cores_find");
[02a09ed]191
192 socket_core_t *sock_core = socket_cores_find(&client->sockets,
193 SOCKET_GET_SOCKET_ID(call));
[e33bceb]194 if (sock_core == NULL) {
195 async_answer_0(callid, ENOENT);
196 goto out;
197 }
[19a4f73]198
[02a09ed]199 udp_sockdata_t *socket =
200 (udp_sockdata_t *) sock_core->specific_data;
201
202 udp_sock_t fsocket;
203
204 fsocket.port = sock_core->port;
205
206 switch (addr->sin_family) {
207 case AF_INET:
208 inet_sockaddr_in_addr(addr, &fsocket.addr);
209 break;
210 case AF_INET6:
211 inet_sockaddr_in6_addr(addr6, &fsocket.addr);
212 break;
213 default:
214 async_answer_0(callid, EINVAL);
215 goto out;
216 }
217
218 udp_error_t urc = udp_uc_set_local(socket->assoc, &fsocket);
219
[e33bceb]220 switch (urc) {
221 case UDP_EOK:
222 rc = EOK;
223 break;
224/* case TCP_ENOTEXIST:
225 rc = ENOTCONN;
226 break;
227 case TCP_ECLOSING:
228 rc = ENOTCONN;
229 break;
230 case TCP_ERESET:
231 rc = ECONNABORTED;
232 break;*/
233 default:
234 assert(false);
235 }
[257feec]236
[a1a101d]237 log_msg(LOG_DEFAULT, LVL_DEBUG, " - success");
[e33bceb]238 async_answer_0(callid, rc);
[02a09ed]239
[e33bceb]240out:
[02a09ed]241 if (addr6 != NULL)
242 free(addr6);
[e33bceb]243}
244
245static void udp_sock_listen(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
246{
[a1a101d]247 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_listen()");
[e33bceb]248 async_answer_0(callid, ENOTSUP);
249}
250
251static void udp_sock_connect(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
252{
[a1a101d]253 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_connect()");
[e33bceb]254 async_answer_0(callid, ENOTSUP);
255}
256
257static void udp_sock_accept(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
258{
[a1a101d]259 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_accept()");
[e33bceb]260 async_answer_0(callid, ENOTSUP);
261}
262
263static void udp_sock_sendto(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
264{
[a1a101d]265 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_send()");
[451481c8]266
[f4a27304]267 uint8_t *buffer = calloc(UDP_FRAGMENT_SIZE, 1);
268 if (buffer == NULL) {
269 async_answer_0(callid, ENOMEM);
270 return;
271 }
272
[02a09ed]273 struct sockaddr_in6 *addr6 = NULL;
274 struct sockaddr_in *addr;
275 udp_sock_t fsocket;
276 udp_sock_t *fsocket_ptr;
[451481c8]277
[e33bceb]278 if (IPC_GET_IMETHOD(call) == NET_SOCKET_SENDTO) {
[02a09ed]279 size_t addr_len;
280 int rc = async_data_write_accept((void **) &addr6, false,
281 0, 0, 0, &addr_len);
[e33bceb]282 if (rc != EOK) {
283 async_answer_0(callid, rc);
[f4a27304]284 goto out;
[02a09ed]285 }
286
287 if ((addr_len != sizeof(struct sockaddr_in)) &&
288 (addr_len != sizeof(struct sockaddr_in6))) {
289 async_answer_0(callid, EINVAL);
[e33bceb]290 goto out;
291 }
[451481c8]292
[02a09ed]293 addr = (struct sockaddr_in *) addr6;
294
295 switch (addr->sin_family) {
296 case AF_INET:
297 inet_sockaddr_in_addr(addr, &fsocket.addr);
298 break;
299 case AF_INET6:
300 inet_sockaddr_in6_addr(addr6, &fsocket.addr);
301 break;
302 default:
[e33bceb]303 async_answer_0(callid, EINVAL);
304 goto out;
305 }
[451481c8]306
[02a09ed]307 fsocket.port = uint16_t_be2host(addr->sin_port);
308 fsocket_ptr = &fsocket;
[451481c8]309 } else
[02a09ed]310 fsocket_ptr = NULL;
[451481c8]311
312 int socket_id = SOCKET_GET_SOCKET_ID(call);
313
[e33bceb]314 SOCKET_GET_FLAGS(call);
[451481c8]315
316 socket_core_t *sock_core =
317 socket_cores_find(&client->sockets, socket_id);
[e33bceb]318 if (sock_core == NULL) {
319 async_answer_0(callid, ENOTSOCK);
320 goto out;
321 }
[451481c8]322
323 udp_sockdata_t *socket =
324 (udp_sockdata_t *) sock_core->specific_data;
325
[6b0b508]326 if (sock_core->port <= 0) {
[92b42442]327 /* Implicitly bind socket to port */
[451481c8]328 int rc = socket_bind_free_port(&gsock, sock_core,
329 UDP_FREE_PORTS_START, UDP_FREE_PORTS_END, last_used_port);
[e33bceb]330 if (rc != EOK) {
331 async_answer_0(callid, rc);
332 goto out;
333 }
[451481c8]334
335 assert(sock_core->port > 0);
[6b0b508]336
[451481c8]337 udp_error_t urc = udp_uc_set_local_port(socket->assoc,
338 sock_core->port);
339
340 if (urc != UDP_EOK) {
341 // TODO: better error handling
342 async_answer_0(callid, EINTR);
343 goto out;
344 }
[6b0b508]345
346 last_used_port = sock_core->port;
[e33bceb]347 }
[451481c8]348
[e33bceb]349 fibril_mutex_lock(&socket->lock);
[451481c8]350
[695b6ff]351 if (inet_addr_is_any(&socket->assoc->ident.local.addr) &&
352 socket->assoc->ident.iplink == 0) {
[92b42442]353 /* Determine local IP address */
[a2e3ee6]354 inet_addr_t loc_addr;
355 inet_addr_t rem_addr;
[451481c8]356
[02a09ed]357 rem_addr = fsocket_ptr ? fsocket.addr :
[19a4f73]358 socket->assoc->ident.foreign.addr;
[451481c8]359
[a2e3ee6]360 int rc = inet_get_srcaddr(&rem_addr, 0, &loc_addr);
[92b42442]361 if (rc != EOK) {
362 fibril_mutex_unlock(&socket->lock);
363 async_answer_0(callid, rc);
[a1a101d]364 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_sendto: Failed to "
[92b42442]365 "determine local address.");
[f4a27304]366 goto out;
[92b42442]367 }
[451481c8]368
[19a4f73]369 socket->assoc->ident.local.addr = loc_addr;
[92b42442]370 }
[451481c8]371
[e33bceb]372 assert(socket->assoc != NULL);
[451481c8]373
374 int fragments = SOCKET_GET_DATA_FRAGMENTS(call);
375 for (int index = 0; index < fragments; index++) {
376 ipc_callid_t wcallid;
377 size_t length;
378
[e33bceb]379 if (!async_data_write_receive(&wcallid, &length)) {
380 fibril_mutex_unlock(&socket->lock);
381 async_answer_0(callid, EINVAL);
382 goto out;
383 }
[451481c8]384
[32d19f7]385 if (length > UDP_FRAGMENT_SIZE)
386 length = UDP_FRAGMENT_SIZE;
[451481c8]387
388 int rc = async_data_write_finalize(wcallid, buffer, length);
[e33bceb]389 if (rc != EOK) {
390 fibril_mutex_unlock(&socket->lock);
391 async_answer_0(callid, rc);
392 goto out;
393 }
[451481c8]394
395 udp_error_t urc =
[02a09ed]396 udp_uc_send(socket->assoc, fsocket_ptr, buffer, length, 0);
[451481c8]397
[e33bceb]398 switch (urc) {
399 case UDP_EOK:
400 rc = EOK;
401 break;
[08a6382]402 case UDP_ENORES:
[0ee053c1]403 rc = ENOMEM;
[e33bceb]404 break;
[08a6382]405 case UDP_EUNSPEC:
406 rc = EINVAL;
407 break;
408 case UDP_ENOROUTE:
409 rc = EIO;
[e33bceb]410 break;
411 default:
412 assert(false);
413 }
[451481c8]414
[e33bceb]415 if (rc != EOK) {
416 fibril_mutex_unlock(&socket->lock);
417 async_answer_0(callid, rc);
418 goto out;
419 }
420 }
[b1bd89ea]421
[451481c8]422 ipc_call_t answer;
423
[b1bd89ea]424 IPC_SET_ARG1(answer, 0);
[32d19f7]425 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, UDP_FRAGMENT_SIZE);
[b1bd89ea]426 async_answer_2(callid, EOK, IPC_GET_ARG1(answer),
427 IPC_GET_ARG2(answer));
[e33bceb]428 fibril_mutex_unlock(&socket->lock);
[b1bd89ea]429
[e33bceb]430out:
[02a09ed]431 if (addr6 != NULL)
432 free(addr6);
[f4a27304]433
434 free(buffer);
[e33bceb]435}
436
437static void udp_sock_recvfrom(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
438{
[a1a101d]439 log_msg(LOG_DEFAULT, LVL_DEBUG, "%p: udp_sock_recv[from]()", client);
[02a09ed]440
441 int socket_id = SOCKET_GET_SOCKET_ID(call);
442
443 socket_core_t *sock_core =
444 socket_cores_find(&client->sockets, socket_id);
[e33bceb]445 if (sock_core == NULL) {
446 async_answer_0(callid, ENOTSOCK);
447 return;
448 }
[02a09ed]449
450 udp_sockdata_t *socket =
451 (udp_sockdata_t *) sock_core->specific_data;
452
[e33bceb]453 fibril_mutex_lock(&socket->lock);
[257feec]454
[e33bceb]455 if (socket->assoc == NULL) {
456 fibril_mutex_unlock(&socket->lock);
457 async_answer_0(callid, ENOTCONN);
458 return;
459 }
[02a09ed]460
[a1a101d]461 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_recvfrom(): lock recv_buffer lock");
[02a09ed]462
[32d19f7]463 fibril_mutex_lock(&socket->recv_buffer_lock);
[02a09ed]464
465 while ((socket->recv_buffer_used == 0) &&
466 (socket->recv_error == UDP_EOK)) {
[a1a101d]467 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_recvfrom(): wait for cv");
[32d19f7]468 fibril_condvar_wait(&socket->recv_buffer_cv,
469 &socket->recv_buffer_lock);
470 }
[257feec]471
[a1a101d]472 log_msg(LOG_DEFAULT, LVL_DEBUG, "Got data in sock recv_buffer");
[02a09ed]473
474 size_t data_len = socket->recv_buffer_used;
475 udp_error_t urc = socket->recv_error;
476
[a1a101d]477 log_msg(LOG_DEFAULT, LVL_DEBUG, "**** recv data_len=%zu", data_len);
[02a09ed]478
479 int rc;
480
[e33bceb]481 switch (urc) {
482 case UDP_EOK:
483 rc = EOK;
484 break;
485/* case TCP_ENOTEXIST:
486 case TCP_ECLOSING:
487 rc = ENOTCONN;
488 break;
489 case TCP_ERESET:
490 rc = ECONNABORTED;
491 break;*/
492 default:
493 assert(false);
494 }
[257feec]495
[a1a101d]496 log_msg(LOG_DEFAULT, LVL_DEBUG, "**** udp_uc_receive -> %d", rc);
[257feec]497
[e33bceb]498 if (rc != EOK) {
[32d19f7]499 fibril_mutex_unlock(&socket->recv_buffer_lock);
[e33bceb]500 fibril_mutex_unlock(&socket->lock);
501 async_answer_0(callid, rc);
502 return;
503 }
[02a09ed]504
505 ipc_callid_t rcallid;
506 size_t addr_size = 0;
507
[e33bceb]508 if (IPC_GET_IMETHOD(call) == NET_SOCKET_RECVFROM) {
[19a4f73]509 /* Fill address */
[02a09ed]510 udp_sock_t *rsock = &socket->recv_fsock;
511 struct sockaddr_in addr;
512 struct sockaddr_in6 addr6;
513 size_t addr_length;
[19a4f73]514
[02a09ed]515 uint16_t addr_af = inet_addr_sockaddr_in(&rsock->addr, &addr,
516 &addr6);
517
518 switch (addr_af) {
519 case AF_INET:
520 addr.sin_port = host2uint16_t_be(rsock->port);
521
522 log_msg(LOG_DEFAULT, LVL_DEBUG, "addr read receive");
523 if (!async_data_read_receive(&rcallid, &addr_length)) {
524 fibril_mutex_unlock(&socket->recv_buffer_lock);
525 fibril_mutex_unlock(&socket->lock);
526 async_answer_0(callid, EINVAL);
527 return;
528 }
529
530 if (addr_length > sizeof(addr))
531 addr_length = sizeof(addr);
532
533 addr_size = sizeof(addr);
534
535 log_msg(LOG_DEFAULT, LVL_DEBUG, "addr read finalize");
536 rc = async_data_read_finalize(rcallid, &addr, addr_length);
537 if (rc != EOK) {
538 fibril_mutex_unlock(&socket->recv_buffer_lock);
539 fibril_mutex_unlock(&socket->lock);
540 async_answer_0(callid, EINVAL);
541 return;
542 }
543
544 break;
545 case AF_INET6:
546 addr6.sin6_port = host2uint16_t_be(rsock->port);
547
548 log_msg(LOG_DEFAULT, LVL_DEBUG, "addr6 read receive");
549 if (!async_data_read_receive(&rcallid, &addr_length)) {
550 fibril_mutex_unlock(&socket->recv_buffer_lock);
551 fibril_mutex_unlock(&socket->lock);
552 async_answer_0(callid, EINVAL);
553 return;
554 }
555
556 if (addr_length > sizeof(addr6))
557 addr_length = sizeof(addr6);
558
559 addr_size = sizeof(addr6);
560
561 log_msg(LOG_DEFAULT, LVL_DEBUG, "addr6 read finalize");
562 rc = async_data_read_finalize(rcallid, &addr6, addr_length);
563 if (rc != EOK) {
564 fibril_mutex_unlock(&socket->recv_buffer_lock);
565 fibril_mutex_unlock(&socket->lock);
566 async_answer_0(callid, EINVAL);
567 return;
568 }
569
570 break;
571 default:
[32d19f7]572 fibril_mutex_unlock(&socket->recv_buffer_lock);
[e33bceb]573 fibril_mutex_unlock(&socket->lock);
574 async_answer_0(callid, EINVAL);
575 return;
576 }
577 }
[02a09ed]578
[a1a101d]579 log_msg(LOG_DEFAULT, LVL_DEBUG, "data read receive");
[02a09ed]580
581 size_t length;
[e33bceb]582 if (!async_data_read_receive(&rcallid, &length)) {
[32d19f7]583 fibril_mutex_unlock(&socket->recv_buffer_lock);
[e33bceb]584 fibril_mutex_unlock(&socket->lock);
585 async_answer_0(callid, EINVAL);
586 return;
587 }
[257feec]588
[e33bceb]589 if (length > data_len)
590 length = data_len;
[257feec]591
[a1a101d]592 log_msg(LOG_DEFAULT, LVL_DEBUG, "data read finalize");
[02a09ed]593
[32d19f7]594 rc = async_data_read_finalize(rcallid, socket->recv_buffer, length);
[02a09ed]595
596 if ((length < data_len) && (rc == EOK))
[e33bceb]597 rc = EOVERFLOW;
[257feec]598
[a1a101d]599 log_msg(LOG_DEFAULT, LVL_DEBUG, "read_data_length <- %zu", length);
[02a09ed]600
601 ipc_call_t answer;
602
[b1bd89ea]603 IPC_SET_ARG2(answer, 0);
[e33bceb]604 SOCKET_SET_READ_DATA_LENGTH(answer, length);
[02a09ed]605 SOCKET_SET_ADDRESS_LENGTH(answer, addr_size);
[b1bd89ea]606 async_answer_3(callid, EOK, IPC_GET_ARG1(answer),
607 IPC_GET_ARG2(answer), IPC_GET_ARG3(answer));
[257feec]608
[32d19f7]609 socket->recv_buffer_used = 0;
[257feec]610
[32d19f7]611 fibril_condvar_broadcast(&socket->recv_buffer_cv);
612 fibril_mutex_unlock(&socket->recv_buffer_lock);
[e33bceb]613 fibril_mutex_unlock(&socket->lock);
614}
615
616static void udp_sock_close(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
617{
[a1a101d]618 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_close()");
[42fd4d2]619 int socket_id = SOCKET_GET_SOCKET_ID(call);
[e33bceb]620
[ccb5165]621 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_close() - find core");
[42fd4d2]622 socket_core_t *sock_core =
623 socket_cores_find(&client->sockets, socket_id);
[e33bceb]624 if (sock_core == NULL) {
[ccb5165]625 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_close() - core not found");
[e33bceb]626 async_answer_0(callid, ENOTSOCK);
627 return;
628 }
629
[ccb5165]630 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_close() - spec data");
[42fd4d2]631 udp_sockdata_t *socket =
632 (udp_sockdata_t *) sock_core->specific_data;
[ccb5165]633 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_close() - lock socket");
[e33bceb]634 fibril_mutex_lock(&socket->lock);
635
[ccb5165]636 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_close() - lock socket buffer");
[141a20d]637 fibril_mutex_lock(&socket->recv_buffer_lock);
[a1e2df13]638 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_close - set socket->sock_core = NULL");
[141a20d]639 socket->sock_core = NULL;
640 fibril_mutex_unlock(&socket->recv_buffer_lock);
641
642 udp_uc_reset(socket->assoc);
643
[42fd4d2]644 int rc = socket_destroy(NULL, socket_id, &client->sockets, &gsock,
[e33bceb]645 udp_free_sock_data);
646 if (rc != EOK) {
[a1e2df13]647 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_close - socket_destroy failed");
[e33bceb]648 fibril_mutex_unlock(&socket->lock);
649 async_answer_0(callid, rc);
650 return;
651 }
652
[a1e2df13]653 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_close - broadcast recv_buffer_cv");
[141a20d]654 fibril_condvar_broadcast(&socket->recv_buffer_cv);
655
[e33bceb]656 fibril_mutex_unlock(&socket->lock);
657 async_answer_0(callid, EOK);
658}
659
660static void udp_sock_getsockopt(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
661{
[a1a101d]662 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_getsockopt()");
[e33bceb]663 async_answer_0(callid, ENOTSUP);
664}
665
666static void udp_sock_setsockopt(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
667{
[695b6ff]668 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_setsockopt)");
669 log_msg(LOG_DEFAULT, LVL_DEBUG, " - async_data_write_accept");
670
671 void *data = NULL;
672 size_t data_len;
673 int rc = async_data_write_accept(&data, false, 0, 0, 0, &data_len);
674 if (rc != EOK) {
675 log_msg(LOG_DEFAULT, LVL_DEBUG, " - failed accepting data");
676 async_answer_0(callid, rc);
677 return;
678 }
679
680 sysarg_t opt_level = SOL_SOCKET;
681 sysarg_t opt_name = SOCKET_GET_OPT_NAME(call);
682
683 if (opt_level != SOL_SOCKET || opt_name != SO_IPLINK ||
684 data_len != sizeof(service_id_t)) {
685 log_msg(LOG_DEFAULT, LVL_DEBUG, " - failed opt_level/name/len");
686 log_msg(LOG_DEFAULT, LVL_DEBUG, " - failed opt_level=%d, "
687 "opt_name=%d, data_len=%zu", (int)opt_level, (int)opt_name,
688 data_len);
689 async_answer_0(callid, EINVAL);
690 return;
691 }
692
693 log_msg(LOG_DEFAULT, LVL_DEBUG, " - call socket_cores_find");
694
695 socket_core_t *sock_core = socket_cores_find(&client->sockets,
696 SOCKET_GET_SOCKET_ID(call));
697 if (sock_core == NULL) {
698 log_msg(LOG_DEFAULT, LVL_DEBUG, " - failed getting sock_core");
699 async_answer_0(callid, ENOENT);
700 return;
701 }
702
703 udp_sockdata_t *socket =
704 (udp_sockdata_t *) sock_core->specific_data;
705
706 service_id_t iplink = *(service_id_t *)data;
707 udp_uc_set_iplink(socket->assoc, iplink);
708
709 log_msg(LOG_DEFAULT, LVL_DEBUG, " - success");
710 async_answer_0(callid, EOK);
[e33bceb]711}
712
[695b6ff]713
[32d19f7]714static int udp_sock_recv_fibril(void *arg)
715{
716 udp_sockdata_t *sock = (udp_sockdata_t *)arg;
717 udp_error_t urc;
718 xflags_t xflags;
719 size_t rcvd;
720
[a1a101d]721 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_recv_fibril()");
[32d19f7]722
[141a20d]723 fibril_mutex_lock(&sock->recv_buffer_lock);
724
[32d19f7]725 while (true) {
[a1a101d]726 log_msg(LOG_DEFAULT, LVL_DEBUG, "[] wait for rcv buffer empty()");
[257feec]727 while ((sock->recv_buffer_used != 0) && (sock->sock_core != NULL)) {
[32d19f7]728 fibril_condvar_wait(&sock->recv_buffer_cv,
729 &sock->recv_buffer_lock);
730 }
[ccb5165]731
732 fibril_mutex_unlock(&sock->recv_buffer_lock);
733
[a1a101d]734 log_msg(LOG_DEFAULT, LVL_DEBUG, "[] call udp_uc_receive()");
[32d19f7]735 urc = udp_uc_receive(sock->assoc, sock->recv_buffer,
736 UDP_FRAGMENT_SIZE, &rcvd, &xflags, &sock->recv_fsock);
[ccb5165]737 fibril_mutex_lock(&sock->recv_buffer_lock);
[32d19f7]738 sock->recv_error = urc;
739
[a1e2df13]740 log_msg(LOG_DEFAULT, LVL_DEBUG, "[] udp_uc_receive -> %d", urc);
[141a20d]741
742 if (sock->sock_core != NULL)
743 udp_sock_notify_data(sock->sock_core);
[ccb5165]744
[32d19f7]745 if (urc != UDP_EOK) {
[a1e2df13]746 log_msg(LOG_DEFAULT, LVL_DEBUG, "[] urc != UDP_EOK, break");
[32d19f7]747 fibril_condvar_broadcast(&sock->recv_buffer_cv);
[02a09ed]748 fibril_mutex_unlock(&sock->recv_buffer_lock);
[32d19f7]749 break;
750 }
[ccb5165]751
[a1a101d]752 log_msg(LOG_DEFAULT, LVL_DEBUG, "[] got data - broadcast recv_buffer_cv");
[ccb5165]753
[32d19f7]754 sock->recv_buffer_used = rcvd;
755 fibril_condvar_broadcast(&sock->recv_buffer_cv);
756 }
757
[a1e2df13]758 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_recv_fibril() exited loop");
[32d19f7]759 udp_uc_destroy(sock->assoc);
760
[a1e2df13]761 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_recv_fibril() terminated");
[141a20d]762
[32d19f7]763 return 0;
764}
765
[e33bceb]766static void udp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
767{
768 ipc_callid_t callid;
769 ipc_call_t call;
770 udp_client_t client;
771
772 /* Accept the connection */
773 async_answer_0(iid, EOK);
774
[695b6ff]775 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_connection: begin");
776
[e33bceb]777 client.sess = async_callback_receive(EXCHANGE_SERIALIZE);
778 socket_cores_initialize(&client.sockets);
779
780 while (true) {
[a1a101d]781 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_connection: wait");
[e33bceb]782 callid = async_get_call(&call);
783 if (!IPC_GET_IMETHOD(call))
784 break;
785
[a1a101d]786 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_connection: METHOD=%d",
[e33bceb]787 (int)IPC_GET_IMETHOD(call));
788
789 switch (IPC_GET_IMETHOD(call)) {
790 case NET_SOCKET:
791 udp_sock_socket(&client, callid, call);
792 break;
793 case NET_SOCKET_BIND:
794 udp_sock_bind(&client, callid, call);
795 break;
796 case NET_SOCKET_LISTEN:
797 udp_sock_listen(&client, callid, call);
798 break;
799 case NET_SOCKET_CONNECT:
800 udp_sock_connect(&client, callid, call);
801 break;
802 case NET_SOCKET_ACCEPT:
803 udp_sock_accept(&client, callid, call);
804 break;
805 case NET_SOCKET_SEND:
806 case NET_SOCKET_SENDTO:
807 udp_sock_sendto(&client, callid, call);
808 break;
809 case NET_SOCKET_RECV:
810 case NET_SOCKET_RECVFROM:
811 udp_sock_recvfrom(&client, callid, call);
812 break;
813 case NET_SOCKET_CLOSE:
814 udp_sock_close(&client, callid, call);
815 break;
816 case NET_SOCKET_GETSOCKOPT:
817 udp_sock_getsockopt(&client, callid, call);
818 break;
819 case NET_SOCKET_SETSOCKOPT:
820 udp_sock_setsockopt(&client, callid, call);
821 break;
822 default:
823 async_answer_0(callid, ENOTSUP);
824 break;
825 }
826 }
[0d520a2]827
828 /* Clean up */
[a1a101d]829 log_msg(LOG_DEFAULT, LVL_DEBUG, "udp_sock_connection: Clean up");
[0d520a2]830 async_hangup(client.sess);
831 socket_cores_release(NULL, &client.sockets, &gsock, udp_free_sock_data);
[e33bceb]832}
833
[66a272f8]834/**
835 * @}
836 */
Note: See TracBrowser for help on using the repository browser.