source: mainline/uspace/srv/net/tcp/service.c@ 1433ecda

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

Fix cstyle: make ccheck-fix and commit only files where all the changes are good.

  • Property mode set to 100644
File size: 29.8 KB
RevLine 
[779541b]1/*
2 * Copyright (c) 2015 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
[b10460a]29/** @addtogroup tcp
[779541b]30 * @{
31 */
32
33/**
34 * @file HelenOS service implementation
35 */
36
37#include <async.h>
38#include <errno.h>
[c1694b6b]39#include <str_error.h>
[779541b]40#include <inet/endpoint.h>
41#include <inet/inet.h>
42#include <io/log.h>
43#include <ipc/services.h>
44#include <ipc/tcp.h>
45#include <loc.h>
46#include <macros.h>
[b10460a]47#include <mem.h>
[779541b]48#include <stdlib.h>
49
50#include "conn.h"
51#include "service.h"
52#include "tcp_type.h"
53#include "ucall.h"
54
55#define NAME "tcp"
56
[b10460a]57/** Maximum amount of data transferred in one send call */
[779541b]58#define MAX_MSG_SIZE DATA_XFER_LIMIT
59
60static void tcp_ev_data(tcp_cconn_t *);
[1d4b815]61static void tcp_ev_connected(tcp_cconn_t *);
62static void tcp_ev_conn_failed(tcp_cconn_t *);
63static void tcp_ev_conn_reset(tcp_cconn_t *);
[b99f6e2]64static void tcp_ev_new_conn(tcp_clst_t *, tcp_cconn_t *);
[779541b]65
[1d4b815]66static void tcp_service_cstate_change(tcp_conn_t *, void *, tcp_cstate_t);
[779541b]67static void tcp_service_recv_data(tcp_conn_t *, void *);
[b99f6e2]68static void tcp_service_lst_cstate_change(tcp_conn_t *, void *, tcp_cstate_t);
69
[b7fd2a0]70static errno_t tcp_cconn_create(tcp_client_t *, tcp_conn_t *, tcp_cconn_t **);
[779541b]71
[b10460a]72/** Connection callbacks to tie us to lower layer */
[779541b]73static tcp_cb_t tcp_service_cb = {
74 .cstate_change = tcp_service_cstate_change,
75 .recv_data = tcp_service_recv_data
76};
77
[b10460a]78/** Sentinel connection callbacks to tie us to lower layer */
[b99f6e2]79static tcp_cb_t tcp_service_lst_cb = {
80 .cstate_change = tcp_service_lst_cstate_change,
81 .recv_data = NULL
82};
83
[b10460a]84/** Connection state has changed.
85 *
86 * @param conn Connection
87 * @param arg Argument (not used)
88 * @param old_state Previous connection state
89 */
[1d4b815]90static void tcp_service_cstate_change(tcp_conn_t *conn, void *arg,
91 tcp_cstate_t old_state)
[779541b]92{
[1d4b815]93 tcp_cstate_t nstate;
94 tcp_cconn_t *cconn;
95
96 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_service_cstate_change()");
97 nstate = conn->cstate;
98 cconn = tcp_uc_get_userptr(conn);
99
100 if ((old_state == st_syn_sent || old_state == st_syn_received) &&
101 (nstate == st_established)) {
102 /* Connection established */
103 tcp_ev_connected(cconn);
104 }
105
106 if (old_state != st_closed && nstate == st_closed && conn->reset) {
[9362cc2]107 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_service_cstate_change: "
108 "Connection reset");
[1d4b815]109 /* Connection reset */
110 tcp_ev_conn_reset(cconn);
[9362cc2]111 } else {
112 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_service_cstate_change: "
113 "old_state=%d nstate=%d conn->reset=%d",
114 old_state, nstate, conn->reset);
[1d4b815]115 }
116
117 /* XXX Failed to establish connection */
[1433ecda]118 if (0)
119 tcp_ev_conn_failed(cconn);
[779541b]120}
121
[b10460a]122/** Sentinel connection state has changed.
123 *
124 * @param conn Connection
125 * @param arg Argument (not used)
126 * @param old_state Previous connection state
127 */
[b99f6e2]128static void tcp_service_lst_cstate_change(tcp_conn_t *conn, void *arg,
129 tcp_cstate_t old_state)
130{
131 tcp_cstate_t nstate;
132 tcp_clst_t *clst;
133 tcp_cconn_t *cconn;
[2f19103]134 inet_ep2_t epp;
[b7fd2a0]135 errno_t rc;
[b99f6e2]136 tcp_error_t trc;
137
138 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_service_lst_cstate_change()");
139 nstate = conn->cstate;
140 clst = tcp_uc_get_userptr(conn);
141
142 if ((old_state == st_syn_sent || old_state == st_syn_received) &&
143 (nstate == st_established)) {
144 /* Connection established */
145 clst->conn = NULL;
146
147 rc = tcp_cconn_create(clst->client, conn, &cconn);
148 if (rc != EOK) {
149 /* XXX Could not create client connection */
150 return;
151 }
152
153 /* XXX Is there a race here (i.e. the connection is already active)? */
154 tcp_uc_set_cb(conn, &tcp_service_cb, cconn);
155
156 /* New incoming connection */
157 tcp_ev_new_conn(clst, cconn);
158 }
159
160 if (old_state != st_closed && nstate == st_closed && conn->reset) {
161 /* Connection reset */
162 /* XXX */
163 }
164
165 /* XXX Failed to establish connection */
166 if (0) {
167 /* XXX */
168 }
169
170 /* Replenish sentinel connection */
171
[2f19103]172 inet_ep2_init(&epp);
173 epp.local = clst->elocal;
174
175 trc = tcp_uc_open(&epp, ap_passive, tcp_open_nonblock,
[b99f6e2]176 &conn);
177 if (trc != TCP_EOK) {
178 /* XXX Could not replenish connection */
179 return;
180 }
181
[8d48c7e]182 conn->name = (char *) "s";
[b99f6e2]183 clst->conn = conn;
184
185 /* XXX Is there a race here (i.e. the connection is already active)? */
186 tcp_uc_set_cb(conn, &tcp_service_lst_cb, clst);
187}
188
[b10460a]189/** Received data became available on connection.
190 *
191 * @param conn Connection
192 * @param arg Client connection
193 */
[779541b]194static void tcp_service_recv_data(tcp_conn_t *conn, void *arg)
195{
196 tcp_cconn_t *cconn = (tcp_cconn_t *)arg;
197
198 tcp_ev_data(cconn);
199}
200
[b10460a]201/** Send 'data' event to client.
202 *
203 * @param cconn Client connection
204 */
[779541b]205static void tcp_ev_data(tcp_cconn_t *cconn)
206{
207 async_exch_t *exch;
208
209 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_ev_data()");
210
211 log_msg(LOG_DEFAULT, LVL_DEBUG, "client=%p\n", cconn->client);
212 log_msg(LOG_DEFAULT, LVL_DEBUG, "sess=%p\n", cconn->client->sess);
213
214 exch = async_exchange_begin(cconn->client->sess);
215 aid_t req = async_send_1(exch, TCP_EV_DATA, cconn->id, NULL);
216 async_exchange_end(exch);
217
[1d4b815]218 async_forget(req);
219}
220
[b10460a]221/** Send 'connected' event to client.
222 *
223 * @param cconn Client connection
224 */
[1d4b815]225static void tcp_ev_connected(tcp_cconn_t *cconn)
226{
227 async_exch_t *exch;
228
229 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_ev_connected()");
230
231 exch = async_exchange_begin(cconn->client->sess);
232 aid_t req = async_send_1(exch, TCP_EV_CONNECTED, cconn->id, NULL);
233 async_exchange_end(exch);
234
235 async_forget(req);
236}
237
[b10460a]238/** Send 'conn_failed' event to client.
239 *
240 * @param cconn Client connection
241 */
[1d4b815]242static void tcp_ev_conn_failed(tcp_cconn_t *cconn)
243{
244 async_exch_t *exch;
245
246 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_ev_conn_failed()");
247
248 exch = async_exchange_begin(cconn->client->sess);
249 aid_t req = async_send_1(exch, TCP_EV_CONN_FAILED, cconn->id, NULL);
250 async_exchange_end(exch);
251
252 async_forget(req);
253}
254
[b10460a]255/** Send 'conn_reset' event to client.
256 *
257 * @param cconn Client connection
258 */
[1d4b815]259static void tcp_ev_conn_reset(tcp_cconn_t *cconn)
260{
261 async_exch_t *exch;
262
263 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_ev_conn_reset()");
264
265 exch = async_exchange_begin(cconn->client->sess);
266 aid_t req = async_send_1(exch, TCP_EV_CONN_RESET, cconn->id, NULL);
267 async_exchange_end(exch);
268
[779541b]269 async_forget(req);
270}
271
[b10460a]272/** Send 'new_conn' event to client.
273 *
274 * @param clst Client listener that received the connection
275 * @param cconn New client connection
276 */
[b99f6e2]277static void tcp_ev_new_conn(tcp_clst_t *clst, tcp_cconn_t *cconn)
278{
279 async_exch_t *exch;
280
281 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_ev_new_conn()");
282
283 exch = async_exchange_begin(clst->client->sess);
284 aid_t req = async_send_2(exch, TCP_EV_NEW_CONN, clst->id, cconn->id,
285 NULL);
286 async_exchange_end(exch);
287
288 async_forget(req);
289}
290
[b10460a]291/** Create client connection.
292 *
293 * This effectively adds a connection into a client's namespace.
294 *
295 * @param client TCP client
296 * @param conn Connection
297 * @param rcconn Place to store pointer to new client connection
298 *
299 * @return EOK on success or ENOMEM if out of memory
300 */
[b7fd2a0]301static errno_t tcp_cconn_create(tcp_client_t *client, tcp_conn_t *conn,
[779541b]302 tcp_cconn_t **rcconn)
303{
304 tcp_cconn_t *cconn;
305 sysarg_t id;
306
307 cconn = calloc(1, sizeof(tcp_cconn_t));
308 if (cconn == NULL)
309 return ENOMEM;
310
311 /* Allocate new ID */
312 id = 0;
313 list_foreach (client->cconn, lclient, tcp_cconn_t, cconn) {
314 if (cconn->id >= id)
315 id = cconn->id + 1;
316 }
317
318 cconn->id = id;
319 cconn->client = client;
320 cconn->conn = conn;
321
322 list_append(&cconn->lclient, &client->cconn);
323 *rcconn = cconn;
324 return EOK;
325}
326
[b10460a]327/** Destroy client connection.
328 *
329 * @param cconn Client connection
330 */
[779541b]331static void tcp_cconn_destroy(tcp_cconn_t *cconn)
332{
333 list_remove(&cconn->lclient);
334 free(cconn);
335}
336
[b10460a]337/** Create client listener.
338 *
339 * Create client listener based on sentinel connection.
340 * XXX Implement actual listener in protocol core
341 *
342 * @param client TCP client
343 * @param conn Sentinel connection
344 * @param rclst Place to store pointer to new client listener
345 *
346 * @return EOK on success or ENOMEM if out of memory
347 */
[b7fd2a0]348static errno_t tcp_clistener_create(tcp_client_t *client, tcp_conn_t *conn,
[779541b]349 tcp_clst_t **rclst)
350{
351 tcp_clst_t *clst;
352 sysarg_t id;
353
354 clst = calloc(1, sizeof(tcp_clst_t));
355 if (clst == NULL)
356 return ENOMEM;
357
358 /* Allocate new ID */
359 id = 0;
360 list_foreach (client->clst, lclient, tcp_clst_t, clst) {
361 if (clst->id >= id)
362 id = clst->id + 1;
363 }
364
365 clst->id = id;
366 clst->client = client;
367 clst->conn = conn;
368
369 list_append(&clst->lclient, &client->clst);
370 *rclst = clst;
371 return EOK;
372}
373
[b10460a]374/** Destroy client listener.
375 *
376 * @param clst Client listener
377 */
[779541b]378static void tcp_clistener_destroy(tcp_clst_t *clst)
379{
380 list_remove(&clst->lclient);
381 free(clst);
382}
383
[b10460a]384/** Get client connection by ID.
385 *
386 * @param client Client
387 * @param id Client connection ID
388 * @param rcconn Place to store pointer to client connection
389 *
390 * @return EOK on success, ENOENT if no client connection with the given ID
391 * is found.
392 */
[b7fd2a0]393static errno_t tcp_cconn_get(tcp_client_t *client, sysarg_t id,
[779541b]394 tcp_cconn_t **rcconn)
395{
396 list_foreach (client->cconn, lclient, tcp_cconn_t, cconn) {
397 if (cconn->id == id) {
398 *rcconn = cconn;
399 return EOK;
400 }
401 }
402
403 return ENOENT;
404}
405
[b10460a]406/** Get client listener by ID.
407 *
408 * @param client Client
409 * @param id Client connection ID
410 * @param rclst Place to store pointer to client listener
411 *
412 * @return EOK on success, ENOENT if no client listener with the given ID
413 * is found.
414 */
[b7fd2a0]415static errno_t tcp_clistener_get(tcp_client_t *client, sysarg_t id,
[779541b]416 tcp_clst_t **rclst)
417{
418 list_foreach (client->clst, lclient, tcp_clst_t, clst) {
419 if (clst->id == id) {
420 *rclst = clst;
421 return EOK;
422 }
423 }
424
425 return ENOENT;
426}
427
[b10460a]428/** Create connection.
429 *
430 * Handle client request to create connection (with parameters unmarshalled).
431 *
432 * @param client TCP client
433 * @param epp Endpoint pair
434 * @param rconn_id Place to store ID of new connection
435 *
[cde999a]436 * @return EOK on success or an error code
[b10460a]437 */
[b7fd2a0]438static errno_t tcp_conn_create_impl(tcp_client_t *client, inet_ep2_t *epp,
[779541b]439 sysarg_t *rconn_id)
440{
441 tcp_conn_t *conn;
442 tcp_cconn_t *cconn;
[b7fd2a0]443 errno_t rc;
[779541b]444 tcp_error_t trc;
445 char *slocal;
446 char *sremote;
447
448 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_create_impl");
449
[2989c7e]450 inet_addr_format(&epp->local.addr, &slocal);
451 inet_addr_format(&epp->remote.addr, &sremote);
[779541b]452 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_create: local=%s remote=%s",
453 slocal, sremote);
[2f19103]454 free(slocal);
455 free(sremote);
[779541b]456
[2989c7e]457 trc = tcp_uc_open(epp, ap_active, tcp_open_nonblock, &conn);
[779541b]458 if (trc != TCP_EOK)
459 return EIO;
460
[8d48c7e]461 conn->name = (char *) "c";
462
[779541b]463 rc = tcp_cconn_create(client, conn, &cconn);
464 if (rc != EOK) {
465 assert(rc == ENOMEM);
466 tcp_conn_delete(conn);
467 return ENOMEM;
468 }
469
470 /* XXX Is there a race here (i.e. the connection is already active)? */
471 tcp_uc_set_cb(conn, &tcp_service_cb, cconn);
472
473 *rconn_id = cconn->id;
474 return EOK;
475}
476
[b10460a]477/** Destroy connection.
478 *
479 * Handle client request to destroy connection (with parameters unmarshalled).
480 *
481 * @param client TCP client
482 * @param conn_id Connection ID
483 * @return EOK on success, ENOENT if no such connection is found
484 */
[b7fd2a0]485static errno_t tcp_conn_destroy_impl(tcp_client_t *client, sysarg_t conn_id)
[779541b]486{
487 tcp_cconn_t *cconn;
[b7fd2a0]488 errno_t rc;
[779541b]489
490 rc = tcp_cconn_get(client, conn_id, &cconn);
491 if (rc != EOK) {
492 assert(rc == ENOENT);
493 return ENOENT;
494 }
495
496 tcp_uc_close(cconn->conn);
[bf7587b0]497 tcp_uc_delete(cconn->conn);
[779541b]498 tcp_cconn_destroy(cconn);
499 return EOK;
500}
501
[b10460a]502/** Create listener.
503 *
504 * Handle client request to create listener (with parameters unmarshalled).
505 *
506 * @param client TCP client
507 * @param ep Endpoint
508 * @param rlst_id Place to store ID of new listener
509 *
[cde999a]510 * @return EOK on success or an error code
[b10460a]511*/
[b7fd2a0]512static errno_t tcp_listener_create_impl(tcp_client_t *client, inet_ep_t *ep,
[779541b]513 sysarg_t *rlst_id)
514{
515 tcp_conn_t *conn;
516 tcp_clst_t *clst;
[2f19103]517 inet_ep2_t epp;
[b7fd2a0]518 errno_t rc;
[779541b]519 tcp_error_t trc;
520
521 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_listener_create_impl");
522
[2f19103]523 inet_ep2_init(&epp);
524 epp.local.addr = ep->addr;
525 epp.local.port = ep->port;
[779541b]526
[2f19103]527 trc = tcp_uc_open(&epp, ap_passive, tcp_open_nonblock, &conn);
[779541b]528 if (trc != TCP_EOK)
529 return EIO;
530
[8d48c7e]531 conn->name = (char *) "s";
532
[779541b]533 rc = tcp_clistener_create(client, conn, &clst);
534 if (rc != EOK) {
535 assert(rc == ENOMEM);
536 tcp_conn_delete(conn);
537 return ENOMEM;
538 }
539
[2f19103]540 clst->elocal = epp.local;
[b99f6e2]541
542 /* XXX Is there a race here (i.e. the connection is already active)? */
543 tcp_uc_set_cb(conn, &tcp_service_lst_cb, clst);
[779541b]544
545 *rlst_id = clst->id;
546 return EOK;
547}
548
[b10460a]549/** Destroy listener.
550 *
551 * Handle client request to destroy listener (with parameters unmarshalled).
552 *
553 * @param client TCP client
554 * @param lst_id Listener ID
555 *
556 * @return EOK on success, ENOENT if no such listener is found
557 */
[b7fd2a0]558static errno_t tcp_listener_destroy_impl(tcp_client_t *client, sysarg_t lst_id)
[779541b]559{
560 tcp_clst_t *clst;
[b7fd2a0]561 errno_t rc;
[779541b]562
563 rc = tcp_clistener_get(client, lst_id, &clst);
564 if (rc != EOK) {
565 assert(rc == ENOENT);
566 return ENOENT;
567 }
568
569// tcp_uc_close(cconn->conn);
570 tcp_clistener_destroy(clst);
571 return EOK;
572}
573
[b10460a]574/** Send FIN.
575 *
576 * Handle client request to send FIN (with parameters unmarshalled).
577 *
578 * @param client TCP client
579 * @param conn_id Connection ID
580 *
[cde999a]581 * @return EOK on success or an error code
[b10460a]582 */
[b7fd2a0]583static errno_t tcp_conn_send_fin_impl(tcp_client_t *client, sysarg_t conn_id)
[779541b]584{
585 tcp_cconn_t *cconn;
[b7fd2a0]586 errno_t rc;
[779541b]587
588 rc = tcp_cconn_get(client, conn_id, &cconn);
589 if (rc != EOK) {
590 assert(rc == ENOENT);
591 return ENOENT;
592 }
593
594 (void) cconn;
595 /* XXX TODO */
596 return EOK;
597}
598
[b10460a]599/** Push connection.
600 *
601 * Handle client request to push connection (with parameters unmarshalled).
602 *
603 * @param client TCP client
604 * @param conn_id Connection ID
605 *
[cde999a]606 * @return EOK on success or an error code
[b10460a]607 */
[b7fd2a0]608static errno_t tcp_conn_push_impl(tcp_client_t *client, sysarg_t conn_id)
[779541b]609{
610 tcp_cconn_t *cconn;
[b7fd2a0]611 errno_t rc;
[779541b]612
613 rc = tcp_cconn_get(client, conn_id, &cconn);
614 if (rc != EOK) {
615 assert(rc == ENOENT);
616 return ENOENT;
617 }
618
619 (void) cconn;
620 /* XXX TODO */
621 return EOK;
622}
623
[b10460a]624/** Reset connection.
625 *
626 * Handle client request to reset connection (with parameters unmarshalled).
627 *
628 * @param client TCP client
629 * @param conn_id Connection ID
630 *
[cde999a]631 * @return EOK on success or an error code
[b10460a]632 */
[b7fd2a0]633static errno_t tcp_conn_reset_impl(tcp_client_t *client, sysarg_t conn_id)
[779541b]634{
635 tcp_cconn_t *cconn;
[b7fd2a0]636 errno_t rc;
[779541b]637
638 rc = tcp_cconn_get(client, conn_id, &cconn);
639 if (rc != EOK) {
640 assert(rc == ENOENT);
641 return ENOENT;
642 }
643
644 tcp_uc_abort(cconn->conn);
645 return EOK;
646}
647
[b10460a]648/** Send data over connection..
649 *
650 * Handle client request to send data (with parameters unmarshalled).
651 *
652 * @param client TCP client
653 * @param conn_id Connection ID
654 * @param data Data buffer
655 * @param size Data size in bytes
656 *
[cde999a]657 * @return EOK on success or an error code
[b10460a]658 */
[b7fd2a0]659static errno_t tcp_conn_send_impl(tcp_client_t *client, sysarg_t conn_id,
[779541b]660 void *data, size_t size)
661{
662 tcp_cconn_t *cconn;
[b7fd2a0]663 errno_t rc;
[7ce8f88]664 tcp_error_t trc;
[779541b]665
666 rc = tcp_cconn_get(client, conn_id, &cconn);
667 if (rc != EOK)
668 return rc;
669
[7ce8f88]670 trc = tcp_uc_send(cconn->conn, data, size, 0);
671 if (trc != TCP_EOK)
672 return EIO;
[779541b]673
674 return EOK;
675}
676
[b10460a]677/** Receive data from connection.
678 *
679 * Handle client request to receive data (with parameters unmarshalled).
680 *
681 * @param client TCP client
682 * @param conn_id Connection ID
683 * @param data Data buffer
684 * @param size Buffer size in bytes
685 * @param nrecv Place to store actual number of bytes received
686 *
[cde999a]687 * @return EOK on success or an error code
[b10460a]688 */
[b7fd2a0]689static errno_t tcp_conn_recv_impl(tcp_client_t *client, sysarg_t conn_id,
[779541b]690 void *data, size_t size, size_t *nrecv)
691{
692 tcp_cconn_t *cconn;
693 xflags_t xflags;
[b7fd2a0]694 errno_t rc;
[7ce8f88]695 tcp_error_t trc;
[779541b]696
697 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_impl()");
698
699 rc = tcp_cconn_get(client, conn_id, &cconn);
700 if (rc != EOK) {
701 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_impl() - conn not found");
702 return rc;
703 }
704
[7ce8f88]705 trc = tcp_uc_receive(cconn->conn, data, size, nrecv, &xflags);
706 if (trc != TCP_EOK) {
707 switch (trc) {
[779541b]708 case TCP_EAGAIN:
709 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_impl() - EAGAIN");
710 return EAGAIN;
[258d77e]711 case TCP_ECLOSING:
712 *nrecv = 0;
713 return EOK;
[779541b]714 default:
[7ce8f88]715 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_impl() - trc=%d", trc);
[779541b]716 return EIO;
717 }
718 }
719
720 return EOK;
721}
722
[b10460a]723/** Create client callback session.
724 *
725 * Handle client request to create callback session.
726 *
[a46e56b]727 * @param client TCP client
728 * @param icall_handle Async request call handle
729 * @param icall Async request data
[b10460a]730 */
[a46e56b]731static void tcp_callback_create_srv(tcp_client_t *client,
732 cap_call_handle_t icall_handle, ipc_call_t *icall)
[779541b]733{
734 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_callback_create_srv()");
735
736 async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE);
737 if (sess == NULL) {
[a46e56b]738 async_answer_0(icall_handle, ENOMEM);
[779541b]739 return;
740 }
741
742 client->sess = sess;
[a46e56b]743 async_answer_0(icall_handle, EOK);
[779541b]744}
745
[b10460a]746/** Create connection.
747 *
748 * Handle client request to create connection.
749 *
[a46e56b]750 * @param client TCP client
751 * @param icall_handle Async request call handle
752 * @param icall Async request data
[b10460a]753 */
[a46e56b]754static void tcp_conn_create_srv(tcp_client_t *client,
755 cap_call_handle_t icall_handle, ipc_call_t *icall)
[779541b]756{
[a46e56b]757 cap_call_handle_t chandle;
[779541b]758 size_t size;
759 inet_ep2_t epp;
760 sysarg_t conn_id;
[b7fd2a0]761 errno_t rc;
[779541b]762
763 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_create_srv()");
764
[a46e56b]765 if (!async_data_write_receive(&chandle, &size)) {
766 async_answer_0(chandle, EREFUSED);
767 async_answer_0(icall_handle, EREFUSED);
[779541b]768 return;
769 }
770
771 if (size != sizeof(inet_ep2_t)) {
[a46e56b]772 async_answer_0(chandle, EINVAL);
773 async_answer_0(icall_handle, EINVAL);
[779541b]774 return;
775 }
776
[a46e56b]777 rc = async_data_write_finalize(chandle, &epp, size);
[779541b]778 if (rc != EOK) {
[a46e56b]779 async_answer_0(chandle, rc);
780 async_answer_0(icall_handle, rc);
[779541b]781 return;
782 }
783
784 rc = tcp_conn_create_impl(client, &epp, &conn_id);
785 if (rc != EOK) {
[a46e56b]786 async_answer_0(icall_handle, rc);
[779541b]787 return;
788 }
789
[a46e56b]790 async_answer_1(icall_handle, EOK, conn_id);
[779541b]791}
792
[b10460a]793/** Destroy connection.
794 *
795 * Handle client request to destroy connection.
796 *
[a46e56b]797 * @param client TCP client
[b752a31]798 * @param icall_handle Async request call handle
[a46e56b]799 * @param icall Async request data
[b10460a]800 */
[a46e56b]801static void tcp_conn_destroy_srv(tcp_client_t *client,
802 cap_call_handle_t icall_handle, ipc_call_t *icall)
[779541b]803{
804 sysarg_t conn_id;
[b7fd2a0]805 errno_t rc;
[779541b]806
807 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_destroy_srv()");
808
809 conn_id = IPC_GET_ARG1(*icall);
810 rc = tcp_conn_destroy_impl(client, conn_id);
[a46e56b]811 async_answer_0(icall_handle, rc);
[779541b]812}
813
[b10460a]814/** Create listener.
815 *
816 * Handle client request to create listener.
817 *
[a46e56b]818 * @param client TCP client
[b752a31]819 * @param icall_handle Async request call handle
[a46e56b]820 * @param icall Async request data
[b10460a]821 */
[a46e56b]822static void tcp_listener_create_srv(tcp_client_t *client,
823 cap_call_handle_t icall_handle, ipc_call_t *icall)
[779541b]824{
[a46e56b]825 cap_call_handle_t chandle;
[779541b]826 size_t size;
827 inet_ep_t ep;
828 sysarg_t lst_id;
[b7fd2a0]829 errno_t rc;
[779541b]830
831 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_listener_create_srv()");
832
[a46e56b]833 if (!async_data_write_receive(&chandle, &size)) {
834 async_answer_0(chandle, EREFUSED);
835 async_answer_0(icall_handle, EREFUSED);
[779541b]836 return;
837 }
838
839 if (size != sizeof(inet_ep_t)) {
[a46e56b]840 async_answer_0(chandle, EINVAL);
841 async_answer_0(icall_handle, EINVAL);
[779541b]842 return;
843 }
844
[a46e56b]845 rc = async_data_write_finalize(chandle, &ep, size);
[779541b]846 if (rc != EOK) {
[a46e56b]847 async_answer_0(chandle, rc);
848 async_answer_0(icall_handle, rc);
[779541b]849 return;
850 }
851
852 rc = tcp_listener_create_impl(client, &ep, &lst_id);
853 if (rc != EOK) {
[a46e56b]854 async_answer_0(icall_handle, rc);
[779541b]855 return;
856 }
857
[a46e56b]858 async_answer_1(icall_handle, EOK, lst_id);
[779541b]859}
860
[b10460a]861/** Destroy listener.
862 *
863 * Handle client request to destroy listener.
864 *
[a46e56b]865 * @param client TCP client
866 * @param icall_handle Async request call handle
867 * @param icall Async request data
[b10460a]868 */
[a46e56b]869static void tcp_listener_destroy_srv(tcp_client_t *client,
870 cap_call_handle_t icall_handle, ipc_call_t *icall)
[779541b]871{
872 sysarg_t lst_id;
[b7fd2a0]873 errno_t rc;
[779541b]874
875 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_listener_destroy_srv()");
876
877 lst_id = IPC_GET_ARG1(*icall);
878 rc = tcp_listener_destroy_impl(client, lst_id);
[a46e56b]879 async_answer_0(icall_handle, rc);
[779541b]880}
881
[b10460a]882/** Send FIN.
883 *
884 * Handle client request to send FIN.
885 *
[a46e56b]886 * @param client TCP client
[b752a31]887 * @param icall_handle Async request call handle
[a46e56b]888 * @param icall Async request data
[b10460a]889 */
[a46e56b]890static void tcp_conn_send_fin_srv(tcp_client_t *client,
891 cap_call_handle_t icall_handle, ipc_call_t *icall)
[779541b]892{
893 sysarg_t conn_id;
[b7fd2a0]894 errno_t rc;
[779541b]895
896 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_send_fin_srv()");
897
898 conn_id = IPC_GET_ARG1(*icall);
899 rc = tcp_conn_send_fin_impl(client, conn_id);
[a46e56b]900 async_answer_0(icall_handle, rc);
[779541b]901}
902
[b10460a]903/** Push connection.
904 *
905 * Handle client request to push connection.
906 *
[a46e56b]907 * @param client TCP client
908 * @param icall_handle Async request call handle
909 * @param icall Async request data
[b10460a]910 */
[a46e56b]911static void tcp_conn_push_srv(tcp_client_t *client,
912 cap_call_handle_t icall_handle, ipc_call_t *icall)
[779541b]913{
914 sysarg_t conn_id;
[b7fd2a0]915 errno_t rc;
[779541b]916
917 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_push_srv()");
918
919 conn_id = IPC_GET_ARG1(*icall);
920 rc = tcp_conn_push_impl(client, conn_id);
[a46e56b]921 async_answer_0(icall_handle, rc);
[779541b]922}
923
[b10460a]924/** Reset connection.
925 *
926 * Handle client request to reset connection.
927 *
[a46e56b]928 * @param client TCP client
929 * @param icall_handle Async request call handle
930 * @param icall Async request data
[b10460a]931 */
[a46e56b]932static void tcp_conn_reset_srv(tcp_client_t *client,
933 cap_call_handle_t icall_handle, ipc_call_t *icall)
[779541b]934{
935 sysarg_t conn_id;
[b7fd2a0]936 errno_t rc;
[779541b]937
938 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_reset_srv()");
939
940 conn_id = IPC_GET_ARG1(*icall);
941 rc = tcp_conn_reset_impl(client, conn_id);
[a46e56b]942 async_answer_0(icall_handle, rc);
[779541b]943}
944
[b10460a]945/** Send data via connection..
946 *
947 * Handle client request to send data via connection.
948 *
[a46e56b]949 * @param client TCP client
950 * @param icall_handle Async request call handle
951 * @param icall Async request data
[b10460a]952 */
[a46e56b]953static void tcp_conn_send_srv(tcp_client_t *client,
954 cap_call_handle_t icall_handle, ipc_call_t *icall)
[779541b]955{
[a46e56b]956 cap_call_handle_t chandle;
[779541b]957 size_t size;
958 sysarg_t conn_id;
959 void *data;
[b7fd2a0]960 errno_t rc;
[779541b]961
962 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_send_srv())");
963
964 /* Receive message data */
965
[a46e56b]966 if (!async_data_write_receive(&chandle, &size)) {
967 async_answer_0(chandle, EREFUSED);
968 async_answer_0(icall_handle, EREFUSED);
[779541b]969 return;
970 }
971
972 if (size > MAX_MSG_SIZE) {
[a46e56b]973 async_answer_0(chandle, EINVAL);
974 async_answer_0(icall_handle, EINVAL);
[779541b]975 return;
976 }
977
978 data = malloc(size);
979 if (data == NULL) {
[a46e56b]980 async_answer_0(chandle, ENOMEM);
981 async_answer_0(icall_handle, ENOMEM);
[4f29118]982 return;
[779541b]983 }
984
[a46e56b]985 rc = async_data_write_finalize(chandle, data, size);
[779541b]986 if (rc != EOK) {
[a46e56b]987 async_answer_0(chandle, rc);
988 async_answer_0(icall_handle, rc);
[779541b]989 free(data);
990 return;
991 }
992
993 conn_id = IPC_GET_ARG1(*icall);
994
995 rc = tcp_conn_send_impl(client, conn_id, data, size);
996 if (rc != EOK) {
[a46e56b]997 async_answer_0(icall_handle, rc);
[779541b]998 free(data);
999 return;
1000 }
1001
[a46e56b]1002 async_answer_0(icall_handle, EOK);
[779541b]1003 free(data);
1004}
1005
[b10460a]1006/** Read received data from connection without blocking.
1007 *
1008 * Handle client request to read received data via connection without blocking.
1009 *
[a46e56b]1010 * @param client TCP client
1011 * @param icall_handle Async request call handle
1012 * @param icall Async request data
[b10460a]1013 */
[a46e56b]1014static void tcp_conn_recv_srv(tcp_client_t *client,
1015 cap_call_handle_t icall_handle, ipc_call_t *icall)
[779541b]1016{
[a46e56b]1017 cap_call_handle_t chandle;
[779541b]1018 sysarg_t conn_id;
1019 size_t size, rsize;
1020 void *data;
[b7fd2a0]1021 errno_t rc;
[779541b]1022
1023 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_srv()");
1024
1025 conn_id = IPC_GET_ARG1(*icall);
1026
[a46e56b]1027 if (!async_data_read_receive(&chandle, &size)) {
1028 async_answer_0(chandle, EREFUSED);
1029 async_answer_0(icall_handle, EREFUSED);
[779541b]1030 return;
1031 }
1032
[204ba47]1033 size = min(size, 16384);
[779541b]1034 data = malloc(size);
1035 if (data == NULL) {
[a46e56b]1036 async_answer_0(chandle, ENOMEM);
1037 async_answer_0(icall_handle, ENOMEM);
[779541b]1038 return;
1039 }
1040
1041 rc = tcp_conn_recv_impl(client, conn_id, data, size, &rsize);
1042 if (rc != EOK) {
[a46e56b]1043 async_answer_0(chandle, rc);
1044 async_answer_0(icall_handle, rc);
[779541b]1045 free(data);
1046 return;
1047 }
1048
[a46e56b]1049 rc = async_data_read_finalize(chandle, data, size);
[779541b]1050 if (rc != EOK) {
[a46e56b]1051 async_answer_0(icall_handle, rc);
[779541b]1052 free(data);
1053 return;
1054 }
1055
[a46e56b]1056 async_answer_1(icall_handle, EOK, rsize);
[779541b]1057 free(data);
1058
1059 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_srv(): OK");
1060}
1061
[b10460a]1062/** Read received data from connection with blocking.
1063 *
1064 * Handle client request to read received data via connection with blocking.
1065 *
[a46e56b]1066 * @param client TCP client
1067 * @param icall_handle Async request call handle
1068 * @param icall Async request data
[b10460a]1069 */
[a46e56b]1070static void tcp_conn_recv_wait_srv(tcp_client_t *client,
1071 cap_call_handle_t icall_handle, ipc_call_t *icall)
[779541b]1072{
[a46e56b]1073 cap_call_handle_t chandle;
[779541b]1074 sysarg_t conn_id;
1075 size_t size, rsize;
1076 void *data;
[b7fd2a0]1077 errno_t rc;
[779541b]1078
1079 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_wait_srv()");
1080
1081 conn_id = IPC_GET_ARG1(*icall);
1082
[a46e56b]1083 if (!async_data_read_receive(&chandle, &size)) {
[779541b]1084 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_wait_srv - data_receive failed");
[a46e56b]1085 async_answer_0(chandle, EREFUSED);
1086 async_answer_0(icall_handle, EREFUSED);
[779541b]1087 return;
1088 }
1089
1090 size = min(size, 16384);
1091 data = malloc(size);
1092 if (data == NULL) {
1093 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_wait_srv - allocation failed");
[a46e56b]1094 async_answer_0(chandle, ENOMEM);
1095 async_answer_0(icall_handle, ENOMEM);
[779541b]1096 return;
1097 }
1098
1099 rc = tcp_conn_recv_impl(client, conn_id, data, size, &rsize);
1100 if (rc != EOK) {
[c1694b6b]1101 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_wait_srv - recv_impl failed rc=%s", str_error_name(rc));
[a46e56b]1102 async_answer_0(chandle, rc);
1103 async_answer_0(icall_handle, rc);
[779541b]1104 free(data);
1105 return;
1106 }
1107
[a46e56b]1108 rc = async_data_read_finalize(chandle, data, size);
[779541b]1109 if (rc != EOK) {
1110 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_wait_srv - finalize failed");
[a46e56b]1111 async_answer_0(icall_handle, rc);
[779541b]1112 free(data);
1113 return;
1114 }
1115
1116 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_wait_srv(): rsize=%zu", size);
[a46e56b]1117 async_answer_1(icall_handle, EOK, rsize);
[779541b]1118 free(data);
1119
1120 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_wait_srv(): OK");
1121}
1122
[b10460a]1123/** Initialize TCP client structure.
1124 *
1125 * @param client TCP client
1126 */
[309469de]1127static void tcp_client_init(tcp_client_t *client)
1128{
1129 memset(client, 0, sizeof(tcp_client_t));
1130 client->sess = NULL;
1131 list_initialize(&client->cconn);
1132 list_initialize(&client->clst);
1133}
1134
[b10460a]1135/** Finalize TCP client structure.
1136 *
1137 * @param client TCP client
1138 */
[309469de]1139static void tcp_client_fini(tcp_client_t *client)
1140{
1141 tcp_cconn_t *cconn;
[be12474]1142 unsigned long n;
[309469de]1143
1144 n = list_count(&client->cconn);
1145 if (n != 0) {
[1d03e86]1146 log_msg(LOG_DEFAULT, LVL_WARN, "Client with %lu active "
[309469de]1147 "connections closed session", n);
1148
1149 while (!list_empty(&client->cconn)) {
1150 cconn = list_get_instance(list_first(&client->cconn),
1151 tcp_cconn_t, lclient);
1152 tcp_uc_close(cconn->conn);
[8499160]1153 tcp_uc_delete(cconn->conn);
[309469de]1154 tcp_cconn_destroy(cconn);
1155 }
1156 }
1157
1158 n = list_count(&client->clst);
1159 if (n != 0) {
[1d03e86]1160 log_msg(LOG_DEFAULT, LVL_WARN, "Client with %lu active "
[309469de]1161 "listeners closed session", n);
1162 /* XXX Destroy listeners */
1163 }
[1f2b07a]1164
1165 if (client->sess != NULL)
1166 async_hangup(client->sess);
[309469de]1167}
1168
[b10460a]1169/** Handle TCP client connection.
1170 *
[a46e56b]1171 * @param icall_handle Connect call handle
1172 * @param icall Connect call data
1173 * @param arg Connection argument
[b10460a]1174 */
[a46e56b]1175static void tcp_client_conn(cap_call_handle_t icall_handle, ipc_call_t *icall,
1176 void *arg)
[779541b]1177{
1178 tcp_client_t client;
1179
1180 /* Accept the connection */
[a46e56b]1181 async_answer_0(icall_handle, EOK);
[779541b]1182
1183 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_client_conn() - client=%p",
1184 &client);
1185
[309469de]1186 tcp_client_init(&client);
[779541b]1187
1188 while (true) {
1189 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_client_conn: wait req");
1190 ipc_call_t call;
[a46e56b]1191 cap_call_handle_t chandle = async_get_call(&call);
[779541b]1192 sysarg_t method = IPC_GET_IMETHOD(call);
1193
1194 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_client_conn: method=%d",
1195 (int)method);
1196 if (!method) {
1197 /* The other side has hung up */
[a46e56b]1198 async_answer_0(chandle, EOK);
[309469de]1199 break;
[779541b]1200 }
1201
1202 switch (method) {
1203 case TCP_CALLBACK_CREATE:
[a46e56b]1204 tcp_callback_create_srv(&client, chandle, &call);
[779541b]1205 break;
1206 case TCP_CONN_CREATE:
[a46e56b]1207 tcp_conn_create_srv(&client, chandle, &call);
[779541b]1208 break;
1209 case TCP_CONN_DESTROY:
[a46e56b]1210 tcp_conn_destroy_srv(&client, chandle, &call);
[779541b]1211 break;
1212 case TCP_LISTENER_CREATE:
[a46e56b]1213 tcp_listener_create_srv(&client, chandle, &call);
[779541b]1214 break;
1215 case TCP_LISTENER_DESTROY:
[a46e56b]1216 tcp_listener_destroy_srv(&client, chandle, &call);
[779541b]1217 break;
1218 case TCP_CONN_SEND_FIN:
[a46e56b]1219 tcp_conn_send_fin_srv(&client, chandle, &call);
[779541b]1220 break;
1221 case TCP_CONN_PUSH:
[a46e56b]1222 tcp_conn_push_srv(&client, chandle, &call);
[779541b]1223 break;
1224 case TCP_CONN_RESET:
[a46e56b]1225 tcp_conn_reset_srv(&client, chandle, &call);
[779541b]1226 break;
1227 case TCP_CONN_SEND:
[a46e56b]1228 tcp_conn_send_srv(&client, chandle, &call);
[779541b]1229 break;
1230 case TCP_CONN_RECV:
[a46e56b]1231 tcp_conn_recv_srv(&client, chandle, &call);
[779541b]1232 break;
1233 case TCP_CONN_RECV_WAIT:
[a46e56b]1234 tcp_conn_recv_wait_srv(&client, chandle, &call);
[779541b]1235 break;
1236 default:
[a46e56b]1237 async_answer_0(chandle, ENOTSUP);
[779541b]1238 break;
1239 }
1240 }
[309469de]1241
1242 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_client_conn TERMINATED");
1243 tcp_client_fini(&client);
[779541b]1244}
1245
[b10460a]1246/** Initialize TCP service.
1247 *
[cde999a]1248 * @return EOK on success or an error code.
[b10460a]1249 */
[b7fd2a0]1250errno_t tcp_service_init(void)
[779541b]1251{
[b7fd2a0]1252 errno_t rc;
[779541b]1253 service_id_t sid;
1254
[b688fd8]1255 async_set_fallback_port_handler(tcp_client_conn, NULL);
[779541b]1256
1257 rc = loc_server_register(NAME);
1258 if (rc != EOK) {
1259 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering server.");
1260 return EIO;
1261 }
1262
1263 rc = loc_service_register(SERVICE_NAME_TCP, &sid);
1264 if (rc != EOK) {
1265 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service.");
1266 return EIO;
1267 }
1268
1269 return EOK;
1270}
1271
1272/**
1273 * @}
1274 */
Note: See TracBrowser for help on using the repository browser.