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

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

tcp_sock_connection() and udp_sock_connection() need to clean up when exiting.

  • Property mode set to 100644
File size: 20.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/modules.h>
45#include <net/socket.h>
46#include <ns.h>
47
48#include "sock.h"
49#include "std.h"
50#include "tcp.h"
51#include "tcp_type.h"
52#include "ucall.h"
53
54#define FRAGMENT_SIZE 1024
55
56#define MAX_BACKLOG 128
57
58/** Free ports pool start. */
59#define TCP_FREE_PORTS_START 1025
60
61/** Free ports pool end. */
62#define TCP_FREE_PORTS_END 65535
63
64static int last_used_port = TCP_FREE_PORTS_START - 1;
65static socket_ports_t gsock;
66
67static void tcp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg);
68static void tcp_sock_cstate_cb(tcp_conn_t *conn, void *arg);
69
70int tcp_sock_init(void)
71{
72 int rc;
73
74 socket_ports_initialize(&gsock);
75
76 async_set_client_connection(tcp_sock_connection);
77
78 rc = service_register(SERVICE_TCP);
79 if (rc != EOK)
80 return EEXIST;
81
82 return EOK;
83}
84
85static void tcp_free_sock_data(socket_core_t *sock_core)
86{
87 tcp_sockdata_t *socket;
88
89 socket = (tcp_sockdata_t *)sock_core->specific_data;
90 (void)socket;
91
92 /* XXX We need to initiate connection cleanup here */
93}
94
95static void tcp_sock_notify_data(socket_core_t *sock_core)
96{
97 log_msg(LVL_DEBUG, "tcp_sock_notify_data(%d)", sock_core->socket_id);
98 async_exch_t *exch = async_exchange_begin(sock_core->sess);
99 async_msg_5(exch, NET_SOCKET_RECEIVED, (sysarg_t)sock_core->socket_id,
100 FRAGMENT_SIZE, 0, 0, 1);
101 async_exchange_end(exch);
102}
103
104static void tcp_sock_notify_aconn(socket_core_t *lsock_core)
105{
106 log_msg(LVL_DEBUG, "tcp_sock_notify_aconn(%d)", lsock_core->socket_id);
107 async_exch_t *exch = async_exchange_begin(lsock_core->sess);
108 async_msg_5(exch, NET_SOCKET_ACCEPTED, (sysarg_t)lsock_core->socket_id,
109 FRAGMENT_SIZE, 0, 0, 0);
110 async_exchange_end(exch);
111}
112
113static void tcp_sock_socket(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
114{
115 tcp_sockdata_t *sock;
116 socket_core_t *sock_core;
117 int sock_id;
118 int rc;
119 ipc_call_t answer;
120
121 log_msg(LVL_DEBUG, "tcp_sock_socket()");
122 sock = calloc(sizeof(tcp_sockdata_t), 1);
123 if (sock == NULL) {
124 async_answer_0(callid, ENOMEM);
125 return;
126 }
127
128 fibril_mutex_initialize(&sock->lock);
129 sock->client = client;
130 sock->laddr.ipv4 = TCP_IPV4_ANY;
131 sock->lconn = NULL;
132 sock->backlog = 0;
133 list_initialize(&sock->ready);
134
135 sock_id = SOCKET_GET_SOCKET_ID(call);
136 rc = socket_create(&client->sockets, client->sess, sock, &sock_id);
137 if (rc != EOK) {
138 async_answer_0(callid, rc);
139 return;
140 }
141
142 sock_core = socket_cores_find(&client->sockets, sock_id);
143 assert(sock_core != NULL);
144 sock->sock_core = sock_core;
145
146 refresh_answer(&answer, NULL);
147 SOCKET_SET_SOCKET_ID(answer, sock_id);
148
149 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
150 SOCKET_SET_HEADER_SIZE(answer, sizeof(tcp_header_t));
151 answer_call(callid, EOK, &answer, 3);
152}
153
154static void tcp_sock_bind(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
155{
156 int rc;
157 struct sockaddr *addr;
158 size_t addr_len;
159 socket_core_t *sock_core;
160 tcp_sockdata_t *socket;
161
162 log_msg(LVL_DEBUG, "tcp_sock_bind()");
163 log_msg(LVL_DEBUG, " - async_data_write_accept");
164 rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &addr_len);
165 if (rc != EOK) {
166 async_answer_0(callid, rc);
167 return;
168 }
169
170 log_msg(LVL_DEBUG, " - call socket_bind");
171 rc = socket_bind(&client->sockets, &gsock, SOCKET_GET_SOCKET_ID(call),
172 addr, addr_len, TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
173 last_used_port);
174 if (rc != EOK) {
175 async_answer_0(callid, rc);
176 return;
177 }
178
179 log_msg(LVL_DEBUG, " - call socket_cores_find");
180 sock_core = socket_cores_find(&client->sockets, SOCKET_GET_SOCKET_ID(call));
181 if (sock_core != NULL) {
182 socket = (tcp_sockdata_t *)sock_core->specific_data;
183 /* XXX Anything to do? */
184 (void) socket;
185 }
186
187 log_msg(LVL_DEBUG, " - success");
188 async_answer_0(callid, EOK);
189}
190
191static void tcp_sock_listen(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
192{
193 int socket_id;
194 int backlog;
195 socket_core_t *sock_core;
196 tcp_sockdata_t *socket;
197 tcp_error_t trc;
198 tcp_sock_t lsocket;
199 tcp_sock_t fsocket;
200 tcp_conn_t *conn;
201 tcp_sock_lconn_t *lconn;
202 int i;
203
204 log_msg(LVL_DEBUG, "tcp_sock_listen()");
205
206 socket_id = SOCKET_GET_SOCKET_ID(call);
207 backlog = SOCKET_GET_BACKLOG(call);
208
209 if (backlog < 0) {
210 async_answer_0(callid, EINVAL);
211 return;
212 }
213
214 if (backlog > MAX_BACKLOG)
215 backlog = MAX_BACKLOG;
216
217 sock_core = socket_cores_find(&client->sockets, socket_id);
218 if (sock_core == NULL) {
219 async_answer_0(callid, ENOTSOCK);
220 return;
221 }
222
223 socket = (tcp_sockdata_t *)sock_core->specific_data;
224
225 /*
226 * Prepare @c backlog listening connections.
227 */
228 fibril_mutex_lock(&socket->lock);
229
230 socket->backlog = backlog;
231 socket->lconn = calloc(sizeof(tcp_conn_t *), backlog);
232 if (socket->lconn == NULL) {
233 fibril_mutex_unlock(&socket->lock);
234 async_answer_0(callid, ENOMEM);
235 return;
236 }
237
238 log_msg(LVL_DEBUG, " - open connections");
239
240 lsocket.addr.ipv4 = TCP_IPV4_ANY;
241 lsocket.port = sock_core->port;
242 fsocket.addr.ipv4 = TCP_IPV4_ANY;
243 fsocket.port = TCP_PORT_ANY;
244
245 for (i = 0; i < backlog; i++) {
246
247 lconn = calloc(sizeof(tcp_sock_lconn_t), 1);
248 if (lconn == NULL) {
249 /* XXX Clean up */
250 fibril_mutex_unlock(&socket->lock);
251 async_answer_0(callid, ENOMEM);
252 return;
253 }
254
255 trc = tcp_uc_open(&lsocket, &fsocket, ap_passive,
256 tcp_open_nonblock, &conn);
257 if (conn == NULL) {
258 /* XXX Clean up */
259 fibril_mutex_unlock(&socket->lock);
260 async_answer_0(callid, ENOMEM);
261 return;
262 }
263
264 tcp_uc_set_cstate_cb(conn, tcp_sock_cstate_cb, lconn);
265
266 assert(trc == TCP_EOK);
267 conn->name = (char *)"S";
268
269 lconn->conn = conn;
270 lconn->socket = socket;
271 link_initialize(&lconn->ready_list);
272 socket->lconn[i] = lconn;
273 }
274
275 fibril_mutex_unlock(&socket->lock);
276 async_answer_0(callid, EOK);
277}
278
279static void tcp_sock_connect(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
280{
281 int rc;
282 struct sockaddr_in *addr;
283 int socket_id;
284 size_t addr_len;
285 socket_core_t *sock_core;
286 tcp_sockdata_t *socket;
287 tcp_error_t trc;
288 tcp_sock_t lsocket;
289 tcp_sock_t fsocket;
290
291 log_msg(LVL_DEBUG, "tcp_sock_connect()");
292
293 rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &addr_len);
294 if (rc != EOK || addr_len != sizeof(struct sockaddr_in)) {
295 async_answer_0(callid, rc);
296 return;
297 }
298
299 socket_id = SOCKET_GET_SOCKET_ID(call);
300
301 sock_core = socket_cores_find(&client->sockets, socket_id);
302 if (sock_core == NULL) {
303 async_answer_0(callid, ENOTSOCK);
304 return;
305 }
306
307 socket = (tcp_sockdata_t *)sock_core->specific_data;
308 if (sock_core->port <= 0) {
309 rc = socket_bind_free_port(&gsock, sock_core,
310 TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
311 last_used_port);
312 if (rc != EOK) {
313 async_answer_0(callid, rc);
314 return;
315 }
316
317 last_used_port = sock_core->port;
318 }
319
320 fibril_mutex_lock(&socket->lock);
321
322 if (socket->laddr.ipv4 == TCP_IPV4_ANY) {
323 /* Determine local IP address */
324 inet_addr_t loc_addr, rem_addr;
325
326 rem_addr.ipv4 = uint32_t_be2host(addr->sin_addr.s_addr);
327 rc = inet_get_srcaddr(&rem_addr, 0, &loc_addr);
328 if (rc != EOK) {
329 fibril_mutex_unlock(&socket->lock);
330 async_answer_0(callid, rc);
331 log_msg(LVL_DEBUG, "tcp_sock_connect: Failed to "
332 "determine local address.");
333 return;
334 }
335
336 socket->laddr.ipv4 = loc_addr.ipv4;
337 log_msg(LVL_DEBUG, "Local IP address is %x", socket->laddr.ipv4);
338 }
339
340 lsocket.addr.ipv4 = socket->laddr.ipv4;
341 lsocket.port = sock_core->port;
342 fsocket.addr.ipv4 = uint32_t_be2host(addr->sin_addr.s_addr);
343 fsocket.port = uint16_t_be2host(addr->sin_port);
344
345 trc = tcp_uc_open(&lsocket, &fsocket, ap_active, 0, &socket->conn);
346
347 if (socket->conn != NULL)
348 socket->conn->name = (char *)"C";
349
350 fibril_mutex_unlock(&socket->lock);
351
352 switch (trc) {
353 case TCP_EOK:
354 rc = EOK;
355 break;
356 case TCP_ERESET:
357 rc = ECONNREFUSED;
358 break;
359 default:
360 assert(false);
361 }
362
363 async_answer_0(callid, rc);
364
365 /* Push one fragment notification to client's queue */
366 tcp_sock_notify_data(sock_core);
367 log_msg(LVL_DEBUG, "tcp_sock_connect(): notify conn\n");
368}
369
370static void tcp_sock_accept(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
371{
372 ipc_call_t answer;
373 int socket_id;
374 int asock_id;
375 socket_core_t *sock_core;
376 socket_core_t *asock_core;
377 tcp_sockdata_t *socket;
378 tcp_sockdata_t *asocket;
379 tcp_error_t trc;
380 tcp_sock_t lsocket;
381 tcp_sock_t fsocket;
382 tcp_conn_t *conn;
383 tcp_conn_t *rconn;
384 tcp_sock_lconn_t *lconn;
385 int rc;
386
387 log_msg(LVL_DEBUG, "tcp_sock_accept()");
388
389 socket_id = SOCKET_GET_SOCKET_ID(call);
390 asock_id = SOCKET_GET_NEW_SOCKET_ID(call);
391
392 sock_core = socket_cores_find(&client->sockets, socket_id);
393 if (sock_core == NULL) {
394 async_answer_0(callid, ENOTSOCK);
395 return;
396 }
397
398 socket = (tcp_sockdata_t *)sock_core->specific_data;
399 fibril_mutex_lock(&socket->lock);
400
401 log_msg(LVL_DEBUG, " - verify socket->conn");
402 if (socket->conn != NULL) {
403 fibril_mutex_unlock(&socket->lock);
404 async_answer_0(callid, EINVAL);
405 return;
406 }
407
408 if (list_empty(&socket->ready)) {
409 fibril_mutex_unlock(&socket->lock);
410 async_answer_0(callid, ENOENT);
411 return;
412 }
413
414 lconn = list_get_instance(list_first(&socket->ready),
415 tcp_sock_lconn_t, ready_list);
416 list_remove(&lconn->ready_list);
417
418 conn = lconn->conn;
419 tcp_uc_set_cstate_cb(conn, NULL, NULL);
420
421 /* Replenish listening connection */
422
423 lsocket.addr.ipv4 = TCP_IPV4_ANY;
424 lsocket.port = sock_core->port;
425 fsocket.addr.ipv4 = TCP_IPV4_ANY;
426 fsocket.port = TCP_PORT_ANY;
427
428 trc = tcp_uc_open(&lsocket, &fsocket, ap_passive, tcp_open_nonblock,
429 &rconn);
430 if (rconn == NULL) {
431 /* XXX Clean up */
432 fibril_mutex_unlock(&socket->lock);
433 async_answer_0(callid, ENOMEM);
434 return;
435 }
436
437 tcp_uc_set_cstate_cb(rconn, tcp_sock_cstate_cb, lconn);
438
439 assert(trc == TCP_EOK);
440 rconn->name = (char *)"S";
441
442 lconn->conn = rconn;
443
444 /* Allocate socket for accepted connection */
445
446 log_msg(LVL_DEBUG, "tcp_sock_accept(): allocate asocket\n");
447 asocket = calloc(sizeof(tcp_sockdata_t), 1);
448 if (asocket == NULL) {
449 fibril_mutex_unlock(&socket->lock);
450 async_answer_0(callid, ENOMEM);
451 return;
452 }
453
454 fibril_mutex_initialize(&asocket->lock);
455 asocket->client = client;
456 asocket->conn = conn;
457 log_msg(LVL_DEBUG, "tcp_sock_accept():create asocket\n");
458
459 rc = socket_create(&client->sockets, client->sess, asocket, &asock_id);
460 if (rc != EOK) {
461 fibril_mutex_unlock(&socket->lock);
462 async_answer_0(callid, rc);
463 return;
464 }
465 log_msg(LVL_DEBUG, "tcp_sock_accept(): find acore\n");
466
467 asock_core = socket_cores_find(&client->sockets, asock_id);
468 assert(asock_core != NULL);
469
470 refresh_answer(&answer, NULL);
471
472 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
473 SOCKET_SET_SOCKET_ID(answer, asock_id);
474 SOCKET_SET_ADDRESS_LENGTH(answer, sizeof(struct sockaddr_in));
475
476 answer_call(callid, asock_core->socket_id, &answer, 3);
477
478 /* Push one fragment notification to client's queue */
479 log_msg(LVL_DEBUG, "tcp_sock_accept(): notify data\n");
480 tcp_sock_notify_data(asock_core);
481 fibril_mutex_unlock(&socket->lock);
482}
483
484static void tcp_sock_send(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
485{
486 int socket_id;
487 int fragments;
488 int index;
489 socket_core_t *sock_core;
490 tcp_sockdata_t *socket;
491 ipc_call_t answer;
492 ipc_callid_t wcallid;
493 size_t length;
494 uint8_t buffer[FRAGMENT_SIZE];
495 tcp_error_t trc;
496 int rc;
497
498 log_msg(LVL_DEBUG, "tcp_sock_send()");
499 socket_id = SOCKET_GET_SOCKET_ID(call);
500 fragments = SOCKET_GET_DATA_FRAGMENTS(call);
501 SOCKET_GET_FLAGS(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 socket = (tcp_sockdata_t *)sock_core->specific_data;
510 fibril_mutex_lock(&socket->lock);
511
512 if (socket->conn == NULL) {
513 fibril_mutex_unlock(&socket->lock);
514 async_answer_0(callid, ENOTCONN);
515 return;
516 }
517
518 for (index = 0; index < fragments; index++) {
519 if (!async_data_write_receive(&wcallid, &length)) {
520 fibril_mutex_unlock(&socket->lock);
521 async_answer_0(callid, EINVAL);
522 return;
523 }
524
525 if (length > FRAGMENT_SIZE)
526 length = FRAGMENT_SIZE;
527
528 rc = async_data_write_finalize(wcallid, buffer, length);
529 if (rc != EOK) {
530 fibril_mutex_unlock(&socket->lock);
531 async_answer_0(callid, rc);
532 return;
533 }
534
535 trc = tcp_uc_send(socket->conn, buffer, length, 0);
536
537 switch (trc) {
538 case TCP_EOK:
539 rc = EOK;
540 break;
541 case TCP_ENOTEXIST:
542 rc = ENOTCONN;
543 break;
544 case TCP_ECLOSING:
545 rc = ENOTCONN;
546 break;
547 case TCP_ERESET:
548 rc = ECONNABORTED;
549 break;
550 default:
551 assert(false);
552 }
553
554 if (rc != EOK) {
555 fibril_mutex_unlock(&socket->lock);
556 async_answer_0(callid, rc);
557 return;
558 }
559 }
560
561 refresh_answer(&answer, NULL);
562 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
563 answer_call(callid, EOK, &answer, 2);
564 fibril_mutex_unlock(&socket->lock);
565}
566
567static void tcp_sock_sendto(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
568{
569 log_msg(LVL_DEBUG, "tcp_sock_sendto()");
570 async_answer_0(callid, ENOTSUP);
571}
572
573static void tcp_sock_recvfrom(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
574{
575 int socket_id;
576 int flags;
577 size_t addr_length, length;
578 socket_core_t *sock_core;
579 tcp_sockdata_t *socket;
580 ipc_call_t answer;
581 ipc_callid_t rcallid;
582 uint8_t buffer[FRAGMENT_SIZE];
583 size_t data_len;
584 xflags_t xflags;
585 tcp_error_t trc;
586 struct sockaddr_in addr;
587 tcp_sock_t *rsock;
588 int rc;
589
590 log_msg(LVL_DEBUG, "%p: tcp_sock_recv[from]()", client);
591
592 socket_id = SOCKET_GET_SOCKET_ID(call);
593 flags = SOCKET_GET_FLAGS(call);
594
595 sock_core = socket_cores_find(&client->sockets, socket_id);
596 if (sock_core == NULL) {
597 async_answer_0(callid, ENOTSOCK);
598 return;
599 }
600
601 socket = (tcp_sockdata_t *)sock_core->specific_data;
602 fibril_mutex_lock(&socket->lock);
603
604 if (socket->conn == NULL) {
605 fibril_mutex_unlock(&socket->lock);
606 async_answer_0(callid, ENOTCONN);
607 return;
608 }
609
610 (void)flags;
611
612 trc = tcp_uc_receive(socket->conn, buffer, FRAGMENT_SIZE, &data_len,
613 &xflags);
614 log_msg(LVL_DEBUG, "**** tcp_uc_receive done");
615
616 switch (trc) {
617 case TCP_EOK:
618 rc = EOK;
619 break;
620 case TCP_ENOTEXIST:
621 case TCP_ECLOSING:
622 rc = ENOTCONN;
623 break;
624 case TCP_ERESET:
625 rc = ECONNABORTED;
626 break;
627 default:
628 assert(false);
629 }
630
631 log_msg(LVL_DEBUG, "**** tcp_uc_receive -> %d", rc);
632 if (rc != EOK) {
633 fibril_mutex_unlock(&socket->lock);
634 async_answer_0(callid, rc);
635 return;
636 }
637
638 if (IPC_GET_IMETHOD(call) == NET_SOCKET_RECVFROM) {
639 /* Fill addr */
640 rsock = &socket->conn->ident.foreign;
641 addr.sin_family = AF_INET;
642 addr.sin_addr.s_addr = host2uint32_t_be(rsock->addr.ipv4);
643 addr.sin_port = host2uint16_t_be(rsock->port);
644
645 log_msg(LVL_DEBUG, "addr read receive");
646 if (!async_data_read_receive(&rcallid, &addr_length)) {
647 fibril_mutex_unlock(&socket->lock);
648 async_answer_0(callid, EINVAL);
649 return;
650 }
651
652 if (addr_length > sizeof(addr))
653 addr_length = sizeof(addr);
654
655 log_msg(LVL_DEBUG, "addr read finalize");
656 rc = async_data_read_finalize(rcallid, &addr, addr_length);
657 if (rc != EOK) {
658 fibril_mutex_unlock(&socket->lock);
659 async_answer_0(callid, EINVAL);
660 return;
661 }
662 }
663
664 log_msg(LVL_DEBUG, "data read receive");
665 if (!async_data_read_receive(&rcallid, &length)) {
666 fibril_mutex_unlock(&socket->lock);
667 async_answer_0(callid, EINVAL);
668 return;
669 }
670
671 if (length > data_len)
672 length = data_len;
673
674 log_msg(LVL_DEBUG, "data read finalize");
675 rc = async_data_read_finalize(rcallid, buffer, length);
676
677 if (length < data_len && rc == EOK)
678 rc = EOVERFLOW;
679
680 SOCKET_SET_READ_DATA_LENGTH(answer, length);
681 answer_call(callid, EOK, &answer, 1);
682
683 /* Push one fragment notification to client's queue */
684 tcp_sock_notify_data(sock_core);
685 fibril_mutex_unlock(&socket->lock);
686}
687
688static void tcp_sock_close(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
689{
690 int socket_id;
691 socket_core_t *sock_core;
692 tcp_sockdata_t *socket;
693 tcp_error_t trc;
694 int rc;
695 uint8_t buffer[FRAGMENT_SIZE];
696 size_t data_len;
697 xflags_t xflags;
698
699 log_msg(LVL_DEBUG, "tcp_sock_close()");
700 socket_id = SOCKET_GET_SOCKET_ID(call);
701
702 sock_core = socket_cores_find(&client->sockets, socket_id);
703 if (sock_core == NULL) {
704 async_answer_0(callid, ENOTSOCK);
705 return;
706 }
707
708 socket = (tcp_sockdata_t *)sock_core->specific_data;
709 fibril_mutex_lock(&socket->lock);
710
711 if (socket->conn != NULL) {
712 trc = tcp_uc_close(socket->conn);
713 if (trc != TCP_EOK && trc != TCP_ENOTEXIST) {
714 fibril_mutex_unlock(&socket->lock);
715 async_answer_0(callid, EBADF);
716 return;
717 }
718
719 /* Drain incoming data. This should really be done in the background. */
720 do {
721 trc = tcp_uc_receive(socket->conn, buffer,
722 FRAGMENT_SIZE, &data_len, &xflags);
723 } while (trc == TCP_EOK);
724
725 tcp_uc_delete(socket->conn);
726 }
727
728 rc = socket_destroy(NULL, socket_id, &client->sockets, &gsock,
729 tcp_free_sock_data);
730 if (rc != EOK) {
731 fibril_mutex_unlock(&socket->lock);
732 async_answer_0(callid, rc);
733 return;
734 }
735
736 fibril_mutex_unlock(&socket->lock);
737 async_answer_0(callid, EOK);
738}
739
740static void tcp_sock_getsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
741{
742 log_msg(LVL_DEBUG, "tcp_sock_getsockopt()");
743 async_answer_0(callid, ENOTSUP);
744}
745
746static void tcp_sock_setsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
747{
748 log_msg(LVL_DEBUG, "tcp_sock_setsockopt()");
749 async_answer_0(callid, ENOTSUP);
750}
751
752/** Called when connection state changes. */
753static void tcp_sock_cstate_cb(tcp_conn_t *conn, void *arg)
754{
755 tcp_conn_status_t cstatus;
756 tcp_sock_lconn_t *lconn = (tcp_sock_lconn_t *)arg;
757 tcp_sockdata_t *socket = lconn->socket;
758
759 log_msg(LVL_DEBUG, "tcp_sock_cstate_cb()");
760 fibril_mutex_lock(&socket->lock);
761 assert(conn == lconn->conn);
762
763 tcp_uc_status(conn, &cstatus);
764 if (cstatus.cstate != st_established) {
765 fibril_mutex_unlock(&socket->lock);
766 return;
767 }
768
769 assert_link_not_used(&lconn->ready_list);
770 list_append(&lconn->ready_list, &socket->ready);
771
772 log_msg(LVL_DEBUG, "tcp_sock_cstate_cb(): notify accept");
773
774 /* Push one accept notification to client's queue */
775 tcp_sock_notify_aconn(socket->sock_core);
776 fibril_mutex_unlock(&socket->lock);
777}
778
779static void tcp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
780{
781 ipc_callid_t callid;
782 ipc_call_t call;
783 tcp_client_t client;
784
785 /* Accept the connection */
786 async_answer_0(iid, EOK);
787
788 client.sess = async_callback_receive(EXCHANGE_SERIALIZE);
789 socket_cores_initialize(&client.sockets);
790
791 while (true) {
792 callid = async_get_call(&call);
793 if (!IPC_GET_IMETHOD(call))
794 break;
795
796 log_msg(LVL_DEBUG, "tcp_sock_connection: METHOD=%d\n",
797 (int)IPC_GET_IMETHOD(call));
798
799 switch (IPC_GET_IMETHOD(call)) {
800 case NET_SOCKET:
801 tcp_sock_socket(&client, callid, call);
802 break;
803 case NET_SOCKET_BIND:
804 tcp_sock_bind(&client, callid, call);
805 break;
806 case NET_SOCKET_LISTEN:
807 tcp_sock_listen(&client, callid, call);
808 break;
809 case NET_SOCKET_CONNECT:
810 tcp_sock_connect(&client, callid, call);
811 break;
812 case NET_SOCKET_ACCEPT:
813 tcp_sock_accept(&client, callid, call);
814 break;
815 case NET_SOCKET_SEND:
816 tcp_sock_send(&client, callid, call);
817 break;
818 case NET_SOCKET_SENDTO:
819 tcp_sock_sendto(&client, callid, call);
820 break;
821 case NET_SOCKET_RECV:
822 case NET_SOCKET_RECVFROM:
823 tcp_sock_recvfrom(&client, callid, call);
824 break;
825 case NET_SOCKET_CLOSE:
826 tcp_sock_close(&client, callid, call);
827 break;
828 case NET_SOCKET_GETSOCKOPT:
829 tcp_sock_getsockopt(&client, callid, call);
830 break;
831 case NET_SOCKET_SETSOCKOPT:
832 tcp_sock_setsockopt(&client, callid, call);
833 break;
834 default:
835 async_answer_0(callid, ENOTSUP);
836 break;
837 }
838 }
839
840 /* Clean up */
841 log_msg(LVL_DEBUG, "tcp_sock_connection: Clean up");
842 async_hangup(client.sess);
843 socket_cores_release(NULL, &client.sockets, &gsock, tcp_free_sock_data);
844}
845
846/**
847 * @}
848 */
Note: See TracBrowser for help on using the repository browser.