source: mainline/uspace/srv/net/tcp/service.c@ 1d03e86

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

Fix formatting strings.

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