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

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

Association map / portrange prototype.

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