source: mainline/uspace/srv/net/tcp/service.c@ 4c6fd56

ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 4c6fd56 was 4c6fd56, checked in by Jiri Svoboda <jiri@…>, 22 months ago

loc_server_register() should be callable more than once (API only)

Now loc_server_register() returns a pointer to a loc_srv_t object,
that is then passed to loc_service_register() and
loc_service_add_to_cat().

Added loc_server_unregister() that unregisters the server
and frees the loc_srv_t object.

Updated all callers. The implementation, however, is a stub.
It is not actually possible to call loc_server_register() more
than once, yet.

  • Property mode set to 100644
File size: 28.3 KB
RevLine 
[779541b]1/*
[4c6fd56]2 * Copyright (c) 2023 Jiri Svoboda
[779541b]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
[ae7d03c]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
[3fafe5e0]569#if 0
570 tcp_uc_close(cconn->conn);
571#endif
[779541b]572 tcp_clistener_destroy(clst);
573 return EOK;
574}
575
[b10460a]576/** Send FIN.
577 *
578 * Handle client request to send FIN (with parameters unmarshalled).
579 *
580 * @param client TCP client
581 * @param conn_id Connection ID
582 *
[cde999a]583 * @return EOK on success or an error code
[b10460a]584 */
[b7fd2a0]585static errno_t tcp_conn_send_fin_impl(tcp_client_t *client, sysarg_t conn_id)
[779541b]586{
587 tcp_cconn_t *cconn;
[b7fd2a0]588 errno_t rc;
[779541b]589
590 rc = tcp_cconn_get(client, conn_id, &cconn);
591 if (rc != EOK) {
592 assert(rc == ENOENT);
593 return ENOENT;
594 }
595
596 (void) cconn;
597 /* XXX TODO */
598 return EOK;
599}
600
[b10460a]601/** Push connection.
602 *
603 * Handle client request to push connection (with parameters unmarshalled).
604 *
605 * @param client TCP client
606 * @param conn_id Connection ID
607 *
[cde999a]608 * @return EOK on success or an error code
[b10460a]609 */
[b7fd2a0]610static errno_t tcp_conn_push_impl(tcp_client_t *client, sysarg_t conn_id)
[779541b]611{
612 tcp_cconn_t *cconn;
[b7fd2a0]613 errno_t rc;
[779541b]614
615 rc = tcp_cconn_get(client, conn_id, &cconn);
616 if (rc != EOK) {
617 assert(rc == ENOENT);
618 return ENOENT;
619 }
620
621 (void) cconn;
622 /* XXX TODO */
623 return EOK;
624}
625
[b10460a]626/** Reset connection.
627 *
628 * Handle client request to reset connection (with parameters unmarshalled).
629 *
630 * @param client TCP client
631 * @param conn_id Connection ID
632 *
[cde999a]633 * @return EOK on success or an error code
[b10460a]634 */
[b7fd2a0]635static errno_t tcp_conn_reset_impl(tcp_client_t *client, sysarg_t conn_id)
[779541b]636{
637 tcp_cconn_t *cconn;
[b7fd2a0]638 errno_t rc;
[779541b]639
640 rc = tcp_cconn_get(client, conn_id, &cconn);
641 if (rc != EOK) {
642 assert(rc == ENOENT);
643 return ENOENT;
644 }
645
646 tcp_uc_abort(cconn->conn);
647 return EOK;
648}
649
[b10460a]650/** Send data over connection..
651 *
652 * Handle client request to send data (with parameters unmarshalled).
653 *
654 * @param client TCP client
655 * @param conn_id Connection ID
656 * @param data Data buffer
657 * @param size Data size in bytes
658 *
[cde999a]659 * @return EOK on success or an error code
[b10460a]660 */
[b7fd2a0]661static errno_t tcp_conn_send_impl(tcp_client_t *client, sysarg_t conn_id,
[779541b]662 void *data, size_t size)
663{
664 tcp_cconn_t *cconn;
[b7fd2a0]665 errno_t rc;
[7ce8f88]666 tcp_error_t trc;
[779541b]667
668 rc = tcp_cconn_get(client, conn_id, &cconn);
669 if (rc != EOK)
670 return rc;
671
[7ce8f88]672 trc = tcp_uc_send(cconn->conn, data, size, 0);
673 if (trc != TCP_EOK)
674 return EIO;
[779541b]675
676 return EOK;
677}
678
[b10460a]679/** Receive data from connection.
680 *
681 * Handle client request to receive data (with parameters unmarshalled).
682 *
683 * @param client TCP client
684 * @param conn_id Connection ID
685 * @param data Data buffer
686 * @param size Buffer size in bytes
687 * @param nrecv Place to store actual number of bytes received
688 *
[cde999a]689 * @return EOK on success or an error code
[b10460a]690 */
[b7fd2a0]691static errno_t tcp_conn_recv_impl(tcp_client_t *client, sysarg_t conn_id,
[779541b]692 void *data, size_t size, size_t *nrecv)
693{
694 tcp_cconn_t *cconn;
695 xflags_t xflags;
[b7fd2a0]696 errno_t rc;
[7ce8f88]697 tcp_error_t trc;
[779541b]698
699 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_impl()");
700
701 rc = tcp_cconn_get(client, conn_id, &cconn);
702 if (rc != EOK) {
703 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_impl() - conn not found");
704 return rc;
705 }
706
[7ce8f88]707 trc = tcp_uc_receive(cconn->conn, data, size, nrecv, &xflags);
708 if (trc != TCP_EOK) {
709 switch (trc) {
[779541b]710 case TCP_EAGAIN:
711 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_impl() - EAGAIN");
712 return EAGAIN;
[258d77e]713 case TCP_ECLOSING:
714 *nrecv = 0;
715 return EOK;
[779541b]716 default:
[7ce8f88]717 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_impl() - trc=%d", trc);
[779541b]718 return EIO;
719 }
720 }
721
722 return EOK;
723}
724
[b10460a]725/** Create client callback session.
726 *
727 * Handle client request to create callback session.
728 *
[984a9ba]729 * @param client TCP client
730 * @param icall Async request data
731 *
[b10460a]732 */
[984a9ba]733static void tcp_callback_create_srv(tcp_client_t *client, ipc_call_t *icall)
[779541b]734{
735 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_callback_create_srv()");
736
737 async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE);
738 if (sess == NULL) {
[984a9ba]739 async_answer_0(icall, ENOMEM);
[779541b]740 return;
741 }
742
743 client->sess = sess;
[984a9ba]744 async_answer_0(icall, EOK);
[779541b]745}
746
[b10460a]747/** Create connection.
748 *
749 * Handle client request to create connection.
750 *
[984a9ba]751 * @param client TCP client
752 * @param icall Async request data
753 *
[b10460a]754 */
[984a9ba]755static void tcp_conn_create_srv(tcp_client_t *client, ipc_call_t *icall)
[779541b]756{
[984a9ba]757 ipc_call_t call;
[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
[984a9ba]765 if (!async_data_write_receive(&call, &size)) {
766 async_answer_0(&call, EREFUSED);
767 async_answer_0(icall, EREFUSED);
[779541b]768 return;
769 }
770
771 if (size != sizeof(inet_ep2_t)) {
[984a9ba]772 async_answer_0(&call, EINVAL);
773 async_answer_0(icall, EINVAL);
[779541b]774 return;
775 }
776
[984a9ba]777 rc = async_data_write_finalize(&call, &epp, size);
[779541b]778 if (rc != EOK) {
[984a9ba]779 async_answer_0(&call, rc);
780 async_answer_0(icall, rc);
[779541b]781 return;
782 }
783
784 rc = tcp_conn_create_impl(client, &epp, &conn_id);
785 if (rc != EOK) {
[984a9ba]786 async_answer_0(icall, rc);
[779541b]787 return;
788 }
789
[984a9ba]790 async_answer_1(icall, EOK, conn_id);
[779541b]791}
792
[b10460a]793/** Destroy connection.
794 *
795 * Handle client request to destroy connection.
796 *
[984a9ba]797 * @param client TCP client
798 * @param icall Async request data
799 *
[b10460a]800 */
[984a9ba]801static void tcp_conn_destroy_srv(tcp_client_t *client, ipc_call_t *icall)
[779541b]802{
803 sysarg_t conn_id;
[b7fd2a0]804 errno_t rc;
[779541b]805
806 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_destroy_srv()");
807
[fafb8e5]808 conn_id = ipc_get_arg1(icall);
[779541b]809 rc = tcp_conn_destroy_impl(client, conn_id);
[984a9ba]810 async_answer_0(icall, rc);
[779541b]811}
812
[b10460a]813/** Create listener.
814 *
815 * Handle client request to create listener.
816 *
[984a9ba]817 * @param client TCP client
818 * @param icall Async request data
819 *
[b10460a]820 */
[984a9ba]821static void tcp_listener_create_srv(tcp_client_t *client, ipc_call_t *icall)
[779541b]822{
[984a9ba]823 ipc_call_t call;
[779541b]824 size_t size;
825 inet_ep_t ep;
826 sysarg_t lst_id;
[b7fd2a0]827 errno_t rc;
[779541b]828
829 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_listener_create_srv()");
830
[984a9ba]831 if (!async_data_write_receive(&call, &size)) {
832 async_answer_0(&call, EREFUSED);
833 async_answer_0(icall, EREFUSED);
[779541b]834 return;
835 }
836
837 if (size != sizeof(inet_ep_t)) {
[984a9ba]838 async_answer_0(&call, EINVAL);
839 async_answer_0(icall, EINVAL);
[779541b]840 return;
841 }
842
[984a9ba]843 rc = async_data_write_finalize(&call, &ep, size);
[779541b]844 if (rc != EOK) {
[984a9ba]845 async_answer_0(&call, rc);
846 async_answer_0(icall, rc);
[779541b]847 return;
848 }
849
850 rc = tcp_listener_create_impl(client, &ep, &lst_id);
851 if (rc != EOK) {
[984a9ba]852 async_answer_0(icall, rc);
[779541b]853 return;
854 }
855
[984a9ba]856 async_answer_1(icall, EOK, lst_id);
[779541b]857}
858
[b10460a]859/** Destroy listener.
860 *
861 * Handle client request to destroy listener.
862 *
[984a9ba]863 * @param client TCP client
864 * @param icall Async request data
865 *
[b10460a]866 */
[984a9ba]867static void tcp_listener_destroy_srv(tcp_client_t *client, ipc_call_t *icall)
[779541b]868{
869 sysarg_t lst_id;
[b7fd2a0]870 errno_t rc;
[779541b]871
872 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_listener_destroy_srv()");
873
[fafb8e5]874 lst_id = ipc_get_arg1(icall);
[779541b]875 rc = tcp_listener_destroy_impl(client, lst_id);
[984a9ba]876 async_answer_0(icall, rc);
[779541b]877}
878
[b10460a]879/** Send FIN.
880 *
881 * Handle client request to send FIN.
882 *
[984a9ba]883 * @param client TCP client
884 * @param icall Async request data
885 *
[b10460a]886 */
[984a9ba]887static void tcp_conn_send_fin_srv(tcp_client_t *client, ipc_call_t *icall)
[779541b]888{
889 sysarg_t conn_id;
[b7fd2a0]890 errno_t rc;
[779541b]891
892 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_send_fin_srv()");
893
[fafb8e5]894 conn_id = ipc_get_arg1(icall);
[779541b]895 rc = tcp_conn_send_fin_impl(client, conn_id);
[984a9ba]896 async_answer_0(icall, rc);
[779541b]897}
898
[b10460a]899/** Push connection.
900 *
901 * Handle client request to push connection.
902 *
[984a9ba]903 * @param client TCP client
904 * @param icall Async request data
905 *
[b10460a]906 */
[984a9ba]907static void tcp_conn_push_srv(tcp_client_t *client, ipc_call_t *icall)
[779541b]908{
909 sysarg_t conn_id;
[b7fd2a0]910 errno_t rc;
[779541b]911
912 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_push_srv()");
913
[fafb8e5]914 conn_id = ipc_get_arg1(icall);
[779541b]915 rc = tcp_conn_push_impl(client, conn_id);
[984a9ba]916 async_answer_0(icall, rc);
[779541b]917}
918
[b10460a]919/** Reset connection.
920 *
921 * Handle client request to reset connection.
922 *
[984a9ba]923 * @param client TCP client
924 * @param icall Async request data
925 *
[b10460a]926 */
[984a9ba]927static void tcp_conn_reset_srv(tcp_client_t *client, ipc_call_t *icall)
[779541b]928{
929 sysarg_t conn_id;
[b7fd2a0]930 errno_t rc;
[779541b]931
932 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_reset_srv()");
933
[fafb8e5]934 conn_id = ipc_get_arg1(icall);
[779541b]935 rc = tcp_conn_reset_impl(client, conn_id);
[984a9ba]936 async_answer_0(icall, rc);
[779541b]937}
938
[b10460a]939/** Send data via connection..
940 *
941 * Handle client request to send data via connection.
942 *
[984a9ba]943 * @param client TCP client
944 * @param icall Async request data
945 *
[b10460a]946 */
[984a9ba]947static void tcp_conn_send_srv(tcp_client_t *client, ipc_call_t *icall)
[779541b]948{
[984a9ba]949 ipc_call_t call;
[779541b]950 size_t size;
951 sysarg_t conn_id;
952 void *data;
[b7fd2a0]953 errno_t rc;
[779541b]954
955 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_send_srv())");
956
957 /* Receive message data */
958
[984a9ba]959 if (!async_data_write_receive(&call, &size)) {
960 async_answer_0(&call, EREFUSED);
961 async_answer_0(icall, EREFUSED);
[779541b]962 return;
963 }
964
965 if (size > MAX_MSG_SIZE) {
[984a9ba]966 async_answer_0(&call, EINVAL);
967 async_answer_0(icall, EINVAL);
[779541b]968 return;
969 }
970
971 data = malloc(size);
972 if (data == NULL) {
[984a9ba]973 async_answer_0(&call, ENOMEM);
974 async_answer_0(icall, ENOMEM);
[4f29118]975 return;
[779541b]976 }
977
[984a9ba]978 rc = async_data_write_finalize(&call, data, size);
[779541b]979 if (rc != EOK) {
[984a9ba]980 async_answer_0(&call, rc);
981 async_answer_0(icall, rc);
[779541b]982 free(data);
983 return;
984 }
985
[fafb8e5]986 conn_id = ipc_get_arg1(icall);
[779541b]987
988 rc = tcp_conn_send_impl(client, conn_id, data, size);
989 if (rc != EOK) {
[984a9ba]990 async_answer_0(icall, rc);
[779541b]991 free(data);
992 return;
993 }
994
[984a9ba]995 async_answer_0(icall, EOK);
[779541b]996 free(data);
997}
998
[b10460a]999/** Read received data from connection without blocking.
1000 *
1001 * Handle client request to read received data via connection without blocking.
1002 *
[984a9ba]1003 * @param client TCP client
1004 * @param icall Async request data
1005 *
[b10460a]1006 */
[984a9ba]1007static void tcp_conn_recv_srv(tcp_client_t *client, ipc_call_t *icall)
[779541b]1008{
[984a9ba]1009 ipc_call_t call;
[779541b]1010 sysarg_t conn_id;
1011 size_t size, rsize;
1012 void *data;
[b7fd2a0]1013 errno_t rc;
[779541b]1014
1015 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_srv()");
1016
[fafb8e5]1017 conn_id = ipc_get_arg1(icall);
[779541b]1018
[984a9ba]1019 if (!async_data_read_receive(&call, &size)) {
1020 async_answer_0(&call, EREFUSED);
1021 async_answer_0(icall, EREFUSED);
[779541b]1022 return;
1023 }
1024
[204ba47]1025 size = min(size, 16384);
[779541b]1026 data = malloc(size);
1027 if (data == NULL) {
[984a9ba]1028 async_answer_0(&call, ENOMEM);
1029 async_answer_0(icall, ENOMEM);
[779541b]1030 return;
1031 }
1032
1033 rc = tcp_conn_recv_impl(client, conn_id, data, size, &rsize);
1034 if (rc != EOK) {
[984a9ba]1035 async_answer_0(&call, rc);
1036 async_answer_0(icall, rc);
[779541b]1037 free(data);
1038 return;
1039 }
1040
[984a9ba]1041 rc = async_data_read_finalize(&call, data, size);
[779541b]1042 if (rc != EOK) {
[984a9ba]1043 async_answer_0(icall, rc);
[779541b]1044 free(data);
1045 return;
1046 }
1047
[984a9ba]1048 async_answer_1(icall, EOK, rsize);
[779541b]1049 free(data);
1050
1051 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_srv(): OK");
1052}
1053
[b10460a]1054/** Read received data from connection with blocking.
1055 *
1056 * Handle client request to read received data via connection with blocking.
1057 *
[984a9ba]1058 * @param client TCP client
1059 * @param icall Async request data
1060 *
[b10460a]1061 */
[984a9ba]1062static void tcp_conn_recv_wait_srv(tcp_client_t *client, ipc_call_t *icall)
[779541b]1063{
[984a9ba]1064 ipc_call_t call;
[779541b]1065 sysarg_t conn_id;
1066 size_t size, rsize;
1067 void *data;
[b7fd2a0]1068 errno_t rc;
[779541b]1069
1070 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_wait_srv()");
1071
[fafb8e5]1072 conn_id = ipc_get_arg1(icall);
[779541b]1073
[984a9ba]1074 if (!async_data_read_receive(&call, &size)) {
[779541b]1075 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_wait_srv - data_receive failed");
[984a9ba]1076 async_answer_0(&call, EREFUSED);
1077 async_answer_0(icall, EREFUSED);
[779541b]1078 return;
1079 }
1080
1081 size = min(size, 16384);
1082 data = malloc(size);
1083 if (data == NULL) {
1084 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_wait_srv - allocation failed");
[984a9ba]1085 async_answer_0(&call, ENOMEM);
1086 async_answer_0(icall, ENOMEM);
[779541b]1087 return;
1088 }
1089
1090 rc = tcp_conn_recv_impl(client, conn_id, data, size, &rsize);
1091 if (rc != EOK) {
[c1694b6b]1092 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_wait_srv - recv_impl failed rc=%s", str_error_name(rc));
[984a9ba]1093 async_answer_0(&call, rc);
1094 async_answer_0(icall, rc);
[779541b]1095 free(data);
1096 return;
1097 }
1098
[984a9ba]1099 rc = async_data_read_finalize(&call, data, size);
[779541b]1100 if (rc != EOK) {
1101 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_wait_srv - finalize failed");
[984a9ba]1102 async_answer_0(icall, rc);
[779541b]1103 free(data);
1104 return;
1105 }
1106
1107 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_wait_srv(): rsize=%zu", size);
[984a9ba]1108 async_answer_1(icall, EOK, rsize);
[779541b]1109 free(data);
1110
1111 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_wait_srv(): OK");
1112}
1113
[b10460a]1114/** Initialize TCP client structure.
1115 *
1116 * @param client TCP client
1117 */
[309469de]1118static void tcp_client_init(tcp_client_t *client)
1119{
1120 memset(client, 0, sizeof(tcp_client_t));
1121 client->sess = NULL;
1122 list_initialize(&client->cconn);
1123 list_initialize(&client->clst);
1124}
1125
[b10460a]1126/** Finalize TCP client structure.
1127 *
1128 * @param client TCP client
1129 */
[309469de]1130static void tcp_client_fini(tcp_client_t *client)
1131{
1132 tcp_cconn_t *cconn;
[be12474]1133 unsigned long n;
[309469de]1134
1135 n = list_count(&client->cconn);
1136 if (n != 0) {
[1d03e86]1137 log_msg(LOG_DEFAULT, LVL_WARN, "Client with %lu active "
[309469de]1138 "connections closed session", n);
1139
1140 while (!list_empty(&client->cconn)) {
1141 cconn = list_get_instance(list_first(&client->cconn),
1142 tcp_cconn_t, lclient);
1143 tcp_uc_close(cconn->conn);
[8499160]1144 tcp_uc_delete(cconn->conn);
[309469de]1145 tcp_cconn_destroy(cconn);
1146 }
1147 }
1148
1149 n = list_count(&client->clst);
1150 if (n != 0) {
[1d03e86]1151 log_msg(LOG_DEFAULT, LVL_WARN, "Client with %lu active "
[309469de]1152 "listeners closed session", n);
1153 /* XXX Destroy listeners */
1154 }
[1f2b07a]1155
1156 if (client->sess != NULL)
1157 async_hangup(client->sess);
[309469de]1158}
1159
[b10460a]1160/** Handle TCP client connection.
1161 *
[984a9ba]1162 * @param icall Connect call data
1163 * @param arg Connection argument
1164 *
[b10460a]1165 */
[984a9ba]1166static void tcp_client_conn(ipc_call_t *icall, void *arg)
[779541b]1167{
1168 tcp_client_t client;
1169
1170 /* Accept the connection */
[beb83c1]1171 async_accept_0(icall);
[779541b]1172
1173 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_client_conn() - client=%p",
1174 &client);
1175
[309469de]1176 tcp_client_init(&client);
[779541b]1177
1178 while (true) {
1179 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_client_conn: wait req");
1180 ipc_call_t call;
[984a9ba]1181 async_get_call(&call);
[fafb8e5]1182 sysarg_t method = ipc_get_imethod(&call);
[779541b]1183
1184 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_client_conn: method=%d",
1185 (int)method);
1186 if (!method) {
1187 /* The other side has hung up */
[984a9ba]1188 async_answer_0(&call, EOK);
[309469de]1189 break;
[779541b]1190 }
1191
1192 switch (method) {
1193 case TCP_CALLBACK_CREATE:
[984a9ba]1194 tcp_callback_create_srv(&client, &call);
[779541b]1195 break;
1196 case TCP_CONN_CREATE:
[984a9ba]1197 tcp_conn_create_srv(&client, &call);
[779541b]1198 break;
1199 case TCP_CONN_DESTROY:
[984a9ba]1200 tcp_conn_destroy_srv(&client, &call);
[779541b]1201 break;
1202 case TCP_LISTENER_CREATE:
[984a9ba]1203 tcp_listener_create_srv(&client, &call);
[779541b]1204 break;
1205 case TCP_LISTENER_DESTROY:
[984a9ba]1206 tcp_listener_destroy_srv(&client, &call);
[779541b]1207 break;
1208 case TCP_CONN_SEND_FIN:
[984a9ba]1209 tcp_conn_send_fin_srv(&client, &call);
[779541b]1210 break;
1211 case TCP_CONN_PUSH:
[984a9ba]1212 tcp_conn_push_srv(&client, &call);
[779541b]1213 break;
1214 case TCP_CONN_RESET:
[984a9ba]1215 tcp_conn_reset_srv(&client, &call);
[779541b]1216 break;
1217 case TCP_CONN_SEND:
[984a9ba]1218 tcp_conn_send_srv(&client, &call);
[779541b]1219 break;
1220 case TCP_CONN_RECV:
[984a9ba]1221 tcp_conn_recv_srv(&client, &call);
[779541b]1222 break;
1223 case TCP_CONN_RECV_WAIT:
[984a9ba]1224 tcp_conn_recv_wait_srv(&client, &call);
[779541b]1225 break;
1226 default:
[984a9ba]1227 async_answer_0(&call, ENOTSUP);
[779541b]1228 break;
1229 }
1230 }
[309469de]1231
1232 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_client_conn TERMINATED");
1233 tcp_client_fini(&client);
[779541b]1234}
1235
[b10460a]1236/** Initialize TCP service.
1237 *
[cde999a]1238 * @return EOK on success or an error code.
[b10460a]1239 */
[b7fd2a0]1240errno_t tcp_service_init(void)
[779541b]1241{
[b7fd2a0]1242 errno_t rc;
[779541b]1243 service_id_t sid;
[4c6fd56]1244 loc_srv_t *srv;
[779541b]1245
[b688fd8]1246 async_set_fallback_port_handler(tcp_client_conn, NULL);
[779541b]1247
[4c6fd56]1248 rc = loc_server_register(NAME, &srv);
[779541b]1249 if (rc != EOK) {
1250 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering server.");
1251 return EIO;
1252 }
1253
[4c6fd56]1254 rc = loc_service_register(srv, SERVICE_NAME_TCP, &sid);
[779541b]1255 if (rc != EOK) {
[4c6fd56]1256 loc_server_unregister(srv);
[779541b]1257 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service.");
1258 return EIO;
1259 }
1260
1261 return EOK;
1262}
1263
1264/**
1265 * @}
1266 */
Note: See TracBrowser for help on using the repository browser.