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

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

do not allocate the buffer on stack (thx Antonin Steinhauser)

  • Property mode set to 100644
File size: 26.0 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;
615 tcp_error_t trc;
616 int rc;
[f4a27304]617
618 uint8_t *buffer = calloc(TCP_SOCK_FRAGMENT_SIZE, 1);
619 if (buffer == NULL) {
620 async_answer_0(callid, ENOMEM);
621 return;
622 }
[04cd242]623
[a1a101d]624 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_send()");
[04cd242]625 socket_id = SOCKET_GET_SOCKET_ID(call);
626 fragments = SOCKET_GET_DATA_FRAGMENTS(call);
627 SOCKET_GET_FLAGS(call);
628
629 sock_core = socket_cores_find(&client->sockets, socket_id);
630 if (sock_core == NULL) {
631 async_answer_0(callid, ENOTSOCK);
[f4a27304]632 goto out;
[04cd242]633 }
634
635 socket = (tcp_sockdata_t *)sock_core->specific_data;
[ae481e0]636 fibril_mutex_lock(&socket->lock);
637
[04cd242]638 if (socket->conn == NULL) {
[ae481e0]639 fibril_mutex_unlock(&socket->lock);
[04cd242]640 async_answer_0(callid, ENOTCONN);
641 return;
642 }
643
644 for (index = 0; index < fragments; index++) {
645 if (!async_data_write_receive(&wcallid, &length)) {
[ae481e0]646 fibril_mutex_unlock(&socket->lock);
[04cd242]647 async_answer_0(callid, EINVAL);
[f4a27304]648 goto out;
[04cd242]649 }
650
[d786dea9]651 if (length > TCP_SOCK_FRAGMENT_SIZE)
652 length = TCP_SOCK_FRAGMENT_SIZE;
[04cd242]653
654 rc = async_data_write_finalize(wcallid, buffer, length);
655 if (rc != EOK) {
[ae481e0]656 fibril_mutex_unlock(&socket->lock);
[04cd242]657 async_answer_0(callid, rc);
[f4a27304]658 goto out;
[04cd242]659 }
660
661 trc = tcp_uc_send(socket->conn, buffer, length, 0);
662
663 switch (trc) {
664 case TCP_EOK:
665 rc = EOK;
666 break;
667 case TCP_ENOTEXIST:
668 rc = ENOTCONN;
669 break;
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
680 if (rc != EOK) {
[ae481e0]681 fibril_mutex_unlock(&socket->lock);
[04cd242]682 async_answer_0(callid, rc);
[f4a27304]683 goto out;
[04cd242]684 }
685 }
686
[b1bd89ea]687 IPC_SET_ARG1(answer, 0);
[d786dea9]688 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, TCP_SOCK_FRAGMENT_SIZE);
[b1bd89ea]689 async_answer_2(callid, EOK, IPC_GET_ARG1(answer),
690 IPC_GET_ARG2(answer));
[ae481e0]691 fibril_mutex_unlock(&socket->lock);
[f4a27304]692
693out:
694 free(buffer);
[04cd242]695}
696
697static void tcp_sock_sendto(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
698{
[a1a101d]699 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_sendto()");
[04cd242]700 async_answer_0(callid, ENOTSUP);
701}
702
[a4ee3ab2]703static void tcp_sock_recvfrom(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
[04cd242]704{
[a1a101d]705 log_msg(LOG_DEFAULT, LVL_DEBUG, "%p: tcp_sock_recv[from]()", client);
[02a09ed]706
707 int socket_id = SOCKET_GET_SOCKET_ID(call);
708
709 socket_core_t *sock_core =
710 socket_cores_find(&client->sockets, socket_id);
[04cd242]711 if (sock_core == NULL) {
712 async_answer_0(callid, ENOTSOCK);
713 return;
714 }
[02a09ed]715
716 tcp_sockdata_t *socket =
717 (tcp_sockdata_t *) sock_core->specific_data;
718
[ae481e0]719 fibril_mutex_lock(&socket->lock);
[257feec]720
[a4ee3ab2]721 if (socket->conn == NULL) {
[ae481e0]722 fibril_mutex_unlock(&socket->lock);
[a4ee3ab2]723 async_answer_0(callid, ENOTCONN);
724 return;
725 }
[02a09ed]726
[a1a101d]727 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_recvfrom(): lock recv_buffer_lock");
[02a09ed]728
[d786dea9]729 fibril_mutex_lock(&socket->recv_buffer_lock);
[02a09ed]730 while ((socket->recv_buffer_used == 0) &&
731 (socket->recv_error == TCP_EOK)) {
[a1a101d]732 log_msg(LOG_DEFAULT, LVL_DEBUG, "wait for recv_buffer_cv + recv_buffer_used != 0");
[d786dea9]733 fibril_condvar_wait(&socket->recv_buffer_cv,
734 &socket->recv_buffer_lock);
735 }
[257feec]736
[a1a101d]737 log_msg(LOG_DEFAULT, LVL_DEBUG, "Got data in sock recv_buffer");
[02a09ed]738
739 size_t data_len = socket->recv_buffer_used;
740 tcp_error_t trc = socket->recv_error;
741 int rc;
742
743 switch (trc) {
[04cd242]744 case TCP_EOK:
745 rc = EOK;
746 break;
747 case TCP_ENOTEXIST:
748 case TCP_ECLOSING:
749 rc = ENOTCONN;
750 break;
[d9e14fa4]751 case TCP_ERESET:
752 rc = ECONNABORTED;
753 break;
[04cd242]754 default:
755 assert(false);
756 }
[257feec]757
[a1a101d]758 log_msg(LOG_DEFAULT, LVL_DEBUG, "**** recv result -> %d", rc);
[257feec]759
[04cd242]760 if (rc != EOK) {
[d786dea9]761 fibril_mutex_unlock(&socket->recv_buffer_lock);
[ae481e0]762 fibril_mutex_unlock(&socket->lock);
[04cd242]763 async_answer_0(callid, rc);
764 return;
765 }
[02a09ed]766
767 ipc_callid_t rcallid;
768
[a4ee3ab2]769 if (IPC_GET_IMETHOD(call) == NET_SOCKET_RECVFROM) {
[a2e3ee6]770 /* Fill address */
[02a09ed]771 tcp_sock_t *rsock = &socket->conn->ident.foreign;
772 struct sockaddr_in addr;
773 struct sockaddr_in6 addr6;
774 size_t addr_length;
[a2e3ee6]775
[02a09ed]776 uint16_t addr_af = inet_addr_sockaddr_in(&rsock->addr, &addr,
777 &addr6);
[a2e3ee6]778
[02a09ed]779 switch (addr_af) {
780 case AF_INET:
781 addr.sin_port = host2uint16_t_be(rsock->port);
782
783 log_msg(LOG_DEFAULT, LVL_DEBUG, "addr read receive");
784 if (!async_data_read_receive(&rcallid, &addr_length)) {
785 fibril_mutex_unlock(&socket->recv_buffer_lock);
786 fibril_mutex_unlock(&socket->lock);
787 async_answer_0(callid, EINVAL);
788 return;
789 }
790
791 if (addr_length > sizeof(addr))
792 addr_length = sizeof(addr);
793
794 log_msg(LOG_DEFAULT, LVL_DEBUG, "addr read finalize");
795 rc = async_data_read_finalize(rcallid, &addr, addr_length);
796 if (rc != EOK) {
797 fibril_mutex_unlock(&socket->recv_buffer_lock);
798 fibril_mutex_unlock(&socket->lock);
799 async_answer_0(callid, EINVAL);
800 return;
801 }
802
803 break;
804 case AF_INET6:
805 addr6.sin6_port = host2uint16_t_be(rsock->port);
806
807 log_msg(LOG_DEFAULT, LVL_DEBUG, "addr6 read receive");
808 if (!async_data_read_receive(&rcallid, &addr_length)) {
809 fibril_mutex_unlock(&socket->recv_buffer_lock);
810 fibril_mutex_unlock(&socket->lock);
811 async_answer_0(callid, EINVAL);
812 return;
813 }
814
815 if (addr_length > sizeof(addr6))
816 addr_length = sizeof(addr6);
817
818 log_msg(LOG_DEFAULT, LVL_DEBUG, "addr6 read finalize");
819 rc = async_data_read_finalize(rcallid, &addr6, addr_length);
820 if (rc != EOK) {
821 fibril_mutex_unlock(&socket->recv_buffer_lock);
822 fibril_mutex_unlock(&socket->lock);
823 async_answer_0(callid, EINVAL);
824 return;
825 }
826
827 break;
828 default:
[d786dea9]829 fibril_mutex_unlock(&socket->recv_buffer_lock);
[ae481e0]830 fibril_mutex_unlock(&socket->lock);
[a4ee3ab2]831 async_answer_0(callid, EINVAL);
832 return;
833 }
834 }
[257feec]835
[a1a101d]836 log_msg(LOG_DEFAULT, LVL_DEBUG, "data read receive");
[02a09ed]837
838 size_t length;
[04cd242]839 if (!async_data_read_receive(&rcallid, &length)) {
[d786dea9]840 fibril_mutex_unlock(&socket->recv_buffer_lock);
[ae481e0]841 fibril_mutex_unlock(&socket->lock);
[04cd242]842 async_answer_0(callid, EINVAL);
843 return;
844 }
[257feec]845
[a4ee3ab2]846 if (length > data_len)
[04cd242]847 length = data_len;
[257feec]848
[a1a101d]849 log_msg(LOG_DEFAULT, LVL_DEBUG, "data read finalize");
[02a09ed]850
[d786dea9]851 rc = async_data_read_finalize(rcallid, socket->recv_buffer, length);
[257feec]852
[9094c0f]853 socket->recv_buffer_used -= length;
[02a09ed]854
[a1a101d]855 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_recvfrom: %zu left in buffer",
[9094c0f]856 socket->recv_buffer_used);
[02a09ed]857
[9094c0f]858 if (socket->recv_buffer_used > 0) {
859 memmove(socket->recv_buffer, socket->recv_buffer + length,
860 socket->recv_buffer_used);
861 tcp_sock_notify_data(socket->sock_core);
862 }
[257feec]863
[d786dea9]864 fibril_condvar_broadcast(&socket->recv_buffer_cv);
[02a09ed]865
866 if ((length < data_len) && (rc == EOK))
[a4ee3ab2]867 rc = EOVERFLOW;
[02a09ed]868
869 ipc_call_t answer;
870
[04cd242]871 SOCKET_SET_READ_DATA_LENGTH(answer, length);
[b1bd89ea]872 async_answer_1(callid, EOK, IPC_GET_ARG1(answer));
[257feec]873
[d786dea9]874 fibril_mutex_unlock(&socket->recv_buffer_lock);
[ae481e0]875 fibril_mutex_unlock(&socket->lock);
[04cd242]876}
877
878static void tcp_sock_close(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
879{
880 int socket_id;
881 socket_core_t *sock_core;
882 tcp_sockdata_t *socket;
[b0d82d1]883 tcp_error_t trc;
[04cd242]884 int rc;
885
[a1a101d]886 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_close()");
[04cd242]887 socket_id = SOCKET_GET_SOCKET_ID(call);
888
889 sock_core = socket_cores_find(&client->sockets, socket_id);
890 if (sock_core == NULL) {
891 async_answer_0(callid, ENOTSOCK);
892 return;
893 }
894
895 socket = (tcp_sockdata_t *)sock_core->specific_data;
[ae481e0]896 fibril_mutex_lock(&socket->lock);
[b0d82d1]897
[415578ef]898 if (socket->conn != NULL) {
[522a4f9]899 trc = tcp_uc_close(socket->conn);
900 if (trc != TCP_EOK && trc != TCP_ENOTEXIST) {
[ae481e0]901 fibril_mutex_unlock(&socket->lock);
[522a4f9]902 async_answer_0(callid, EBADF);
[415578ef]903 return;
904 }
905 }
[7a8c1c4e]906
[798105ca]907 /* Grab recv_buffer_lock because of CV wait in tcp_sock_recv_fibril() */
908 fibril_mutex_lock(&socket->recv_buffer_lock);
909 socket->sock_core = NULL;
910 fibril_mutex_unlock(&socket->recv_buffer_lock);
911
[c76e926]912 rc = socket_destroy(NULL, socket_id, &client->sockets, &gsock,
[04cd242]913 tcp_free_sock_data);
914 if (rc != EOK) {
[ae481e0]915 fibril_mutex_unlock(&socket->lock);
[04cd242]916 async_answer_0(callid, rc);
917 return;
918 }
919
[ae481e0]920 fibril_mutex_unlock(&socket->lock);
[04cd242]921 async_answer_0(callid, EOK);
922}
923
924static void tcp_sock_getsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
925{
[a1a101d]926 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_getsockopt()");
[04cd242]927 async_answer_0(callid, ENOTSUP);
928}
929
930static void tcp_sock_setsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
931{
[a1a101d]932 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_setsockopt()");
[04cd242]933 async_answer_0(callid, ENOTSUP);
934}
935
[ae481e0]936/** Called when connection state changes. */
937static void tcp_sock_cstate_cb(tcp_conn_t *conn, void *arg)
938{
939 tcp_conn_status_t cstatus;
940 tcp_sock_lconn_t *lconn = (tcp_sock_lconn_t *)arg;
941 tcp_sockdata_t *socket = lconn->socket;
942
[a1a101d]943 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_cstate_cb()");
[ae481e0]944 fibril_mutex_lock(&socket->lock);
945 assert(conn == lconn->conn);
946
947 tcp_uc_status(conn, &cstatus);
948 if (cstatus.cstate != st_established) {
949 fibril_mutex_unlock(&socket->lock);
950 return;
951 }
952
953 assert_link_not_used(&lconn->ready_list);
954 list_append(&lconn->ready_list, &socket->ready);
955
[a1a101d]956 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_cstate_cb(): notify accept");
[ae481e0]957
958 /* Push one accept notification to client's queue */
959 tcp_sock_notify_aconn(socket->sock_core);
960 fibril_mutex_unlock(&socket->lock);
961}
962
[d786dea9]963static int tcp_sock_recv_fibril(void *arg)
964{
965 tcp_sockdata_t *sock = (tcp_sockdata_t *)arg;
966 size_t data_len;
967 xflags_t xflags;
968 tcp_error_t trc;
969
[a1a101d]970 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_recv_fibril()");
[d786dea9]971
[798105ca]972 fibril_mutex_lock(&sock->recv_buffer_lock);
973
[d786dea9]974 while (true) {
[a1a101d]975 log_msg(LOG_DEFAULT, LVL_DEBUG, "call tcp_uc_receive()");
[798105ca]976 while (sock->recv_buffer_used != 0 && sock->sock_core != NULL)
[d786dea9]977 fibril_condvar_wait(&sock->recv_buffer_cv,
978 &sock->recv_buffer_lock);
979
980 trc = tcp_uc_receive(sock->conn, sock->recv_buffer,
981 TCP_SOCK_FRAGMENT_SIZE, &data_len, &xflags);
982
983 if (trc != TCP_EOK) {
984 sock->recv_error = trc;
[7c912b6]985 fibril_condvar_broadcast(&sock->recv_buffer_cv);
[798105ca]986 if (sock->sock_core != NULL)
987 tcp_sock_notify_data(sock->sock_core);
[d786dea9]988 break;
989 }
990
[a1a101d]991 log_msg(LOG_DEFAULT, LVL_DEBUG, "got data - broadcast recv_buffer_cv");
[d786dea9]992
993 sock->recv_buffer_used = data_len;
994 fibril_condvar_broadcast(&sock->recv_buffer_cv);
[798105ca]995 if (sock->sock_core != NULL)
996 tcp_sock_notify_data(sock->sock_core);
[d786dea9]997 }
998
[798105ca]999 fibril_mutex_unlock(&sock->recv_buffer_lock);
1000
[d786dea9]1001 tcp_uc_delete(sock->conn);
1002
1003 return 0;
1004}
1005
[c76e926]1006static void tcp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
[04cd242]1007{
1008 ipc_callid_t callid;
1009 ipc_call_t call;
1010 tcp_client_t client;
1011
1012 /* Accept the connection */
1013 async_answer_0(iid, EOK);
1014
[c76e926]1015 client.sess = async_callback_receive(EXCHANGE_SERIALIZE);
[04cd242]1016 socket_cores_initialize(&client.sockets);
1017
1018 while (true) {
1019 callid = async_get_call(&call);
1020 if (!IPC_GET_IMETHOD(call))
1021 break;
1022
[a1a101d]1023 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_connection: METHOD=%d\n",
[04cd242]1024 (int)IPC_GET_IMETHOD(call));
1025
1026 switch (IPC_GET_IMETHOD(call)) {
1027 case NET_SOCKET:
1028 tcp_sock_socket(&client, callid, call);
1029 break;
1030 case NET_SOCKET_BIND:
1031 tcp_sock_bind(&client, callid, call);
1032 break;
1033 case NET_SOCKET_LISTEN:
1034 tcp_sock_listen(&client, callid, call);
1035 break;
1036 case NET_SOCKET_CONNECT:
1037 tcp_sock_connect(&client, callid, call);
1038 break;
1039 case NET_SOCKET_ACCEPT:
1040 tcp_sock_accept(&client, callid, call);
1041 break;
1042 case NET_SOCKET_SEND:
1043 tcp_sock_send(&client, callid, call);
1044 break;
1045 case NET_SOCKET_SENDTO:
1046 tcp_sock_sendto(&client, callid, call);
1047 break;
1048 case NET_SOCKET_RECV:
1049 case NET_SOCKET_RECVFROM:
1050 tcp_sock_recvfrom(&client, callid, call);
1051 break;
1052 case NET_SOCKET_CLOSE:
1053 tcp_sock_close(&client, callid, call);
1054 break;
1055 case NET_SOCKET_GETSOCKOPT:
1056 tcp_sock_getsockopt(&client, callid, call);
1057 break;
1058 case NET_SOCKET_SETSOCKOPT:
1059 tcp_sock_setsockopt(&client, callid, call);
1060 break;
1061 default:
1062 async_answer_0(callid, ENOTSUP);
1063 break;
1064 }
1065 }
[0d520a2]1066
1067 /* Clean up */
[a1a101d]1068 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_connection: Clean up");
[0d520a2]1069 async_hangup(client.sess);
1070 socket_cores_release(NULL, &client.sockets, &gsock, tcp_free_sock_data);
[04cd242]1071}
1072
1073/**
1074 * @}
1075 */
Note: See TracBrowser for help on using the repository browser.