source: mainline/uspace/srv/tcp/sock.c@ 4d9fe7b

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

Remove network stack under uspace/srv/net (except TCP).

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