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

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

TCP and UDP client code needs to make sure callback connection handler has terminated before freeing session-related data.

  • Property mode set to 100644
File size: 21.7 KB
Line 
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
29/** @addtogroup udp
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>
46#include <stdlib.h>
47
48#include "conn.h"
49#include "service.h"
50#include "tcp_type.h"
51#include "ucall.h"
52
53#define NAME "tcp"
54
55#define MAX_MSG_SIZE DATA_XFER_LIMIT
56
57static void tcp_ev_data(tcp_cconn_t *);
58static void tcp_ev_connected(tcp_cconn_t *);
59static void tcp_ev_conn_failed(tcp_cconn_t *);
60static void tcp_ev_conn_reset(tcp_cconn_t *);
61static void tcp_ev_new_conn(tcp_clst_t *, tcp_cconn_t *);
62
63static void tcp_service_cstate_change(tcp_conn_t *, void *, tcp_cstate_t);
64static void tcp_service_recv_data(tcp_conn_t *, void *);
65static void tcp_service_lst_cstate_change(tcp_conn_t *, void *, tcp_cstate_t);
66
67static int tcp_cconn_create(tcp_client_t *, tcp_conn_t *, tcp_cconn_t **);
68
69static tcp_cb_t tcp_service_cb = {
70 .cstate_change = tcp_service_cstate_change,
71 .recv_data = tcp_service_recv_data
72};
73
74static tcp_cb_t tcp_service_lst_cb = {
75 .cstate_change = tcp_service_lst_cstate_change,
76 .recv_data = NULL
77};
78
79static void tcp_service_cstate_change(tcp_conn_t *conn, void *arg,
80 tcp_cstate_t old_state)
81{
82 tcp_cstate_t nstate;
83 tcp_cconn_t *cconn;
84
85 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_service_cstate_change()");
86 nstate = conn->cstate;
87 cconn = tcp_uc_get_userptr(conn);
88
89 if ((old_state == st_syn_sent || old_state == st_syn_received) &&
90 (nstate == st_established)) {
91 /* Connection established */
92 tcp_ev_connected(cconn);
93 }
94
95 if (old_state != st_closed && nstate == st_closed && conn->reset) {
96 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_service_cstate_change: "
97 "Connection reset");
98 /* Connection reset */
99 tcp_ev_conn_reset(cconn);
100 } else {
101 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_service_cstate_change: "
102 "old_state=%d nstate=%d conn->reset=%d",
103 old_state, nstate, conn->reset);
104 }
105
106 /* XXX Failed to establish connection */
107 if (0) tcp_ev_conn_failed(cconn);
108}
109
110static void tcp_service_lst_cstate_change(tcp_conn_t *conn, void *arg,
111 tcp_cstate_t old_state)
112{
113 tcp_cstate_t nstate;
114 tcp_clst_t *clst;
115 tcp_cconn_t *cconn;
116 inet_ep2_t epp;
117 int rc;
118 tcp_error_t trc;
119
120 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_service_lst_cstate_change()");
121 nstate = conn->cstate;
122 clst = tcp_uc_get_userptr(conn);
123
124 if ((old_state == st_syn_sent || old_state == st_syn_received) &&
125 (nstate == st_established)) {
126 /* Connection established */
127 clst->conn = NULL;
128
129 rc = tcp_cconn_create(clst->client, conn, &cconn);
130 if (rc != EOK) {
131 /* XXX Could not create client connection */
132 return;
133 }
134
135 /* XXX Is there a race here (i.e. the connection is already active)? */
136 tcp_uc_set_cb(conn, &tcp_service_cb, cconn);
137
138 /* New incoming connection */
139 tcp_ev_new_conn(clst, cconn);
140 }
141
142 if (old_state != st_closed && nstate == st_closed && conn->reset) {
143 /* Connection reset */
144 /* XXX */
145 }
146
147 /* XXX Failed to establish connection */
148 if (0) {
149 /* XXX */
150 }
151
152 /* Replenish sentinel connection */
153
154 inet_ep2_init(&epp);
155 epp.local = clst->elocal;
156
157 trc = tcp_uc_open(&epp, ap_passive, tcp_open_nonblock,
158 &conn);
159 if (trc != TCP_EOK) {
160 /* XXX Could not replenish connection */
161 return;
162 }
163
164 conn->name = (char *) "s";
165 clst->conn = conn;
166
167 /* XXX Is there a race here (i.e. the connection is already active)? */
168 tcp_uc_set_cb(conn, &tcp_service_lst_cb, clst);
169}
170
171static void tcp_service_recv_data(tcp_conn_t *conn, void *arg)
172{
173 tcp_cconn_t *cconn = (tcp_cconn_t *)arg;
174
175 tcp_ev_data(cconn);
176}
177
178static void tcp_ev_data(tcp_cconn_t *cconn)
179{
180 async_exch_t *exch;
181
182 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_ev_data()");
183
184 log_msg(LOG_DEFAULT, LVL_DEBUG, "client=%p\n", cconn->client);
185 log_msg(LOG_DEFAULT, LVL_DEBUG, "sess=%p\n", cconn->client->sess);
186
187 exch = async_exchange_begin(cconn->client->sess);
188 aid_t req = async_send_1(exch, TCP_EV_DATA, cconn->id, NULL);
189 async_exchange_end(exch);
190
191 async_forget(req);
192}
193
194static void tcp_ev_connected(tcp_cconn_t *cconn)
195{
196 async_exch_t *exch;
197
198 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_ev_connected()");
199
200 exch = async_exchange_begin(cconn->client->sess);
201 aid_t req = async_send_1(exch, TCP_EV_CONNECTED, cconn->id, NULL);
202 async_exchange_end(exch);
203
204 async_forget(req);
205}
206
207static void tcp_ev_conn_failed(tcp_cconn_t *cconn)
208{
209 async_exch_t *exch;
210
211 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_ev_conn_failed()");
212
213 exch = async_exchange_begin(cconn->client->sess);
214 aid_t req = async_send_1(exch, TCP_EV_CONN_FAILED, cconn->id, NULL);
215 async_exchange_end(exch);
216
217 async_forget(req);
218}
219
220static void tcp_ev_conn_reset(tcp_cconn_t *cconn)
221{
222 async_exch_t *exch;
223
224 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_ev_conn_reset()");
225
226 exch = async_exchange_begin(cconn->client->sess);
227 aid_t req = async_send_1(exch, TCP_EV_CONN_RESET, cconn->id, NULL);
228 async_exchange_end(exch);
229
230 async_forget(req);
231}
232
233/** New incoming connection */
234static void tcp_ev_new_conn(tcp_clst_t *clst, tcp_cconn_t *cconn)
235{
236 async_exch_t *exch;
237
238 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_ev_new_conn()");
239
240 exch = async_exchange_begin(clst->client->sess);
241 aid_t req = async_send_2(exch, TCP_EV_NEW_CONN, clst->id, cconn->id,
242 NULL);
243 async_exchange_end(exch);
244
245 async_forget(req);
246}
247
248static int tcp_cconn_create(tcp_client_t *client, tcp_conn_t *conn,
249 tcp_cconn_t **rcconn)
250{
251 tcp_cconn_t *cconn;
252 sysarg_t id;
253
254 cconn = calloc(1, sizeof(tcp_cconn_t));
255 if (cconn == NULL)
256 return ENOMEM;
257
258 /* Allocate new ID */
259 id = 0;
260 list_foreach (client->cconn, lclient, tcp_cconn_t, cconn) {
261 if (cconn->id >= id)
262 id = cconn->id + 1;
263 }
264
265 cconn->id = id;
266 cconn->client = client;
267 cconn->conn = conn;
268
269 list_append(&cconn->lclient, &client->cconn);
270 *rcconn = cconn;
271 return EOK;
272}
273
274static void tcp_cconn_destroy(tcp_cconn_t *cconn)
275{
276 list_remove(&cconn->lclient);
277 free(cconn);
278}
279
280static int tcp_clistener_create(tcp_client_t *client, tcp_conn_t *conn,
281 tcp_clst_t **rclst)
282{
283 tcp_clst_t *clst;
284 sysarg_t id;
285
286 clst = calloc(1, sizeof(tcp_clst_t));
287 if (clst == NULL)
288 return ENOMEM;
289
290 /* Allocate new ID */
291 id = 0;
292 list_foreach (client->clst, lclient, tcp_clst_t, clst) {
293 if (clst->id >= id)
294 id = clst->id + 1;
295 }
296
297 clst->id = id;
298 clst->client = client;
299 clst->conn = conn;
300
301 list_append(&clst->lclient, &client->clst);
302 *rclst = clst;
303 return EOK;
304}
305
306static void tcp_clistener_destroy(tcp_clst_t *clst)
307{
308 list_remove(&clst->lclient);
309 free(clst);
310}
311
312static int tcp_cconn_get(tcp_client_t *client, sysarg_t id,
313 tcp_cconn_t **rcconn)
314{
315 list_foreach (client->cconn, lclient, tcp_cconn_t, cconn) {
316 if (cconn->id == id) {
317 *rcconn = cconn;
318 return EOK;
319 }
320 }
321
322 return ENOENT;
323}
324
325static int tcp_clistener_get(tcp_client_t *client, sysarg_t id,
326 tcp_clst_t **rclst)
327{
328 list_foreach (client->clst, lclient, tcp_clst_t, clst) {
329 if (clst->id == id) {
330 *rclst = clst;
331 return EOK;
332 }
333 }
334
335 return ENOENT;
336}
337
338
339static int tcp_conn_create_impl(tcp_client_t *client, inet_ep2_t *epp,
340 sysarg_t *rconn_id)
341{
342 tcp_conn_t *conn;
343 tcp_cconn_t *cconn;
344 int rc;
345 tcp_error_t trc;
346 char *slocal;
347 char *sremote;
348
349 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_create_impl");
350
351 inet_addr_format(&epp->local.addr, &slocal);
352 inet_addr_format(&epp->remote.addr, &sremote);
353 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_create: local=%s remote=%s",
354 slocal, sremote);
355 free(slocal);
356 free(sremote);
357
358 trc = tcp_uc_open(epp, ap_active, tcp_open_nonblock, &conn);
359 if (trc != TCP_EOK)
360 return EIO;
361
362 conn->name = (char *) "c";
363
364 rc = tcp_cconn_create(client, conn, &cconn);
365 if (rc != EOK) {
366 assert(rc == ENOMEM);
367 tcp_conn_delete(conn);
368 return ENOMEM;
369 }
370
371 /* XXX Is there a race here (i.e. the connection is already active)? */
372 tcp_uc_set_cb(conn, &tcp_service_cb, cconn);
373
374 *rconn_id = cconn->id;
375 return EOK;
376}
377
378static int tcp_conn_destroy_impl(tcp_client_t *client, sysarg_t conn_id)
379{
380 tcp_cconn_t *cconn;
381 int rc;
382
383 rc = tcp_cconn_get(client, conn_id, &cconn);
384 if (rc != EOK) {
385 assert(rc == ENOENT);
386 return ENOENT;
387 }
388
389 tcp_uc_close(cconn->conn);
390 tcp_uc_delete(cconn->conn);
391 tcp_cconn_destroy(cconn);
392 return EOK;
393}
394
395static int tcp_listener_create_impl(tcp_client_t *client, inet_ep_t *ep,
396 sysarg_t *rlst_id)
397{
398 tcp_conn_t *conn;
399 tcp_clst_t *clst;
400 inet_ep2_t epp;
401 int rc;
402 tcp_error_t trc;
403
404 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_listener_create_impl");
405
406 inet_ep2_init(&epp);
407 epp.local.addr = ep->addr;
408 epp.local.port = ep->port;
409
410 trc = tcp_uc_open(&epp, ap_passive, tcp_open_nonblock, &conn);
411 if (trc != TCP_EOK)
412 return EIO;
413
414 conn->name = (char *) "s";
415
416 rc = tcp_clistener_create(client, conn, &clst);
417 if (rc != EOK) {
418 assert(rc == ENOMEM);
419 tcp_conn_delete(conn);
420 return ENOMEM;
421 }
422
423 clst->elocal = epp.local;
424
425 /* XXX Is there a race here (i.e. the connection is already active)? */
426 tcp_uc_set_cb(conn, &tcp_service_lst_cb, clst);
427
428 *rlst_id = clst->id;
429 return EOK;
430}
431
432static int tcp_listener_destroy_impl(tcp_client_t *client, sysarg_t lst_id)
433{
434 tcp_clst_t *clst;
435 int rc;
436
437 rc = tcp_clistener_get(client, lst_id, &clst);
438 if (rc != EOK) {
439 assert(rc == ENOENT);
440 return ENOENT;
441 }
442
443// tcp_uc_close(cconn->conn);
444 tcp_clistener_destroy(clst);
445 return EOK;
446}
447
448static int tcp_conn_send_fin_impl(tcp_client_t *client, sysarg_t conn_id)
449{
450 tcp_cconn_t *cconn;
451 int rc;
452
453 rc = tcp_cconn_get(client, conn_id, &cconn);
454 if (rc != EOK) {
455 assert(rc == ENOENT);
456 return ENOENT;
457 }
458
459 (void) cconn;
460 /* XXX TODO */
461 return EOK;
462}
463
464static int tcp_conn_push_impl(tcp_client_t *client, sysarg_t conn_id)
465{
466 tcp_cconn_t *cconn;
467 int rc;
468
469 rc = tcp_cconn_get(client, conn_id, &cconn);
470 if (rc != EOK) {
471 assert(rc == ENOENT);
472 return ENOENT;
473 }
474
475 (void) cconn;
476 /* XXX TODO */
477 return EOK;
478}
479
480static int tcp_conn_reset_impl(tcp_client_t *client, sysarg_t conn_id)
481{
482 tcp_cconn_t *cconn;
483 int rc;
484
485 rc = tcp_cconn_get(client, conn_id, &cconn);
486 if (rc != EOK) {
487 assert(rc == ENOENT);
488 return ENOENT;
489 }
490
491 tcp_uc_abort(cconn->conn);
492 return EOK;
493}
494
495static int tcp_conn_send_impl(tcp_client_t *client, sysarg_t conn_id,
496 void *data, size_t size)
497{
498 tcp_cconn_t *cconn;
499 int rc;
500
501 rc = tcp_cconn_get(client, conn_id, &cconn);
502 if (rc != EOK)
503 return rc;
504
505 rc = tcp_uc_send(cconn->conn, data, size, 0);
506 if (rc != EOK)
507 return rc;
508
509 return EOK;
510}
511
512static int tcp_conn_recv_impl(tcp_client_t *client, sysarg_t conn_id,
513 void *data, size_t size, size_t *nrecv)
514{
515 tcp_cconn_t *cconn;
516 xflags_t xflags;
517 int rc;
518
519 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_impl()");
520
521 rc = tcp_cconn_get(client, conn_id, &cconn);
522 if (rc != EOK) {
523 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_impl() - conn not found");
524 return rc;
525 }
526
527 rc = tcp_uc_receive(cconn->conn, data, size, nrecv, &xflags);
528 if (rc != EOK) {
529 switch (rc) {
530 case TCP_EAGAIN:
531 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_impl() - EAGAIN");
532 return EAGAIN;
533 default:
534 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_impl() - trc=%d", rc);
535 return EIO;
536 }
537 }
538
539 return EOK;
540}
541
542static void tcp_callback_create_srv(tcp_client_t *client, ipc_callid_t iid,
543 ipc_call_t *icall)
544{
545 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_callback_create_srv()");
546
547 async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE);
548 if (sess == NULL) {
549 async_answer_0(iid, ENOMEM);
550 return;
551 }
552
553 client->sess = sess;
554 async_answer_0(iid, EOK);
555}
556
557static void tcp_conn_create_srv(tcp_client_t *client, ipc_callid_t iid,
558 ipc_call_t *icall)
559{
560 ipc_callid_t callid;
561 size_t size;
562 inet_ep2_t epp;
563 sysarg_t conn_id;
564 int rc;
565
566 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_create_srv()");
567
568 if (!async_data_write_receive(&callid, &size)) {
569 async_answer_0(callid, EREFUSED);
570 async_answer_0(iid, EREFUSED);
571 return;
572 }
573
574 if (size != sizeof(inet_ep2_t)) {
575 async_answer_0(callid, EINVAL);
576 async_answer_0(iid, EINVAL);
577 return;
578 }
579
580 rc = async_data_write_finalize(callid, &epp, size);
581 if (rc != EOK) {
582 async_answer_0(callid, rc);
583 async_answer_0(iid, rc);
584 return;
585 }
586
587 rc = tcp_conn_create_impl(client, &epp, &conn_id);
588 if (rc != EOK) {
589 async_answer_0(iid, rc);
590 return;
591 }
592
593 async_answer_1(iid, EOK, conn_id);
594}
595
596static void tcp_conn_destroy_srv(tcp_client_t *client, ipc_callid_t iid,
597 ipc_call_t *icall)
598{
599 sysarg_t conn_id;
600 int rc;
601
602 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_destroy_srv()");
603
604 conn_id = IPC_GET_ARG1(*icall);
605 rc = tcp_conn_destroy_impl(client, conn_id);
606 async_answer_0(iid, rc);
607}
608
609static void tcp_listener_create_srv(tcp_client_t *client, ipc_callid_t iid,
610 ipc_call_t *icall)
611{
612 ipc_callid_t callid;
613 size_t size;
614 inet_ep_t ep;
615 sysarg_t lst_id;
616 int rc;
617
618 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_listener_create_srv()");
619
620 if (!async_data_write_receive(&callid, &size)) {
621 async_answer_0(callid, EREFUSED);
622 async_answer_0(iid, EREFUSED);
623 return;
624 }
625
626 if (size != sizeof(inet_ep_t)) {
627 async_answer_0(callid, EINVAL);
628 async_answer_0(iid, EINVAL);
629 return;
630 }
631
632 rc = async_data_write_finalize(callid, &ep, size);
633 if (rc != EOK) {
634 async_answer_0(callid, rc);
635 async_answer_0(iid, rc);
636 return;
637 }
638
639 rc = tcp_listener_create_impl(client, &ep, &lst_id);
640 if (rc != EOK) {
641 async_answer_0(iid, rc);
642 return;
643 }
644
645 async_answer_1(iid, EOK, lst_id);
646}
647
648static void tcp_listener_destroy_srv(tcp_client_t *client, ipc_callid_t iid,
649 ipc_call_t *icall)
650{
651 sysarg_t lst_id;
652 int rc;
653
654 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_listener_destroy_srv()");
655
656 lst_id = IPC_GET_ARG1(*icall);
657 rc = tcp_listener_destroy_impl(client, lst_id);
658 async_answer_0(iid, rc);
659}
660
661static void tcp_conn_send_fin_srv(tcp_client_t *client, ipc_callid_t iid,
662 ipc_call_t *icall)
663{
664 sysarg_t conn_id;
665 int rc;
666
667 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_send_fin_srv()");
668
669 conn_id = IPC_GET_ARG1(*icall);
670 rc = tcp_conn_send_fin_impl(client, conn_id);
671 async_answer_0(iid, rc);
672}
673
674static void tcp_conn_push_srv(tcp_client_t *client, ipc_callid_t iid,
675 ipc_call_t *icall)
676{
677 sysarg_t conn_id;
678 int rc;
679
680 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_push_srv()");
681
682 conn_id = IPC_GET_ARG1(*icall);
683 rc = tcp_conn_push_impl(client, conn_id);
684 async_answer_0(iid, rc);
685}
686
687static void tcp_conn_reset_srv(tcp_client_t *client, ipc_callid_t iid,
688 ipc_call_t *icall)
689{
690 sysarg_t conn_id;
691 int rc;
692
693 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_reset_srv()");
694
695 conn_id = IPC_GET_ARG1(*icall);
696 rc = tcp_conn_reset_impl(client, conn_id);
697 async_answer_0(iid, rc);
698}
699
700static void tcp_conn_send_srv(tcp_client_t *client, ipc_callid_t iid,
701 ipc_call_t *icall)
702{
703 ipc_callid_t callid;
704 size_t size;
705 sysarg_t conn_id;
706 void *data;
707 int rc;
708
709 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_send_srv())");
710
711 /* Receive message data */
712
713 if (!async_data_write_receive(&callid, &size)) {
714 async_answer_0(callid, EREFUSED);
715 async_answer_0(iid, EREFUSED);
716 return;
717 }
718
719 if (size > MAX_MSG_SIZE) {
720 async_answer_0(callid, EINVAL);
721 async_answer_0(iid, EINVAL);
722 return;
723 }
724
725 data = malloc(size);
726 if (data == NULL) {
727 async_answer_0(callid, ENOMEM);
728 async_answer_0(iid, ENOMEM);
729 }
730
731 rc = async_data_write_finalize(callid, data, size);
732 if (rc != EOK) {
733 async_answer_0(callid, rc);
734 async_answer_0(iid, rc);
735 free(data);
736 return;
737 }
738
739 conn_id = IPC_GET_ARG1(*icall);
740
741 rc = tcp_conn_send_impl(client, conn_id, data, size);
742 if (rc != EOK) {
743 async_answer_0(iid, rc);
744 free(data);
745 return;
746 }
747
748 async_answer_0(iid, EOK);
749 free(data);
750}
751
752static void tcp_conn_recv_srv(tcp_client_t *client, ipc_callid_t iid,
753 ipc_call_t *icall)
754{
755 ipc_callid_t callid;
756 sysarg_t conn_id;
757 size_t size, rsize;
758 void *data;
759 int rc;
760
761 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_srv()");
762
763 conn_id = IPC_GET_ARG1(*icall);
764
765 if (!async_data_read_receive(&callid, &size)) {
766 async_answer_0(callid, EREFUSED);
767 async_answer_0(iid, EREFUSED);
768 return;
769 }
770
771 size = min(size, 16384);
772 data = malloc(size);
773 if (data == NULL) {
774 async_answer_0(callid, ENOMEM);
775 async_answer_0(iid, ENOMEM);
776 return;
777 }
778
779 rc = tcp_conn_recv_impl(client, conn_id, data, size, &rsize);
780 if (rc != EOK) {
781 async_answer_0(callid, rc);
782 async_answer_0(iid, rc);
783 free(data);
784 return;
785 }
786
787 rc = async_data_read_finalize(callid, data, size);
788 if (rc != EOK) {
789 async_answer_0(iid, rc);
790 free(data);
791 return;
792 }
793
794 async_answer_1(iid, EOK, rsize);
795 free(data);
796
797 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_srv(): OK");
798}
799
800static void tcp_conn_recv_wait_srv(tcp_client_t *client, ipc_callid_t iid,
801 ipc_call_t *icall)
802{
803 ipc_callid_t callid;
804 sysarg_t conn_id;
805 size_t size, rsize;
806 void *data;
807 int rc;
808
809 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_wait_srv()");
810
811 conn_id = IPC_GET_ARG1(*icall);
812
813 if (!async_data_read_receive(&callid, &size)) {
814 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_wait_srv - data_receive failed");
815 async_answer_0(callid, EREFUSED);
816 async_answer_0(iid, EREFUSED);
817 return;
818 }
819
820 size = min(size, 16384);
821 data = malloc(size);
822 if (data == NULL) {
823 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_wait_srv - allocation failed");
824 async_answer_0(callid, ENOMEM);
825 async_answer_0(iid, ENOMEM);
826 return;
827 }
828
829 rc = tcp_conn_recv_impl(client, conn_id, data, size, &rsize);
830 if (rc != EOK) {
831 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_wait_srv - recv_impl failed rc=%d", rc);
832 async_answer_0(callid, rc);
833 async_answer_0(iid, rc);
834 free(data);
835 return;
836 }
837
838 rc = async_data_read_finalize(callid, data, size);
839 if (rc != EOK) {
840 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_wait_srv - finalize failed");
841 async_answer_0(iid, rc);
842 free(data);
843 return;
844 }
845
846 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_wait_srv(): rsize=%zu", size);
847 async_answer_1(iid, EOK, rsize);
848 free(data);
849
850 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_wait_srv(): OK");
851}
852
853#include <mem.h>
854
855static void tcp_client_init(tcp_client_t *client)
856{
857 memset(client, 0, sizeof(tcp_client_t));
858 client->sess = NULL;
859 list_initialize(&client->cconn);
860 list_initialize(&client->clst);
861}
862
863static void tcp_client_fini(tcp_client_t *client)
864{
865 tcp_cconn_t *cconn;
866 size_t n;
867
868 n = list_count(&client->cconn);
869 if (n != 0) {
870 log_msg(LOG_DEFAULT, LVL_WARN, "Client with %zu active "
871 "connections closed session", n);
872
873 while (!list_empty(&client->cconn)) {
874 cconn = list_get_instance(list_first(&client->cconn),
875 tcp_cconn_t, lclient);
876 tcp_uc_close(cconn->conn);
877 tcp_uc_delete(cconn->conn);
878 tcp_cconn_destroy(cconn);
879 }
880 }
881
882 n = list_count(&client->clst);
883 if (n != 0) {
884 log_msg(LOG_DEFAULT, LVL_WARN, "Client with %zu active "
885 "listeners closed session", n);
886 /* XXX Destroy listeners */
887 }
888
889 if (client->sess != NULL)
890 async_hangup(client->sess);
891}
892
893static void tcp_client_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
894{
895 tcp_client_t client;
896
897 /* Accept the connection */
898 async_answer_0(iid, EOK);
899
900 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_client_conn() - client=%p",
901 &client);
902
903 tcp_client_init(&client);
904
905 while (true) {
906 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_client_conn: wait req");
907 ipc_call_t call;
908 ipc_callid_t callid = async_get_call(&call);
909 sysarg_t method = IPC_GET_IMETHOD(call);
910
911 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_client_conn: method=%d",
912 (int)method);
913 if (!method) {
914 /* The other side has hung up */
915 async_answer_0(callid, EOK);
916 break;
917 }
918
919 switch (method) {
920 case TCP_CALLBACK_CREATE:
921 tcp_callback_create_srv(&client, callid, &call);
922 break;
923 case TCP_CONN_CREATE:
924 tcp_conn_create_srv(&client, callid, &call);
925 break;
926 case TCP_CONN_DESTROY:
927 tcp_conn_destroy_srv(&client, callid, &call);
928 break;
929 case TCP_LISTENER_CREATE:
930 tcp_listener_create_srv(&client, callid, &call);
931 break;
932 case TCP_LISTENER_DESTROY:
933 tcp_listener_destroy_srv(&client, callid, &call);
934 break;
935 case TCP_CONN_SEND_FIN:
936 tcp_conn_send_fin_srv(&client, callid, &call);
937 break;
938 case TCP_CONN_PUSH:
939 tcp_conn_push_srv(&client, callid, &call);
940 break;
941 case TCP_CONN_RESET:
942 tcp_conn_reset_srv(&client, callid, &call);
943 break;
944 case TCP_CONN_SEND:
945 tcp_conn_send_srv(&client, callid, &call);
946 break;
947 case TCP_CONN_RECV:
948 tcp_conn_recv_srv(&client, callid, &call);
949 break;
950 case TCP_CONN_RECV_WAIT:
951 tcp_conn_recv_wait_srv(&client, callid, &call);
952 break;
953 default:
954 async_answer_0(callid, ENOTSUP);
955 break;
956 }
957 }
958
959 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_client_conn TERMINATED");
960 tcp_client_fini(&client);
961}
962
963int tcp_service_init(void)
964{
965 int rc;
966 service_id_t sid;
967
968 async_set_client_connection(tcp_client_conn);
969
970 rc = loc_server_register(NAME);
971 if (rc != EOK) {
972 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering server.");
973 return EIO;
974 }
975
976 rc = loc_service_register(SERVICE_NAME_TCP, &sid);
977 if (rc != EOK) {
978 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service.");
979 return EIO;
980 }
981
982 return EOK;
983}
984
985/**
986 * @}
987 */
Note: See TracBrowser for help on using the repository browser.