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

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

tcp_sock_recv_fibril() needs to handle situation when sock_core goes away before TCP signals end of connection.

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