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

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

get rid of net/modules.{c|h}

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