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

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

Delete connection and prevent further callbacks.

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