source: mainline/uspace/srv/net/tcp/service.c@ 8d48c7e

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

Find the association to deliver the datagram using amap.

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