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

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

Move network-related servers to srv/net.

  • Property mode set to 100644
File size: 14.4 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/modules.h>
46#include <net/socket.h>
47#include <ns.h>
48
49#include "sock.h"
50#include "std.h"
51#include "udp_type.h"
52#include "ucall.h"
53
54#define FRAGMENT_SIZE 1024
55
56/** Free ports pool start. */
57#define UDP_FREE_PORTS_START 1025
58
59/** Free ports pool end. */
60#define UDP_FREE_PORTS_END 65535
61
62static int last_used_port = UDP_FREE_PORTS_START - 1;
63static socket_ports_t gsock;
64
65static void udp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg);
66
67int udp_sock_init(void)
68{
69 int rc;
70
71 socket_ports_initialize(&gsock);
72
73 async_set_client_connection(udp_sock_connection);
74
75 rc = service_register(SERVICE_UDP);
76 if (rc != EOK)
77 return EEXIST;
78
79 return EOK;
80}
81
82static void udp_free_sock_data(socket_core_t *sock_core)
83{
84 udp_sockdata_t *socket;
85
86 socket = (udp_sockdata_t *)sock_core->specific_data;
87 (void)socket;
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
137 refresh_answer(&answer, NULL);
138 SOCKET_SET_SOCKET_ID(answer, sock_id);
139
140 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
141 SOCKET_SET_HEADER_SIZE(answer, sizeof(udp_header_t));
142 answer_call(callid, EOK, &answer, 3);
143}
144
145static void udp_sock_bind(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
146{
147 int rc;
148 struct sockaddr_in *addr;
149 size_t addr_size;
150 socket_core_t *sock_core;
151 udp_sockdata_t *socket;
152 udp_sock_t fsock;
153 udp_error_t urc;
154
155 log_msg(LVL_DEBUG, "udp_sock_bind()");
156 log_msg(LVL_DEBUG, " - async_data_write_accept");
157
158 addr = NULL;
159
160 rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &addr_size);
161 if (rc != EOK) {
162 async_answer_0(callid, rc);
163 goto out;
164 }
165
166 log_msg(LVL_DEBUG, " - call socket_bind");
167 rc = socket_bind(&client->sockets, &gsock, SOCKET_GET_SOCKET_ID(call),
168 addr, addr_size, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END,
169 last_used_port);
170 if (rc != EOK) {
171 async_answer_0(callid, rc);
172 goto out;
173 }
174
175 if (addr_size != sizeof(struct sockaddr_in)) {
176 async_answer_0(callid, EINVAL);
177 goto out;
178 }
179
180 log_msg(LVL_DEBUG, " - call socket_cores_find");
181 sock_core = socket_cores_find(&client->sockets, SOCKET_GET_SOCKET_ID(call));
182 if (sock_core == NULL) {
183 async_answer_0(callid, ENOENT);
184 goto out;
185 }
186
187 socket = (udp_sockdata_t *)sock_core->specific_data;
188
189 fsock.addr.ipv4 = uint32_t_be2host(addr->sin_addr.s_addr);
190 fsock.port = sock_core->port;
191 urc = udp_uc_set_local(socket->assoc, &fsock);
192
193 switch (urc) {
194 case UDP_EOK:
195 rc = EOK;
196 break;
197/* case TCP_ENOTEXIST:
198 rc = ENOTCONN;
199 break;
200 case TCP_ECLOSING:
201 rc = ENOTCONN;
202 break;
203 case TCP_ERESET:
204 rc = ECONNABORTED;
205 break;*/
206 default:
207 assert(false);
208 }
209
210 udp_sock_notify_data(sock_core);
211
212 log_msg(LVL_DEBUG, " - success");
213 async_answer_0(callid, rc);
214out:
215 if (addr != NULL)
216 free(addr);
217}
218
219static void udp_sock_listen(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
220{
221 log_msg(LVL_DEBUG, "udp_sock_listen()");
222 async_answer_0(callid, ENOTSUP);
223}
224
225static void udp_sock_connect(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
226{
227 log_msg(LVL_DEBUG, "udp_sock_connect()");
228 async_answer_0(callid, ENOTSUP);
229}
230
231static void udp_sock_accept(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
232{
233 log_msg(LVL_DEBUG, "udp_sock_accept()");
234 async_answer_0(callid, ENOTSUP);
235}
236
237static void udp_sock_sendto(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
238{
239 int socket_id;
240 int fragments;
241 int index;
242 struct sockaddr_in *addr;
243 size_t addr_size;
244 socket_core_t *sock_core;
245 udp_sockdata_t *socket;
246 udp_sock_t fsock, *fsockp;
247 ipc_call_t answer;
248 ipc_callid_t wcallid;
249 size_t length;
250 uint8_t buffer[FRAGMENT_SIZE];
251 udp_error_t urc;
252 int rc;
253
254 log_msg(LVL_DEBUG, "udp_sock_send()");
255
256 addr = NULL;
257
258 if (IPC_GET_IMETHOD(call) == NET_SOCKET_SENDTO) {
259 rc = async_data_write_accept((void **) &addr, false,
260 0, 0, 0, &addr_size);
261 if (rc != EOK) {
262 async_answer_0(callid, rc);
263 goto out;
264 }
265
266 if (addr_size != sizeof(struct sockaddr_in)) {
267 async_answer_0(callid, EINVAL);
268 goto out;
269 }
270
271 fsock.addr.ipv4 = uint32_t_be2host(addr->sin_addr.s_addr);
272 fsock.port = uint16_t_be2host(addr->sin_port);
273 fsockp = &fsock;
274 } else {
275 fsockp = NULL;
276 }
277
278 socket_id = SOCKET_GET_SOCKET_ID(call);
279 fragments = SOCKET_GET_DATA_FRAGMENTS(call);
280 SOCKET_GET_FLAGS(call);
281
282 sock_core = socket_cores_find(&client->sockets, socket_id);
283 if (sock_core == NULL) {
284 async_answer_0(callid, ENOTSOCK);
285 goto out;
286 }
287
288 if (sock_core->port == 0) {
289 /* Implicitly bind socket to port */
290 rc = socket_bind(&client->sockets, &gsock, SOCKET_GET_SOCKET_ID(call),
291 addr, addr_size, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END,
292 last_used_port);
293 if (rc != EOK) {
294 async_answer_0(callid, rc);
295 goto out;
296 }
297
298 udp_sock_notify_data(sock_core);
299 }
300
301 socket = (udp_sockdata_t *)sock_core->specific_data;
302 fibril_mutex_lock(&socket->lock);
303
304 if (socket->assoc->ident.local.addr.ipv4 == UDP_IPV4_ANY) {
305 /* Determine local IP address */
306 inet_addr_t loc_addr, rem_addr;
307
308 rem_addr.ipv4 = fsockp ? fsock.addr.ipv4 :
309 socket->assoc->ident.foreign.addr.ipv4;
310
311 rc = inet_get_srcaddr(&rem_addr, 0, &loc_addr);
312 if (rc != EOK) {
313 fibril_mutex_unlock(&socket->lock);
314 async_answer_0(callid, rc);
315 log_msg(LVL_DEBUG, "udp_sock_sendto: Failed to "
316 "determine local address.");
317 return;
318 }
319
320 socket->assoc->ident.local.addr.ipv4 = loc_addr.ipv4;
321 log_msg(LVL_DEBUG, "Local IP address is %x",
322 socket->assoc->ident.local.addr.ipv4);
323 }
324
325
326 assert(socket->assoc != NULL);
327
328 for (index = 0; index < fragments; index++) {
329 if (!async_data_write_receive(&wcallid, &length)) {
330 fibril_mutex_unlock(&socket->lock);
331 async_answer_0(callid, EINVAL);
332 goto out;
333 }
334
335 if (length > FRAGMENT_SIZE)
336 length = FRAGMENT_SIZE;
337
338 rc = async_data_write_finalize(wcallid, buffer, length);
339 if (rc != EOK) {
340 fibril_mutex_unlock(&socket->lock);
341 async_answer_0(callid, rc);
342 goto out;
343 }
344
345 urc = udp_uc_send(socket->assoc, fsockp, buffer, length, 0);
346
347 switch (urc) {
348 case UDP_EOK:
349 rc = EOK;
350 break;
351/* case TCP_ENOTEXIST:
352 rc = ENOTCONN;
353 break;
354 case TCP_ECLOSING:
355 rc = ENOTCONN;
356 break;
357 case TCP_ERESET:
358 rc = ECONNABORTED;
359 break;*/
360 default:
361 assert(false);
362 }
363
364 if (rc != EOK) {
365 fibril_mutex_unlock(&socket->lock);
366 async_answer_0(callid, rc);
367 goto out;
368 }
369 }
370
371 refresh_answer(&answer, NULL);
372 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
373 answer_call(callid, EOK, &answer, 2);
374 fibril_mutex_unlock(&socket->lock);
375out:
376 if (addr != NULL)
377 free(addr);
378}
379
380static void udp_sock_recvfrom(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
381{
382 int socket_id;
383 int flags;
384 size_t addr_length, length;
385 socket_core_t *sock_core;
386 udp_sockdata_t *socket;
387 ipc_call_t answer;
388 ipc_callid_t rcallid;
389 uint8_t buffer[FRAGMENT_SIZE];
390 size_t data_len;
391 xflags_t xflags;
392 udp_error_t urc;
393 struct sockaddr_in addr;
394 udp_sock_t rsock;
395 int rc;
396
397 log_msg(LVL_DEBUG, "%p: udp_sock_recv[from]()", client);
398
399 socket_id = SOCKET_GET_SOCKET_ID(call);
400 flags = SOCKET_GET_FLAGS(call);
401
402 sock_core = socket_cores_find(&client->sockets, socket_id);
403 if (sock_core == NULL) {
404 async_answer_0(callid, ENOTSOCK);
405 return;
406 }
407
408 socket = (udp_sockdata_t *)sock_core->specific_data;
409 fibril_mutex_lock(&socket->lock);
410
411 if (socket->assoc == NULL) {
412 fibril_mutex_unlock(&socket->lock);
413 async_answer_0(callid, ENOTCONN);
414 return;
415 }
416
417 (void)flags;
418
419 urc = udp_uc_receive(socket->assoc, buffer, FRAGMENT_SIZE, &data_len,
420 &xflags, &rsock);
421 log_msg(LVL_DEBUG, "**** udp_uc_receive done, data_len=%zu", data_len);
422
423 switch (urc) {
424 case UDP_EOK:
425 rc = EOK;
426 break;
427/* case TCP_ENOTEXIST:
428 case TCP_ECLOSING:
429 rc = ENOTCONN;
430 break;
431 case TCP_ERESET:
432 rc = ECONNABORTED;
433 break;*/
434 default:
435 assert(false);
436 }
437
438 log_msg(LVL_DEBUG, "**** udp_uc_receive -> %d", rc);
439 if (rc != EOK) {
440 fibril_mutex_unlock(&socket->lock);
441 async_answer_0(callid, rc);
442 return;
443 }
444
445 if (IPC_GET_IMETHOD(call) == NET_SOCKET_RECVFROM) {
446 /* Fill addr */
447 addr.sin_family = AF_INET;
448 addr.sin_addr.s_addr = host2uint32_t_be(rsock.addr.ipv4);
449 addr.sin_port = host2uint16_t_be(rsock.port);
450
451 log_msg(LVL_DEBUG, "addr read receive");
452 if (!async_data_read_receive(&rcallid, &addr_length)) {
453 fibril_mutex_unlock(&socket->lock);
454 async_answer_0(callid, EINVAL);
455 return;
456 }
457
458 if (addr_length > sizeof(addr))
459 addr_length = sizeof(addr);
460
461 log_msg(LVL_DEBUG, "addr read finalize");
462 rc = async_data_read_finalize(rcallid, &addr, addr_length);
463 if (rc != EOK) {
464 fibril_mutex_unlock(&socket->lock);
465 async_answer_0(callid, EINVAL);
466 return;
467 }
468 }
469
470 log_msg(LVL_DEBUG, "data read receive");
471 if (!async_data_read_receive(&rcallid, &length)) {
472 fibril_mutex_unlock(&socket->lock);
473 async_answer_0(callid, EINVAL);
474 return;
475 }
476
477 if (length > data_len)
478 length = data_len;
479
480 log_msg(LVL_DEBUG, "data read finalize");
481 rc = async_data_read_finalize(rcallid, buffer, length);
482
483 if (length < data_len && rc == EOK)
484 rc = EOVERFLOW;
485
486 log_msg(LVL_DEBUG, "read_data_length <- %zu", length);
487 SOCKET_SET_READ_DATA_LENGTH(answer, length);
488 SOCKET_SET_ADDRESS_LENGTH(answer, sizeof(addr));
489 answer_call(callid, EOK, &answer, 3);
490
491 /* Push one fragment notification to client's queue */
492 udp_sock_notify_data(sock_core);
493 fibril_mutex_unlock(&socket->lock);
494}
495
496static void udp_sock_close(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
497{
498 int socket_id;
499 socket_core_t *sock_core;
500 udp_sockdata_t *socket;
501 int rc;
502
503 log_msg(LVL_DEBUG, "tcp_sock_close()");
504 socket_id = SOCKET_GET_SOCKET_ID(call);
505
506 sock_core = socket_cores_find(&client->sockets, socket_id);
507 if (sock_core == NULL) {
508 async_answer_0(callid, ENOTSOCK);
509 return;
510 }
511
512 socket = (udp_sockdata_t *)sock_core->specific_data;
513 fibril_mutex_lock(&socket->lock);
514
515 assert(socket->assoc != NULL);
516 udp_uc_destroy(socket->assoc);
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
603/**
604 * @}
605 */
Note: See TracBrowser for help on using the repository browser.