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

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

use new network address infrastructure (towards IPv6 support)

  • Property mode set to 100644
File size: 24.6 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, ipc_call_t call)
357{
358 int rc;
359 struct sockaddr_in *addr;
360 int socket_id;
361 size_t addr_len;
362 socket_core_t *sock_core;
363 tcp_sockdata_t *socket;
364 tcp_error_t trc;
365 tcp_sock_t lsocket;
366 tcp_sock_t fsocket;
367
368 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_connect()");
369
370 rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &addr_len);
371 if (rc != EOK || addr_len != sizeof(struct sockaddr_in)) {
372 async_answer_0(callid, rc);
373 return;
374 }
375
376 socket_id = SOCKET_GET_SOCKET_ID(call);
377
378 sock_core = socket_cores_find(&client->sockets, socket_id);
379 if (sock_core == NULL) {
380 async_answer_0(callid, ENOTSOCK);
381 return;
382 }
383
384 socket = (tcp_sockdata_t *)sock_core->specific_data;
385 if (sock_core->port <= 0) {
386 rc = socket_bind_free_port(&gsock, sock_core,
387 TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
388 last_used_port);
389 if (rc != EOK) {
390 async_answer_0(callid, rc);
391 return;
392 }
393
394 last_used_port = sock_core->port;
395 }
396
397 fibril_mutex_lock(&socket->lock);
398
399 if (inet_addr_is_any(&socket->laddr)) {
400 /* Determine local IP address */
401 inet_addr_t loc_addr;
402 inet_addr_t rem_addr;
403
404 inet_addr_unpack(uint32_t_be2host(addr->sin_addr.s_addr),
405 &rem_addr);
406 rc = inet_get_srcaddr(&rem_addr, 0, &loc_addr);
407 if (rc != EOK) {
408 fibril_mutex_unlock(&socket->lock);
409 async_answer_0(callid, rc);
410 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_connect: Failed to "
411 "determine local address.");
412 return;
413 }
414
415 socket->laddr = loc_addr;
416 }
417
418 lsocket.addr = socket->laddr;
419 lsocket.port = sock_core->port;
420
421 inet_addr_unpack(uint32_t_be2host(addr->sin_addr.s_addr),
422 &fsocket.addr);
423 fsocket.port = uint16_t_be2host(addr->sin_port);
424
425 trc = tcp_uc_open(&lsocket, &fsocket, ap_active, 0, &socket->conn);
426
427 if (socket->conn != NULL)
428 socket->conn->name = (char *)"C";
429
430 fibril_mutex_unlock(&socket->lock);
431
432 switch (trc) {
433 case TCP_EOK:
434 rc = EOK;
435 break;
436 case TCP_ERESET:
437 rc = ECONNREFUSED;
438 break;
439 default:
440 assert(false);
441 }
442
443 if (rc == EOK)
444 fibril_add_ready(socket->recv_fibril);
445
446 async_answer_0(callid, rc);
447}
448
449static void tcp_sock_accept(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
450{
451 ipc_call_t answer;
452 int socket_id;
453 int asock_id;
454 socket_core_t *sock_core;
455 tcp_sockdata_t *socket;
456 tcp_sockdata_t *asocket;
457 tcp_error_t trc;
458 tcp_sock_t lsocket;
459 tcp_sock_t fsocket;
460 tcp_conn_t *conn;
461 tcp_conn_t *rconn;
462 tcp_sock_lconn_t *lconn;
463 int rc;
464
465 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_accept()");
466
467 socket_id = SOCKET_GET_SOCKET_ID(call);
468 asock_id = SOCKET_GET_NEW_SOCKET_ID(call);
469
470 sock_core = socket_cores_find(&client->sockets, socket_id);
471 if (sock_core == NULL) {
472 async_answer_0(callid, ENOTSOCK);
473 return;
474 }
475
476 if (sock_core->port <= 0) {
477 rc = socket_bind_free_port(&gsock, sock_core,
478 TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
479 last_used_port);
480 if (rc != EOK) {
481 async_answer_0(callid, rc);
482 return;
483 }
484
485 last_used_port = sock_core->port;
486 }
487
488 socket = (tcp_sockdata_t *)sock_core->specific_data;
489 fibril_mutex_lock(&socket->lock);
490
491 log_msg(LOG_DEFAULT, LVL_DEBUG, " - verify socket->conn");
492 if (socket->conn != NULL) {
493 fibril_mutex_unlock(&socket->lock);
494 async_answer_0(callid, EINVAL);
495 return;
496 }
497
498 if (list_empty(&socket->ready)) {
499 fibril_mutex_unlock(&socket->lock);
500 async_answer_0(callid, ENOENT);
501 return;
502 }
503
504 lconn = list_get_instance(list_first(&socket->ready),
505 tcp_sock_lconn_t, ready_list);
506 list_remove(&lconn->ready_list);
507
508 conn = lconn->conn;
509 tcp_uc_set_cstate_cb(conn, NULL, NULL);
510
511 /* Replenish listening connection */
512
513 inet_addr_any(&lsocket.addr);
514 lsocket.port = sock_core->port;
515
516 inet_addr_any(&fsocket.addr);
517 fsocket.port = TCP_PORT_ANY;
518
519 trc = tcp_uc_open(&lsocket, &fsocket, ap_passive, tcp_open_nonblock,
520 &rconn);
521 if (rconn == NULL) {
522 /* XXX Clean up */
523 fibril_mutex_unlock(&socket->lock);
524 async_answer_0(callid, ENOMEM);
525 return;
526 }
527
528 tcp_uc_set_cstate_cb(rconn, tcp_sock_cstate_cb, lconn);
529
530 assert(trc == TCP_EOK);
531 rconn->name = (char *)"S";
532
533 lconn->conn = rconn;
534
535 /* Allocate socket for accepted connection */
536
537 rc = tcp_sock_create(client, &asocket);
538 if (rc != EOK) {
539 fibril_mutex_unlock(&socket->lock);
540 async_answer_0(callid, rc);
541 return;
542 }
543
544 asocket->conn = conn;
545 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_accept():create asocket\n");
546
547 rc = tcp_sock_finish_setup(asocket, &asock_id);
548 if (rc != EOK) {
549 tcp_sock_uncreate(asocket);
550 fibril_mutex_unlock(&socket->lock);
551 async_answer_0(callid, rc);
552 return;
553 }
554
555 fibril_add_ready(asocket->recv_fibril);
556
557 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_accept(): find acore\n");
558
559 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, TCP_SOCK_FRAGMENT_SIZE);
560 SOCKET_SET_SOCKET_ID(answer, asock_id);
561 SOCKET_SET_ADDRESS_LENGTH(answer, sizeof(struct sockaddr_in));
562
563 async_answer_3(callid, asocket->sock_core->socket_id,
564 IPC_GET_ARG1(answer), IPC_GET_ARG2(answer),
565 IPC_GET_ARG3(answer));
566
567 /* Push one fragment notification to client's queue */
568 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_accept(): notify data\n");
569 fibril_mutex_unlock(&socket->lock);
570}
571
572static void tcp_sock_send(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
573{
574 int socket_id;
575 int fragments;
576 int index;
577 socket_core_t *sock_core;
578 tcp_sockdata_t *socket;
579 ipc_call_t answer;
580 ipc_callid_t wcallid;
581 size_t length;
582 uint8_t buffer[TCP_SOCK_FRAGMENT_SIZE];
583 tcp_error_t trc;
584 int rc;
585
586 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_send()");
587 socket_id = SOCKET_GET_SOCKET_ID(call);
588 fragments = SOCKET_GET_DATA_FRAGMENTS(call);
589 SOCKET_GET_FLAGS(call);
590
591 sock_core = socket_cores_find(&client->sockets, socket_id);
592 if (sock_core == NULL) {
593 async_answer_0(callid, ENOTSOCK);
594 return;
595 }
596
597 socket = (tcp_sockdata_t *)sock_core->specific_data;
598 fibril_mutex_lock(&socket->lock);
599
600 if (socket->conn == NULL) {
601 fibril_mutex_unlock(&socket->lock);
602 async_answer_0(callid, ENOTCONN);
603 return;
604 }
605
606 for (index = 0; index < fragments; index++) {
607 if (!async_data_write_receive(&wcallid, &length)) {
608 fibril_mutex_unlock(&socket->lock);
609 async_answer_0(callid, EINVAL);
610 return;
611 }
612
613 if (length > TCP_SOCK_FRAGMENT_SIZE)
614 length = TCP_SOCK_FRAGMENT_SIZE;
615
616 rc = async_data_write_finalize(wcallid, buffer, length);
617 if (rc != EOK) {
618 fibril_mutex_unlock(&socket->lock);
619 async_answer_0(callid, rc);
620 return;
621 }
622
623 trc = tcp_uc_send(socket->conn, buffer, length, 0);
624
625 switch (trc) {
626 case TCP_EOK:
627 rc = EOK;
628 break;
629 case TCP_ENOTEXIST:
630 rc = ENOTCONN;
631 break;
632 case TCP_ECLOSING:
633 rc = ENOTCONN;
634 break;
635 case TCP_ERESET:
636 rc = ECONNABORTED;
637 break;
638 default:
639 assert(false);
640 }
641
642 if (rc != EOK) {
643 fibril_mutex_unlock(&socket->lock);
644 async_answer_0(callid, rc);
645 return;
646 }
647 }
648
649 IPC_SET_ARG1(answer, 0);
650 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, TCP_SOCK_FRAGMENT_SIZE);
651 async_answer_2(callid, EOK, IPC_GET_ARG1(answer),
652 IPC_GET_ARG2(answer));
653 fibril_mutex_unlock(&socket->lock);
654}
655
656static void tcp_sock_sendto(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
657{
658 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_sendto()");
659 async_answer_0(callid, ENOTSUP);
660}
661
662static void tcp_sock_recvfrom(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
663{
664 int socket_id;
665 int flags;
666 size_t addr_length, length;
667 socket_core_t *sock_core;
668 tcp_sockdata_t *socket;
669 ipc_call_t answer;
670 ipc_callid_t rcallid;
671 size_t data_len;
672 struct sockaddr_in addr;
673 tcp_sock_t *rsock;
674 int rc;
675
676 log_msg(LOG_DEFAULT, LVL_DEBUG, "%p: tcp_sock_recv[from]()", client);
677
678 socket_id = SOCKET_GET_SOCKET_ID(call);
679 flags = SOCKET_GET_FLAGS(call);
680
681 sock_core = socket_cores_find(&client->sockets, socket_id);
682 if (sock_core == NULL) {
683 async_answer_0(callid, ENOTSOCK);
684 return;
685 }
686
687 socket = (tcp_sockdata_t *)sock_core->specific_data;
688 fibril_mutex_lock(&socket->lock);
689
690 if (socket->conn == NULL) {
691 fibril_mutex_unlock(&socket->lock);
692 async_answer_0(callid, ENOTCONN);
693 return;
694 }
695
696 (void)flags;
697
698 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_recvfrom(): lock recv_buffer_lock");
699 fibril_mutex_lock(&socket->recv_buffer_lock);
700 while (socket->recv_buffer_used == 0 && socket->recv_error == TCP_EOK) {
701 log_msg(LOG_DEFAULT, LVL_DEBUG, "wait for recv_buffer_cv + recv_buffer_used != 0");
702 fibril_condvar_wait(&socket->recv_buffer_cv,
703 &socket->recv_buffer_lock);
704 }
705
706 log_msg(LOG_DEFAULT, LVL_DEBUG, "Got data in sock recv_buffer");
707
708 data_len = socket->recv_buffer_used;
709 rc = socket->recv_error;
710
711 switch (socket->recv_error) {
712 case TCP_EOK:
713 rc = EOK;
714 break;
715 case TCP_ENOTEXIST:
716 case TCP_ECLOSING:
717 rc = ENOTCONN;
718 break;
719 case TCP_ERESET:
720 rc = ECONNABORTED;
721 break;
722 default:
723 assert(false);
724 }
725
726 log_msg(LOG_DEFAULT, LVL_DEBUG, "**** recv result -> %d", rc);
727 if (rc != EOK) {
728 fibril_mutex_unlock(&socket->recv_buffer_lock);
729 fibril_mutex_unlock(&socket->lock);
730 async_answer_0(callid, rc);
731 return;
732 }
733
734 if (IPC_GET_IMETHOD(call) == NET_SOCKET_RECVFROM) {
735 /* Fill address */
736 rsock = &socket->conn->ident.foreign;
737
738 uint32_t rsock_addr;
739 int rc = inet_addr_pack(&rsock->addr, &rsock_addr);
740 if (rc != EOK) {
741 fibril_mutex_unlock(&socket->recv_buffer_lock);
742 fibril_mutex_unlock(&socket->lock);
743 async_answer_0(callid, rc);
744 return;
745 }
746
747 addr.sin_family = AF_INET;
748 addr.sin_addr.s_addr = host2uint32_t_be(rsock_addr);
749 addr.sin_port = host2uint16_t_be(rsock->port);
750
751 log_msg(LOG_DEFAULT, LVL_DEBUG, "addr read receive");
752 if (!async_data_read_receive(&rcallid, &addr_length)) {
753 fibril_mutex_unlock(&socket->recv_buffer_lock);
754 fibril_mutex_unlock(&socket->lock);
755 async_answer_0(callid, EINVAL);
756 return;
757 }
758
759 if (addr_length > sizeof(addr))
760 addr_length = sizeof(addr);
761
762 log_msg(LOG_DEFAULT, LVL_DEBUG, "addr read finalize");
763 rc = async_data_read_finalize(rcallid, &addr, addr_length);
764 if (rc != EOK) {
765 fibril_mutex_unlock(&socket->recv_buffer_lock);
766 fibril_mutex_unlock(&socket->lock);
767 async_answer_0(callid, EINVAL);
768 return;
769 }
770 }
771
772 log_msg(LOG_DEFAULT, LVL_DEBUG, "data read receive");
773 if (!async_data_read_receive(&rcallid, &length)) {
774 fibril_mutex_unlock(&socket->recv_buffer_lock);
775 fibril_mutex_unlock(&socket->lock);
776 async_answer_0(callid, EINVAL);
777 return;
778 }
779
780 if (length > data_len)
781 length = data_len;
782
783 log_msg(LOG_DEFAULT, LVL_DEBUG, "data read finalize");
784 rc = async_data_read_finalize(rcallid, socket->recv_buffer, length);
785
786 socket->recv_buffer_used -= length;
787 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_recvfrom: %zu left in buffer",
788 socket->recv_buffer_used);
789 if (socket->recv_buffer_used > 0) {
790 memmove(socket->recv_buffer, socket->recv_buffer + length,
791 socket->recv_buffer_used);
792 tcp_sock_notify_data(socket->sock_core);
793 }
794
795 fibril_condvar_broadcast(&socket->recv_buffer_cv);
796
797 if (length < data_len && rc == EOK)
798 rc = EOVERFLOW;
799
800 SOCKET_SET_READ_DATA_LENGTH(answer, length);
801 async_answer_1(callid, EOK, IPC_GET_ARG1(answer));
802
803 fibril_mutex_unlock(&socket->recv_buffer_lock);
804 fibril_mutex_unlock(&socket->lock);
805}
806
807static void tcp_sock_close(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
808{
809 int socket_id;
810 socket_core_t *sock_core;
811 tcp_sockdata_t *socket;
812 tcp_error_t trc;
813 int rc;
814
815 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_close()");
816 socket_id = SOCKET_GET_SOCKET_ID(call);
817
818 sock_core = socket_cores_find(&client->sockets, socket_id);
819 if (sock_core == NULL) {
820 async_answer_0(callid, ENOTSOCK);
821 return;
822 }
823
824 socket = (tcp_sockdata_t *)sock_core->specific_data;
825 fibril_mutex_lock(&socket->lock);
826
827 if (socket->conn != NULL) {
828 trc = tcp_uc_close(socket->conn);
829 if (trc != TCP_EOK && trc != TCP_ENOTEXIST) {
830 fibril_mutex_unlock(&socket->lock);
831 async_answer_0(callid, EBADF);
832 return;
833 }
834 }
835
836 /* Grab recv_buffer_lock because of CV wait in tcp_sock_recv_fibril() */
837 fibril_mutex_lock(&socket->recv_buffer_lock);
838 socket->sock_core = NULL;
839 fibril_mutex_unlock(&socket->recv_buffer_lock);
840
841 rc = socket_destroy(NULL, socket_id, &client->sockets, &gsock,
842 tcp_free_sock_data);
843 if (rc != EOK) {
844 fibril_mutex_unlock(&socket->lock);
845 async_answer_0(callid, rc);
846 return;
847 }
848
849 fibril_mutex_unlock(&socket->lock);
850 async_answer_0(callid, EOK);
851}
852
853static void tcp_sock_getsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
854{
855 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_getsockopt()");
856 async_answer_0(callid, ENOTSUP);
857}
858
859static void tcp_sock_setsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
860{
861 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_setsockopt()");
862 async_answer_0(callid, ENOTSUP);
863}
864
865/** Called when connection state changes. */
866static void tcp_sock_cstate_cb(tcp_conn_t *conn, void *arg)
867{
868 tcp_conn_status_t cstatus;
869 tcp_sock_lconn_t *lconn = (tcp_sock_lconn_t *)arg;
870 tcp_sockdata_t *socket = lconn->socket;
871
872 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_cstate_cb()");
873 fibril_mutex_lock(&socket->lock);
874 assert(conn == lconn->conn);
875
876 tcp_uc_status(conn, &cstatus);
877 if (cstatus.cstate != st_established) {
878 fibril_mutex_unlock(&socket->lock);
879 return;
880 }
881
882 assert_link_not_used(&lconn->ready_list);
883 list_append(&lconn->ready_list, &socket->ready);
884
885 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_cstate_cb(): notify accept");
886
887 /* Push one accept notification to client's queue */
888 tcp_sock_notify_aconn(socket->sock_core);
889 fibril_mutex_unlock(&socket->lock);
890}
891
892static int tcp_sock_recv_fibril(void *arg)
893{
894 tcp_sockdata_t *sock = (tcp_sockdata_t *)arg;
895 size_t data_len;
896 xflags_t xflags;
897 tcp_error_t trc;
898
899 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_recv_fibril()");
900
901 fibril_mutex_lock(&sock->recv_buffer_lock);
902
903 while (true) {
904 log_msg(LOG_DEFAULT, LVL_DEBUG, "call tcp_uc_receive()");
905 while (sock->recv_buffer_used != 0 && sock->sock_core != NULL)
906 fibril_condvar_wait(&sock->recv_buffer_cv,
907 &sock->recv_buffer_lock);
908
909 trc = tcp_uc_receive(sock->conn, sock->recv_buffer,
910 TCP_SOCK_FRAGMENT_SIZE, &data_len, &xflags);
911
912 if (trc != TCP_EOK) {
913 sock->recv_error = trc;
914 fibril_condvar_broadcast(&sock->recv_buffer_cv);
915 if (sock->sock_core != NULL)
916 tcp_sock_notify_data(sock->sock_core);
917 break;
918 }
919
920 log_msg(LOG_DEFAULT, LVL_DEBUG, "got data - broadcast recv_buffer_cv");
921
922 sock->recv_buffer_used = data_len;
923 fibril_condvar_broadcast(&sock->recv_buffer_cv);
924 if (sock->sock_core != NULL)
925 tcp_sock_notify_data(sock->sock_core);
926 }
927
928 fibril_mutex_unlock(&sock->recv_buffer_lock);
929
930 tcp_uc_delete(sock->conn);
931
932 return 0;
933}
934
935static void tcp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
936{
937 ipc_callid_t callid;
938 ipc_call_t call;
939 tcp_client_t client;
940
941 /* Accept the connection */
942 async_answer_0(iid, EOK);
943
944 client.sess = async_callback_receive(EXCHANGE_SERIALIZE);
945 socket_cores_initialize(&client.sockets);
946
947 while (true) {
948 callid = async_get_call(&call);
949 if (!IPC_GET_IMETHOD(call))
950 break;
951
952 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_connection: METHOD=%d\n",
953 (int)IPC_GET_IMETHOD(call));
954
955 switch (IPC_GET_IMETHOD(call)) {
956 case NET_SOCKET:
957 tcp_sock_socket(&client, callid, call);
958 break;
959 case NET_SOCKET_BIND:
960 tcp_sock_bind(&client, callid, call);
961 break;
962 case NET_SOCKET_LISTEN:
963 tcp_sock_listen(&client, callid, call);
964 break;
965 case NET_SOCKET_CONNECT:
966 tcp_sock_connect(&client, callid, call);
967 break;
968 case NET_SOCKET_ACCEPT:
969 tcp_sock_accept(&client, callid, call);
970 break;
971 case NET_SOCKET_SEND:
972 tcp_sock_send(&client, callid, call);
973 break;
974 case NET_SOCKET_SENDTO:
975 tcp_sock_sendto(&client, callid, call);
976 break;
977 case NET_SOCKET_RECV:
978 case NET_SOCKET_RECVFROM:
979 tcp_sock_recvfrom(&client, callid, call);
980 break;
981 case NET_SOCKET_CLOSE:
982 tcp_sock_close(&client, callid, call);
983 break;
984 case NET_SOCKET_GETSOCKOPT:
985 tcp_sock_getsockopt(&client, callid, call);
986 break;
987 case NET_SOCKET_SETSOCKOPT:
988 tcp_sock_setsockopt(&client, callid, call);
989 break;
990 default:
991 async_answer_0(callid, ENOTSUP);
992 break;
993 }
994 }
995
996 /* Clean up */
997 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_connection: Clean up");
998 async_hangup(client.sess);
999 socket_cores_release(NULL, &client.sockets, &gsock, tcp_free_sock_data);
1000}
1001
1002/**
1003 * @}
1004 */
Note: See TracBrowser for help on using the repository browser.