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

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

make tcp_sock_bind() structurally similar to udp_sock_bind()
if calling listen() or accept() before bind() then find to a free port

  • Property mode set to 100644
File size: 24.4 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
[0ac2158]181 sock->laddr.ipv4 = TCP_IPV4_ANY;
[ae481e0]182 sock->lconn = NULL;
183 sock->backlog = 0;
[04cd242]184
185 sock_id = SOCKET_GET_SOCKET_ID(call);
[d786dea9]186 rc = tcp_sock_finish_setup(sock, &sock_id);
[04cd242]187 if (rc != EOK) {
[d786dea9]188 tcp_sock_uncreate(sock);
[04cd242]189 async_answer_0(callid, rc);
190 return;
191 }
192
193 SOCKET_SET_SOCKET_ID(answer, sock_id);
194
[d786dea9]195 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, TCP_SOCK_FRAGMENT_SIZE);
[04cd242]196 SOCKET_SET_HEADER_SIZE(answer, sizeof(tcp_header_t));
[b1bd89ea]197
198 async_answer_3(callid, EOK, IPC_GET_ARG1(answer),
199 IPC_GET_ARG2(answer), IPC_GET_ARG3(answer));
[04cd242]200}
201
202static void tcp_sock_bind(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
203{
204 int rc;
[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
[ae481e0]316 lsocket.addr.ipv4 = TCP_IPV4_ANY;
317 lsocket.port = sock_core->port;
318 fsocket.addr.ipv4 = TCP_IPV4_ANY;
319 fsocket.port = TCP_PORT_ANY;
[05bfce7]320
[ae481e0]321 for (i = 0; i < backlog; i++) {
322
[db81577]323 lconn = calloc(1, sizeof(tcp_sock_lconn_t));
[ae481e0]324 if (lconn == NULL) {
325 /* XXX Clean up */
326 fibril_mutex_unlock(&socket->lock);
327 async_answer_0(callid, ENOMEM);
328 return;
329 }
330
331 trc = tcp_uc_open(&lsocket, &fsocket, ap_passive,
332 tcp_open_nonblock, &conn);
333 if (conn == NULL) {
334 /* XXX Clean up */
335 fibril_mutex_unlock(&socket->lock);
336 async_answer_0(callid, ENOMEM);
337 return;
338 }
339
340 tcp_uc_set_cstate_cb(conn, tcp_sock_cstate_cb, lconn);
341
342 assert(trc == TCP_EOK);
343 conn->name = (char *)"S";
344
345 lconn->conn = conn;
346 lconn->socket = socket;
347 link_initialize(&lconn->ready_list);
348 socket->lconn[i] = lconn;
349 }
350
351 fibril_mutex_unlock(&socket->lock);
[a4ee3ab2]352 async_answer_0(callid, EOK);
[04cd242]353}
354
355static void tcp_sock_connect(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
356{
357 int rc;
358 struct sockaddr_in *addr;
359 int socket_id;
360 size_t addr_len;
361 socket_core_t *sock_core;
362 tcp_sockdata_t *socket;
363 tcp_error_t trc;
[0ac2158]364 tcp_sock_t lsocket;
[04cd242]365 tcp_sock_t fsocket;
366
[a1a101d]367 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_connect()");
[04cd242]368
369 rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &addr_len);
370 if (rc != EOK || addr_len != sizeof(struct sockaddr_in)) {
371 async_answer_0(callid, rc);
372 return;
373 }
374
375 socket_id = SOCKET_GET_SOCKET_ID(call);
376
377 sock_core = socket_cores_find(&client->sockets, socket_id);
378 if (sock_core == NULL) {
379 async_answer_0(callid, ENOTSOCK);
380 return;
381 }
382
383 socket = (tcp_sockdata_t *)sock_core->specific_data;
[a4ee3ab2]384 if (sock_core->port <= 0) {
385 rc = socket_bind_free_port(&gsock, sock_core,
386 TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
387 last_used_port);
388 if (rc != EOK) {
389 async_answer_0(callid, rc);
390 return;
391 }
[05bfce7]392
[a4ee3ab2]393 last_used_port = sock_core->port;
394 }
[04cd242]395
[ae481e0]396 fibril_mutex_lock(&socket->lock);
397
[0ac2158]398 if (socket->laddr.ipv4 == TCP_IPV4_ANY) {
[c76e926]399 /* Determine local IP address */
400 inet_addr_t loc_addr, rem_addr;
401
402 rem_addr.ipv4 = uint32_t_be2host(addr->sin_addr.s_addr);
403 rc = inet_get_srcaddr(&rem_addr, 0, &loc_addr);
[0ac2158]404 if (rc != EOK) {
[ae481e0]405 fibril_mutex_unlock(&socket->lock);
[0ac2158]406 async_answer_0(callid, rc);
[a1a101d]407 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_connect: Failed to "
[c76e926]408 "determine local address.");
[0ac2158]409 return;
410 }
411
[c76e926]412 socket->laddr.ipv4 = loc_addr.ipv4;
[a1a101d]413 log_msg(LOG_DEFAULT, LVL_DEBUG, "Local IP address is %x", socket->laddr.ipv4);
[0ac2158]414 }
415
416 lsocket.addr.ipv4 = socket->laddr.ipv4;
417 lsocket.port = sock_core->port;
[04cd242]418 fsocket.addr.ipv4 = uint32_t_be2host(addr->sin_addr.s_addr);
419 fsocket.port = uint16_t_be2host(addr->sin_port);
420
[ae481e0]421 trc = tcp_uc_open(&lsocket, &fsocket, ap_active, 0, &socket->conn);
[704586fb]422
423 if (socket->conn != NULL)
424 socket->conn->name = (char *)"C";
[04cd242]425
[ae481e0]426 fibril_mutex_unlock(&socket->lock);
427
[04cd242]428 switch (trc) {
429 case TCP_EOK:
430 rc = EOK;
431 break;
432 case TCP_ERESET:
433 rc = ECONNREFUSED;
434 break;
435 default:
436 assert(false);
437 }
438
[d786dea9]439 if (rc == EOK)
440 fibril_add_ready(socket->recv_fibril);
[8fcf74f]441
[d786dea9]442 async_answer_0(callid, rc);
[04cd242]443}
444
445static void tcp_sock_accept(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
446{
447 ipc_call_t answer;
448 int socket_id;
[a4ee3ab2]449 int asock_id;
[04cd242]450 socket_core_t *sock_core;
451 tcp_sockdata_t *socket;
[a4ee3ab2]452 tcp_sockdata_t *asocket;
453 tcp_error_t trc;
[0ac2158]454 tcp_sock_t lsocket;
[a4ee3ab2]455 tcp_sock_t fsocket;
456 tcp_conn_t *conn;
[ae481e0]457 tcp_conn_t *rconn;
458 tcp_sock_lconn_t *lconn;
[a4ee3ab2]459 int rc;
[04cd242]460
[a1a101d]461 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_accept()");
[04cd242]462
463 socket_id = SOCKET_GET_SOCKET_ID(call);
[a4ee3ab2]464 asock_id = SOCKET_GET_NEW_SOCKET_ID(call);
[04cd242]465
466 sock_core = socket_cores_find(&client->sockets, socket_id);
467 if (sock_core == NULL) {
468 async_answer_0(callid, ENOTSOCK);
469 return;
470 }
[05bfce7]471
472 if (sock_core->port <= 0) {
473 rc = socket_bind_free_port(&gsock, sock_core,
474 TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
475 last_used_port);
476 if (rc != EOK) {
477 async_answer_0(callid, rc);
478 return;
479 }
480
481 last_used_port = sock_core->port;
482 }
[04cd242]483
484 socket = (tcp_sockdata_t *)sock_core->specific_data;
[ae481e0]485 fibril_mutex_lock(&socket->lock);
[a4ee3ab2]486
[a1a101d]487 log_msg(LOG_DEFAULT, LVL_DEBUG, " - verify socket->conn");
[a4ee3ab2]488 if (socket->conn != NULL) {
[ae481e0]489 fibril_mutex_unlock(&socket->lock);
[a4ee3ab2]490 async_answer_0(callid, EINVAL);
491 return;
492 }
493
[ae481e0]494 if (list_empty(&socket->ready)) {
495 fibril_mutex_unlock(&socket->lock);
496 async_answer_0(callid, ENOENT);
497 return;
498 }
499
500 lconn = list_get_instance(list_first(&socket->ready),
501 tcp_sock_lconn_t, ready_list);
502 list_remove(&lconn->ready_list);
503
504 conn = lconn->conn;
505 tcp_uc_set_cstate_cb(conn, NULL, NULL);
506
507 /* Replenish listening connection */
[a4ee3ab2]508
[0ac2158]509 lsocket.addr.ipv4 = TCP_IPV4_ANY;
510 lsocket.port = sock_core->port;
[3aa2642a]511 fsocket.addr.ipv4 = TCP_IPV4_ANY;
512 fsocket.port = TCP_PORT_ANY;
[a4ee3ab2]513
[ae481e0]514 trc = tcp_uc_open(&lsocket, &fsocket, ap_passive, tcp_open_nonblock,
515 &rconn);
516 if (rconn == NULL) {
517 /* XXX Clean up */
518 fibril_mutex_unlock(&socket->lock);
519 async_answer_0(callid, ENOMEM);
520 return;
521 }
[a4ee3ab2]522
[ae481e0]523 tcp_uc_set_cstate_cb(rconn, tcp_sock_cstate_cb, lconn);
[a4ee3ab2]524
[ae481e0]525 assert(trc == TCP_EOK);
526 rconn->name = (char *)"S";
[a4ee3ab2]527
[ae481e0]528 lconn->conn = rconn;
529
530 /* Allocate socket for accepted connection */
[a4ee3ab2]531
[d786dea9]532 rc = tcp_sock_create(client, &asocket);
533 if (rc != EOK) {
[ae481e0]534 fibril_mutex_unlock(&socket->lock);
[d786dea9]535 async_answer_0(callid, rc);
[a4ee3ab2]536 return;
537 }
538
539 asocket->conn = conn;
[a1a101d]540 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_accept():create asocket\n");
[a4ee3ab2]541
[d786dea9]542 rc = tcp_sock_finish_setup(asocket, &asock_id);
[a4ee3ab2]543 if (rc != EOK) {
[d786dea9]544 tcp_sock_uncreate(asocket);
[ae481e0]545 fibril_mutex_unlock(&socket->lock);
[a4ee3ab2]546 async_answer_0(callid, rc);
547 return;
548 }
549
[d786dea9]550 fibril_add_ready(asocket->recv_fibril);
[a4ee3ab2]551
[a1a101d]552 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_accept(): find acore\n");
[d786dea9]553
554 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, TCP_SOCK_FRAGMENT_SIZE);
[a4ee3ab2]555 SOCKET_SET_SOCKET_ID(answer, asock_id);
556 SOCKET_SET_ADDRESS_LENGTH(answer, sizeof(struct sockaddr_in));
[b1bd89ea]557
[d786dea9]558 async_answer_3(callid, asocket->sock_core->socket_id,
[b1bd89ea]559 IPC_GET_ARG1(answer), IPC_GET_ARG2(answer),
560 IPC_GET_ARG3(answer));
561
[a4ee3ab2]562 /* Push one fragment notification to client's queue */
[a1a101d]563 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_accept(): notify data\n");
[ae481e0]564 fibril_mutex_unlock(&socket->lock);
[04cd242]565}
566
567static void tcp_sock_send(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
568{
569 int socket_id;
570 int fragments;
571 int index;
572 socket_core_t *sock_core;
573 tcp_sockdata_t *socket;
574 ipc_call_t answer;
575 ipc_callid_t wcallid;
576 size_t length;
[d786dea9]577 uint8_t buffer[TCP_SOCK_FRAGMENT_SIZE];
[04cd242]578 tcp_error_t trc;
579 int rc;
580
[a1a101d]581 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_send()");
[04cd242]582 socket_id = SOCKET_GET_SOCKET_ID(call);
583 fragments = SOCKET_GET_DATA_FRAGMENTS(call);
584 SOCKET_GET_FLAGS(call);
585
586 sock_core = socket_cores_find(&client->sockets, socket_id);
587 if (sock_core == NULL) {
588 async_answer_0(callid, ENOTSOCK);
589 return;
590 }
591
592 socket = (tcp_sockdata_t *)sock_core->specific_data;
[ae481e0]593 fibril_mutex_lock(&socket->lock);
594
[04cd242]595 if (socket->conn == NULL) {
[ae481e0]596 fibril_mutex_unlock(&socket->lock);
[04cd242]597 async_answer_0(callid, ENOTCONN);
598 return;
599 }
600
601 for (index = 0; index < fragments; index++) {
602 if (!async_data_write_receive(&wcallid, &length)) {
[ae481e0]603 fibril_mutex_unlock(&socket->lock);
[04cd242]604 async_answer_0(callid, EINVAL);
605 return;
606 }
607
[d786dea9]608 if (length > TCP_SOCK_FRAGMENT_SIZE)
609 length = TCP_SOCK_FRAGMENT_SIZE;
[04cd242]610
611 rc = async_data_write_finalize(wcallid, buffer, length);
612 if (rc != EOK) {
[ae481e0]613 fibril_mutex_unlock(&socket->lock);
[04cd242]614 async_answer_0(callid, rc);
615 return;
616 }
617
618 trc = tcp_uc_send(socket->conn, buffer, length, 0);
619
620 switch (trc) {
621 case TCP_EOK:
622 rc = EOK;
623 break;
624 case TCP_ENOTEXIST:
625 rc = ENOTCONN;
626 break;
627 case TCP_ECLOSING:
628 rc = ENOTCONN;
629 break;
[d9e14fa4]630 case TCP_ERESET:
631 rc = ECONNABORTED;
632 break;
[04cd242]633 default:
634 assert(false);
635 }
636
637 if (rc != EOK) {
[ae481e0]638 fibril_mutex_unlock(&socket->lock);
[04cd242]639 async_answer_0(callid, rc);
640 return;
641 }
642 }
643
[b1bd89ea]644 IPC_SET_ARG1(answer, 0);
[d786dea9]645 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, TCP_SOCK_FRAGMENT_SIZE);
[b1bd89ea]646 async_answer_2(callid, EOK, IPC_GET_ARG1(answer),
647 IPC_GET_ARG2(answer));
[ae481e0]648 fibril_mutex_unlock(&socket->lock);
[04cd242]649}
650
651static void tcp_sock_sendto(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
652{
[a1a101d]653 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_sendto()");
[04cd242]654 async_answer_0(callid, ENOTSUP);
655}
656
[a4ee3ab2]657static void tcp_sock_recvfrom(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
[04cd242]658{
659 int socket_id;
660 int flags;
[a4ee3ab2]661 size_t addr_length, length;
[04cd242]662 socket_core_t *sock_core;
663 tcp_sockdata_t *socket;
664 ipc_call_t answer;
665 ipc_callid_t rcallid;
666 size_t data_len;
[a4ee3ab2]667 struct sockaddr_in addr;
668 tcp_sock_t *rsock;
[04cd242]669 int rc;
670
[a1a101d]671 log_msg(LOG_DEFAULT, LVL_DEBUG, "%p: tcp_sock_recv[from]()", client);
[04cd242]672
673 socket_id = SOCKET_GET_SOCKET_ID(call);
674 flags = SOCKET_GET_FLAGS(call);
675
676 sock_core = socket_cores_find(&client->sockets, socket_id);
677 if (sock_core == NULL) {
678 async_answer_0(callid, ENOTSOCK);
679 return;
680 }
681
682 socket = (tcp_sockdata_t *)sock_core->specific_data;
[ae481e0]683 fibril_mutex_lock(&socket->lock);
684
[a4ee3ab2]685 if (socket->conn == NULL) {
[ae481e0]686 fibril_mutex_unlock(&socket->lock);
[a4ee3ab2]687 async_answer_0(callid, ENOTCONN);
688 return;
689 }
[04cd242]690
691 (void)flags;
692
[a1a101d]693 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_recvfrom(): lock recv_buffer_lock");
[d786dea9]694 fibril_mutex_lock(&socket->recv_buffer_lock);
[7c912b6]695 while (socket->recv_buffer_used == 0 && socket->recv_error == TCP_EOK) {
[a1a101d]696 log_msg(LOG_DEFAULT, LVL_DEBUG, "wait for recv_buffer_cv + recv_buffer_used != 0");
[d786dea9]697 fibril_condvar_wait(&socket->recv_buffer_cv,
698 &socket->recv_buffer_lock);
699 }
[04cd242]700
[a1a101d]701 log_msg(LOG_DEFAULT, LVL_DEBUG, "Got data in sock recv_buffer");
[d786dea9]702
703 data_len = socket->recv_buffer_used;
704 rc = socket->recv_error;
705
706 switch (socket->recv_error) {
[04cd242]707 case TCP_EOK:
708 rc = EOK;
709 break;
710 case TCP_ENOTEXIST:
711 case TCP_ECLOSING:
712 rc = ENOTCONN;
713 break;
[d9e14fa4]714 case TCP_ERESET:
715 rc = ECONNABORTED;
716 break;
[04cd242]717 default:
718 assert(false);
719 }
720
[a1a101d]721 log_msg(LOG_DEFAULT, LVL_DEBUG, "**** recv result -> %d", rc);
[04cd242]722 if (rc != EOK) {
[d786dea9]723 fibril_mutex_unlock(&socket->recv_buffer_lock);
[ae481e0]724 fibril_mutex_unlock(&socket->lock);
[04cd242]725 async_answer_0(callid, rc);
726 return;
727 }
728
[a4ee3ab2]729 if (IPC_GET_IMETHOD(call) == NET_SOCKET_RECVFROM) {
730 /* Fill addr */
731 rsock = &socket->conn->ident.foreign;
732 addr.sin_family = AF_INET;
733 addr.sin_addr.s_addr = host2uint32_t_be(rsock->addr.ipv4);
734 addr.sin_port = host2uint16_t_be(rsock->port);
735
[a1a101d]736 log_msg(LOG_DEFAULT, LVL_DEBUG, "addr read receive");
[a4ee3ab2]737 if (!async_data_read_receive(&rcallid, &addr_length)) {
[d786dea9]738 fibril_mutex_unlock(&socket->recv_buffer_lock);
[ae481e0]739 fibril_mutex_unlock(&socket->lock);
[a4ee3ab2]740 async_answer_0(callid, EINVAL);
741 return;
742 }
743
744 if (addr_length > sizeof(addr))
745 addr_length = sizeof(addr);
746
[a1a101d]747 log_msg(LOG_DEFAULT, LVL_DEBUG, "addr read finalize");
[a4ee3ab2]748 rc = async_data_read_finalize(rcallid, &addr, addr_length);
749 if (rc != EOK) {
[d786dea9]750 fibril_mutex_unlock(&socket->recv_buffer_lock);
[ae481e0]751 fibril_mutex_unlock(&socket->lock);
[a4ee3ab2]752 async_answer_0(callid, EINVAL);
753 return;
754 }
755 }
756
[a1a101d]757 log_msg(LOG_DEFAULT, LVL_DEBUG, "data read receive");
[04cd242]758 if (!async_data_read_receive(&rcallid, &length)) {
[d786dea9]759 fibril_mutex_unlock(&socket->recv_buffer_lock);
[ae481e0]760 fibril_mutex_unlock(&socket->lock);
[04cd242]761 async_answer_0(callid, EINVAL);
762 return;
763 }
764
[a4ee3ab2]765 if (length > data_len)
[04cd242]766 length = data_len;
767
[a1a101d]768 log_msg(LOG_DEFAULT, LVL_DEBUG, "data read finalize");
[d786dea9]769 rc = async_data_read_finalize(rcallid, socket->recv_buffer, length);
770
[9094c0f]771 socket->recv_buffer_used -= length;
[a1a101d]772 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_recvfrom: %zu left in buffer",
[9094c0f]773 socket->recv_buffer_used);
774 if (socket->recv_buffer_used > 0) {
775 memmove(socket->recv_buffer, socket->recv_buffer + length,
776 socket->recv_buffer_used);
777 tcp_sock_notify_data(socket->sock_core);
778 }
779
[d786dea9]780 fibril_condvar_broadcast(&socket->recv_buffer_cv);
[a4ee3ab2]781
782 if (length < data_len && rc == EOK)
783 rc = EOVERFLOW;
[04cd242]784
785 SOCKET_SET_READ_DATA_LENGTH(answer, length);
[b1bd89ea]786 async_answer_1(callid, EOK, IPC_GET_ARG1(answer));
[d786dea9]787
788 fibril_mutex_unlock(&socket->recv_buffer_lock);
[ae481e0]789 fibril_mutex_unlock(&socket->lock);
[04cd242]790}
791
792static void tcp_sock_close(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
793{
794 int socket_id;
795 socket_core_t *sock_core;
796 tcp_sockdata_t *socket;
[b0d82d1]797 tcp_error_t trc;
[04cd242]798 int rc;
799
[a1a101d]800 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_close()");
[04cd242]801 socket_id = SOCKET_GET_SOCKET_ID(call);
802
803 sock_core = socket_cores_find(&client->sockets, socket_id);
804 if (sock_core == NULL) {
805 async_answer_0(callid, ENOTSOCK);
806 return;
807 }
808
809 socket = (tcp_sockdata_t *)sock_core->specific_data;
[ae481e0]810 fibril_mutex_lock(&socket->lock);
[b0d82d1]811
[415578ef]812 if (socket->conn != NULL) {
[522a4f9]813 trc = tcp_uc_close(socket->conn);
814 if (trc != TCP_EOK && trc != TCP_ENOTEXIST) {
[ae481e0]815 fibril_mutex_unlock(&socket->lock);
[522a4f9]816 async_answer_0(callid, EBADF);
[415578ef]817 return;
818 }
819 }
[7a8c1c4e]820
[798105ca]821 /* Grab recv_buffer_lock because of CV wait in tcp_sock_recv_fibril() */
822 fibril_mutex_lock(&socket->recv_buffer_lock);
823 socket->sock_core = NULL;
824 fibril_mutex_unlock(&socket->recv_buffer_lock);
825
[c76e926]826 rc = socket_destroy(NULL, socket_id, &client->sockets, &gsock,
[04cd242]827 tcp_free_sock_data);
828 if (rc != EOK) {
[ae481e0]829 fibril_mutex_unlock(&socket->lock);
[04cd242]830 async_answer_0(callid, rc);
831 return;
832 }
833
[ae481e0]834 fibril_mutex_unlock(&socket->lock);
[04cd242]835 async_answer_0(callid, EOK);
836}
837
838static void tcp_sock_getsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
839{
[a1a101d]840 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_getsockopt()");
[04cd242]841 async_answer_0(callid, ENOTSUP);
842}
843
844static void tcp_sock_setsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
845{
[a1a101d]846 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_setsockopt()");
[04cd242]847 async_answer_0(callid, ENOTSUP);
848}
849
[ae481e0]850/** Called when connection state changes. */
851static void tcp_sock_cstate_cb(tcp_conn_t *conn, void *arg)
852{
853 tcp_conn_status_t cstatus;
854 tcp_sock_lconn_t *lconn = (tcp_sock_lconn_t *)arg;
855 tcp_sockdata_t *socket = lconn->socket;
856
[a1a101d]857 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_cstate_cb()");
[ae481e0]858 fibril_mutex_lock(&socket->lock);
859 assert(conn == lconn->conn);
860
861 tcp_uc_status(conn, &cstatus);
862 if (cstatus.cstate != st_established) {
863 fibril_mutex_unlock(&socket->lock);
864 return;
865 }
866
867 assert_link_not_used(&lconn->ready_list);
868 list_append(&lconn->ready_list, &socket->ready);
869
[a1a101d]870 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_cstate_cb(): notify accept");
[ae481e0]871
872 /* Push one accept notification to client's queue */
873 tcp_sock_notify_aconn(socket->sock_core);
874 fibril_mutex_unlock(&socket->lock);
875}
876
[d786dea9]877static int tcp_sock_recv_fibril(void *arg)
878{
879 tcp_sockdata_t *sock = (tcp_sockdata_t *)arg;
880 size_t data_len;
881 xflags_t xflags;
882 tcp_error_t trc;
883
[a1a101d]884 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_recv_fibril()");
[d786dea9]885
[798105ca]886 fibril_mutex_lock(&sock->recv_buffer_lock);
887
[d786dea9]888 while (true) {
[a1a101d]889 log_msg(LOG_DEFAULT, LVL_DEBUG, "call tcp_uc_receive()");
[798105ca]890 while (sock->recv_buffer_used != 0 && sock->sock_core != NULL)
[d786dea9]891 fibril_condvar_wait(&sock->recv_buffer_cv,
892 &sock->recv_buffer_lock);
893
894 trc = tcp_uc_receive(sock->conn, sock->recv_buffer,
895 TCP_SOCK_FRAGMENT_SIZE, &data_len, &xflags);
896
897 if (trc != TCP_EOK) {
898 sock->recv_error = trc;
[7c912b6]899 fibril_condvar_broadcast(&sock->recv_buffer_cv);
[798105ca]900 if (sock->sock_core != NULL)
901 tcp_sock_notify_data(sock->sock_core);
[d786dea9]902 break;
903 }
904
[a1a101d]905 log_msg(LOG_DEFAULT, LVL_DEBUG, "got data - broadcast recv_buffer_cv");
[d786dea9]906
907 sock->recv_buffer_used = data_len;
908 fibril_condvar_broadcast(&sock->recv_buffer_cv);
[798105ca]909 if (sock->sock_core != NULL)
910 tcp_sock_notify_data(sock->sock_core);
[d786dea9]911 }
912
[798105ca]913 fibril_mutex_unlock(&sock->recv_buffer_lock);
914
[d786dea9]915 tcp_uc_delete(sock->conn);
916
917 return 0;
918}
919
[c76e926]920static void tcp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
[04cd242]921{
922 ipc_callid_t callid;
923 ipc_call_t call;
924 tcp_client_t client;
925
926 /* Accept the connection */
927 async_answer_0(iid, EOK);
928
[c76e926]929 client.sess = async_callback_receive(EXCHANGE_SERIALIZE);
[04cd242]930 socket_cores_initialize(&client.sockets);
931
932 while (true) {
933 callid = async_get_call(&call);
934 if (!IPC_GET_IMETHOD(call))
935 break;
936
[a1a101d]937 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_connection: METHOD=%d\n",
[04cd242]938 (int)IPC_GET_IMETHOD(call));
939
940 switch (IPC_GET_IMETHOD(call)) {
941 case NET_SOCKET:
942 tcp_sock_socket(&client, callid, call);
943 break;
944 case NET_SOCKET_BIND:
945 tcp_sock_bind(&client, callid, call);
946 break;
947 case NET_SOCKET_LISTEN:
948 tcp_sock_listen(&client, callid, call);
949 break;
950 case NET_SOCKET_CONNECT:
951 tcp_sock_connect(&client, callid, call);
952 break;
953 case NET_SOCKET_ACCEPT:
954 tcp_sock_accept(&client, callid, call);
955 break;
956 case NET_SOCKET_SEND:
957 tcp_sock_send(&client, callid, call);
958 break;
959 case NET_SOCKET_SENDTO:
960 tcp_sock_sendto(&client, callid, call);
961 break;
962 case NET_SOCKET_RECV:
963 case NET_SOCKET_RECVFROM:
964 tcp_sock_recvfrom(&client, callid, call);
965 break;
966 case NET_SOCKET_CLOSE:
967 tcp_sock_close(&client, callid, call);
968 break;
969 case NET_SOCKET_GETSOCKOPT:
970 tcp_sock_getsockopt(&client, callid, call);
971 break;
972 case NET_SOCKET_SETSOCKOPT:
973 tcp_sock_setsockopt(&client, callid, call);
974 break;
975 default:
976 async_answer_0(callid, ENOTSUP);
977 break;
978 }
979 }
[0d520a2]980
981 /* Clean up */
[a1a101d]982 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_sock_connection: Clean up");
[0d520a2]983 async_hangup(client.sess);
984 socket_cores_release(NULL, &client.sockets, &gsock, tcp_free_sock_data);
[04cd242]985}
986
987/**
988 * @}
989 */
Note: See TracBrowser for help on using the repository browser.