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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 12df1f1 was 02a09ed, checked in by Martin Decky <martin@…>, 12 years ago

add basic infrastructure for IPv6 (inactive)
make inet_addr_t a universal address type

  • Property mode set to 100644
File size: 25.9 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{
[a1a101d]93 log_msg(LOG_DEFAULT, 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{
[a1a101d]102 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_notify_aconn(%d)", lsock_core->socket_id);
[a4ee3ab2]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
[a1a101d]113 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_create()");
[d786dea9]114 *rsock = NULL;
115
[db81577]116 sock = calloc(1, sizeof(tcp_sockdata_t));
[d786dea9]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{
[a1a101d]135 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_uncreate()");
[d786dea9]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
[a1a101d]144 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_finish_setup()");
[d786dea9]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
[a1a101d]173 log_msg(LOG_DEFAULT, 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
[a2e3ee6]181 inet_addr_any(&sock->laddr);
[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;
[05bfce7]205 struct sockaddr_in *addr;
206 size_t addr_size;
[04cd242]207 socket_core_t *sock_core;
208 tcp_sockdata_t *socket;
[05bfce7]209
[a1a101d]210 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_bind()");
211 log_msg(LOG_DEFAULT, LVL_DEBUG, " - async_data_write_accept");
[05bfce7]212
213 addr = NULL;
214
215 rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &addr_size);
[04cd242]216 if (rc != EOK) {
217 async_answer_0(callid, rc);
[05bfce7]218 goto out;
[04cd242]219 }
[05bfce7]220
221 if (addr_size != sizeof(struct sockaddr_in)) {
222 async_answer_0(callid, EINVAL);
223 goto out;
224 }
225
[a1a101d]226 log_msg(LOG_DEFAULT, LVL_DEBUG, " - call socket_bind");
[04cd242]227 rc = socket_bind(&client->sockets, &gsock, SOCKET_GET_SOCKET_ID(call),
[05bfce7]228 addr, addr_size, TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
[04cd242]229 last_used_port);
230 if (rc != EOK) {
231 async_answer_0(callid, rc);
[05bfce7]232 goto out;
[04cd242]233 }
[05bfce7]234
[a1a101d]235 log_msg(LOG_DEFAULT, LVL_DEBUG, " - call socket_cores_find");
[04cd242]236 sock_core = socket_cores_find(&client->sockets, SOCKET_GET_SOCKET_ID(call));
[05bfce7]237 if (sock_core == NULL) {
238 async_answer_0(callid, ENOENT);
239 goto out;
[04cd242]240 }
[05bfce7]241
242 socket = (tcp_sockdata_t *)sock_core->specific_data;
243 /* XXX Anything to do? */
244 (void) socket;
245
[a1a101d]246 log_msg(LOG_DEFAULT, LVL_DEBUG, " - success");
[a4ee3ab2]247 async_answer_0(callid, EOK);
[05bfce7]248
249out:
250 if (addr != NULL)
251 free(addr);
[04cd242]252}
253
254static void tcp_sock_listen(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
255{
256 int socket_id;
257 int backlog;
258 socket_core_t *sock_core;
259 tcp_sockdata_t *socket;
[ae481e0]260 tcp_error_t trc;
261 tcp_sock_t lsocket;
262 tcp_sock_t fsocket;
263 tcp_conn_t *conn;
264 tcp_sock_lconn_t *lconn;
265 int i;
[05bfce7]266 int rc;
[04cd242]267
[a1a101d]268 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_listen()");
[04cd242]269
270 socket_id = SOCKET_GET_SOCKET_ID(call);
271 backlog = SOCKET_GET_BACKLOG(call);
272
273 if (backlog < 0) {
274 async_answer_0(callid, EINVAL);
275 return;
276 }
277
[ae481e0]278 if (backlog > MAX_BACKLOG)
279 backlog = MAX_BACKLOG;
280
[04cd242]281 sock_core = socket_cores_find(&client->sockets, socket_id);
282 if (sock_core == NULL) {
283 async_answer_0(callid, ENOTSOCK);
284 return;
285 }
[05bfce7]286
287 if (sock_core->port <= 0) {
288 rc = socket_bind_free_port(&gsock, sock_core,
289 TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
290 last_used_port);
291 if (rc != EOK) {
292 async_answer_0(callid, rc);
293 return;
294 }
295
296 last_used_port = sock_core->port;
297 }
298
299 socket = (tcp_sockdata_t *) sock_core->specific_data;
300
[a4ee3ab2]301 /*
[ae481e0]302 * Prepare @c backlog listening connections.
[a4ee3ab2]303 */
[ae481e0]304 fibril_mutex_lock(&socket->lock);
[05bfce7]305
[ae481e0]306 socket->backlog = backlog;
[db81577]307 socket->lconn = calloc(backlog, sizeof(tcp_conn_t *));
[ae481e0]308 if (socket->lconn == NULL) {
309 fibril_mutex_unlock(&socket->lock);
310 async_answer_0(callid, ENOMEM);
311 return;
312 }
[05bfce7]313
[a1a101d]314 log_msg(LOG_DEFAULT, LVL_DEBUG, " - open connections");
[05bfce7]315
[a2e3ee6]316 inet_addr_any(&lsocket.addr);
[ae481e0]317 lsocket.port = sock_core->port;
[a2e3ee6]318
319 inet_addr_any(&fsocket.addr);
[ae481e0]320 fsocket.port = TCP_PORT_ANY;
[05bfce7]321
[ae481e0]322 for (i = 0; i < backlog; i++) {
323
[db81577]324 lconn = calloc(1, sizeof(tcp_sock_lconn_t));
[ae481e0]325 if (lconn == NULL) {
326 /* XXX Clean up */
327 fibril_mutex_unlock(&socket->lock);
328 async_answer_0(callid, ENOMEM);
329 return;
330 }
331
332 trc = tcp_uc_open(&lsocket, &fsocket, ap_passive,
333 tcp_open_nonblock, &conn);
334 if (conn == NULL) {
335 /* XXX Clean up */
336 fibril_mutex_unlock(&socket->lock);
337 async_answer_0(callid, ENOMEM);
338 return;
339 }
340
341 tcp_uc_set_cstate_cb(conn, tcp_sock_cstate_cb, lconn);
342
343 assert(trc == TCP_EOK);
344 conn->name = (char *)"S";
345
346 lconn->conn = conn;
347 lconn->socket = socket;
348 link_initialize(&lconn->ready_list);
349 socket->lconn[i] = lconn;
350 }
351
352 fibril_mutex_unlock(&socket->lock);
[a4ee3ab2]353 async_answer_0(callid, EOK);
[04cd242]354}
355
[02a09ed]356static void tcp_sock_connect(tcp_client_t *client, ipc_callid_t callid,
357 ipc_call_t call)
[04cd242]358{
[a1a101d]359 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_connect()");
[02a09ed]360
361 struct sockaddr_in6 *addr6 = NULL;
362 size_t addr_len;
363 int rc = async_data_write_accept((void **) &addr6, false, 0, 0, 0, &addr_len);
364 if (rc != EOK) {
[04cd242]365 async_answer_0(callid, rc);
366 return;
367 }
[02a09ed]368
369 if ((addr_len != sizeof(struct sockaddr_in)) &&
370 (addr_len != sizeof(struct sockaddr_in6))) {
371 async_answer_0(callid, EINVAL);
372 goto out;
373 }
374
375 struct sockaddr_in *addr = (struct sockaddr_in *) addr6;
376
377 int socket_id = SOCKET_GET_SOCKET_ID(call);
378 socket_core_t *sock_core = socket_cores_find(&client->sockets,
379 socket_id);
[04cd242]380 if (sock_core == NULL) {
381 async_answer_0(callid, ENOTSOCK);
[02a09ed]382 goto out;
[04cd242]383 }
[02a09ed]384
385 tcp_sockdata_t *socket =
386 (tcp_sockdata_t *) sock_core->specific_data;
387
[a4ee3ab2]388 if (sock_core->port <= 0) {
389 rc = socket_bind_free_port(&gsock, sock_core,
390 TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
391 last_used_port);
392 if (rc != EOK) {
393 async_answer_0(callid, rc);
[02a09ed]394 goto out;
[a4ee3ab2]395 }
[05bfce7]396
[a4ee3ab2]397 last_used_port = sock_core->port;
398 }
[02a09ed]399
[ae481e0]400 fibril_mutex_lock(&socket->lock);
[02a09ed]401
[a2e3ee6]402 if (inet_addr_is_any(&socket->laddr)) {
[c76e926]403 /* Determine local IP address */
[a2e3ee6]404 inet_addr_t loc_addr;
405 inet_addr_t rem_addr;
406
[02a09ed]407 switch (addr->sin_family) {
408 case AF_INET:
409 inet_sockaddr_in_addr(addr, &rem_addr);
410 break;
411 case AF_INET6:
412 inet_sockaddr_in6_addr(addr6, &rem_addr);
413 break;
414 default:
415 fibril_mutex_unlock(&socket->lock);
416 async_answer_0(callid, EINVAL);
417 goto out;
418 }
419
[c76e926]420 rc = inet_get_srcaddr(&rem_addr, 0, &loc_addr);
[0ac2158]421 if (rc != EOK) {
[ae481e0]422 fibril_mutex_unlock(&socket->lock);
[0ac2158]423 async_answer_0(callid, rc);
[a1a101d]424 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_connect: Failed to "
[c76e926]425 "determine local address.");
[02a09ed]426 goto out;
[0ac2158]427 }
[a2e3ee6]428
429 socket->laddr = loc_addr;
[0ac2158]430 }
[a2e3ee6]431
[02a09ed]432 tcp_sock_t lsocket;
433 tcp_sock_t fsocket;
434
[a2e3ee6]435 lsocket.addr = socket->laddr;
[0ac2158]436 lsocket.port = sock_core->port;
[a2e3ee6]437
[02a09ed]438 switch (addr->sin_family) {
439 case AF_INET:
440 inet_sockaddr_in_addr(addr, &fsocket.addr);
441 break;
442 case AF_INET6:
443 inet_sockaddr_in6_addr(addr6, &fsocket.addr);
444 break;
445 default:
446 fibril_mutex_unlock(&socket->lock);
447 async_answer_0(callid, EINVAL);
448 goto out;
449 }
450
[04cd242]451 fsocket.port = uint16_t_be2host(addr->sin_port);
[02a09ed]452
453 tcp_error_t trc = tcp_uc_open(&lsocket, &fsocket, ap_active, 0,
454 &socket->conn);
455
[704586fb]456 if (socket->conn != NULL)
[02a09ed]457 socket->conn->name = (char *) "C";
458
[ae481e0]459 fibril_mutex_unlock(&socket->lock);
[257feec]460
[04cd242]461 switch (trc) {
462 case TCP_EOK:
463 rc = EOK;
464 break;
465 case TCP_ERESET:
466 rc = ECONNREFUSED;
467 break;
468 default:
469 assert(false);
470 }
[257feec]471
[d786dea9]472 if (rc == EOK)
473 fibril_add_ready(socket->recv_fibril);
[257feec]474
[d786dea9]475 async_answer_0(callid, rc);
[02a09ed]476
477out:
478 if (addr6 != NULL)
479 free(addr6);
[04cd242]480}
481
482static void tcp_sock_accept(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
483{
484 ipc_call_t answer;
485 int socket_id;
[a4ee3ab2]486 int asock_id;
[04cd242]487 socket_core_t *sock_core;
488 tcp_sockdata_t *socket;
[a4ee3ab2]489 tcp_sockdata_t *asocket;
490 tcp_error_t trc;
[0ac2158]491 tcp_sock_t lsocket;
[a4ee3ab2]492 tcp_sock_t fsocket;
493 tcp_conn_t *conn;
[ae481e0]494 tcp_conn_t *rconn;
495 tcp_sock_lconn_t *lconn;
[a4ee3ab2]496 int rc;
[04cd242]497
[a1a101d]498 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_accept()");
[04cd242]499
500 socket_id = SOCKET_GET_SOCKET_ID(call);
[a4ee3ab2]501 asock_id = SOCKET_GET_NEW_SOCKET_ID(call);
[04cd242]502
503 sock_core = socket_cores_find(&client->sockets, socket_id);
504 if (sock_core == NULL) {
505 async_answer_0(callid, ENOTSOCK);
506 return;
507 }
[05bfce7]508
509 if (sock_core->port <= 0) {
510 rc = socket_bind_free_port(&gsock, sock_core,
511 TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
512 last_used_port);
513 if (rc != EOK) {
514 async_answer_0(callid, rc);
515 return;
516 }
517
518 last_used_port = sock_core->port;
519 }
[04cd242]520
521 socket = (tcp_sockdata_t *)sock_core->specific_data;
[ae481e0]522 fibril_mutex_lock(&socket->lock);
[a4ee3ab2]523
[a1a101d]524 log_msg(LOG_DEFAULT, LVL_DEBUG, " - verify socket->conn");
[a4ee3ab2]525 if (socket->conn != NULL) {
[ae481e0]526 fibril_mutex_unlock(&socket->lock);
[a4ee3ab2]527 async_answer_0(callid, EINVAL);
528 return;
529 }
530
[ae481e0]531 if (list_empty(&socket->ready)) {
532 fibril_mutex_unlock(&socket->lock);
533 async_answer_0(callid, ENOENT);
534 return;
535 }
536
537 lconn = list_get_instance(list_first(&socket->ready),
538 tcp_sock_lconn_t, ready_list);
539 list_remove(&lconn->ready_list);
540
541 conn = lconn->conn;
542 tcp_uc_set_cstate_cb(conn, NULL, NULL);
543
544 /* Replenish listening connection */
[a4ee3ab2]545
[a2e3ee6]546 inet_addr_any(&lsocket.addr);
[0ac2158]547 lsocket.port = sock_core->port;
[a2e3ee6]548
549 inet_addr_any(&fsocket.addr);
[3aa2642a]550 fsocket.port = TCP_PORT_ANY;
[a4ee3ab2]551
[ae481e0]552 trc = tcp_uc_open(&lsocket, &fsocket, ap_passive, tcp_open_nonblock,
553 &rconn);
554 if (rconn == NULL) {
555 /* XXX Clean up */
556 fibril_mutex_unlock(&socket->lock);
557 async_answer_0(callid, ENOMEM);
558 return;
559 }
[a4ee3ab2]560
[ae481e0]561 tcp_uc_set_cstate_cb(rconn, tcp_sock_cstate_cb, lconn);
[a4ee3ab2]562
[ae481e0]563 assert(trc == TCP_EOK);
564 rconn->name = (char *)"S";
[a4ee3ab2]565
[ae481e0]566 lconn->conn = rconn;
567
568 /* Allocate socket for accepted connection */
[a4ee3ab2]569
[d786dea9]570 rc = tcp_sock_create(client, &asocket);
571 if (rc != EOK) {
[ae481e0]572 fibril_mutex_unlock(&socket->lock);
[d786dea9]573 async_answer_0(callid, rc);
[a4ee3ab2]574 return;
575 }
576
577 asocket->conn = conn;
[a1a101d]578 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_accept():create asocket\n");
[a4ee3ab2]579
[d786dea9]580 rc = tcp_sock_finish_setup(asocket, &asock_id);
[a4ee3ab2]581 if (rc != EOK) {
[d786dea9]582 tcp_sock_uncreate(asocket);
[ae481e0]583 fibril_mutex_unlock(&socket->lock);
[a4ee3ab2]584 async_answer_0(callid, rc);
585 return;
586 }
587
[d786dea9]588 fibril_add_ready(asocket->recv_fibril);
[a4ee3ab2]589
[a1a101d]590 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_accept(): find acore\n");
[d786dea9]591
592 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, TCP_SOCK_FRAGMENT_SIZE);
[a4ee3ab2]593 SOCKET_SET_SOCKET_ID(answer, asock_id);
594 SOCKET_SET_ADDRESS_LENGTH(answer, sizeof(struct sockaddr_in));
[b1bd89ea]595
[d786dea9]596 async_answer_3(callid, asocket->sock_core->socket_id,
[b1bd89ea]597 IPC_GET_ARG1(answer), IPC_GET_ARG2(answer),
598 IPC_GET_ARG3(answer));
599
[a4ee3ab2]600 /* Push one fragment notification to client's queue */
[a1a101d]601 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_accept(): notify data\n");
[ae481e0]602 fibril_mutex_unlock(&socket->lock);
[04cd242]603}
604
605static void tcp_sock_send(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
606{
607 int socket_id;
608 int fragments;
609 int index;
610 socket_core_t *sock_core;
611 tcp_sockdata_t *socket;
612 ipc_call_t answer;
613 ipc_callid_t wcallid;
614 size_t length;
[d786dea9]615 uint8_t buffer[TCP_SOCK_FRAGMENT_SIZE];
[04cd242]616 tcp_error_t trc;
617 int rc;
618
[a1a101d]619 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_send()");
[04cd242]620 socket_id = SOCKET_GET_SOCKET_ID(call);
621 fragments = SOCKET_GET_DATA_FRAGMENTS(call);
622 SOCKET_GET_FLAGS(call);
623
624 sock_core = socket_cores_find(&client->sockets, socket_id);
625 if (sock_core == NULL) {
626 async_answer_0(callid, ENOTSOCK);
627 return;
628 }
629
630 socket = (tcp_sockdata_t *)sock_core->specific_data;
[ae481e0]631 fibril_mutex_lock(&socket->lock);
632
[04cd242]633 if (socket->conn == NULL) {
[ae481e0]634 fibril_mutex_unlock(&socket->lock);
[04cd242]635 async_answer_0(callid, ENOTCONN);
636 return;
637 }
638
639 for (index = 0; index < fragments; index++) {
640 if (!async_data_write_receive(&wcallid, &length)) {
[ae481e0]641 fibril_mutex_unlock(&socket->lock);
[04cd242]642 async_answer_0(callid, EINVAL);
643 return;
644 }
645
[d786dea9]646 if (length > TCP_SOCK_FRAGMENT_SIZE)
647 length = TCP_SOCK_FRAGMENT_SIZE;
[04cd242]648
649 rc = async_data_write_finalize(wcallid, buffer, length);
650 if (rc != EOK) {
[ae481e0]651 fibril_mutex_unlock(&socket->lock);
[04cd242]652 async_answer_0(callid, rc);
653 return;
654 }
655
656 trc = tcp_uc_send(socket->conn, buffer, length, 0);
657
658 switch (trc) {
659 case TCP_EOK:
660 rc = EOK;
661 break;
662 case TCP_ENOTEXIST:
663 rc = ENOTCONN;
664 break;
665 case TCP_ECLOSING:
666 rc = ENOTCONN;
667 break;
[d9e14fa4]668 case TCP_ERESET:
669 rc = ECONNABORTED;
670 break;
[04cd242]671 default:
672 assert(false);
673 }
674
675 if (rc != EOK) {
[ae481e0]676 fibril_mutex_unlock(&socket->lock);
[04cd242]677 async_answer_0(callid, rc);
678 return;
679 }
680 }
681
[b1bd89ea]682 IPC_SET_ARG1(answer, 0);
[d786dea9]683 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, TCP_SOCK_FRAGMENT_SIZE);
[b1bd89ea]684 async_answer_2(callid, EOK, IPC_GET_ARG1(answer),
685 IPC_GET_ARG2(answer));
[ae481e0]686 fibril_mutex_unlock(&socket->lock);
[04cd242]687}
688
689static void tcp_sock_sendto(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
690{
[a1a101d]691 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_sendto()");
[04cd242]692 async_answer_0(callid, ENOTSUP);
693}
694
[a4ee3ab2]695static void tcp_sock_recvfrom(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
[04cd242]696{
[a1a101d]697 log_msg(LOG_DEFAULT, LVL_DEBUG, "%p: tcp_sock_recv[from]()", client);
[02a09ed]698
699 int socket_id = SOCKET_GET_SOCKET_ID(call);
700
701 socket_core_t *sock_core =
702 socket_cores_find(&client->sockets, socket_id);
[04cd242]703 if (sock_core == NULL) {
704 async_answer_0(callid, ENOTSOCK);
705 return;
706 }
[02a09ed]707
708 tcp_sockdata_t *socket =
709 (tcp_sockdata_t *) sock_core->specific_data;
710
[ae481e0]711 fibril_mutex_lock(&socket->lock);
[257feec]712
[a4ee3ab2]713 if (socket->conn == NULL) {
[ae481e0]714 fibril_mutex_unlock(&socket->lock);
[a4ee3ab2]715 async_answer_0(callid, ENOTCONN);
716 return;
717 }
[02a09ed]718
[a1a101d]719 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_recvfrom(): lock recv_buffer_lock");
[02a09ed]720
[d786dea9]721 fibril_mutex_lock(&socket->recv_buffer_lock);
[02a09ed]722 while ((socket->recv_buffer_used == 0) &&
723 (socket->recv_error == TCP_EOK)) {
[a1a101d]724 log_msg(LOG_DEFAULT, LVL_DEBUG, "wait for recv_buffer_cv + recv_buffer_used != 0");
[d786dea9]725 fibril_condvar_wait(&socket->recv_buffer_cv,
726 &socket->recv_buffer_lock);
727 }
[257feec]728
[a1a101d]729 log_msg(LOG_DEFAULT, LVL_DEBUG, "Got data in sock recv_buffer");
[02a09ed]730
731 size_t data_len = socket->recv_buffer_used;
732 tcp_error_t trc = socket->recv_error;
733 int rc;
734
735 switch (trc) {
[04cd242]736 case TCP_EOK:
737 rc = EOK;
738 break;
739 case TCP_ENOTEXIST:
740 case TCP_ECLOSING:
741 rc = ENOTCONN;
742 break;
[d9e14fa4]743 case TCP_ERESET:
744 rc = ECONNABORTED;
745 break;
[04cd242]746 default:
747 assert(false);
748 }
[257feec]749
[a1a101d]750 log_msg(LOG_DEFAULT, LVL_DEBUG, "**** recv result -> %d", rc);
[257feec]751
[04cd242]752 if (rc != EOK) {
[d786dea9]753 fibril_mutex_unlock(&socket->recv_buffer_lock);
[ae481e0]754 fibril_mutex_unlock(&socket->lock);
[04cd242]755 async_answer_0(callid, rc);
756 return;
757 }
[02a09ed]758
759 ipc_callid_t rcallid;
760
[a4ee3ab2]761 if (IPC_GET_IMETHOD(call) == NET_SOCKET_RECVFROM) {
[a2e3ee6]762 /* Fill address */
[02a09ed]763 tcp_sock_t *rsock = &socket->conn->ident.foreign;
764 struct sockaddr_in addr;
765 struct sockaddr_in6 addr6;
766 size_t addr_length;
[a2e3ee6]767
[02a09ed]768 uint16_t addr_af = inet_addr_sockaddr_in(&rsock->addr, &addr,
769 &addr6);
[a2e3ee6]770
[02a09ed]771 switch (addr_af) {
772 case AF_INET:
773 addr.sin_port = host2uint16_t_be(rsock->port);
774
775 log_msg(LOG_DEFAULT, LVL_DEBUG, "addr read receive");
776 if (!async_data_read_receive(&rcallid, &addr_length)) {
777 fibril_mutex_unlock(&socket->recv_buffer_lock);
778 fibril_mutex_unlock(&socket->lock);
779 async_answer_0(callid, EINVAL);
780 return;
781 }
782
783 if (addr_length > sizeof(addr))
784 addr_length = sizeof(addr);
785
786 log_msg(LOG_DEFAULT, LVL_DEBUG, "addr read finalize");
787 rc = async_data_read_finalize(rcallid, &addr, addr_length);
788 if (rc != EOK) {
789 fibril_mutex_unlock(&socket->recv_buffer_lock);
790 fibril_mutex_unlock(&socket->lock);
791 async_answer_0(callid, EINVAL);
792 return;
793 }
794
795 break;
796 case AF_INET6:
797 addr6.sin6_port = host2uint16_t_be(rsock->port);
798
799 log_msg(LOG_DEFAULT, LVL_DEBUG, "addr6 read receive");
800 if (!async_data_read_receive(&rcallid, &addr_length)) {
801 fibril_mutex_unlock(&socket->recv_buffer_lock);
802 fibril_mutex_unlock(&socket->lock);
803 async_answer_0(callid, EINVAL);
804 return;
805 }
806
807 if (addr_length > sizeof(addr6))
808 addr_length = sizeof(addr6);
809
810 log_msg(LOG_DEFAULT, LVL_DEBUG, "addr6 read finalize");
811 rc = async_data_read_finalize(rcallid, &addr6, addr_length);
812 if (rc != EOK) {
813 fibril_mutex_unlock(&socket->recv_buffer_lock);
814 fibril_mutex_unlock(&socket->lock);
815 async_answer_0(callid, EINVAL);
816 return;
817 }
818
819 break;
820 default:
[d786dea9]821 fibril_mutex_unlock(&socket->recv_buffer_lock);
[ae481e0]822 fibril_mutex_unlock(&socket->lock);
[a4ee3ab2]823 async_answer_0(callid, EINVAL);
824 return;
825 }
826 }
[257feec]827
[a1a101d]828 log_msg(LOG_DEFAULT, LVL_DEBUG, "data read receive");
[02a09ed]829
830 size_t length;
[04cd242]831 if (!async_data_read_receive(&rcallid, &length)) {
[d786dea9]832 fibril_mutex_unlock(&socket->recv_buffer_lock);
[ae481e0]833 fibril_mutex_unlock(&socket->lock);
[04cd242]834 async_answer_0(callid, EINVAL);
835 return;
836 }
[257feec]837
[a4ee3ab2]838 if (length > data_len)
[04cd242]839 length = data_len;
[257feec]840
[a1a101d]841 log_msg(LOG_DEFAULT, LVL_DEBUG, "data read finalize");
[02a09ed]842
[d786dea9]843 rc = async_data_read_finalize(rcallid, socket->recv_buffer, length);
[257feec]844
[9094c0f]845 socket->recv_buffer_used -= length;
[02a09ed]846
[a1a101d]847 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_recvfrom: %zu left in buffer",
[9094c0f]848 socket->recv_buffer_used);
[02a09ed]849
[9094c0f]850 if (socket->recv_buffer_used > 0) {
851 memmove(socket->recv_buffer, socket->recv_buffer + length,
852 socket->recv_buffer_used);
853 tcp_sock_notify_data(socket->sock_core);
854 }
[257feec]855
[d786dea9]856 fibril_condvar_broadcast(&socket->recv_buffer_cv);
[02a09ed]857
858 if ((length < data_len) && (rc == EOK))
[a4ee3ab2]859 rc = EOVERFLOW;
[02a09ed]860
861 ipc_call_t answer;
862
[04cd242]863 SOCKET_SET_READ_DATA_LENGTH(answer, length);
[b1bd89ea]864 async_answer_1(callid, EOK, IPC_GET_ARG1(answer));
[257feec]865
[d786dea9]866 fibril_mutex_unlock(&socket->recv_buffer_lock);
[ae481e0]867 fibril_mutex_unlock(&socket->lock);
[04cd242]868}
869
870static void tcp_sock_close(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
871{
872 int socket_id;
873 socket_core_t *sock_core;
874 tcp_sockdata_t *socket;
[b0d82d1]875 tcp_error_t trc;
[04cd242]876 int rc;
877
[a1a101d]878 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_close()");
[04cd242]879 socket_id = SOCKET_GET_SOCKET_ID(call);
880
881 sock_core = socket_cores_find(&client->sockets, socket_id);
882 if (sock_core == NULL) {
883 async_answer_0(callid, ENOTSOCK);
884 return;
885 }
886
887 socket = (tcp_sockdata_t *)sock_core->specific_data;
[ae481e0]888 fibril_mutex_lock(&socket->lock);
[b0d82d1]889
[415578ef]890 if (socket->conn != NULL) {
[522a4f9]891 trc = tcp_uc_close(socket->conn);
892 if (trc != TCP_EOK && trc != TCP_ENOTEXIST) {
[ae481e0]893 fibril_mutex_unlock(&socket->lock);
[522a4f9]894 async_answer_0(callid, EBADF);
[415578ef]895 return;
896 }
897 }
[7a8c1c4e]898
[798105ca]899 /* Grab recv_buffer_lock because of CV wait in tcp_sock_recv_fibril() */
900 fibril_mutex_lock(&socket->recv_buffer_lock);
901 socket->sock_core = NULL;
902 fibril_mutex_unlock(&socket->recv_buffer_lock);
903
[c76e926]904 rc = socket_destroy(NULL, socket_id, &client->sockets, &gsock,
[04cd242]905 tcp_free_sock_data);
906 if (rc != EOK) {
[ae481e0]907 fibril_mutex_unlock(&socket->lock);
[04cd242]908 async_answer_0(callid, rc);
909 return;
910 }
911
[ae481e0]912 fibril_mutex_unlock(&socket->lock);
[04cd242]913 async_answer_0(callid, EOK);
914}
915
916static void tcp_sock_getsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
917{
[a1a101d]918 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_getsockopt()");
[04cd242]919 async_answer_0(callid, ENOTSUP);
920}
921
922static void tcp_sock_setsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
923{
[a1a101d]924 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_setsockopt()");
[04cd242]925 async_answer_0(callid, ENOTSUP);
926}
927
[ae481e0]928/** Called when connection state changes. */
929static void tcp_sock_cstate_cb(tcp_conn_t *conn, void *arg)
930{
931 tcp_conn_status_t cstatus;
932 tcp_sock_lconn_t *lconn = (tcp_sock_lconn_t *)arg;
933 tcp_sockdata_t *socket = lconn->socket;
934
[a1a101d]935 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_cstate_cb()");
[ae481e0]936 fibril_mutex_lock(&socket->lock);
937 assert(conn == lconn->conn);
938
939 tcp_uc_status(conn, &cstatus);
940 if (cstatus.cstate != st_established) {
941 fibril_mutex_unlock(&socket->lock);
942 return;
943 }
944
945 assert_link_not_used(&lconn->ready_list);
946 list_append(&lconn->ready_list, &socket->ready);
947
[a1a101d]948 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_cstate_cb(): notify accept");
[ae481e0]949
950 /* Push one accept notification to client's queue */
951 tcp_sock_notify_aconn(socket->sock_core);
952 fibril_mutex_unlock(&socket->lock);
953}
954
[d786dea9]955static int tcp_sock_recv_fibril(void *arg)
956{
957 tcp_sockdata_t *sock = (tcp_sockdata_t *)arg;
958 size_t data_len;
959 xflags_t xflags;
960 tcp_error_t trc;
961
[a1a101d]962 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_recv_fibril()");
[d786dea9]963
[798105ca]964 fibril_mutex_lock(&sock->recv_buffer_lock);
965
[d786dea9]966 while (true) {
[a1a101d]967 log_msg(LOG_DEFAULT, LVL_DEBUG, "call tcp_uc_receive()");
[798105ca]968 while (sock->recv_buffer_used != 0 && sock->sock_core != NULL)
[d786dea9]969 fibril_condvar_wait(&sock->recv_buffer_cv,
970 &sock->recv_buffer_lock);
971
972 trc = tcp_uc_receive(sock->conn, sock->recv_buffer,
973 TCP_SOCK_FRAGMENT_SIZE, &data_len, &xflags);
974
975 if (trc != TCP_EOK) {
976 sock->recv_error = trc;
[7c912b6]977 fibril_condvar_broadcast(&sock->recv_buffer_cv);
[798105ca]978 if (sock->sock_core != NULL)
979 tcp_sock_notify_data(sock->sock_core);
[d786dea9]980 break;
981 }
982
[a1a101d]983 log_msg(LOG_DEFAULT, LVL_DEBUG, "got data - broadcast recv_buffer_cv");
[d786dea9]984
985 sock->recv_buffer_used = data_len;
986 fibril_condvar_broadcast(&sock->recv_buffer_cv);
[798105ca]987 if (sock->sock_core != NULL)
988 tcp_sock_notify_data(sock->sock_core);
[d786dea9]989 }
990
[798105ca]991 fibril_mutex_unlock(&sock->recv_buffer_lock);
992
[d786dea9]993 tcp_uc_delete(sock->conn);
994
995 return 0;
996}
997
[c76e926]998static void tcp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
[04cd242]999{
1000 ipc_callid_t callid;
1001 ipc_call_t call;
1002 tcp_client_t client;
1003
1004 /* Accept the connection */
1005 async_answer_0(iid, EOK);
1006
[c76e926]1007 client.sess = async_callback_receive(EXCHANGE_SERIALIZE);
[04cd242]1008 socket_cores_initialize(&client.sockets);
1009
1010 while (true) {
1011 callid = async_get_call(&call);
1012 if (!IPC_GET_IMETHOD(call))
1013 break;
1014
[a1a101d]1015 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_connection: METHOD=%d\n",
[04cd242]1016 (int)IPC_GET_IMETHOD(call));
1017
1018 switch (IPC_GET_IMETHOD(call)) {
1019 case NET_SOCKET:
1020 tcp_sock_socket(&client, callid, call);
1021 break;
1022 case NET_SOCKET_BIND:
1023 tcp_sock_bind(&client, callid, call);
1024 break;
1025 case NET_SOCKET_LISTEN:
1026 tcp_sock_listen(&client, callid, call);
1027 break;
1028 case NET_SOCKET_CONNECT:
1029 tcp_sock_connect(&client, callid, call);
1030 break;
1031 case NET_SOCKET_ACCEPT:
1032 tcp_sock_accept(&client, callid, call);
1033 break;
1034 case NET_SOCKET_SEND:
1035 tcp_sock_send(&client, callid, call);
1036 break;
1037 case NET_SOCKET_SENDTO:
1038 tcp_sock_sendto(&client, callid, call);
1039 break;
1040 case NET_SOCKET_RECV:
1041 case NET_SOCKET_RECVFROM:
1042 tcp_sock_recvfrom(&client, callid, call);
1043 break;
1044 case NET_SOCKET_CLOSE:
1045 tcp_sock_close(&client, callid, call);
1046 break;
1047 case NET_SOCKET_GETSOCKOPT:
1048 tcp_sock_getsockopt(&client, callid, call);
1049 break;
1050 case NET_SOCKET_SETSOCKOPT:
1051 tcp_sock_setsockopt(&client, callid, call);
1052 break;
1053 default:
1054 async_answer_0(callid, ENOTSUP);
1055 break;
1056 }
1057 }
[0d520a2]1058
1059 /* Clean up */
[a1a101d]1060 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_connection: Clean up");
[0d520a2]1061 async_hangup(client.sess);
1062 socket_cores_release(NULL, &client.sockets, &gsock, tcp_free_sock_data);
[04cd242]1063}
1064
1065/**
1066 * @}
1067 */
Note: See TracBrowser for help on using the repository browser.