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

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

Move network-related servers to srv/net.

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