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

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

cstyle (no change in functionality)

  • Property mode set to 100644
File size: 22.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(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(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(LVL_DEBUG, "tcp_sock_create()");
114 *rsock = NULL;
115
116 sock = calloc(sizeof(tcp_sockdata_t), 1);
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(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(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 return rc;
155
156 sock_core = socket_cores_find(&sock->client->sockets, *sock_id);
157 assert(sock_core != NULL);
158 sock->sock_core = sock_core;
159
160 return EOK;
161}
162
163static void tcp_sock_socket(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
164{
165 tcp_sockdata_t *sock;
166 int sock_id;
167 int rc;
168 ipc_call_t answer;
169
170 log_msg(LVL_DEBUG, "tcp_sock_socket()");
171
172 rc = tcp_sock_create(client, &sock);
173 if (rc != EOK) {
174 async_answer_0(callid, rc);
175 return;
176 }
177
178 sock->laddr.ipv4 = TCP_IPV4_ANY;
179 sock->lconn = NULL;
180 sock->backlog = 0;
181
182 sock_id = SOCKET_GET_SOCKET_ID(call);
183 rc = tcp_sock_finish_setup(sock, &sock_id);
184 if (rc != EOK) {
185 tcp_sock_uncreate(sock);
186 async_answer_0(callid, rc);
187 return;
188 }
189
190 SOCKET_SET_SOCKET_ID(answer, sock_id);
191
192 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, TCP_SOCK_FRAGMENT_SIZE);
193 SOCKET_SET_HEADER_SIZE(answer, sizeof(tcp_header_t));
194
195 async_answer_3(callid, EOK, IPC_GET_ARG1(answer),
196 IPC_GET_ARG2(answer), IPC_GET_ARG3(answer));
197}
198
199static void tcp_sock_bind(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
200{
201 int rc;
202 struct sockaddr *addr;
203 size_t addr_len;
204 socket_core_t *sock_core;
205 tcp_sockdata_t *socket;
206
207 log_msg(LVL_DEBUG, "tcp_sock_bind()");
208 log_msg(LVL_DEBUG, " - async_data_write_accept");
209 rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &addr_len);
210 if (rc != EOK) {
211 async_answer_0(callid, rc);
212 return;
213 }
214
215 log_msg(LVL_DEBUG, " - call socket_bind");
216 rc = socket_bind(&client->sockets, &gsock, SOCKET_GET_SOCKET_ID(call),
217 addr, addr_len, TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
218 last_used_port);
219 if (rc != EOK) {
220 async_answer_0(callid, rc);
221 return;
222 }
223
224 log_msg(LVL_DEBUG, " - call socket_cores_find");
225 sock_core = socket_cores_find(&client->sockets, SOCKET_GET_SOCKET_ID(call));
226 if (sock_core != NULL) {
227 socket = (tcp_sockdata_t *)sock_core->specific_data;
228 /* XXX Anything to do? */
229 (void) socket;
230 }
231
232 log_msg(LVL_DEBUG, " - success");
233 async_answer_0(callid, EOK);
234}
235
236static void tcp_sock_listen(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
237{
238 int socket_id;
239 int backlog;
240 socket_core_t *sock_core;
241 tcp_sockdata_t *socket;
242 tcp_error_t trc;
243 tcp_sock_t lsocket;
244 tcp_sock_t fsocket;
245 tcp_conn_t *conn;
246 tcp_sock_lconn_t *lconn;
247 int i;
248
249 log_msg(LVL_DEBUG, "tcp_sock_listen()");
250
251 socket_id = SOCKET_GET_SOCKET_ID(call);
252 backlog = SOCKET_GET_BACKLOG(call);
253
254 if (backlog < 0) {
255 async_answer_0(callid, EINVAL);
256 return;
257 }
258
259 if (backlog > MAX_BACKLOG)
260 backlog = MAX_BACKLOG;
261
262 sock_core = socket_cores_find(&client->sockets, socket_id);
263 if (sock_core == NULL) {
264 async_answer_0(callid, ENOTSOCK);
265 return;
266 }
267
268 socket = (tcp_sockdata_t *)sock_core->specific_data;
269
270 /*
271 * Prepare @c backlog listening connections.
272 */
273 fibril_mutex_lock(&socket->lock);
274
275 socket->backlog = backlog;
276 socket->lconn = calloc(sizeof(tcp_conn_t *), backlog);
277 if (socket->lconn == NULL) {
278 fibril_mutex_unlock(&socket->lock);
279 async_answer_0(callid, ENOMEM);
280 return;
281 }
282
283 log_msg(LVL_DEBUG, " - open connections");
284
285 lsocket.addr.ipv4 = TCP_IPV4_ANY;
286 lsocket.port = sock_core->port;
287 fsocket.addr.ipv4 = TCP_IPV4_ANY;
288 fsocket.port = TCP_PORT_ANY;
289
290 for (i = 0; i < backlog; i++) {
291
292 lconn = calloc(sizeof(tcp_sock_lconn_t), 1);
293 if (lconn == NULL) {
294 /* XXX Clean up */
295 fibril_mutex_unlock(&socket->lock);
296 async_answer_0(callid, ENOMEM);
297 return;
298 }
299
300 trc = tcp_uc_open(&lsocket, &fsocket, ap_passive,
301 tcp_open_nonblock, &conn);
302 if (conn == NULL) {
303 /* XXX Clean up */
304 fibril_mutex_unlock(&socket->lock);
305 async_answer_0(callid, ENOMEM);
306 return;
307 }
308
309 tcp_uc_set_cstate_cb(conn, tcp_sock_cstate_cb, lconn);
310
311 assert(trc == TCP_EOK);
312 conn->name = (char *)"S";
313
314 lconn->conn = conn;
315 lconn->socket = socket;
316 link_initialize(&lconn->ready_list);
317 socket->lconn[i] = lconn;
318 }
319
320 fibril_mutex_unlock(&socket->lock);
321 async_answer_0(callid, EOK);
322}
323
324static void tcp_sock_connect(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
325{
326 int rc;
327 struct sockaddr_in *addr;
328 int socket_id;
329 size_t addr_len;
330 socket_core_t *sock_core;
331 tcp_sockdata_t *socket;
332 tcp_error_t trc;
333 tcp_sock_t lsocket;
334 tcp_sock_t fsocket;
335
336 log_msg(LVL_DEBUG, "tcp_sock_connect()");
337
338 rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &addr_len);
339 if (rc != EOK || addr_len != sizeof(struct sockaddr_in)) {
340 async_answer_0(callid, rc);
341 return;
342 }
343
344 socket_id = SOCKET_GET_SOCKET_ID(call);
345
346 sock_core = socket_cores_find(&client->sockets, socket_id);
347 if (sock_core == NULL) {
348 async_answer_0(callid, ENOTSOCK);
349 return;
350 }
351
352 socket = (tcp_sockdata_t *)sock_core->specific_data;
353 if (sock_core->port <= 0) {
354 rc = socket_bind_free_port(&gsock, sock_core,
355 TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
356 last_used_port);
357 if (rc != EOK) {
358 async_answer_0(callid, rc);
359 return;
360 }
361
362 last_used_port = sock_core->port;
363 }
364
365 fibril_mutex_lock(&socket->lock);
366
367 if (socket->laddr.ipv4 == TCP_IPV4_ANY) {
368 /* Determine local IP address */
369 inet_addr_t loc_addr, rem_addr;
370
371 rem_addr.ipv4 = uint32_t_be2host(addr->sin_addr.s_addr);
372 rc = inet_get_srcaddr(&rem_addr, 0, &loc_addr);
373 if (rc != EOK) {
374 fibril_mutex_unlock(&socket->lock);
375 async_answer_0(callid, rc);
376 log_msg(LVL_DEBUG, "tcp_sock_connect: Failed to "
377 "determine local address.");
378 return;
379 }
380
381 socket->laddr.ipv4 = loc_addr.ipv4;
382 log_msg(LVL_DEBUG, "Local IP address is %x", socket->laddr.ipv4);
383 }
384
385 lsocket.addr.ipv4 = socket->laddr.ipv4;
386 lsocket.port = sock_core->port;
387 fsocket.addr.ipv4 = uint32_t_be2host(addr->sin_addr.s_addr);
388 fsocket.port = uint16_t_be2host(addr->sin_port);
389
390 trc = tcp_uc_open(&lsocket, &fsocket, ap_active, 0, &socket->conn);
391
392 if (socket->conn != NULL)
393 socket->conn->name = (char *)"C";
394
395 fibril_mutex_unlock(&socket->lock);
396
397 switch (trc) {
398 case TCP_EOK:
399 rc = EOK;
400 break;
401 case TCP_ERESET:
402 rc = ECONNREFUSED;
403 break;
404 default:
405 assert(false);
406 }
407
408 if (rc == EOK)
409 fibril_add_ready(socket->recv_fibril);
410
411 async_answer_0(callid, rc);
412}
413
414static void tcp_sock_accept(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
415{
416 ipc_call_t answer;
417 int socket_id;
418 int asock_id;
419 socket_core_t *sock_core;
420 tcp_sockdata_t *socket;
421 tcp_sockdata_t *asocket;
422 tcp_error_t trc;
423 tcp_sock_t lsocket;
424 tcp_sock_t fsocket;
425 tcp_conn_t *conn;
426 tcp_conn_t *rconn;
427 tcp_sock_lconn_t *lconn;
428 int rc;
429
430 log_msg(LVL_DEBUG, "tcp_sock_accept()");
431
432 socket_id = SOCKET_GET_SOCKET_ID(call);
433 asock_id = SOCKET_GET_NEW_SOCKET_ID(call);
434
435 sock_core = socket_cores_find(&client->sockets, socket_id);
436 if (sock_core == NULL) {
437 async_answer_0(callid, ENOTSOCK);
438 return;
439 }
440
441 socket = (tcp_sockdata_t *)sock_core->specific_data;
442 fibril_mutex_lock(&socket->lock);
443
444 log_msg(LVL_DEBUG, " - verify socket->conn");
445 if (socket->conn != NULL) {
446 fibril_mutex_unlock(&socket->lock);
447 async_answer_0(callid, EINVAL);
448 return;
449 }
450
451 if (list_empty(&socket->ready)) {
452 fibril_mutex_unlock(&socket->lock);
453 async_answer_0(callid, ENOENT);
454 return;
455 }
456
457 lconn = list_get_instance(list_first(&socket->ready),
458 tcp_sock_lconn_t, ready_list);
459 list_remove(&lconn->ready_list);
460
461 conn = lconn->conn;
462 tcp_uc_set_cstate_cb(conn, NULL, NULL);
463
464 /* Replenish listening connection */
465
466 lsocket.addr.ipv4 = TCP_IPV4_ANY;
467 lsocket.port = sock_core->port;
468 fsocket.addr.ipv4 = TCP_IPV4_ANY;
469 fsocket.port = TCP_PORT_ANY;
470
471 trc = tcp_uc_open(&lsocket, &fsocket, ap_passive, tcp_open_nonblock,
472 &rconn);
473 if (rconn == NULL) {
474 /* XXX Clean up */
475 fibril_mutex_unlock(&socket->lock);
476 async_answer_0(callid, ENOMEM);
477 return;
478 }
479
480 tcp_uc_set_cstate_cb(rconn, tcp_sock_cstate_cb, lconn);
481
482 assert(trc == TCP_EOK);
483 rconn->name = (char *)"S";
484
485 lconn->conn = rconn;
486
487 /* Allocate socket for accepted connection */
488
489 rc = tcp_sock_create(client, &asocket);
490 if (rc != EOK) {
491 fibril_mutex_unlock(&socket->lock);
492 async_answer_0(callid, rc);
493 return;
494 }
495
496 asocket->conn = conn;
497 log_msg(LVL_DEBUG, "tcp_sock_accept():create asocket\n");
498
499 rc = tcp_sock_finish_setup(asocket, &asock_id);
500 if (rc != EOK) {
501 tcp_sock_uncreate(asocket);
502 fibril_mutex_unlock(&socket->lock);
503 async_answer_0(callid, rc);
504 return;
505 }
506
507 fibril_add_ready(asocket->recv_fibril);
508
509 log_msg(LVL_DEBUG, "tcp_sock_accept(): find acore\n");
510
511 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, TCP_SOCK_FRAGMENT_SIZE);
512 SOCKET_SET_SOCKET_ID(answer, asock_id);
513 SOCKET_SET_ADDRESS_LENGTH(answer, sizeof(struct sockaddr_in));
514
515 async_answer_3(callid, asocket->sock_core->socket_id,
516 IPC_GET_ARG1(answer), IPC_GET_ARG2(answer),
517 IPC_GET_ARG3(answer));
518
519 /* Push one fragment notification to client's queue */
520 log_msg(LVL_DEBUG, "tcp_sock_accept(): notify data\n");
521 fibril_mutex_unlock(&socket->lock);
522}
523
524static void tcp_sock_send(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
525{
526 int socket_id;
527 int fragments;
528 int index;
529 socket_core_t *sock_core;
530 tcp_sockdata_t *socket;
531 ipc_call_t answer;
532 ipc_callid_t wcallid;
533 size_t length;
534 uint8_t buffer[TCP_SOCK_FRAGMENT_SIZE];
535 tcp_error_t trc;
536 int rc;
537
538 log_msg(LVL_DEBUG, "tcp_sock_send()");
539 socket_id = SOCKET_GET_SOCKET_ID(call);
540 fragments = SOCKET_GET_DATA_FRAGMENTS(call);
541 SOCKET_GET_FLAGS(call);
542
543 sock_core = socket_cores_find(&client->sockets, socket_id);
544 if (sock_core == NULL) {
545 async_answer_0(callid, ENOTSOCK);
546 return;
547 }
548
549 socket = (tcp_sockdata_t *)sock_core->specific_data;
550 fibril_mutex_lock(&socket->lock);
551
552 if (socket->conn == NULL) {
553 fibril_mutex_unlock(&socket->lock);
554 async_answer_0(callid, ENOTCONN);
555 return;
556 }
557
558 for (index = 0; index < fragments; index++) {
559 if (!async_data_write_receive(&wcallid, &length)) {
560 fibril_mutex_unlock(&socket->lock);
561 async_answer_0(callid, EINVAL);
562 return;
563 }
564
565 if (length > TCP_SOCK_FRAGMENT_SIZE)
566 length = TCP_SOCK_FRAGMENT_SIZE;
567
568 rc = async_data_write_finalize(wcallid, buffer, length);
569 if (rc != EOK) {
570 fibril_mutex_unlock(&socket->lock);
571 async_answer_0(callid, rc);
572 return;
573 }
574
575 trc = tcp_uc_send(socket->conn, buffer, length, 0);
576
577 switch (trc) {
578 case TCP_EOK:
579 rc = EOK;
580 break;
581 case TCP_ENOTEXIST:
582 rc = ENOTCONN;
583 break;
584 case TCP_ECLOSING:
585 rc = ENOTCONN;
586 break;
587 case TCP_ERESET:
588 rc = ECONNABORTED;
589 break;
590 default:
591 assert(false);
592 }
593
594 if (rc != EOK) {
595 fibril_mutex_unlock(&socket->lock);
596 async_answer_0(callid, rc);
597 return;
598 }
599 }
600
601 IPC_SET_ARG1(answer, 0);
602 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, TCP_SOCK_FRAGMENT_SIZE);
603 async_answer_2(callid, EOK, IPC_GET_ARG1(answer),
604 IPC_GET_ARG2(answer));
605 fibril_mutex_unlock(&socket->lock);
606}
607
608static void tcp_sock_sendto(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
609{
610 log_msg(LVL_DEBUG, "tcp_sock_sendto()");
611 async_answer_0(callid, ENOTSUP);
612}
613
614static void tcp_sock_recvfrom(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
615{
616 int socket_id;
617 int flags;
618 size_t addr_length, length;
619 socket_core_t *sock_core;
620 tcp_sockdata_t *socket;
621 ipc_call_t answer;
622 ipc_callid_t rcallid;
623 size_t data_len;
624 struct sockaddr_in addr;
625 tcp_sock_t *rsock;
626 int rc;
627
628 log_msg(LVL_DEBUG, "%p: tcp_sock_recv[from]()", client);
629
630 socket_id = SOCKET_GET_SOCKET_ID(call);
631 flags = SOCKET_GET_FLAGS(call);
632
633 sock_core = socket_cores_find(&client->sockets, socket_id);
634 if (sock_core == NULL) {
635 async_answer_0(callid, ENOTSOCK);
636 return;
637 }
638
639 socket = (tcp_sockdata_t *)sock_core->specific_data;
640 fibril_mutex_lock(&socket->lock);
641
642 if (socket->conn == NULL) {
643 fibril_mutex_unlock(&socket->lock);
644 async_answer_0(callid, ENOTCONN);
645 return;
646 }
647
648 (void)flags;
649
650 log_msg(LVL_DEBUG, "tcp_sock_recvfrom(): lock recv_buffer_lock");
651 fibril_mutex_lock(&socket->recv_buffer_lock);
652 while (socket->recv_buffer_used == 0 && socket->recv_error == TCP_EOK) {
653 log_msg(LVL_DEBUG, "wait for recv_buffer_cv + recv_buffer_used != 0");
654 fibril_condvar_wait(&socket->recv_buffer_cv,
655 &socket->recv_buffer_lock);
656 }
657
658 log_msg(LVL_DEBUG, "Got data in sock recv_buffer");
659
660 data_len = socket->recv_buffer_used;
661 rc = socket->recv_error;
662
663 switch (socket->recv_error) {
664 case TCP_EOK:
665 rc = EOK;
666 break;
667 case TCP_ENOTEXIST:
668 case TCP_ECLOSING:
669 rc = ENOTCONN;
670 break;
671 case TCP_ERESET:
672 rc = ECONNABORTED;
673 break;
674 default:
675 assert(false);
676 }
677
678 log_msg(LVL_DEBUG, "**** recv result -> %d", rc);
679 if (rc != EOK) {
680 fibril_mutex_unlock(&socket->recv_buffer_lock);
681 fibril_mutex_unlock(&socket->lock);
682 async_answer_0(callid, rc);
683 return;
684 }
685
686 if (IPC_GET_IMETHOD(call) == NET_SOCKET_RECVFROM) {
687 /* Fill addr */
688 rsock = &socket->conn->ident.foreign;
689 addr.sin_family = AF_INET;
690 addr.sin_addr.s_addr = host2uint32_t_be(rsock->addr.ipv4);
691 addr.sin_port = host2uint16_t_be(rsock->port);
692
693 log_msg(LVL_DEBUG, "addr read receive");
694 if (!async_data_read_receive(&rcallid, &addr_length)) {
695 fibril_mutex_unlock(&socket->recv_buffer_lock);
696 fibril_mutex_unlock(&socket->lock);
697 async_answer_0(callid, EINVAL);
698 return;
699 }
700
701 if (addr_length > sizeof(addr))
702 addr_length = sizeof(addr);
703
704 log_msg(LVL_DEBUG, "addr read finalize");
705 rc = async_data_read_finalize(rcallid, &addr, addr_length);
706 if (rc != EOK) {
707 fibril_mutex_unlock(&socket->recv_buffer_lock);
708 fibril_mutex_unlock(&socket->lock);
709 async_answer_0(callid, EINVAL);
710 return;
711 }
712 }
713
714 log_msg(LVL_DEBUG, "data read receive");
715 if (!async_data_read_receive(&rcallid, &length)) {
716 fibril_mutex_unlock(&socket->recv_buffer_lock);
717 fibril_mutex_unlock(&socket->lock);
718 async_answer_0(callid, EINVAL);
719 return;
720 }
721
722 if (length > data_len)
723 length = data_len;
724
725 log_msg(LVL_DEBUG, "data read finalize");
726 rc = async_data_read_finalize(rcallid, socket->recv_buffer, length);
727
728 socket->recv_buffer_used -= length;
729 log_msg(LVL_DEBUG, "tcp_sock_recvfrom: %zu left in buffer",
730 socket->recv_buffer_used);
731 if (socket->recv_buffer_used > 0) {
732 memmove(socket->recv_buffer, socket->recv_buffer + length,
733 socket->recv_buffer_used);
734 tcp_sock_notify_data(socket->sock_core);
735 }
736
737 fibril_condvar_broadcast(&socket->recv_buffer_cv);
738
739 if (length < data_len && rc == EOK)
740 rc = EOVERFLOW;
741
742 SOCKET_SET_READ_DATA_LENGTH(answer, length);
743 async_answer_1(callid, EOK, IPC_GET_ARG1(answer));
744
745 fibril_mutex_unlock(&socket->recv_buffer_lock);
746 fibril_mutex_unlock(&socket->lock);
747}
748
749static void tcp_sock_close(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
750{
751 int socket_id;
752 socket_core_t *sock_core;
753 tcp_sockdata_t *socket;
754 tcp_error_t trc;
755 int rc;
756
757 log_msg(LVL_DEBUG, "tcp_sock_close()");
758 socket_id = SOCKET_GET_SOCKET_ID(call);
759
760 sock_core = socket_cores_find(&client->sockets, socket_id);
761 if (sock_core == NULL) {
762 async_answer_0(callid, ENOTSOCK);
763 return;
764 }
765
766 socket = (tcp_sockdata_t *)sock_core->specific_data;
767 fibril_mutex_lock(&socket->lock);
768
769 if (socket->conn != NULL) {
770 trc = tcp_uc_close(socket->conn);
771 if (trc != TCP_EOK && trc != TCP_ENOTEXIST) {
772 fibril_mutex_unlock(&socket->lock);
773 async_answer_0(callid, EBADF);
774 return;
775 }
776 }
777
778 rc = socket_destroy(NULL, socket_id, &client->sockets, &gsock,
779 tcp_free_sock_data);
780 if (rc != EOK) {
781 fibril_mutex_unlock(&socket->lock);
782 async_answer_0(callid, rc);
783 return;
784 }
785
786 fibril_mutex_unlock(&socket->lock);
787 async_answer_0(callid, EOK);
788}
789
790static void tcp_sock_getsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
791{
792 log_msg(LVL_DEBUG, "tcp_sock_getsockopt()");
793 async_answer_0(callid, ENOTSUP);
794}
795
796static void tcp_sock_setsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
797{
798 log_msg(LVL_DEBUG, "tcp_sock_setsockopt()");
799 async_answer_0(callid, ENOTSUP);
800}
801
802/** Called when connection state changes. */
803static void tcp_sock_cstate_cb(tcp_conn_t *conn, void *arg)
804{
805 tcp_conn_status_t cstatus;
806 tcp_sock_lconn_t *lconn = (tcp_sock_lconn_t *)arg;
807 tcp_sockdata_t *socket = lconn->socket;
808
809 log_msg(LVL_DEBUG, "tcp_sock_cstate_cb()");
810 fibril_mutex_lock(&socket->lock);
811 assert(conn == lconn->conn);
812
813 tcp_uc_status(conn, &cstatus);
814 if (cstatus.cstate != st_established) {
815 fibril_mutex_unlock(&socket->lock);
816 return;
817 }
818
819 assert_link_not_used(&lconn->ready_list);
820 list_append(&lconn->ready_list, &socket->ready);
821
822 log_msg(LVL_DEBUG, "tcp_sock_cstate_cb(): notify accept");
823
824 /* Push one accept notification to client's queue */
825 tcp_sock_notify_aconn(socket->sock_core);
826 fibril_mutex_unlock(&socket->lock);
827}
828
829static int tcp_sock_recv_fibril(void *arg)
830{
831 tcp_sockdata_t *sock = (tcp_sockdata_t *)arg;
832 size_t data_len;
833 xflags_t xflags;
834 tcp_error_t trc;
835
836 log_msg(LVL_DEBUG, "tcp_sock_recv_fibril()");
837
838 while (true) {
839 log_msg(LVL_DEBUG, "call tcp_uc_receive()");
840 fibril_mutex_lock(&sock->recv_buffer_lock);
841 while (sock->recv_buffer_used != 0)
842 fibril_condvar_wait(&sock->recv_buffer_cv,
843 &sock->recv_buffer_lock);
844
845 trc = tcp_uc_receive(sock->conn, sock->recv_buffer,
846 TCP_SOCK_FRAGMENT_SIZE, &data_len, &xflags);
847
848 if (trc != TCP_EOK) {
849 sock->recv_error = trc;
850 fibril_condvar_broadcast(&sock->recv_buffer_cv);
851 fibril_mutex_unlock(&sock->recv_buffer_lock);
852 tcp_sock_notify_data(sock->sock_core);
853 break;
854 }
855
856 log_msg(LVL_DEBUG, "got data - broadcast recv_buffer_cv");
857
858 sock->recv_buffer_used = data_len;
859 fibril_condvar_broadcast(&sock->recv_buffer_cv);
860 fibril_mutex_unlock(&sock->recv_buffer_lock);
861 tcp_sock_notify_data(sock->sock_core);
862 }
863
864 tcp_uc_delete(sock->conn);
865
866 return 0;
867}
868
869static void tcp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
870{
871 ipc_callid_t callid;
872 ipc_call_t call;
873 tcp_client_t client;
874
875 /* Accept the connection */
876 async_answer_0(iid, EOK);
877
878 client.sess = async_callback_receive(EXCHANGE_SERIALIZE);
879 socket_cores_initialize(&client.sockets);
880
881 while (true) {
882 callid = async_get_call(&call);
883 if (!IPC_GET_IMETHOD(call))
884 break;
885
886 log_msg(LVL_DEBUG, "tcp_sock_connection: METHOD=%d\n",
887 (int)IPC_GET_IMETHOD(call));
888
889 switch (IPC_GET_IMETHOD(call)) {
890 case NET_SOCKET:
891 tcp_sock_socket(&client, callid, call);
892 break;
893 case NET_SOCKET_BIND:
894 tcp_sock_bind(&client, callid, call);
895 break;
896 case NET_SOCKET_LISTEN:
897 tcp_sock_listen(&client, callid, call);
898 break;
899 case NET_SOCKET_CONNECT:
900 tcp_sock_connect(&client, callid, call);
901 break;
902 case NET_SOCKET_ACCEPT:
903 tcp_sock_accept(&client, callid, call);
904 break;
905 case NET_SOCKET_SEND:
906 tcp_sock_send(&client, callid, call);
907 break;
908 case NET_SOCKET_SENDTO:
909 tcp_sock_sendto(&client, callid, call);
910 break;
911 case NET_SOCKET_RECV:
912 case NET_SOCKET_RECVFROM:
913 tcp_sock_recvfrom(&client, callid, call);
914 break;
915 case NET_SOCKET_CLOSE:
916 tcp_sock_close(&client, callid, call);
917 break;
918 case NET_SOCKET_GETSOCKOPT:
919 tcp_sock_getsockopt(&client, callid, call);
920 break;
921 case NET_SOCKET_SETSOCKOPT:
922 tcp_sock_setsockopt(&client, callid, call);
923 break;
924 default:
925 async_answer_0(callid, ENOTSUP);
926 break;
927 }
928 }
929
930 /* Clean up */
931 log_msg(LVL_DEBUG, "tcp_sock_connection: Clean up");
932 async_hangup(client.sess);
933 socket_cores_release(NULL, &client.sockets, &gsock, tcp_free_sock_data);
934}
935
936/**
937 * @}
938 */
Note: See TracBrowser for help on using the repository browser.