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

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

Accepting connections.

  • 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_cconn_destroy(cconn);
408 return EOK;
409}
410
411static int tcp_listener_create_impl(tcp_client_t *client, inet_ep_t *ep,
412 sysarg_t *rlst_id)
413{
414 tcp_conn_t *conn;
415 tcp_clst_t *clst;
416 tcp_sock_t local;
417 int rc;
418 tcp_error_t trc;
419
420 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_listener_create_impl");
421
422 local.addr = ep->addr;
423 local.port = ep->port;
424
425 trc = tcp_uc_open(&local, NULL, ap_passive, tcp_open_nonblock, &conn);
426 if (trc != TCP_EOK)
427 return EIO;
428
429 rc = tcp_clistener_create(client, conn, &clst);
430 if (rc != EOK) {
431 assert(rc == ENOMEM);
432 tcp_conn_delete(conn);
433 return ENOMEM;
434 }
435
436 clst->elocal = local;
437
438 /* XXX Is there a race here (i.e. the connection is already active)? */
439 tcp_uc_set_cb(conn, &tcp_service_lst_cb, clst);
440
441 *rlst_id = clst->id;
442 return EOK;
443}
444
445static int tcp_listener_destroy_impl(tcp_client_t *client, sysarg_t lst_id)
446{
447 tcp_clst_t *clst;
448 int rc;
449
450 rc = tcp_clistener_get(client, lst_id, &clst);
451 if (rc != EOK) {
452 assert(rc == ENOENT);
453 return ENOENT;
454 }
455
456// tcp_uc_close(cconn->conn);
457 tcp_clistener_destroy(clst);
458 return EOK;
459}
460
461static int tcp_conn_send_fin_impl(tcp_client_t *client, sysarg_t conn_id)
462{
463 tcp_cconn_t *cconn;
464 int rc;
465
466 rc = tcp_cconn_get(client, conn_id, &cconn);
467 if (rc != EOK) {
468 assert(rc == ENOENT);
469 return ENOENT;
470 }
471
472 (void) cconn;
473 /* XXX TODO */
474 return EOK;
475}
476
477static int tcp_conn_push_impl(tcp_client_t *client, sysarg_t conn_id)
478{
479 tcp_cconn_t *cconn;
480 int rc;
481
482 rc = tcp_cconn_get(client, conn_id, &cconn);
483 if (rc != EOK) {
484 assert(rc == ENOENT);
485 return ENOENT;
486 }
487
488 (void) cconn;
489 /* XXX TODO */
490 return EOK;
491}
492
493static int tcp_conn_reset_impl(tcp_client_t *client, sysarg_t conn_id)
494{
495 tcp_cconn_t *cconn;
496 int rc;
497
498 rc = tcp_cconn_get(client, conn_id, &cconn);
499 if (rc != EOK) {
500 assert(rc == ENOENT);
501 return ENOENT;
502 }
503
504 tcp_uc_abort(cconn->conn);
505 return EOK;
506}
507
508static int tcp_conn_send_impl(tcp_client_t *client, sysarg_t conn_id,
509 void *data, size_t size)
510{
511 tcp_cconn_t *cconn;
512 int rc;
513
514 rc = tcp_cconn_get(client, conn_id, &cconn);
515 if (rc != EOK)
516 return rc;
517
518 rc = tcp_uc_send(cconn->conn, data, size, 0);
519 if (rc != EOK)
520 return rc;
521
522 return EOK;
523}
524
525static int tcp_conn_recv_impl(tcp_client_t *client, sysarg_t conn_id,
526 void *data, size_t size, size_t *nrecv)
527{
528 tcp_cconn_t *cconn;
529 xflags_t xflags;
530 int rc;
531
532 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_impl()");
533
534 rc = tcp_cconn_get(client, conn_id, &cconn);
535 if (rc != EOK) {
536 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_impl() - conn not found");
537 return rc;
538 }
539
540 rc = tcp_uc_receive(cconn->conn, data, size, nrecv, &xflags);
541 if (rc != EOK) {
542 switch (rc) {
543 case TCP_EAGAIN:
544 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_impl() - EAGAIN");
545 return EAGAIN;
546 default:
547 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_impl() - trc=%d", rc);
548 return EIO;
549 }
550 }
551
552 return EOK;
553}
554
555static void tcp_callback_create_srv(tcp_client_t *client, ipc_callid_t iid,
556 ipc_call_t *icall)
557{
558 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_callback_create_srv()");
559
560 async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE);
561 if (sess == NULL) {
562 async_answer_0(iid, ENOMEM);
563 return;
564 }
565
566 client->sess = sess;
567 async_answer_0(iid, EOK);
568}
569
570static void tcp_conn_create_srv(tcp_client_t *client, ipc_callid_t iid,
571 ipc_call_t *icall)
572{
573 ipc_callid_t callid;
574 size_t size;
575 inet_ep2_t epp;
576 sysarg_t conn_id;
577 int rc;
578
579 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_create_srv()");
580
581 if (!async_data_write_receive(&callid, &size)) {
582 async_answer_0(callid, EREFUSED);
583 async_answer_0(iid, EREFUSED);
584 return;
585 }
586
587 if (size != sizeof(inet_ep2_t)) {
588 async_answer_0(callid, EINVAL);
589 async_answer_0(iid, EINVAL);
590 return;
591 }
592
593 rc = async_data_write_finalize(callid, &epp, size);
594 if (rc != EOK) {
595 async_answer_0(callid, rc);
596 async_answer_0(iid, rc);
597 return;
598 }
599
600 rc = tcp_conn_create_impl(client, &epp, &conn_id);
601 if (rc != EOK) {
602 async_answer_0(iid, rc);
603 return;
604 }
605
606 async_answer_1(iid, EOK, conn_id);
607}
608
609static void tcp_conn_destroy_srv(tcp_client_t *client, ipc_callid_t iid,
610 ipc_call_t *icall)
611{
612 sysarg_t conn_id;
613 int rc;
614
615 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_destroy_srv()");
616
617 conn_id = IPC_GET_ARG1(*icall);
618 rc = tcp_conn_destroy_impl(client, conn_id);
619 async_answer_0(iid, rc);
620}
621
622static void tcp_listener_create_srv(tcp_client_t *client, ipc_callid_t iid,
623 ipc_call_t *icall)
624{
625 ipc_callid_t callid;
626 size_t size;
627 inet_ep_t ep;
628 sysarg_t lst_id;
629 int rc;
630
631 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_listener_create_srv()");
632
633 if (!async_data_write_receive(&callid, &size)) {
634 async_answer_0(callid, EREFUSED);
635 async_answer_0(iid, EREFUSED);
636 return;
637 }
638
639 if (size != sizeof(inet_ep_t)) {
640 async_answer_0(callid, EINVAL);
641 async_answer_0(iid, EINVAL);
642 return;
643 }
644
645 rc = async_data_write_finalize(callid, &ep, size);
646 if (rc != EOK) {
647 async_answer_0(callid, rc);
648 async_answer_0(iid, rc);
649 return;
650 }
651
652 rc = tcp_listener_create_impl(client, &ep, &lst_id);
653 if (rc != EOK) {
654 async_answer_0(iid, rc);
655 return;
656 }
657
658 async_answer_1(iid, EOK, lst_id);
659}
660
661static void tcp_listener_destroy_srv(tcp_client_t *client, ipc_callid_t iid,
662 ipc_call_t *icall)
663{
664 sysarg_t lst_id;
665 int rc;
666
667 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_listener_destroy_srv()");
668
669 lst_id = IPC_GET_ARG1(*icall);
670 rc = tcp_listener_destroy_impl(client, lst_id);
671 async_answer_0(iid, rc);
672}
673
674static void tcp_conn_send_fin_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_send_fin_srv()");
681
682 conn_id = IPC_GET_ARG1(*icall);
683 rc = tcp_conn_send_fin_impl(client, conn_id);
684 async_answer_0(iid, rc);
685}
686
687static void tcp_conn_push_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_push_srv()");
694
695 conn_id = IPC_GET_ARG1(*icall);
696 rc = tcp_conn_push_impl(client, conn_id);
697 async_answer_0(iid, rc);
698}
699
700static void tcp_conn_reset_srv(tcp_client_t *client, ipc_callid_t iid,
701 ipc_call_t *icall)
702{
703 sysarg_t conn_id;
704 int rc;
705
706 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_reset_srv()");
707
708 conn_id = IPC_GET_ARG1(*icall);
709 rc = tcp_conn_reset_impl(client, conn_id);
710 async_answer_0(iid, rc);
711}
712
713static void tcp_conn_send_srv(tcp_client_t *client, ipc_callid_t iid,
714 ipc_call_t *icall)
715{
716 ipc_callid_t callid;
717 size_t size;
718 sysarg_t conn_id;
719 void *data;
720 int rc;
721
722 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_send_srv())");
723
724 /* Receive message data */
725
726 if (!async_data_write_receive(&callid, &size)) {
727 async_answer_0(callid, EREFUSED);
728 async_answer_0(iid, EREFUSED);
729 return;
730 }
731
732 if (size > MAX_MSG_SIZE) {
733 async_answer_0(callid, EINVAL);
734 async_answer_0(iid, EINVAL);
735 return;
736 }
737
738 data = malloc(size);
739 if (data == NULL) {
740 async_answer_0(callid, ENOMEM);
741 async_answer_0(iid, ENOMEM);
742 }
743
744 rc = async_data_write_finalize(callid, data, size);
745 if (rc != EOK) {
746 async_answer_0(callid, rc);
747 async_answer_0(iid, rc);
748 free(data);
749 return;
750 }
751
752 conn_id = IPC_GET_ARG1(*icall);
753
754 rc = tcp_conn_send_impl(client, conn_id, data, size);
755 if (rc != EOK) {
756 async_answer_0(iid, rc);
757 free(data);
758 return;
759 }
760
761 async_answer_0(iid, EOK);
762 free(data);
763}
764
765static void tcp_conn_recv_srv(tcp_client_t *client, ipc_callid_t iid,
766 ipc_call_t *icall)
767{
768 ipc_callid_t callid;
769 sysarg_t conn_id;
770 size_t size, rsize;
771 void *data;
772 int rc;
773
774 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_srv()");
775
776 conn_id = IPC_GET_ARG1(*icall);
777
778 if (!async_data_read_receive(&callid, &size)) {
779 async_answer_0(callid, EREFUSED);
780 async_answer_0(iid, EREFUSED);
781 return;
782 }
783
784 size = max(size, 16384);
785 data = malloc(size);
786 if (data == NULL) {
787 async_answer_0(callid, ENOMEM);
788 async_answer_0(iid, ENOMEM);
789 return;
790 }
791
792 rc = tcp_conn_recv_impl(client, conn_id, data, size, &rsize);
793 if (rc != EOK) {
794 async_answer_0(callid, rc);
795 async_answer_0(iid, rc);
796 free(data);
797 return;
798 }
799
800 rc = async_data_read_finalize(callid, data, size);
801 if (rc != EOK) {
802 async_answer_0(iid, rc);
803 free(data);
804 return;
805 }
806
807 async_answer_1(iid, EOK, rsize);
808 free(data);
809
810 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_srv(): OK");
811}
812
813static void tcp_conn_recv_wait_srv(tcp_client_t *client, ipc_callid_t iid,
814 ipc_call_t *icall)
815{
816 ipc_callid_t callid;
817 sysarg_t conn_id;
818 size_t size, rsize;
819 void *data;
820 int rc;
821
822 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_wait_srv()");
823
824 conn_id = IPC_GET_ARG1(*icall);
825
826 if (!async_data_read_receive(&callid, &size)) {
827 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_wait_srv - data_receive failed");
828 async_answer_0(callid, EREFUSED);
829 async_answer_0(iid, EREFUSED);
830 return;
831 }
832
833 size = min(size, 16384);
834 data = malloc(size);
835 if (data == NULL) {
836 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_wait_srv - allocation failed");
837 async_answer_0(callid, ENOMEM);
838 async_answer_0(iid, ENOMEM);
839 return;
840 }
841
842 rc = tcp_conn_recv_impl(client, conn_id, data, size, &rsize);
843 if (rc != EOK) {
844 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_wait_srv - recv_impl failed rc=%d", rc);
845 async_answer_0(callid, rc);
846 async_answer_0(iid, rc);
847 free(data);
848 return;
849 }
850
851 rc = async_data_read_finalize(callid, data, size);
852 if (rc != EOK) {
853 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_wait_srv - finalize failed");
854 async_answer_0(iid, rc);
855 free(data);
856 return;
857 }
858
859 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_wait_srv(): rsize=%zu", size);
860 async_answer_1(iid, EOK, rsize);
861 free(data);
862
863 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_recv_wait_srv(): OK");
864}
865
866#include <mem.h>
867
868static void tcp_client_init(tcp_client_t *client)
869{
870 memset(client, 0, sizeof(tcp_client_t));
871 client->sess = NULL;
872 list_initialize(&client->cconn);
873 list_initialize(&client->clst);
874}
875
876static void tcp_client_fini(tcp_client_t *client)
877{
878 tcp_cconn_t *cconn;
879 size_t n;
880
881 n = list_count(&client->cconn);
882 if (n != 0) {
883 log_msg(LOG_DEFAULT, LVL_WARN, "Client with %zu active "
884 "connections closed session", n);
885
886 while (!list_empty(&client->cconn)) {
887 cconn = list_get_instance(list_first(&client->cconn),
888 tcp_cconn_t, lclient);
889 tcp_uc_close(cconn->conn);
890 tcp_cconn_destroy(cconn);
891 }
892 }
893
894 n = list_count(&client->clst);
895 if (n != 0) {
896 log_msg(LOG_DEFAULT, LVL_WARN, "Client with %zu active "
897 "listeners closed session", n);
898 /* XXX Destroy listeners */
899 }
900}
901
902static void tcp_client_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
903{
904 tcp_client_t client;
905
906 /* Accept the connection */
907 async_answer_0(iid, EOK);
908
909 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_client_conn() - client=%p",
910 &client);
911
912 tcp_client_init(&client);
913
914 while (true) {
915 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_client_conn: wait req");
916 ipc_call_t call;
917 ipc_callid_t callid = async_get_call(&call);
918 sysarg_t method = IPC_GET_IMETHOD(call);
919
920 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_client_conn: method=%d",
921 (int)method);
922 if (!method) {
923 /* The other side has hung up */
924 async_answer_0(callid, EOK);
925 break;
926 }
927
928 switch (method) {
929 case TCP_CALLBACK_CREATE:
930 tcp_callback_create_srv(&client, callid, &call);
931 break;
932 case TCP_CONN_CREATE:
933 tcp_conn_create_srv(&client, callid, &call);
934 break;
935 case TCP_CONN_DESTROY:
936 tcp_conn_destroy_srv(&client, callid, &call);
937 break;
938 case TCP_LISTENER_CREATE:
939 tcp_listener_create_srv(&client, callid, &call);
940 break;
941 case TCP_LISTENER_DESTROY:
942 tcp_listener_destroy_srv(&client, callid, &call);
943 break;
944 case TCP_CONN_SEND_FIN:
945 tcp_conn_send_fin_srv(&client, callid, &call);
946 break;
947 case TCP_CONN_PUSH:
948 tcp_conn_push_srv(&client, callid, &call);
949 break;
950 case TCP_CONN_RESET:
951 tcp_conn_reset_srv(&client, callid, &call);
952 break;
953 case TCP_CONN_SEND:
954 tcp_conn_send_srv(&client, callid, &call);
955 break;
956 case TCP_CONN_RECV:
957 tcp_conn_recv_srv(&client, callid, &call);
958 break;
959 case TCP_CONN_RECV_WAIT:
960 tcp_conn_recv_wait_srv(&client, callid, &call);
961 break;
962 default:
963 async_answer_0(callid, ENOTSUP);
964 break;
965 }
966 }
967
968 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_client_conn TERMINATED");
969 tcp_client_fini(&client);
970}
971
972int tcp_service_init(void)
973{
974 int rc;
975 service_id_t sid;
976
977 async_set_client_connection(tcp_client_conn);
978
979 rc = loc_server_register(NAME);
980 if (rc != EOK) {
981 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering server.");
982 return EIO;
983 }
984
985 rc = loc_service_register(SERVICE_NAME_TCP, &sid);
986 if (rc != EOK) {
987 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service.");
988 return EIO;
989 }
990
991 return EOK;
992}
993
994/**
995 * @}
996 */
Note: See TracBrowser for help on using the repository browser.