source: mainline/uspace/srv/net/tcp/sock.c@ 12df1f1

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

add basic infrastructure for IPv6 (inactive)
make inet_addr_t a universal address type

  • Property mode set to 100644
File size: 25.9 KB
Line 
1/*
2 * Copyright (c) 2008 Lukas Mejdrech
3 * Copyright (c) 2011 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 tcp
31 * @{
32 */
33
34/**
35 * @file Socket provider
36 */
37
38#include <async.h>
39#include <errno.h>
40#include <inet/inet.h>
41#include <io/log.h>
42#include <ipc/services.h>
43#include <ipc/socket.h>
44#include <net/socket.h>
45#include <ns.h>
46
47#include "sock.h"
48#include "std.h"
49#include "tcp.h"
50#include "tcp_type.h"
51#include "ucall.h"
52
53#define MAX_BACKLOG 128
54
55/** Free ports pool start. */
56#define TCP_FREE_PORTS_START 1025
57
58/** Free ports pool end. */
59#define TCP_FREE_PORTS_END 65535
60
61static int last_used_port = TCP_FREE_PORTS_START - 1;
62static socket_ports_t gsock;
63
64static void tcp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg);
65static void tcp_sock_cstate_cb(tcp_conn_t *conn, void *arg);
66static int tcp_sock_recv_fibril(void *arg);
67
68int tcp_sock_init(void)
69{
70 socket_ports_initialize(&gsock);
71
72 async_set_client_connection(tcp_sock_connection);
73
74 int rc = service_register(SERVICE_TCP);
75 if (rc != EOK)
76 return EEXIST;
77
78 return EOK;
79}
80
81static void tcp_free_sock_data(socket_core_t *sock_core)
82{
83 tcp_sockdata_t *socket;
84
85 socket = (tcp_sockdata_t *)sock_core->specific_data;
86 (void)socket;
87
88 /* XXX We need to initiate connection cleanup here */
89}
90
91static void tcp_sock_notify_data(socket_core_t *sock_core)
92{
93 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_notify_data(%d)", sock_core->socket_id);
94 async_exch_t *exch = async_exchange_begin(sock_core->sess);
95 async_msg_5(exch, NET_SOCKET_RECEIVED, (sysarg_t)sock_core->socket_id,
96 TCP_SOCK_FRAGMENT_SIZE, 0, 0, 1);
97 async_exchange_end(exch);
98}
99
100static void tcp_sock_notify_aconn(socket_core_t *lsock_core)
101{
102 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_notify_aconn(%d)", lsock_core->socket_id);
103 async_exch_t *exch = async_exchange_begin(lsock_core->sess);
104 async_msg_5(exch, NET_SOCKET_ACCEPTED, (sysarg_t)lsock_core->socket_id,
105 TCP_SOCK_FRAGMENT_SIZE, 0, 0, 0);
106 async_exchange_end(exch);
107}
108
109static int tcp_sock_create(tcp_client_t *client, tcp_sockdata_t **rsock)
110{
111 tcp_sockdata_t *sock;
112
113 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_create()");
114 *rsock = NULL;
115
116 sock = calloc(1, sizeof(tcp_sockdata_t));
117 if (sock == NULL)
118 return ENOMEM;
119
120 fibril_mutex_initialize(&sock->lock);
121 sock->client = client;
122
123 sock->recv_buffer_used = 0;
124 sock->recv_error = TCP_EOK;
125 fibril_mutex_initialize(&sock->recv_buffer_lock);
126 fibril_condvar_initialize(&sock->recv_buffer_cv);
127 list_initialize(&sock->ready);
128
129 *rsock = sock;
130 return EOK;
131}
132
133static void tcp_sock_uncreate(tcp_sockdata_t *sock)
134{
135 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_uncreate()");
136 free(sock);
137}
138
139static int tcp_sock_finish_setup(tcp_sockdata_t *sock, int *sock_id)
140{
141 socket_core_t *sock_core;
142 int rc;
143
144 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_finish_setup()");
145
146 sock->recv_fibril = fibril_create(tcp_sock_recv_fibril, sock);
147 if (sock->recv_fibril == 0)
148 return ENOMEM;
149
150 rc = socket_create(&sock->client->sockets, sock->client->sess,
151 sock, sock_id);
152
153 if (rc != EOK) {
154 fibril_destroy(sock->recv_fibril);
155 sock->recv_fibril = 0;
156 return rc;
157 }
158
159 sock_core = socket_cores_find(&sock->client->sockets, *sock_id);
160 assert(sock_core != NULL);
161 sock->sock_core = sock_core;
162
163 return EOK;
164}
165
166static void tcp_sock_socket(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
167{
168 tcp_sockdata_t *sock;
169 int sock_id;
170 int rc;
171 ipc_call_t answer;
172
173 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_socket()");
174
175 rc = tcp_sock_create(client, &sock);
176 if (rc != EOK) {
177 async_answer_0(callid, rc);
178 return;
179 }
180
181 inet_addr_any(&sock->laddr);
182 sock->lconn = NULL;
183 sock->backlog = 0;
184
185 sock_id = SOCKET_GET_SOCKET_ID(call);
186 rc = tcp_sock_finish_setup(sock, &sock_id);
187 if (rc != EOK) {
188 tcp_sock_uncreate(sock);
189 async_answer_0(callid, rc);
190 return;
191 }
192
193 SOCKET_SET_SOCKET_ID(answer, sock_id);
194
195 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, TCP_SOCK_FRAGMENT_SIZE);
196 SOCKET_SET_HEADER_SIZE(answer, sizeof(tcp_header_t));
197
198 async_answer_3(callid, EOK, IPC_GET_ARG1(answer),
199 IPC_GET_ARG2(answer), IPC_GET_ARG3(answer));
200}
201
202static void tcp_sock_bind(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
203{
204 int rc;
205 struct sockaddr_in *addr;
206 size_t addr_size;
207 socket_core_t *sock_core;
208 tcp_sockdata_t *socket;
209
210 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_bind()");
211 log_msg(LOG_DEFAULT, LVL_DEBUG, " - async_data_write_accept");
212
213 addr = NULL;
214
215 rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &addr_size);
216 if (rc != EOK) {
217 async_answer_0(callid, rc);
218 goto out;
219 }
220
221 if (addr_size != sizeof(struct sockaddr_in)) {
222 async_answer_0(callid, EINVAL);
223 goto out;
224 }
225
226 log_msg(LOG_DEFAULT, LVL_DEBUG, " - call socket_bind");
227 rc = socket_bind(&client->sockets, &gsock, SOCKET_GET_SOCKET_ID(call),
228 addr, addr_size, TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
229 last_used_port);
230 if (rc != EOK) {
231 async_answer_0(callid, rc);
232 goto out;
233 }
234
235 log_msg(LOG_DEFAULT, LVL_DEBUG, " - call socket_cores_find");
236 sock_core = socket_cores_find(&client->sockets, SOCKET_GET_SOCKET_ID(call));
237 if (sock_core == NULL) {
238 async_answer_0(callid, ENOENT);
239 goto out;
240 }
241
242 socket = (tcp_sockdata_t *)sock_core->specific_data;
243 /* XXX Anything to do? */
244 (void) socket;
245
246 log_msg(LOG_DEFAULT, LVL_DEBUG, " - success");
247 async_answer_0(callid, EOK);
248
249out:
250 if (addr != NULL)
251 free(addr);
252}
253
254static void tcp_sock_listen(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
255{
256 int socket_id;
257 int backlog;
258 socket_core_t *sock_core;
259 tcp_sockdata_t *socket;
260 tcp_error_t trc;
261 tcp_sock_t lsocket;
262 tcp_sock_t fsocket;
263 tcp_conn_t *conn;
264 tcp_sock_lconn_t *lconn;
265 int i;
266 int rc;
267
268 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_listen()");
269
270 socket_id = SOCKET_GET_SOCKET_ID(call);
271 backlog = SOCKET_GET_BACKLOG(call);
272
273 if (backlog < 0) {
274 async_answer_0(callid, EINVAL);
275 return;
276 }
277
278 if (backlog > MAX_BACKLOG)
279 backlog = MAX_BACKLOG;
280
281 sock_core = socket_cores_find(&client->sockets, socket_id);
282 if (sock_core == NULL) {
283 async_answer_0(callid, ENOTSOCK);
284 return;
285 }
286
287 if (sock_core->port <= 0) {
288 rc = socket_bind_free_port(&gsock, sock_core,
289 TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
290 last_used_port);
291 if (rc != EOK) {
292 async_answer_0(callid, rc);
293 return;
294 }
295
296 last_used_port = sock_core->port;
297 }
298
299 socket = (tcp_sockdata_t *) sock_core->specific_data;
300
301 /*
302 * Prepare @c backlog listening connections.
303 */
304 fibril_mutex_lock(&socket->lock);
305
306 socket->backlog = backlog;
307 socket->lconn = calloc(backlog, sizeof(tcp_conn_t *));
308 if (socket->lconn == NULL) {
309 fibril_mutex_unlock(&socket->lock);
310 async_answer_0(callid, ENOMEM);
311 return;
312 }
313
314 log_msg(LOG_DEFAULT, LVL_DEBUG, " - open connections");
315
316 inet_addr_any(&lsocket.addr);
317 lsocket.port = sock_core->port;
318
319 inet_addr_any(&fsocket.addr);
320 fsocket.port = TCP_PORT_ANY;
321
322 for (i = 0; i < backlog; i++) {
323
324 lconn = calloc(1, sizeof(tcp_sock_lconn_t));
325 if (lconn == NULL) {
326 /* XXX Clean up */
327 fibril_mutex_unlock(&socket->lock);
328 async_answer_0(callid, ENOMEM);
329 return;
330 }
331
332 trc = tcp_uc_open(&lsocket, &fsocket, ap_passive,
333 tcp_open_nonblock, &conn);
334 if (conn == NULL) {
335 /* XXX Clean up */
336 fibril_mutex_unlock(&socket->lock);
337 async_answer_0(callid, ENOMEM);
338 return;
339 }
340
341 tcp_uc_set_cstate_cb(conn, tcp_sock_cstate_cb, lconn);
342
343 assert(trc == TCP_EOK);
344 conn->name = (char *)"S";
345
346 lconn->conn = conn;
347 lconn->socket = socket;
348 link_initialize(&lconn->ready_list);
349 socket->lconn[i] = lconn;
350 }
351
352 fibril_mutex_unlock(&socket->lock);
353 async_answer_0(callid, EOK);
354}
355
356static void tcp_sock_connect(tcp_client_t *client, ipc_callid_t callid,
357 ipc_call_t call)
358{
359 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_connect()");
360
361 struct sockaddr_in6 *addr6 = NULL;
362 size_t addr_len;
363 int rc = async_data_write_accept((void **) &addr6, false, 0, 0, 0, &addr_len);
364 if (rc != EOK) {
365 async_answer_0(callid, rc);
366 return;
367 }
368
369 if ((addr_len != sizeof(struct sockaddr_in)) &&
370 (addr_len != sizeof(struct sockaddr_in6))) {
371 async_answer_0(callid, EINVAL);
372 goto out;
373 }
374
375 struct sockaddr_in *addr = (struct sockaddr_in *) addr6;
376
377 int socket_id = SOCKET_GET_SOCKET_ID(call);
378 socket_core_t *sock_core = socket_cores_find(&client->sockets,
379 socket_id);
380 if (sock_core == NULL) {
381 async_answer_0(callid, ENOTSOCK);
382 goto out;
383 }
384
385 tcp_sockdata_t *socket =
386 (tcp_sockdata_t *) sock_core->specific_data;
387
388 if (sock_core->port <= 0) {
389 rc = socket_bind_free_port(&gsock, sock_core,
390 TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
391 last_used_port);
392 if (rc != EOK) {
393 async_answer_0(callid, rc);
394 goto out;
395 }
396
397 last_used_port = sock_core->port;
398 }
399
400 fibril_mutex_lock(&socket->lock);
401
402 if (inet_addr_is_any(&socket->laddr)) {
403 /* Determine local IP address */
404 inet_addr_t loc_addr;
405 inet_addr_t rem_addr;
406
407 switch (addr->sin_family) {
408 case AF_INET:
409 inet_sockaddr_in_addr(addr, &rem_addr);
410 break;
411 case AF_INET6:
412 inet_sockaddr_in6_addr(addr6, &rem_addr);
413 break;
414 default:
415 fibril_mutex_unlock(&socket->lock);
416 async_answer_0(callid, EINVAL);
417 goto out;
418 }
419
420 rc = inet_get_srcaddr(&rem_addr, 0, &loc_addr);
421 if (rc != EOK) {
422 fibril_mutex_unlock(&socket->lock);
423 async_answer_0(callid, rc);
424 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_connect: Failed to "
425 "determine local address.");
426 goto out;
427 }
428
429 socket->laddr = loc_addr;
430 }
431
432 tcp_sock_t lsocket;
433 tcp_sock_t fsocket;
434
435 lsocket.addr = socket->laddr;
436 lsocket.port = sock_core->port;
437
438 switch (addr->sin_family) {
439 case AF_INET:
440 inet_sockaddr_in_addr(addr, &fsocket.addr);
441 break;
442 case AF_INET6:
443 inet_sockaddr_in6_addr(addr6, &fsocket.addr);
444 break;
445 default:
446 fibril_mutex_unlock(&socket->lock);
447 async_answer_0(callid, EINVAL);
448 goto out;
449 }
450
451 fsocket.port = uint16_t_be2host(addr->sin_port);
452
453 tcp_error_t trc = tcp_uc_open(&lsocket, &fsocket, ap_active, 0,
454 &socket->conn);
455
456 if (socket->conn != NULL)
457 socket->conn->name = (char *) "C";
458
459 fibril_mutex_unlock(&socket->lock);
460
461 switch (trc) {
462 case TCP_EOK:
463 rc = EOK;
464 break;
465 case TCP_ERESET:
466 rc = ECONNREFUSED;
467 break;
468 default:
469 assert(false);
470 }
471
472 if (rc == EOK)
473 fibril_add_ready(socket->recv_fibril);
474
475 async_answer_0(callid, rc);
476
477out:
478 if (addr6 != NULL)
479 free(addr6);
480}
481
482static void tcp_sock_accept(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
483{
484 ipc_call_t answer;
485 int socket_id;
486 int asock_id;
487 socket_core_t *sock_core;
488 tcp_sockdata_t *socket;
489 tcp_sockdata_t *asocket;
490 tcp_error_t trc;
491 tcp_sock_t lsocket;
492 tcp_sock_t fsocket;
493 tcp_conn_t *conn;
494 tcp_conn_t *rconn;
495 tcp_sock_lconn_t *lconn;
496 int rc;
497
498 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_accept()");
499
500 socket_id = SOCKET_GET_SOCKET_ID(call);
501 asock_id = SOCKET_GET_NEW_SOCKET_ID(call);
502
503 sock_core = socket_cores_find(&client->sockets, socket_id);
504 if (sock_core == NULL) {
505 async_answer_0(callid, ENOTSOCK);
506 return;
507 }
508
509 if (sock_core->port <= 0) {
510 rc = socket_bind_free_port(&gsock, sock_core,
511 TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
512 last_used_port);
513 if (rc != EOK) {
514 async_answer_0(callid, rc);
515 return;
516 }
517
518 last_used_port = sock_core->port;
519 }
520
521 socket = (tcp_sockdata_t *)sock_core->specific_data;
522 fibril_mutex_lock(&socket->lock);
523
524 log_msg(LOG_DEFAULT, LVL_DEBUG, " - verify socket->conn");
525 if (socket->conn != NULL) {
526 fibril_mutex_unlock(&socket->lock);
527 async_answer_0(callid, EINVAL);
528 return;
529 }
530
531 if (list_empty(&socket->ready)) {
532 fibril_mutex_unlock(&socket->lock);
533 async_answer_0(callid, ENOENT);
534 return;
535 }
536
537 lconn = list_get_instance(list_first(&socket->ready),
538 tcp_sock_lconn_t, ready_list);
539 list_remove(&lconn->ready_list);
540
541 conn = lconn->conn;
542 tcp_uc_set_cstate_cb(conn, NULL, NULL);
543
544 /* Replenish listening connection */
545
546 inet_addr_any(&lsocket.addr);
547 lsocket.port = sock_core->port;
548
549 inet_addr_any(&fsocket.addr);
550 fsocket.port = TCP_PORT_ANY;
551
552 trc = tcp_uc_open(&lsocket, &fsocket, ap_passive, tcp_open_nonblock,
553 &rconn);
554 if (rconn == NULL) {
555 /* XXX Clean up */
556 fibril_mutex_unlock(&socket->lock);
557 async_answer_0(callid, ENOMEM);
558 return;
559 }
560
561 tcp_uc_set_cstate_cb(rconn, tcp_sock_cstate_cb, lconn);
562
563 assert(trc == TCP_EOK);
564 rconn->name = (char *)"S";
565
566 lconn->conn = rconn;
567
568 /* Allocate socket for accepted connection */
569
570 rc = tcp_sock_create(client, &asocket);
571 if (rc != EOK) {
572 fibril_mutex_unlock(&socket->lock);
573 async_answer_0(callid, rc);
574 return;
575 }
576
577 asocket->conn = conn;
578 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_accept():create asocket\n");
579
580 rc = tcp_sock_finish_setup(asocket, &asock_id);
581 if (rc != EOK) {
582 tcp_sock_uncreate(asocket);
583 fibril_mutex_unlock(&socket->lock);
584 async_answer_0(callid, rc);
585 return;
586 }
587
588 fibril_add_ready(asocket->recv_fibril);
589
590 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_accept(): find acore\n");
591
592 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, TCP_SOCK_FRAGMENT_SIZE);
593 SOCKET_SET_SOCKET_ID(answer, asock_id);
594 SOCKET_SET_ADDRESS_LENGTH(answer, sizeof(struct sockaddr_in));
595
596 async_answer_3(callid, asocket->sock_core->socket_id,
597 IPC_GET_ARG1(answer), IPC_GET_ARG2(answer),
598 IPC_GET_ARG3(answer));
599
600 /* Push one fragment notification to client's queue */
601 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_accept(): notify data\n");
602 fibril_mutex_unlock(&socket->lock);
603}
604
605static void tcp_sock_send(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
606{
607 int socket_id;
608 int fragments;
609 int index;
610 socket_core_t *sock_core;
611 tcp_sockdata_t *socket;
612 ipc_call_t answer;
613 ipc_callid_t wcallid;
614 size_t length;
615 uint8_t buffer[TCP_SOCK_FRAGMENT_SIZE];
616 tcp_error_t trc;
617 int rc;
618
619 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_send()");
620 socket_id = SOCKET_GET_SOCKET_ID(call);
621 fragments = SOCKET_GET_DATA_FRAGMENTS(call);
622 SOCKET_GET_FLAGS(call);
623
624 sock_core = socket_cores_find(&client->sockets, socket_id);
625 if (sock_core == NULL) {
626 async_answer_0(callid, ENOTSOCK);
627 return;
628 }
629
630 socket = (tcp_sockdata_t *)sock_core->specific_data;
631 fibril_mutex_lock(&socket->lock);
632
633 if (socket->conn == NULL) {
634 fibril_mutex_unlock(&socket->lock);
635 async_answer_0(callid, ENOTCONN);
636 return;
637 }
638
639 for (index = 0; index < fragments; index++) {
640 if (!async_data_write_receive(&wcallid, &length)) {
641 fibril_mutex_unlock(&socket->lock);
642 async_answer_0(callid, EINVAL);
643 return;
644 }
645
646 if (length > TCP_SOCK_FRAGMENT_SIZE)
647 length = TCP_SOCK_FRAGMENT_SIZE;
648
649 rc = async_data_write_finalize(wcallid, buffer, length);
650 if (rc != EOK) {
651 fibril_mutex_unlock(&socket->lock);
652 async_answer_0(callid, rc);
653 return;
654 }
655
656 trc = tcp_uc_send(socket->conn, buffer, length, 0);
657
658 switch (trc) {
659 case TCP_EOK:
660 rc = EOK;
661 break;
662 case TCP_ENOTEXIST:
663 rc = ENOTCONN;
664 break;
665 case TCP_ECLOSING:
666 rc = ENOTCONN;
667 break;
668 case TCP_ERESET:
669 rc = ECONNABORTED;
670 break;
671 default:
672 assert(false);
673 }
674
675 if (rc != EOK) {
676 fibril_mutex_unlock(&socket->lock);
677 async_answer_0(callid, rc);
678 return;
679 }
680 }
681
682 IPC_SET_ARG1(answer, 0);
683 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, TCP_SOCK_FRAGMENT_SIZE);
684 async_answer_2(callid, EOK, IPC_GET_ARG1(answer),
685 IPC_GET_ARG2(answer));
686 fibril_mutex_unlock(&socket->lock);
687}
688
689static void tcp_sock_sendto(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
690{
691 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_sendto()");
692 async_answer_0(callid, ENOTSUP);
693}
694
695static void tcp_sock_recvfrom(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
696{
697 log_msg(LOG_DEFAULT, LVL_DEBUG, "%p: tcp_sock_recv[from]()", client);
698
699 int socket_id = SOCKET_GET_SOCKET_ID(call);
700
701 socket_core_t *sock_core =
702 socket_cores_find(&client->sockets, socket_id);
703 if (sock_core == NULL) {
704 async_answer_0(callid, ENOTSOCK);
705 return;
706 }
707
708 tcp_sockdata_t *socket =
709 (tcp_sockdata_t *) sock_core->specific_data;
710
711 fibril_mutex_lock(&socket->lock);
712
713 if (socket->conn == NULL) {
714 fibril_mutex_unlock(&socket->lock);
715 async_answer_0(callid, ENOTCONN);
716 return;
717 }
718
719 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_recvfrom(): lock recv_buffer_lock");
720
721 fibril_mutex_lock(&socket->recv_buffer_lock);
722 while ((socket->recv_buffer_used == 0) &&
723 (socket->recv_error == TCP_EOK)) {
724 log_msg(LOG_DEFAULT, LVL_DEBUG, "wait for recv_buffer_cv + recv_buffer_used != 0");
725 fibril_condvar_wait(&socket->recv_buffer_cv,
726 &socket->recv_buffer_lock);
727 }
728
729 log_msg(LOG_DEFAULT, LVL_DEBUG, "Got data in sock recv_buffer");
730
731 size_t data_len = socket->recv_buffer_used;
732 tcp_error_t trc = socket->recv_error;
733 int rc;
734
735 switch (trc) {
736 case TCP_EOK:
737 rc = EOK;
738 break;
739 case TCP_ENOTEXIST:
740 case TCP_ECLOSING:
741 rc = ENOTCONN;
742 break;
743 case TCP_ERESET:
744 rc = ECONNABORTED;
745 break;
746 default:
747 assert(false);
748 }
749
750 log_msg(LOG_DEFAULT, LVL_DEBUG, "**** recv result -> %d", rc);
751
752 if (rc != EOK) {
753 fibril_mutex_unlock(&socket->recv_buffer_lock);
754 fibril_mutex_unlock(&socket->lock);
755 async_answer_0(callid, rc);
756 return;
757 }
758
759 ipc_callid_t rcallid;
760
761 if (IPC_GET_IMETHOD(call) == NET_SOCKET_RECVFROM) {
762 /* Fill address */
763 tcp_sock_t *rsock = &socket->conn->ident.foreign;
764 struct sockaddr_in addr;
765 struct sockaddr_in6 addr6;
766 size_t addr_length;
767
768 uint16_t addr_af = inet_addr_sockaddr_in(&rsock->addr, &addr,
769 &addr6);
770
771 switch (addr_af) {
772 case AF_INET:
773 addr.sin_port = host2uint16_t_be(rsock->port);
774
775 log_msg(LOG_DEFAULT, LVL_DEBUG, "addr read receive");
776 if (!async_data_read_receive(&rcallid, &addr_length)) {
777 fibril_mutex_unlock(&socket->recv_buffer_lock);
778 fibril_mutex_unlock(&socket->lock);
779 async_answer_0(callid, EINVAL);
780 return;
781 }
782
783 if (addr_length > sizeof(addr))
784 addr_length = sizeof(addr);
785
786 log_msg(LOG_DEFAULT, LVL_DEBUG, "addr read finalize");
787 rc = async_data_read_finalize(rcallid, &addr, addr_length);
788 if (rc != EOK) {
789 fibril_mutex_unlock(&socket->recv_buffer_lock);
790 fibril_mutex_unlock(&socket->lock);
791 async_answer_0(callid, EINVAL);
792 return;
793 }
794
795 break;
796 case AF_INET6:
797 addr6.sin6_port = host2uint16_t_be(rsock->port);
798
799 log_msg(LOG_DEFAULT, LVL_DEBUG, "addr6 read receive");
800 if (!async_data_read_receive(&rcallid, &addr_length)) {
801 fibril_mutex_unlock(&socket->recv_buffer_lock);
802 fibril_mutex_unlock(&socket->lock);
803 async_answer_0(callid, EINVAL);
804 return;
805 }
806
807 if (addr_length > sizeof(addr6))
808 addr_length = sizeof(addr6);
809
810 log_msg(LOG_DEFAULT, LVL_DEBUG, "addr6 read finalize");
811 rc = async_data_read_finalize(rcallid, &addr6, addr_length);
812 if (rc != EOK) {
813 fibril_mutex_unlock(&socket->recv_buffer_lock);
814 fibril_mutex_unlock(&socket->lock);
815 async_answer_0(callid, EINVAL);
816 return;
817 }
818
819 break;
820 default:
821 fibril_mutex_unlock(&socket->recv_buffer_lock);
822 fibril_mutex_unlock(&socket->lock);
823 async_answer_0(callid, EINVAL);
824 return;
825 }
826 }
827
828 log_msg(LOG_DEFAULT, LVL_DEBUG, "data read receive");
829
830 size_t length;
831 if (!async_data_read_receive(&rcallid, &length)) {
832 fibril_mutex_unlock(&socket->recv_buffer_lock);
833 fibril_mutex_unlock(&socket->lock);
834 async_answer_0(callid, EINVAL);
835 return;
836 }
837
838 if (length > data_len)
839 length = data_len;
840
841 log_msg(LOG_DEFAULT, LVL_DEBUG, "data read finalize");
842
843 rc = async_data_read_finalize(rcallid, socket->recv_buffer, length);
844
845 socket->recv_buffer_used -= length;
846
847 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_recvfrom: %zu left in buffer",
848 socket->recv_buffer_used);
849
850 if (socket->recv_buffer_used > 0) {
851 memmove(socket->recv_buffer, socket->recv_buffer + length,
852 socket->recv_buffer_used);
853 tcp_sock_notify_data(socket->sock_core);
854 }
855
856 fibril_condvar_broadcast(&socket->recv_buffer_cv);
857
858 if ((length < data_len) && (rc == EOK))
859 rc = EOVERFLOW;
860
861 ipc_call_t answer;
862
863 SOCKET_SET_READ_DATA_LENGTH(answer, length);
864 async_answer_1(callid, EOK, IPC_GET_ARG1(answer));
865
866 fibril_mutex_unlock(&socket->recv_buffer_lock);
867 fibril_mutex_unlock(&socket->lock);
868}
869
870static void tcp_sock_close(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
871{
872 int socket_id;
873 socket_core_t *sock_core;
874 tcp_sockdata_t *socket;
875 tcp_error_t trc;
876 int rc;
877
878 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_close()");
879 socket_id = SOCKET_GET_SOCKET_ID(call);
880
881 sock_core = socket_cores_find(&client->sockets, socket_id);
882 if (sock_core == NULL) {
883 async_answer_0(callid, ENOTSOCK);
884 return;
885 }
886
887 socket = (tcp_sockdata_t *)sock_core->specific_data;
888 fibril_mutex_lock(&socket->lock);
889
890 if (socket->conn != NULL) {
891 trc = tcp_uc_close(socket->conn);
892 if (trc != TCP_EOK && trc != TCP_ENOTEXIST) {
893 fibril_mutex_unlock(&socket->lock);
894 async_answer_0(callid, EBADF);
895 return;
896 }
897 }
898
899 /* Grab recv_buffer_lock because of CV wait in tcp_sock_recv_fibril() */
900 fibril_mutex_lock(&socket->recv_buffer_lock);
901 socket->sock_core = NULL;
902 fibril_mutex_unlock(&socket->recv_buffer_lock);
903
904 rc = socket_destroy(NULL, socket_id, &client->sockets, &gsock,
905 tcp_free_sock_data);
906 if (rc != EOK) {
907 fibril_mutex_unlock(&socket->lock);
908 async_answer_0(callid, rc);
909 return;
910 }
911
912 fibril_mutex_unlock(&socket->lock);
913 async_answer_0(callid, EOK);
914}
915
916static void tcp_sock_getsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
917{
918 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_getsockopt()");
919 async_answer_0(callid, ENOTSUP);
920}
921
922static void tcp_sock_setsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
923{
924 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_setsockopt()");
925 async_answer_0(callid, ENOTSUP);
926}
927
928/** Called when connection state changes. */
929static void tcp_sock_cstate_cb(tcp_conn_t *conn, void *arg)
930{
931 tcp_conn_status_t cstatus;
932 tcp_sock_lconn_t *lconn = (tcp_sock_lconn_t *)arg;
933 tcp_sockdata_t *socket = lconn->socket;
934
935 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_cstate_cb()");
936 fibril_mutex_lock(&socket->lock);
937 assert(conn == lconn->conn);
938
939 tcp_uc_status(conn, &cstatus);
940 if (cstatus.cstate != st_established) {
941 fibril_mutex_unlock(&socket->lock);
942 return;
943 }
944
945 assert_link_not_used(&lconn->ready_list);
946 list_append(&lconn->ready_list, &socket->ready);
947
948 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_cstate_cb(): notify accept");
949
950 /* Push one accept notification to client's queue */
951 tcp_sock_notify_aconn(socket->sock_core);
952 fibril_mutex_unlock(&socket->lock);
953}
954
955static int tcp_sock_recv_fibril(void *arg)
956{
957 tcp_sockdata_t *sock = (tcp_sockdata_t *)arg;
958 size_t data_len;
959 xflags_t xflags;
960 tcp_error_t trc;
961
962 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_recv_fibril()");
963
964 fibril_mutex_lock(&sock->recv_buffer_lock);
965
966 while (true) {
967 log_msg(LOG_DEFAULT, LVL_DEBUG, "call tcp_uc_receive()");
968 while (sock->recv_buffer_used != 0 && sock->sock_core != NULL)
969 fibril_condvar_wait(&sock->recv_buffer_cv,
970 &sock->recv_buffer_lock);
971
972 trc = tcp_uc_receive(sock->conn, sock->recv_buffer,
973 TCP_SOCK_FRAGMENT_SIZE, &data_len, &xflags);
974
975 if (trc != TCP_EOK) {
976 sock->recv_error = trc;
977 fibril_condvar_broadcast(&sock->recv_buffer_cv);
978 if (sock->sock_core != NULL)
979 tcp_sock_notify_data(sock->sock_core);
980 break;
981 }
982
983 log_msg(LOG_DEFAULT, LVL_DEBUG, "got data - broadcast recv_buffer_cv");
984
985 sock->recv_buffer_used = data_len;
986 fibril_condvar_broadcast(&sock->recv_buffer_cv);
987 if (sock->sock_core != NULL)
988 tcp_sock_notify_data(sock->sock_core);
989 }
990
991 fibril_mutex_unlock(&sock->recv_buffer_lock);
992
993 tcp_uc_delete(sock->conn);
994
995 return 0;
996}
997
998static void tcp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
999{
1000 ipc_callid_t callid;
1001 ipc_call_t call;
1002 tcp_client_t client;
1003
1004 /* Accept the connection */
1005 async_answer_0(iid, EOK);
1006
1007 client.sess = async_callback_receive(EXCHANGE_SERIALIZE);
1008 socket_cores_initialize(&client.sockets);
1009
1010 while (true) {
1011 callid = async_get_call(&call);
1012 if (!IPC_GET_IMETHOD(call))
1013 break;
1014
1015 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_connection: METHOD=%d\n",
1016 (int)IPC_GET_IMETHOD(call));
1017
1018 switch (IPC_GET_IMETHOD(call)) {
1019 case NET_SOCKET:
1020 tcp_sock_socket(&client, callid, call);
1021 break;
1022 case NET_SOCKET_BIND:
1023 tcp_sock_bind(&client, callid, call);
1024 break;
1025 case NET_SOCKET_LISTEN:
1026 tcp_sock_listen(&client, callid, call);
1027 break;
1028 case NET_SOCKET_CONNECT:
1029 tcp_sock_connect(&client, callid, call);
1030 break;
1031 case NET_SOCKET_ACCEPT:
1032 tcp_sock_accept(&client, callid, call);
1033 break;
1034 case NET_SOCKET_SEND:
1035 tcp_sock_send(&client, callid, call);
1036 break;
1037 case NET_SOCKET_SENDTO:
1038 tcp_sock_sendto(&client, callid, call);
1039 break;
1040 case NET_SOCKET_RECV:
1041 case NET_SOCKET_RECVFROM:
1042 tcp_sock_recvfrom(&client, callid, call);
1043 break;
1044 case NET_SOCKET_CLOSE:
1045 tcp_sock_close(&client, callid, call);
1046 break;
1047 case NET_SOCKET_GETSOCKOPT:
1048 tcp_sock_getsockopt(&client, callid, call);
1049 break;
1050 case NET_SOCKET_SETSOCKOPT:
1051 tcp_sock_setsockopt(&client, callid, call);
1052 break;
1053 default:
1054 async_answer_0(callid, ENOTSUP);
1055 break;
1056 }
1057 }
1058
1059 /* Clean up */
1060 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_connection: Clean up");
1061 async_hangup(client.sess);
1062 socket_cores_release(NULL, &client.sockets, &gsock, tcp_free_sock_data);
1063}
1064
1065/**
1066 * @}
1067 */
Note: See TracBrowser for help on using the repository browser.