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

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

do not allocate the buffer on stack (thx Antonin Steinhauser)

  • Property mode set to 100644
File size: 26.0 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 tcp_error_t trc;
616 int rc;
617
618 uint8_t *buffer = calloc(TCP_SOCK_FRAGMENT_SIZE, 1);
619 if (buffer == NULL) {
620 async_answer_0(callid, ENOMEM);
621 return;
622 }
623
624 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_send()");
625 socket_id = SOCKET_GET_SOCKET_ID(call);
626 fragments = SOCKET_GET_DATA_FRAGMENTS(call);
627 SOCKET_GET_FLAGS(call);
628
629 sock_core = socket_cores_find(&client->sockets, socket_id);
630 if (sock_core == NULL) {
631 async_answer_0(callid, ENOTSOCK);
632 goto out;
633 }
634
635 socket = (tcp_sockdata_t *)sock_core->specific_data;
636 fibril_mutex_lock(&socket->lock);
637
638 if (socket->conn == NULL) {
639 fibril_mutex_unlock(&socket->lock);
640 async_answer_0(callid, ENOTCONN);
641 return;
642 }
643
644 for (index = 0; index < fragments; index++) {
645 if (!async_data_write_receive(&wcallid, &length)) {
646 fibril_mutex_unlock(&socket->lock);
647 async_answer_0(callid, EINVAL);
648 goto out;
649 }
650
651 if (length > TCP_SOCK_FRAGMENT_SIZE)
652 length = TCP_SOCK_FRAGMENT_SIZE;
653
654 rc = async_data_write_finalize(wcallid, buffer, length);
655 if (rc != EOK) {
656 fibril_mutex_unlock(&socket->lock);
657 async_answer_0(callid, rc);
658 goto out;
659 }
660
661 trc = tcp_uc_send(socket->conn, buffer, length, 0);
662
663 switch (trc) {
664 case TCP_EOK:
665 rc = EOK;
666 break;
667 case TCP_ENOTEXIST:
668 rc = ENOTCONN;
669 break;
670 case TCP_ECLOSING:
671 rc = ENOTCONN;
672 break;
673 case TCP_ERESET:
674 rc = ECONNABORTED;
675 break;
676 default:
677 assert(false);
678 }
679
680 if (rc != EOK) {
681 fibril_mutex_unlock(&socket->lock);
682 async_answer_0(callid, rc);
683 goto out;
684 }
685 }
686
687 IPC_SET_ARG1(answer, 0);
688 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, TCP_SOCK_FRAGMENT_SIZE);
689 async_answer_2(callid, EOK, IPC_GET_ARG1(answer),
690 IPC_GET_ARG2(answer));
691 fibril_mutex_unlock(&socket->lock);
692
693out:
694 free(buffer);
695}
696
697static void tcp_sock_sendto(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
698{
699 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_sendto()");
700 async_answer_0(callid, ENOTSUP);
701}
702
703static void tcp_sock_recvfrom(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
704{
705 log_msg(LOG_DEFAULT, LVL_DEBUG, "%p: tcp_sock_recv[from]()", client);
706
707 int socket_id = SOCKET_GET_SOCKET_ID(call);
708
709 socket_core_t *sock_core =
710 socket_cores_find(&client->sockets, socket_id);
711 if (sock_core == NULL) {
712 async_answer_0(callid, ENOTSOCK);
713 return;
714 }
715
716 tcp_sockdata_t *socket =
717 (tcp_sockdata_t *) sock_core->specific_data;
718
719 fibril_mutex_lock(&socket->lock);
720
721 if (socket->conn == NULL) {
722 fibril_mutex_unlock(&socket->lock);
723 async_answer_0(callid, ENOTCONN);
724 return;
725 }
726
727 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_recvfrom(): lock recv_buffer_lock");
728
729 fibril_mutex_lock(&socket->recv_buffer_lock);
730 while ((socket->recv_buffer_used == 0) &&
731 (socket->recv_error == TCP_EOK)) {
732 log_msg(LOG_DEFAULT, LVL_DEBUG, "wait for recv_buffer_cv + recv_buffer_used != 0");
733 fibril_condvar_wait(&socket->recv_buffer_cv,
734 &socket->recv_buffer_lock);
735 }
736
737 log_msg(LOG_DEFAULT, LVL_DEBUG, "Got data in sock recv_buffer");
738
739 size_t data_len = socket->recv_buffer_used;
740 tcp_error_t trc = socket->recv_error;
741 int rc;
742
743 switch (trc) {
744 case TCP_EOK:
745 rc = EOK;
746 break;
747 case TCP_ENOTEXIST:
748 case TCP_ECLOSING:
749 rc = ENOTCONN;
750 break;
751 case TCP_ERESET:
752 rc = ECONNABORTED;
753 break;
754 default:
755 assert(false);
756 }
757
758 log_msg(LOG_DEFAULT, LVL_DEBUG, "**** recv result -> %d", rc);
759
760 if (rc != EOK) {
761 fibril_mutex_unlock(&socket->recv_buffer_lock);
762 fibril_mutex_unlock(&socket->lock);
763 async_answer_0(callid, rc);
764 return;
765 }
766
767 ipc_callid_t rcallid;
768
769 if (IPC_GET_IMETHOD(call) == NET_SOCKET_RECVFROM) {
770 /* Fill address */
771 tcp_sock_t *rsock = &socket->conn->ident.foreign;
772 struct sockaddr_in addr;
773 struct sockaddr_in6 addr6;
774 size_t addr_length;
775
776 uint16_t addr_af = inet_addr_sockaddr_in(&rsock->addr, &addr,
777 &addr6);
778
779 switch (addr_af) {
780 case AF_INET:
781 addr.sin_port = host2uint16_t_be(rsock->port);
782
783 log_msg(LOG_DEFAULT, LVL_DEBUG, "addr read receive");
784 if (!async_data_read_receive(&rcallid, &addr_length)) {
785 fibril_mutex_unlock(&socket->recv_buffer_lock);
786 fibril_mutex_unlock(&socket->lock);
787 async_answer_0(callid, EINVAL);
788 return;
789 }
790
791 if (addr_length > sizeof(addr))
792 addr_length = sizeof(addr);
793
794 log_msg(LOG_DEFAULT, LVL_DEBUG, "addr read finalize");
795 rc = async_data_read_finalize(rcallid, &addr, addr_length);
796 if (rc != EOK) {
797 fibril_mutex_unlock(&socket->recv_buffer_lock);
798 fibril_mutex_unlock(&socket->lock);
799 async_answer_0(callid, EINVAL);
800 return;
801 }
802
803 break;
804 case AF_INET6:
805 addr6.sin6_port = host2uint16_t_be(rsock->port);
806
807 log_msg(LOG_DEFAULT, LVL_DEBUG, "addr6 read receive");
808 if (!async_data_read_receive(&rcallid, &addr_length)) {
809 fibril_mutex_unlock(&socket->recv_buffer_lock);
810 fibril_mutex_unlock(&socket->lock);
811 async_answer_0(callid, EINVAL);
812 return;
813 }
814
815 if (addr_length > sizeof(addr6))
816 addr_length = sizeof(addr6);
817
818 log_msg(LOG_DEFAULT, LVL_DEBUG, "addr6 read finalize");
819 rc = async_data_read_finalize(rcallid, &addr6, addr_length);
820 if (rc != EOK) {
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 break;
828 default:
829 fibril_mutex_unlock(&socket->recv_buffer_lock);
830 fibril_mutex_unlock(&socket->lock);
831 async_answer_0(callid, EINVAL);
832 return;
833 }
834 }
835
836 log_msg(LOG_DEFAULT, LVL_DEBUG, "data read receive");
837
838 size_t length;
839 if (!async_data_read_receive(&rcallid, &length)) {
840 fibril_mutex_unlock(&socket->recv_buffer_lock);
841 fibril_mutex_unlock(&socket->lock);
842 async_answer_0(callid, EINVAL);
843 return;
844 }
845
846 if (length > data_len)
847 length = data_len;
848
849 log_msg(LOG_DEFAULT, LVL_DEBUG, "data read finalize");
850
851 rc = async_data_read_finalize(rcallid, socket->recv_buffer, length);
852
853 socket->recv_buffer_used -= length;
854
855 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_recvfrom: %zu left in buffer",
856 socket->recv_buffer_used);
857
858 if (socket->recv_buffer_used > 0) {
859 memmove(socket->recv_buffer, socket->recv_buffer + length,
860 socket->recv_buffer_used);
861 tcp_sock_notify_data(socket->sock_core);
862 }
863
864 fibril_condvar_broadcast(&socket->recv_buffer_cv);
865
866 if ((length < data_len) && (rc == EOK))
867 rc = EOVERFLOW;
868
869 ipc_call_t answer;
870
871 SOCKET_SET_READ_DATA_LENGTH(answer, length);
872 async_answer_1(callid, EOK, IPC_GET_ARG1(answer));
873
874 fibril_mutex_unlock(&socket->recv_buffer_lock);
875 fibril_mutex_unlock(&socket->lock);
876}
877
878static void tcp_sock_close(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
879{
880 int socket_id;
881 socket_core_t *sock_core;
882 tcp_sockdata_t *socket;
883 tcp_error_t trc;
884 int rc;
885
886 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_close()");
887 socket_id = SOCKET_GET_SOCKET_ID(call);
888
889 sock_core = socket_cores_find(&client->sockets, socket_id);
890 if (sock_core == NULL) {
891 async_answer_0(callid, ENOTSOCK);
892 return;
893 }
894
895 socket = (tcp_sockdata_t *)sock_core->specific_data;
896 fibril_mutex_lock(&socket->lock);
897
898 if (socket->conn != NULL) {
899 trc = tcp_uc_close(socket->conn);
900 if (trc != TCP_EOK && trc != TCP_ENOTEXIST) {
901 fibril_mutex_unlock(&socket->lock);
902 async_answer_0(callid, EBADF);
903 return;
904 }
905 }
906
907 /* Grab recv_buffer_lock because of CV wait in tcp_sock_recv_fibril() */
908 fibril_mutex_lock(&socket->recv_buffer_lock);
909 socket->sock_core = NULL;
910 fibril_mutex_unlock(&socket->recv_buffer_lock);
911
912 rc = socket_destroy(NULL, socket_id, &client->sockets, &gsock,
913 tcp_free_sock_data);
914 if (rc != EOK) {
915 fibril_mutex_unlock(&socket->lock);
916 async_answer_0(callid, rc);
917 return;
918 }
919
920 fibril_mutex_unlock(&socket->lock);
921 async_answer_0(callid, EOK);
922}
923
924static void tcp_sock_getsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
925{
926 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_getsockopt()");
927 async_answer_0(callid, ENOTSUP);
928}
929
930static void tcp_sock_setsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
931{
932 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_setsockopt()");
933 async_answer_0(callid, ENOTSUP);
934}
935
936/** Called when connection state changes. */
937static void tcp_sock_cstate_cb(tcp_conn_t *conn, void *arg)
938{
939 tcp_conn_status_t cstatus;
940 tcp_sock_lconn_t *lconn = (tcp_sock_lconn_t *)arg;
941 tcp_sockdata_t *socket = lconn->socket;
942
943 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_cstate_cb()");
944 fibril_mutex_lock(&socket->lock);
945 assert(conn == lconn->conn);
946
947 tcp_uc_status(conn, &cstatus);
948 if (cstatus.cstate != st_established) {
949 fibril_mutex_unlock(&socket->lock);
950 return;
951 }
952
953 assert_link_not_used(&lconn->ready_list);
954 list_append(&lconn->ready_list, &socket->ready);
955
956 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_cstate_cb(): notify accept");
957
958 /* Push one accept notification to client's queue */
959 tcp_sock_notify_aconn(socket->sock_core);
960 fibril_mutex_unlock(&socket->lock);
961}
962
963static int tcp_sock_recv_fibril(void *arg)
964{
965 tcp_sockdata_t *sock = (tcp_sockdata_t *)arg;
966 size_t data_len;
967 xflags_t xflags;
968 tcp_error_t trc;
969
970 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_recv_fibril()");
971
972 fibril_mutex_lock(&sock->recv_buffer_lock);
973
974 while (true) {
975 log_msg(LOG_DEFAULT, LVL_DEBUG, "call tcp_uc_receive()");
976 while (sock->recv_buffer_used != 0 && sock->sock_core != NULL)
977 fibril_condvar_wait(&sock->recv_buffer_cv,
978 &sock->recv_buffer_lock);
979
980 trc = tcp_uc_receive(sock->conn, sock->recv_buffer,
981 TCP_SOCK_FRAGMENT_SIZE, &data_len, &xflags);
982
983 if (trc != TCP_EOK) {
984 sock->recv_error = trc;
985 fibril_condvar_broadcast(&sock->recv_buffer_cv);
986 if (sock->sock_core != NULL)
987 tcp_sock_notify_data(sock->sock_core);
988 break;
989 }
990
991 log_msg(LOG_DEFAULT, LVL_DEBUG, "got data - broadcast recv_buffer_cv");
992
993 sock->recv_buffer_used = data_len;
994 fibril_condvar_broadcast(&sock->recv_buffer_cv);
995 if (sock->sock_core != NULL)
996 tcp_sock_notify_data(sock->sock_core);
997 }
998
999 fibril_mutex_unlock(&sock->recv_buffer_lock);
1000
1001 tcp_uc_delete(sock->conn);
1002
1003 return 0;
1004}
1005
1006static void tcp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
1007{
1008 ipc_callid_t callid;
1009 ipc_call_t call;
1010 tcp_client_t client;
1011
1012 /* Accept the connection */
1013 async_answer_0(iid, EOK);
1014
1015 client.sess = async_callback_receive(EXCHANGE_SERIALIZE);
1016 socket_cores_initialize(&client.sockets);
1017
1018 while (true) {
1019 callid = async_get_call(&call);
1020 if (!IPC_GET_IMETHOD(call))
1021 break;
1022
1023 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_connection: METHOD=%d\n",
1024 (int)IPC_GET_IMETHOD(call));
1025
1026 switch (IPC_GET_IMETHOD(call)) {
1027 case NET_SOCKET:
1028 tcp_sock_socket(&client, callid, call);
1029 break;
1030 case NET_SOCKET_BIND:
1031 tcp_sock_bind(&client, callid, call);
1032 break;
1033 case NET_SOCKET_LISTEN:
1034 tcp_sock_listen(&client, callid, call);
1035 break;
1036 case NET_SOCKET_CONNECT:
1037 tcp_sock_connect(&client, callid, call);
1038 break;
1039 case NET_SOCKET_ACCEPT:
1040 tcp_sock_accept(&client, callid, call);
1041 break;
1042 case NET_SOCKET_SEND:
1043 tcp_sock_send(&client, callid, call);
1044 break;
1045 case NET_SOCKET_SENDTO:
1046 tcp_sock_sendto(&client, callid, call);
1047 break;
1048 case NET_SOCKET_RECV:
1049 case NET_SOCKET_RECVFROM:
1050 tcp_sock_recvfrom(&client, callid, call);
1051 break;
1052 case NET_SOCKET_CLOSE:
1053 tcp_sock_close(&client, callid, call);
1054 break;
1055 case NET_SOCKET_GETSOCKOPT:
1056 tcp_sock_getsockopt(&client, callid, call);
1057 break;
1058 case NET_SOCKET_SETSOCKOPT:
1059 tcp_sock_setsockopt(&client, callid, call);
1060 break;
1061 default:
1062 async_answer_0(callid, ENOTSUP);
1063 break;
1064 }
1065 }
1066
1067 /* Clean up */
1068 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_connection: Clean up");
1069 async_hangup(client.sess);
1070 socket_cores_release(NULL, &client.sockets, &gsock, tcp_free_sock_data);
1071}
1072
1073/**
1074 * @}
1075 */
Note: See TracBrowser for help on using the repository browser.