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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since df3f85f was b1bd89ea, checked in by Martin Decky <martin@…>, 13 years ago

get rid of net/modules.{c|h}

  • Property mode set to 100644
File size: 14.7 KB
Line 
1/*
2 * Copyright (c) 2008 Lukas Mejdrech
3 * Copyright (c) 2012 Jiri Svoboda
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
38#include <async.h>
39#include <byteorder.h>
40#include <errno.h>
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>
47
48#include "sock.h"
49#include "std.h"
50#include "udp_type.h"
51#include "ucall.h"
52
53#define FRAGMENT_SIZE 1024
54
55/** Free ports pool start. */
56#define UDP_FREE_PORTS_START 1025
57
58/** Free ports pool end. */
59#define UDP_FREE_PORTS_END 65535
60
61static int last_used_port = UDP_FREE_PORTS_START - 1;
62static socket_ports_t gsock;
63
64static void udp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg);
65
66int udp_sock_init(void)
67{
68 int rc;
69
70 socket_ports_initialize(&gsock);
71
72 async_set_client_connection(udp_sock_connection);
73
74 rc = service_register(SERVICE_UDP);
75 if (rc != EOK)
76 return EEXIST;
77
78 return EOK;
79}
80
81static void udp_free_sock_data(socket_core_t *sock_core)
82{
83 udp_sockdata_t *socket;
84
85 socket = (udp_sockdata_t *)sock_core->specific_data;
86 assert(socket->assoc != NULL);
87 udp_uc_destroy(socket->assoc);
88}
89
90static void udp_sock_notify_data(socket_core_t *sock_core)
91{
92 log_msg(LVL_DEBUG, "udp_sock_notify_data(%d)", sock_core->socket_id);
93 async_exch_t *exch = async_exchange_begin(sock_core->sess);
94 async_msg_5(exch, NET_SOCKET_RECEIVED, (sysarg_t)sock_core->socket_id,
95 FRAGMENT_SIZE, 0, 0, 1);
96 async_exchange_end(exch);
97}
98
99static void udp_sock_socket(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
100{
101 udp_sockdata_t *sock;
102 socket_core_t *sock_core;
103 int sock_id;
104 int rc;
105 ipc_call_t answer;
106
107 log_msg(LVL_DEBUG, "udp_sock_socket()");
108 sock = calloc(sizeof(udp_sockdata_t), 1);
109 if (sock == NULL) {
110 async_answer_0(callid, ENOMEM);
111 return;
112 }
113
114 fibril_mutex_initialize(&sock->lock);
115 sock->client = client;
116
117 rc = udp_uc_create(&sock->assoc);
118 if (rc != EOK) {
119 udp_uc_destroy(sock->assoc);
120 free(sock);
121 async_answer_0(callid, rc);
122 return;
123 }
124
125 sock_id = SOCKET_GET_SOCKET_ID(call);
126 rc = socket_create(&client->sockets, client->sess, sock, &sock_id);
127 if (rc != EOK) {
128 async_answer_0(callid, rc);
129 return;
130 }
131
132 sock_core = socket_cores_find(&client->sockets, sock_id);
133 assert(sock_core != NULL);
134 sock->sock_core = sock_core;
135
136 SOCKET_SET_SOCKET_ID(answer, sock_id);
137
138 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
139 SOCKET_SET_HEADER_SIZE(answer, sizeof(udp_header_t));
140 async_answer_3(callid, EOK, IPC_GET_ARG1(answer),
141 IPC_GET_ARG2(answer), IPC_GET_ARG3(answer));
142}
143
144static void udp_sock_bind(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
145{
146 int rc;
147 struct sockaddr_in *addr;
148 size_t addr_size;
149 socket_core_t *sock_core;
150 udp_sockdata_t *socket;
151 udp_sock_t fsock;
152 udp_error_t urc;
153
154 log_msg(LVL_DEBUG, "udp_sock_bind()");
155 log_msg(LVL_DEBUG, " - async_data_write_accept");
156
157 addr = NULL;
158
159 rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &addr_size);
160 if (rc != EOK) {
161 async_answer_0(callid, rc);
162 goto out;
163 }
164
165 log_msg(LVL_DEBUG, " - call socket_bind");
166 rc = socket_bind(&client->sockets, &gsock, SOCKET_GET_SOCKET_ID(call),
167 addr, addr_size, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END,
168 last_used_port);
169 if (rc != EOK) {
170 async_answer_0(callid, rc);
171 goto out;
172 }
173
174 if (addr_size != sizeof(struct sockaddr_in)) {
175 async_answer_0(callid, EINVAL);
176 goto out;
177 }
178
179 log_msg(LVL_DEBUG, " - call socket_cores_find");
180 sock_core = socket_cores_find(&client->sockets, SOCKET_GET_SOCKET_ID(call));
181 if (sock_core == NULL) {
182 async_answer_0(callid, ENOENT);
183 goto out;
184 }
185
186 socket = (udp_sockdata_t *)sock_core->specific_data;
187
188 fsock.addr.ipv4 = uint32_t_be2host(addr->sin_addr.s_addr);
189 fsock.port = sock_core->port;
190 urc = udp_uc_set_local(socket->assoc, &fsock);
191
192 switch (urc) {
193 case UDP_EOK:
194 rc = EOK;
195 break;
196/* case TCP_ENOTEXIST:
197 rc = ENOTCONN;
198 break;
199 case TCP_ECLOSING:
200 rc = ENOTCONN;
201 break;
202 case TCP_ERESET:
203 rc = ECONNABORTED;
204 break;*/
205 default:
206 assert(false);
207 }
208
209 udp_sock_notify_data(sock_core);
210
211 log_msg(LVL_DEBUG, " - success");
212 async_answer_0(callid, rc);
213out:
214 if (addr != NULL)
215 free(addr);
216}
217
218static void udp_sock_listen(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
219{
220 log_msg(LVL_DEBUG, "udp_sock_listen()");
221 async_answer_0(callid, ENOTSUP);
222}
223
224static void udp_sock_connect(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
225{
226 log_msg(LVL_DEBUG, "udp_sock_connect()");
227 async_answer_0(callid, ENOTSUP);
228}
229
230static void udp_sock_accept(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
231{
232 log_msg(LVL_DEBUG, "udp_sock_accept()");
233 async_answer_0(callid, ENOTSUP);
234}
235
236static void udp_sock_sendto(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
237{
238 int socket_id;
239 int fragments;
240 int index;
241 struct sockaddr_in *addr;
242 size_t addr_size;
243 socket_core_t *sock_core;
244 udp_sockdata_t *socket;
245 udp_sock_t fsock, *fsockp;
246 ipc_call_t answer;
247 ipc_callid_t wcallid;
248 size_t length;
249 uint8_t buffer[FRAGMENT_SIZE];
250 udp_error_t urc;
251 int rc;
252
253 log_msg(LVL_DEBUG, "udp_sock_send()");
254
255 addr = NULL;
256
257 if (IPC_GET_IMETHOD(call) == NET_SOCKET_SENDTO) {
258 rc = async_data_write_accept((void **) &addr, false,
259 0, 0, 0, &addr_size);
260 if (rc != EOK) {
261 async_answer_0(callid, rc);
262 goto out;
263 }
264
265 if (addr_size != sizeof(struct sockaddr_in)) {
266 async_answer_0(callid, EINVAL);
267 goto out;
268 }
269
270 fsock.addr.ipv4 = uint32_t_be2host(addr->sin_addr.s_addr);
271 fsock.port = uint16_t_be2host(addr->sin_port);
272 fsockp = &fsock;
273 } else {
274 fsockp = NULL;
275 }
276
277 socket_id = SOCKET_GET_SOCKET_ID(call);
278 fragments = SOCKET_GET_DATA_FRAGMENTS(call);
279 SOCKET_GET_FLAGS(call);
280
281 sock_core = socket_cores_find(&client->sockets, socket_id);
282 if (sock_core == NULL) {
283 async_answer_0(callid, ENOTSOCK);
284 goto out;
285 }
286
287 if (sock_core->port == 0) {
288 /* Implicitly bind socket to port */
289 rc = socket_bind(&client->sockets, &gsock, SOCKET_GET_SOCKET_ID(call),
290 addr, addr_size, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END,
291 last_used_port);
292 if (rc != EOK) {
293 async_answer_0(callid, rc);
294 goto out;
295 }
296
297 udp_sock_notify_data(sock_core);
298 }
299
300 socket = (udp_sockdata_t *)sock_core->specific_data;
301 fibril_mutex_lock(&socket->lock);
302
303 if (socket->assoc->ident.local.addr.ipv4 == UDP_IPV4_ANY) {
304 /* Determine local IP address */
305 inet_addr_t loc_addr, rem_addr;
306
307 rem_addr.ipv4 = fsockp ? fsock.addr.ipv4 :
308 socket->assoc->ident.foreign.addr.ipv4;
309
310 rc = inet_get_srcaddr(&rem_addr, 0, &loc_addr);
311 if (rc != EOK) {
312 fibril_mutex_unlock(&socket->lock);
313 async_answer_0(callid, rc);
314 log_msg(LVL_DEBUG, "udp_sock_sendto: Failed to "
315 "determine local address.");
316 return;
317 }
318
319 socket->assoc->ident.local.addr.ipv4 = loc_addr.ipv4;
320 log_msg(LVL_DEBUG, "Local IP address is %x",
321 socket->assoc->ident.local.addr.ipv4);
322 }
323
324
325 assert(socket->assoc != NULL);
326
327 for (index = 0; index < fragments; index++) {
328 if (!async_data_write_receive(&wcallid, &length)) {
329 fibril_mutex_unlock(&socket->lock);
330 async_answer_0(callid, EINVAL);
331 goto out;
332 }
333
334 if (length > FRAGMENT_SIZE)
335 length = FRAGMENT_SIZE;
336
337 rc = async_data_write_finalize(wcallid, buffer, length);
338 if (rc != EOK) {
339 fibril_mutex_unlock(&socket->lock);
340 async_answer_0(callid, rc);
341 goto out;
342 }
343
344 urc = udp_uc_send(socket->assoc, fsockp, buffer, length, 0);
345
346 switch (urc) {
347 case UDP_EOK:
348 rc = EOK;
349 break;
350/* case TCP_ENOTEXIST:
351 rc = ENOTCONN;
352 break;
353 case TCP_ECLOSING:
354 rc = ENOTCONN;
355 break;
356 case TCP_ERESET:
357 rc = ECONNABORTED;
358 break;*/
359 default:
360 assert(false);
361 }
362
363 if (rc != EOK) {
364 fibril_mutex_unlock(&socket->lock);
365 async_answer_0(callid, rc);
366 goto out;
367 }
368 }
369
370 IPC_SET_ARG1(answer, 0);
371 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
372 async_answer_2(callid, EOK, IPC_GET_ARG1(answer),
373 IPC_GET_ARG2(answer));
374 fibril_mutex_unlock(&socket->lock);
375
376out:
377 if (addr != NULL)
378 free(addr);
379}
380
381static void udp_sock_recvfrom(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
382{
383 int socket_id;
384 int flags;
385 size_t addr_length, length;
386 socket_core_t *sock_core;
387 udp_sockdata_t *socket;
388 ipc_call_t answer;
389 ipc_callid_t rcallid;
390 uint8_t buffer[FRAGMENT_SIZE];
391 size_t data_len;
392 xflags_t xflags;
393 udp_error_t urc;
394 struct sockaddr_in addr;
395 udp_sock_t rsock;
396 int rc;
397
398 log_msg(LVL_DEBUG, "%p: udp_sock_recv[from]()", client);
399
400 socket_id = SOCKET_GET_SOCKET_ID(call);
401 flags = SOCKET_GET_FLAGS(call);
402
403 sock_core = socket_cores_find(&client->sockets, socket_id);
404 if (sock_core == NULL) {
405 async_answer_0(callid, ENOTSOCK);
406 return;
407 }
408
409 socket = (udp_sockdata_t *)sock_core->specific_data;
410 fibril_mutex_lock(&socket->lock);
411
412 if (socket->assoc == NULL) {
413 fibril_mutex_unlock(&socket->lock);
414 async_answer_0(callid, ENOTCONN);
415 return;
416 }
417
418 (void)flags;
419
420 urc = udp_uc_receive(socket->assoc, buffer, FRAGMENT_SIZE, &data_len,
421 &xflags, &rsock);
422 log_msg(LVL_DEBUG, "**** udp_uc_receive done, data_len=%zu", data_len);
423
424 switch (urc) {
425 case UDP_EOK:
426 rc = EOK;
427 break;
428/* case TCP_ENOTEXIST:
429 case TCP_ECLOSING:
430 rc = ENOTCONN;
431 break;
432 case TCP_ERESET:
433 rc = ECONNABORTED;
434 break;*/
435 default:
436 assert(false);
437 }
438
439 log_msg(LVL_DEBUG, "**** udp_uc_receive -> %d", rc);
440 if (rc != EOK) {
441 fibril_mutex_unlock(&socket->lock);
442 async_answer_0(callid, rc);
443 return;
444 }
445
446 if (IPC_GET_IMETHOD(call) == NET_SOCKET_RECVFROM) {
447 /* Fill addr */
448 addr.sin_family = AF_INET;
449 addr.sin_addr.s_addr = host2uint32_t_be(rsock.addr.ipv4);
450 addr.sin_port = host2uint16_t_be(rsock.port);
451
452 log_msg(LVL_DEBUG, "addr read receive");
453 if (!async_data_read_receive(&rcallid, &addr_length)) {
454 fibril_mutex_unlock(&socket->lock);
455 async_answer_0(callid, EINVAL);
456 return;
457 }
458
459 if (addr_length > sizeof(addr))
460 addr_length = sizeof(addr);
461
462 log_msg(LVL_DEBUG, "addr read finalize");
463 rc = async_data_read_finalize(rcallid, &addr, addr_length);
464 if (rc != EOK) {
465 fibril_mutex_unlock(&socket->lock);
466 async_answer_0(callid, EINVAL);
467 return;
468 }
469 }
470
471 log_msg(LVL_DEBUG, "data read receive");
472 if (!async_data_read_receive(&rcallid, &length)) {
473 fibril_mutex_unlock(&socket->lock);
474 async_answer_0(callid, EINVAL);
475 return;
476 }
477
478 if (length > data_len)
479 length = data_len;
480
481 log_msg(LVL_DEBUG, "data read finalize");
482 rc = async_data_read_finalize(rcallid, buffer, length);
483
484 if (length < data_len && rc == EOK)
485 rc = EOVERFLOW;
486
487 log_msg(LVL_DEBUG, "read_data_length <- %zu", length);
488 IPC_SET_ARG2(answer, 0);
489 SOCKET_SET_READ_DATA_LENGTH(answer, length);
490 SOCKET_SET_ADDRESS_LENGTH(answer, sizeof(addr));
491 async_answer_3(callid, EOK, IPC_GET_ARG1(answer),
492 IPC_GET_ARG2(answer), IPC_GET_ARG3(answer));
493
494 /* Push one fragment notification to client's queue */
495 udp_sock_notify_data(sock_core);
496 fibril_mutex_unlock(&socket->lock);
497}
498
499static void udp_sock_close(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
500{
501 int socket_id;
502 socket_core_t *sock_core;
503 udp_sockdata_t *socket;
504 int rc;
505
506 log_msg(LVL_DEBUG, "tcp_sock_close()");
507 socket_id = SOCKET_GET_SOCKET_ID(call);
508
509 sock_core = socket_cores_find(&client->sockets, socket_id);
510 if (sock_core == NULL) {
511 async_answer_0(callid, ENOTSOCK);
512 return;
513 }
514
515 socket = (udp_sockdata_t *)sock_core->specific_data;
516 fibril_mutex_lock(&socket->lock);
517
518 rc = socket_destroy(NULL, socket_id, &client->sockets, &gsock,
519 udp_free_sock_data);
520 if (rc != EOK) {
521 fibril_mutex_unlock(&socket->lock);
522 async_answer_0(callid, rc);
523 return;
524 }
525
526 fibril_mutex_unlock(&socket->lock);
527 async_answer_0(callid, EOK);
528}
529
530static void udp_sock_getsockopt(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
531{
532 log_msg(LVL_DEBUG, "udp_sock_getsockopt()");
533 async_answer_0(callid, ENOTSUP);
534}
535
536static void udp_sock_setsockopt(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
537{
538 log_msg(LVL_DEBUG, "udp_sock_setsockopt()");
539 async_answer_0(callid, ENOTSUP);
540}
541
542static void udp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
543{
544 ipc_callid_t callid;
545 ipc_call_t call;
546 udp_client_t client;
547
548 /* Accept the connection */
549 async_answer_0(iid, EOK);
550
551 client.sess = async_callback_receive(EXCHANGE_SERIALIZE);
552 socket_cores_initialize(&client.sockets);
553
554 while (true) {
555 log_msg(LVL_DEBUG, "udp_sock_connection: wait");
556 callid = async_get_call(&call);
557 if (!IPC_GET_IMETHOD(call))
558 break;
559
560 log_msg(LVL_DEBUG, "udp_sock_connection: METHOD=%d",
561 (int)IPC_GET_IMETHOD(call));
562
563 switch (IPC_GET_IMETHOD(call)) {
564 case NET_SOCKET:
565 udp_sock_socket(&client, callid, call);
566 break;
567 case NET_SOCKET_BIND:
568 udp_sock_bind(&client, callid, call);
569 break;
570 case NET_SOCKET_LISTEN:
571 udp_sock_listen(&client, callid, call);
572 break;
573 case NET_SOCKET_CONNECT:
574 udp_sock_connect(&client, callid, call);
575 break;
576 case NET_SOCKET_ACCEPT:
577 udp_sock_accept(&client, callid, call);
578 break;
579 case NET_SOCKET_SEND:
580 case NET_SOCKET_SENDTO:
581 udp_sock_sendto(&client, callid, call);
582 break;
583 case NET_SOCKET_RECV:
584 case NET_SOCKET_RECVFROM:
585 udp_sock_recvfrom(&client, callid, call);
586 break;
587 case NET_SOCKET_CLOSE:
588 udp_sock_close(&client, callid, call);
589 break;
590 case NET_SOCKET_GETSOCKOPT:
591 udp_sock_getsockopt(&client, callid, call);
592 break;
593 case NET_SOCKET_SETSOCKOPT:
594 udp_sock_setsockopt(&client, callid, call);
595 break;
596 default:
597 async_answer_0(callid, ENOTSUP);
598 break;
599 }
600 }
601
602 /* Clean up */
603 log_msg(LVL_DEBUG, "udp_sock_connection: Clean up");
604 async_hangup(client.sess);
605 socket_cores_release(NULL, &client.sockets, &gsock, udp_free_sock_data);
606}
607
608/**
609 * @}
610 */
Note: See TracBrowser for help on using the repository browser.