source: mainline/uspace/srv/net/tl/tcp/sock.c@ a4ee3ab2

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

Implement listen, accept, recvfrom.

  • Property mode set to 100644
File size: 15.7 KB
Line 
1/*
2 * Copyright (c) 2008 Lukas Mejdrech
3 * Copyright (c) 2011 Jiri Svoboda
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup tcp
31 * @{
32 */
33
34/**
35 * @file Socket provider
36 */
37
38#include <async.h>
39#include <errno.h>
40#include <io/log.h>
41#include <ipc/socket.h>
42#include <net/modules.h>
43#include <net/socket.h>
44
45#include "sock.h"
46#include "std.h"
47#include "tcp.h"
48#include "tcp_type.h"
49#include "ucall.h"
50
51#define FRAGMENT_SIZE 1024
52
53/** Free ports pool start. */
54#define TCP_FREE_PORTS_START 1025
55
56/** Free ports pool end. */
57#define TCP_FREE_PORTS_END 65535
58
59static int last_used_port = TCP_FREE_PORTS_START - 1;
60static socket_ports_t gsock;
61
62void tcp_sock_init(void)
63{
64 socket_ports_initialize(&gsock);
65}
66
67static void tcp_free_sock_data(socket_core_t *sock_core)
68{
69 tcp_sockdata_t *socket;
70
71 socket = (tcp_sockdata_t *)sock_core->specific_data;
72 (void)socket;
73}
74
75static void tcp_sock_notify_data(socket_core_t *sock_core)
76{
77 log_msg(LVL_DEBUG, "tcp_sock_notify_data(%d)", sock_core->socket_id);
78 async_exch_t *exch = async_exchange_begin(sock_core->sess);
79 async_msg_5(exch, NET_SOCKET_RECEIVED, (sysarg_t)sock_core->socket_id,
80 FRAGMENT_SIZE, 0, 0, 1);
81 async_exchange_end(exch);
82}
83
84static void tcp_sock_notify_aconn(socket_core_t *lsock_core)
85{
86 log_msg(LVL_DEBUG, "tcp_sock_notify_aconn(%d)", lsock_core->socket_id);
87 async_exch_t *exch = async_exchange_begin(lsock_core->sess);
88 async_msg_5(exch, NET_SOCKET_ACCEPTED, (sysarg_t)lsock_core->socket_id,
89 FRAGMENT_SIZE, 0, 0, 0);
90 async_exchange_end(exch);
91}
92
93static void tcp_sock_socket(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
94{
95 tcp_sockdata_t *sock;
96 int sock_id;
97 int rc;
98 ipc_call_t answer;
99
100 log_msg(LVL_DEBUG, "tcp_sock_socket()");
101 sock = calloc(sizeof(tcp_sockdata_t), 1);
102 if (sock == NULL) {
103 async_answer_0(callid, ENOMEM);
104 return;
105 }
106
107 sock->client = client;
108
109 sock_id = SOCKET_GET_SOCKET_ID(call);
110 rc = socket_create(&client->sockets, client->sess, sock, &sock_id);
111 if (rc != EOK) {
112 async_answer_0(callid, rc);
113 return;
114 }
115
116 refresh_answer(&answer, NULL);
117 SOCKET_SET_SOCKET_ID(answer, sock_id);
118
119 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
120 SOCKET_SET_HEADER_SIZE(answer, sizeof(tcp_header_t));
121 answer_call(callid, EOK, &answer, 3);
122}
123
124static void tcp_sock_bind(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
125{
126 int rc;
127 struct sockaddr *addr;
128 size_t addr_len;
129 socket_core_t *sock_core;
130 tcp_sockdata_t *socket;
131
132 log_msg(LVL_DEBUG, "tcp_sock_bind()");
133 log_msg(LVL_DEBUG, " - async_data_write_accept");
134 rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &addr_len);
135 if (rc != EOK) {
136 async_answer_0(callid, rc);
137 return;
138 }
139
140 log_msg(LVL_DEBUG, " - call socket_bind");
141 rc = socket_bind(&client->sockets, &gsock, SOCKET_GET_SOCKET_ID(call),
142 addr, addr_len, TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
143 last_used_port);
144 if (rc != EOK) {
145 async_answer_0(callid, rc);
146 return;
147 }
148
149 log_msg(LVL_DEBUG, " - call socket_cores_find");
150 sock_core = socket_cores_find(&client->sockets, SOCKET_GET_SOCKET_ID(call));
151 if (sock_core != NULL) {
152 socket = (tcp_sockdata_t *)sock_core->specific_data;
153 /* XXX Anything to do? */
154 (void) socket;
155 }
156
157 log_msg(LVL_DEBUG, " - success");
158 async_answer_0(callid, EOK);
159
160 /* Push one fragment notification to client's queue */
161 tcp_sock_notify_data(sock_core);
162}
163
164static void tcp_sock_listen(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
165{
166 int socket_id;
167 int backlog;
168 socket_core_t *sock_core;
169 tcp_sockdata_t *socket;
170
171 log_msg(LVL_DEBUG, "tcp_sock_listen()");
172
173 socket_id = SOCKET_GET_SOCKET_ID(call);
174 backlog = SOCKET_GET_BACKLOG(call);
175
176 if (backlog < 0) {
177 async_answer_0(callid, EINVAL);
178 return;
179 }
180
181 sock_core = socket_cores_find(&client->sockets, socket_id);
182 if (sock_core == NULL) {
183 async_answer_0(callid, ENOTSOCK);
184 return;
185 }
186
187 socket = (tcp_sockdata_t *)sock_core->specific_data;
188
189 /*
190 * XXX We do not do anything and defer action to accept().
191 * This is a slight difference in semantics, but most servers
192 * would just listen() and immediately accept() in a loop.
193 *
194 * The only difference is that there is a window between
195 * listen() and accept() or two accept()s where we refuse
196 * connections.
197 */
198 (void)backlog;
199 (void)socket;
200
201 async_answer_0(callid, EOK);
202 log_msg(LVL_DEBUG, "tcp_sock_listen(): notify data\n");
203 /* Push one accept notification to client's queue */
204 tcp_sock_notify_aconn(sock_core);
205}
206
207static void tcp_sock_connect(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
208{
209 int rc;
210 struct sockaddr_in *addr;
211 int socket_id;
212 size_t addr_len;
213 socket_core_t *sock_core;
214 tcp_sockdata_t *socket;
215 tcp_error_t trc;
216 tcp_sock_t fsocket;
217 uint16_t lport;
218
219 log_msg(LVL_DEBUG, "tcp_sock_connect()");
220
221 rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &addr_len);
222 if (rc != EOK || addr_len != sizeof(struct sockaddr_in)) {
223 async_answer_0(callid, rc);
224 return;
225 }
226
227 socket_id = SOCKET_GET_SOCKET_ID(call);
228
229 sock_core = socket_cores_find(&client->sockets, socket_id);
230 if (sock_core == NULL) {
231 async_answer_0(callid, ENOTSOCK);
232 return;
233 }
234
235 socket = (tcp_sockdata_t *)sock_core->specific_data;
236 if (sock_core->port <= 0) {
237 rc = socket_bind_free_port(&gsock, sock_core,
238 TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
239 last_used_port);
240 if (rc != EOK) {
241 async_answer_0(callid, rc);
242 return;
243 }
244
245 last_used_port = sock_core->port;
246 }
247
248 lport = sock_core->port;
249 fsocket.addr.ipv4 = uint32_t_be2host(addr->sin_addr.s_addr);
250 fsocket.port = uint16_t_be2host(addr->sin_port);
251
252 trc = tcp_uc_open(lport, &fsocket, ap_active, &socket->conn);
253
254 switch (trc) {
255 case TCP_EOK:
256 rc = EOK;
257 break;
258 case TCP_ERESET:
259 rc = ECONNREFUSED;
260 break;
261 default:
262 assert(false);
263 }
264
265 async_answer_0(callid, rc);
266}
267
268static void tcp_sock_accept(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
269{
270 ipc_call_t answer;
271 int socket_id;
272 int asock_id;
273 socket_core_t *sock_core;
274 socket_core_t *asock_core;
275 tcp_sockdata_t *socket;
276 tcp_sockdata_t *asocket;
277 tcp_error_t trc;
278 tcp_sock_t fsocket;
279 tcp_conn_t *conn;
280 int rc;
281
282 log_msg(LVL_DEBUG, "tcp_sock_accept()");
283
284 socket_id = SOCKET_GET_SOCKET_ID(call);
285 asock_id = SOCKET_GET_NEW_SOCKET_ID(call);
286
287 sock_core = socket_cores_find(&client->sockets, socket_id);
288 if (sock_core == NULL) {
289 async_answer_0(callid, ENOTSOCK);
290 return;
291 }
292
293 socket = (tcp_sockdata_t *)sock_core->specific_data;
294
295 log_msg(LVL_DEBUG, " - verify socket->conn");
296 if (socket->conn != NULL) {
297 async_answer_0(callid, EINVAL);
298 return;
299 }
300
301 log_msg(LVL_DEBUG, " - open connection");
302
303 fsocket.addr.ipv4 = 0x7f000001; /* XXX */
304 fsocket.port = 1025; /* XXX */
305
306 trc = tcp_uc_open(sock_core->port, &fsocket, ap_passive, &conn);
307
308 log_msg(LVL_DEBUG, " - decode TCP return code");
309
310 switch (trc) {
311 case TCP_EOK:
312 rc = EOK;
313 break;
314 case TCP_ERESET:
315 rc = ECONNABORTED;
316 break;
317 default:
318 assert(false);
319 }
320
321 log_msg(LVL_DEBUG, " - check TCP return code");
322 if (rc != EOK) {
323 async_answer_0(callid, rc);
324 return;
325 }
326
327 log_msg(LVL_DEBUG, "tcp_sock_accept(): allocate asocket\n");
328 asocket = calloc(sizeof(tcp_sockdata_t), 1);
329 if (asocket == NULL) {
330 async_answer_0(callid, ENOMEM);
331 return;
332 }
333
334 asocket->client = client;
335 asocket->conn = conn;
336 log_msg(LVL_DEBUG, "tcp_sock_accept():create asocket\n");
337
338 rc = socket_create(&client->sockets, client->sess, asocket, &asock_id);
339 if (rc != EOK) {
340 async_answer_0(callid, rc);
341 return;
342 }
343 log_msg(LVL_DEBUG, "tcp_sock_accept(): find acore\n");
344
345 asock_core = socket_cores_find(&client->sockets, asock_id);
346 assert(asock_core != NULL);
347
348 refresh_answer(&answer, NULL);
349
350 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
351 SOCKET_SET_SOCKET_ID(answer, asock_id);
352 SOCKET_SET_ADDRESS_LENGTH(answer, sizeof(struct sockaddr_in));
353
354 answer_call(callid, asock_core->socket_id, &answer, 3);
355
356 /* Push one accept notification to client's queue */
357 tcp_sock_notify_aconn(sock_core);
358
359 /* Push one fragment notification to client's queue */
360 tcp_sock_notify_data(asock_core);
361 log_msg(LVL_DEBUG, "tcp_sock_listen(): notify aconn\n");
362
363}
364
365static void tcp_sock_send(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
366{
367 int socket_id;
368 int fragments;
369 int index;
370 socket_core_t *sock_core;
371 tcp_sockdata_t *socket;
372 ipc_call_t answer;
373 ipc_callid_t wcallid;
374 size_t length;
375 uint8_t buffer[FRAGMENT_SIZE];
376 tcp_error_t trc;
377 int rc;
378
379 log_msg(LVL_DEBUG, "tcp_sock_send()");
380 socket_id = SOCKET_GET_SOCKET_ID(call);
381 fragments = SOCKET_GET_DATA_FRAGMENTS(call);
382 SOCKET_GET_FLAGS(call);
383
384 sock_core = socket_cores_find(&client->sockets, socket_id);
385 if (sock_core == NULL) {
386 async_answer_0(callid, ENOTSOCK);
387 return;
388 }
389
390 socket = (tcp_sockdata_t *)sock_core->specific_data;
391 if (socket->conn == NULL) {
392 async_answer_0(callid, ENOTCONN);
393 return;
394 }
395
396 for (index = 0; index < fragments; index++) {
397 if (!async_data_write_receive(&wcallid, &length)) {
398 async_answer_0(callid, EINVAL);
399 return;
400 }
401
402 if (length > FRAGMENT_SIZE)
403 length = FRAGMENT_SIZE;
404
405 rc = async_data_write_finalize(wcallid, buffer, length);
406 if (rc != EOK) {
407 async_answer_0(callid, rc);
408 return;
409 }
410
411 trc = tcp_uc_send(socket->conn, buffer, length, 0);
412
413 switch (trc) {
414 case TCP_EOK:
415 rc = EOK;
416 break;
417 case TCP_ENOTEXIST:
418 rc = ENOTCONN;
419 break;
420 case TCP_ECLOSING:
421 rc = ENOTCONN;
422 break;
423 default:
424 assert(false);
425 }
426
427 if (rc != EOK) {
428 async_answer_0(callid, rc);
429 return;
430 }
431 }
432
433 refresh_answer(&answer, NULL);
434 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
435 answer_call(callid, EOK, &answer, 2);
436}
437
438static void tcp_sock_sendto(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
439{
440 log_msg(LVL_DEBUG, "tcp_sock_sendto()");
441 async_answer_0(callid, ENOTSUP);
442}
443
444static void tcp_sock_recvfrom(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
445{
446 int socket_id;
447 int flags;
448 size_t addr_length, length;
449 socket_core_t *sock_core;
450 tcp_sockdata_t *socket;
451 ipc_call_t answer;
452 ipc_callid_t rcallid;
453 uint8_t buffer[FRAGMENT_SIZE];
454 size_t data_len;
455 xflags_t xflags;
456 tcp_error_t trc;
457 struct sockaddr_in addr;
458 tcp_sock_t *rsock;
459 int rc;
460
461 log_msg(LVL_DEBUG, "tcp_sock_recv[from]()");
462
463 socket_id = SOCKET_GET_SOCKET_ID(call);
464 flags = SOCKET_GET_FLAGS(call);
465
466 sock_core = socket_cores_find(&client->sockets, socket_id);
467 if (sock_core == NULL) {
468 async_answer_0(callid, ENOTSOCK);
469 return;
470 }
471
472 socket = (tcp_sockdata_t *)sock_core->specific_data;
473 if (socket->conn == NULL) {
474 async_answer_0(callid, ENOTCONN);
475 return;
476 }
477
478 (void)flags;
479
480 trc = tcp_uc_receive(socket->conn, buffer, FRAGMENT_SIZE, &data_len,
481 &xflags);
482 log_msg(LVL_DEBUG, "**** tcp_uc_receive done");
483
484 switch (trc) {
485 case TCP_EOK:
486 rc = EOK;
487 break;
488 case TCP_ENOTEXIST:
489 case TCP_ECLOSING:
490 rc = ENOTCONN;
491 break;
492 default:
493 assert(false);
494 }
495
496 log_msg(LVL_DEBUG, "**** tcp_uc_receive -> %d", rc);
497 if (rc != EOK) {
498 async_answer_0(callid, rc);
499 return;
500 }
501
502 if (IPC_GET_IMETHOD(call) == NET_SOCKET_RECVFROM) {
503 /* Fill addr */
504 rsock = &socket->conn->ident.foreign;
505 addr.sin_family = AF_INET;
506 addr.sin_addr.s_addr = host2uint32_t_be(rsock->addr.ipv4);
507 addr.sin_port = host2uint16_t_be(rsock->port);
508
509 log_msg(LVL_DEBUG, "addr read receive");
510 if (!async_data_read_receive(&rcallid, &addr_length)) {
511 async_answer_0(callid, EINVAL);
512 return;
513 }
514
515 if (addr_length > sizeof(addr))
516 addr_length = sizeof(addr);
517
518 log_msg(LVL_DEBUG, "addr read finalize");
519 rc = async_data_read_finalize(rcallid, &addr, addr_length);
520 if (rc != EOK) {
521 async_answer_0(callid, EINVAL);
522 return;
523 }
524 }
525
526 log_msg(LVL_DEBUG, "data read receive");
527 if (!async_data_read_receive(&rcallid, &length)) {
528 async_answer_0(callid, EINVAL);
529 return;
530 }
531
532 if (length > data_len)
533 length = data_len;
534
535 log_msg(LVL_DEBUG, "data read finalize");
536 rc = async_data_read_finalize(rcallid, buffer, length);
537
538 if (length < data_len && rc == EOK)
539 rc = EOVERFLOW;
540
541 SOCKET_SET_READ_DATA_LENGTH(answer, length);
542 answer_call(callid, EOK, &answer, 1);
543
544 /* Push one fragment notification to client's queue */
545 tcp_sock_notify_data(sock_core);
546}
547
548static void tcp_sock_close(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
549{
550 int socket_id;
551 socket_core_t *sock_core;
552 tcp_sockdata_t *socket;
553 int rc;
554
555 log_msg(LVL_DEBUG, "tcp_sock_close()");
556 socket_id = SOCKET_GET_SOCKET_ID(call);
557
558 sock_core = socket_cores_find(&client->sockets, socket_id);
559 if (sock_core == NULL) {
560 async_answer_0(callid, ENOTSOCK);
561 return;
562 }
563
564 socket = (tcp_sockdata_t *)sock_core->specific_data;
565 (void) socket;
566 /* XXX Close */
567
568 rc = socket_destroy(net_sess, socket_id, &client->sockets, &gsock,
569 tcp_free_sock_data);
570 if (rc != EOK) {
571 async_answer_0(callid, rc);
572 return;
573 }
574
575 async_answer_0(callid, EOK);
576}
577
578static void tcp_sock_getsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
579{
580 log_msg(LVL_DEBUG, "tcp_sock_getsockopt()");
581 async_answer_0(callid, ENOTSUP);
582}
583
584static void tcp_sock_setsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
585{
586 log_msg(LVL_DEBUG, "tcp_sock_setsockopt()");
587 async_answer_0(callid, ENOTSUP);
588}
589
590int tcp_sock_connection(async_sess_t *sess, ipc_callid_t iid, ipc_call_t icall)
591{
592 ipc_callid_t callid;
593 ipc_call_t call;
594 tcp_client_t client;
595
596 /* Accept the connection */
597 async_answer_0(iid, EOK);
598
599 client.sess = sess;
600 socket_cores_initialize(&client.sockets);
601
602 while (true) {
603 callid = async_get_call(&call);
604 if (!IPC_GET_IMETHOD(call))
605 break;
606
607 log_msg(LVL_DEBUG, "tcp_sock_connection: METHOD=%d\n",
608 (int)IPC_GET_IMETHOD(call));
609
610 switch (IPC_GET_IMETHOD(call)) {
611 case NET_SOCKET:
612 tcp_sock_socket(&client, callid, call);
613 break;
614 case NET_SOCKET_BIND:
615 tcp_sock_bind(&client, callid, call);
616 break;
617 case NET_SOCKET_LISTEN:
618 tcp_sock_listen(&client, callid, call);
619 break;
620 case NET_SOCKET_CONNECT:
621 tcp_sock_connect(&client, callid, call);
622 break;
623 case NET_SOCKET_ACCEPT:
624 tcp_sock_accept(&client, callid, call);
625 break;
626 case NET_SOCKET_SEND:
627 tcp_sock_send(&client, callid, call);
628 break;
629 case NET_SOCKET_SENDTO:
630 tcp_sock_sendto(&client, callid, call);
631 break;
632 case NET_SOCKET_RECV:
633 case NET_SOCKET_RECVFROM:
634 tcp_sock_recvfrom(&client, callid, call);
635 break;
636 case NET_SOCKET_CLOSE:
637 tcp_sock_close(&client, callid, call);
638 break;
639 case NET_SOCKET_GETSOCKOPT:
640 tcp_sock_getsockopt(&client, callid, call);
641 break;
642 case NET_SOCKET_SETSOCKOPT:
643 tcp_sock_setsockopt(&client, callid, call);
644 break;
645 default:
646 async_answer_0(callid, ENOTSUP);
647 break;
648 }
649 }
650
651 return EOK;
652}
653
654/**
655 * @}
656 */
Note: See TracBrowser for help on using the repository browser.