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

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

Use a receive fibril in TCP socket provider to make reception non-blocking. This is more of a hack, the whole code needs to be revamped.

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