source: mainline/uspace/srv/net/tl/tcp/tcp.c@ 727f04f

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

Fix incoming TCP FIN handling. Signal end of data on the socket. Do not ACK if no new data arrived.

  • Property mode set to 100644
File size: 70.1 KB
Line 
1/*
2 * Copyright (c) 2008 Lukas Mejdrech
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 tcp
30 * @{
31 */
32
33/** @file
34 * TCP module implementation.
35 * @see tcp.h
36 */
37
38#include "tcp.h"
39#include "tcp_header.h"
40#include "tcp_module.h"
41
42#include <assert.h>
43#include <async.h>
44#include <fibril_synch.h>
45#include <malloc.h>
46/* TODO remove stdio */
47#include <stdio.h>
48#include <errno.h>
49
50#include <ipc/ipc.h>
51#include <ipc/services.h>
52#include <ipc/net.h>
53#include <ipc/tl.h>
54#include <ipc/socket.h>
55
56#include <net/socket_codes.h>
57#include <net/ip_protocols.h>
58#include <net/in.h>
59#include <net/in6.h>
60#include <net/inet.h>
61#include <net/modules.h>
62
63#include <adt/dynamic_fifo.h>
64#include <packet_client.h>
65#include <packet_remote.h>
66#include <net_checksum.h>
67#include <ip_client.h>
68#include <ip_interface.h>
69#include <icmp_client.h>
70#include <icmp_interface.h>
71#include <net_interface.h>
72#include <socket_core.h>
73#include <tl_common.h>
74#include <tl_local.h>
75#include <tl_interface.h>
76
77/** TCP module name. */
78#define NAME "TCP protocol"
79
80/** The TCP window default value. */
81#define NET_DEFAULT_TCP_WINDOW 10240
82
83/** Initial timeout for new connections. */
84#define NET_DEFAULT_TCP_INITIAL_TIMEOUT 3000000L
85
86/** Default timeout for closing. */
87#define NET_DEFAULT_TCP_TIME_WAIT_TIMEOUT 2000L
88
89/** The initial outgoing sequence number. */
90#define TCP_INITIAL_SEQUENCE_NUMBER 2999
91
92/** Maximum TCP fragment size. */
93#define MAX_TCP_FRAGMENT_SIZE 65535
94
95/** Free ports pool start. */
96#define TCP_FREE_PORTS_START 1025
97
98/** Free ports pool end. */
99#define TCP_FREE_PORTS_END 65535
100
101/** Timeout for connection initialization, SYN sent. */
102#define TCP_SYN_SENT_TIMEOUT 1000000L
103
104/** The maximum number of timeouts in a row before singaling connection lost. */
105#define TCP_MAX_TIMEOUTS 8
106
107/** The number of acknowledgements before retransmit. */
108#define TCP_FAST_RETRANSMIT_COUNT 3
109
110/** Returns a value indicating whether the value is in the interval respecting
111 * the possible overflow.
112 *
113 * The high end and/or the value may overflow, be lower than the low value.
114 *
115 * @param[in] lower The last value before the interval.
116 * @param[in] value The value to be checked.
117 * @param[in] higher_equal The last value in the interval.
118 */
119#define IS_IN_INTERVAL_OVERFLOW(lower, value, higher_equal) \
120 ((((lower) < (value)) && (((value) <= (higher_equal)) || \
121 ((higher_equal) < (lower)))) || (((value) <= (higher_equal)) && \
122 ((higher_equal) < (lower))))
123
124/** Type definition of the TCP timeout.
125 * @see tcp_timeout
126 */
127typedef struct tcp_timeout tcp_timeout_t;
128
129/** TCP reply timeout data.
130 * Used as a timeouting fibril argument.
131 * @see tcp_timeout()
132 */
133struct tcp_timeout {
134 /** TCP global data are going to be read only. */
135 int globals_read_only;
136
137 /** Socket port. */
138 int port;
139
140 /** Local sockets. */
141 socket_cores_t *local_sockets;
142
143 /** Socket identifier. */
144 int socket_id;
145
146 /** Socket state. */
147 tcp_socket_state_t state;
148
149 /** Sent packet sequence number. */
150 int sequence_number;
151
152 /** Timeout in microseconds. */
153 suseconds_t timeout;
154
155 /** Port map key. */
156 char *key;
157
158 /** Port map key length. */
159 size_t key_length;
160};
161
162static int tcp_release_and_return(packet_t *, int);
163static void tcp_prepare_operation_header(socket_core_t *, tcp_socket_data_t *,
164 tcp_header_t *, int synchronize, int);
165static int tcp_prepare_timeout(int (*)(void *), socket_core_t *,
166 tcp_socket_data_t *, size_t, tcp_socket_state_t, suseconds_t, int);
167static void tcp_free_socket_data(socket_core_t *);
168
169static int tcp_timeout(void *);
170
171static int tcp_release_after_timeout(void *);
172
173static int tcp_process_packet(device_id_t, packet_t *, services_t);
174static int tcp_connect_core(socket_core_t *, socket_cores_t *,
175 struct sockaddr *, socklen_t);
176static int tcp_queue_prepare_packet(socket_core_t *, tcp_socket_data_t *,
177 packet_t *, size_t);
178static int tcp_queue_packet(socket_core_t *, tcp_socket_data_t *, packet_t *,
179 size_t);
180static packet_t *tcp_get_packets_to_send(socket_core_t *, tcp_socket_data_t *);
181static void tcp_send_packets(device_id_t, packet_t *);
182
183static void tcp_process_acknowledgement(socket_core_t *, tcp_socket_data_t *,
184 tcp_header_t *);
185static packet_t *tcp_send_prepare_packet(socket_core_t *, tcp_socket_data_t *,
186 packet_t *, size_t, size_t);
187static packet_t *tcp_prepare_copy(socket_core_t *, tcp_socket_data_t *,
188 packet_t *, size_t, size_t);
189/* static */ void tcp_retransmit_packet(socket_core_t *, tcp_socket_data_t *,
190 size_t);
191static int tcp_create_notification_packet(packet_t **, socket_core_t *,
192 tcp_socket_data_t *, int, int);
193static void tcp_refresh_socket_data(tcp_socket_data_t *);
194
195static void tcp_initialize_socket_data(tcp_socket_data_t *);
196
197static int tcp_process_listen(socket_core_t *, tcp_socket_data_t *,
198 tcp_header_t *, packet_t *, struct sockaddr *, struct sockaddr *, size_t);
199static int tcp_process_syn_sent(socket_core_t *, tcp_socket_data_t *,
200 tcp_header_t *, packet_t *);
201static int tcp_process_syn_received(socket_core_t *, tcp_socket_data_t *,
202 tcp_header_t *, packet_t *);
203static int tcp_process_established(socket_core_t *, tcp_socket_data_t *,
204 tcp_header_t *, packet_t *, int, size_t);
205static int tcp_queue_received_packet(socket_core_t *, tcp_socket_data_t *,
206 packet_t *, int, size_t);
207static void tcp_queue_received_end_of_data(socket_core_t *socket);
208
209static int tcp_received_msg(device_id_t, packet_t *, services_t, services_t);
210static int tcp_process_client_messages(ipc_callid_t, ipc_call_t);
211
212static int tcp_listen_message(socket_cores_t *, int, int);
213static int tcp_connect_message(socket_cores_t *, int, struct sockaddr *,
214 socklen_t);
215static int tcp_recvfrom_message(socket_cores_t *, int, int, size_t *);
216static int tcp_send_message(socket_cores_t *, int, int, size_t *, int);
217static int tcp_accept_message(socket_cores_t *, int, int, size_t *, size_t *);
218static int tcp_close_message(socket_cores_t *, int);
219
220/** TCP global data. */
221tcp_globals_t tcp_globals;
222
223/** Initializes the TCP module.
224 *
225 * @param[in] client_connection The client connection processing function. The
226 * module skeleton propagates its own one.
227 * @return EOK on success.
228 * @return ENOMEM if there is not enough memory left.
229 */
230int tcp_initialize(async_client_conn_t client_connection)
231{
232 int rc;
233
234 assert(client_connection);
235
236 fibril_rwlock_initialize(&tcp_globals.lock);
237 fibril_rwlock_write_lock(&tcp_globals.lock);
238
239 tcp_globals.icmp_phone = icmp_connect_module(SERVICE_ICMP,
240 ICMP_CONNECT_TIMEOUT);
241 tcp_globals.ip_phone = ip_bind_service(SERVICE_IP, IPPROTO_TCP,
242 SERVICE_TCP, client_connection);
243 if (tcp_globals.ip_phone < 0) {
244 fibril_rwlock_write_unlock(&tcp_globals.lock);
245 return tcp_globals.ip_phone;
246 }
247
248 rc = socket_ports_initialize(&tcp_globals.sockets);
249 if (rc != EOK)
250 goto out;
251
252 rc = packet_dimensions_initialize(&tcp_globals.dimensions);
253 if (rc != EOK) {
254 socket_ports_destroy(&tcp_globals.sockets);
255 goto out;
256 }
257
258 tcp_globals.last_used_port = TCP_FREE_PORTS_START - 1;
259
260out:
261 fibril_rwlock_write_unlock(&tcp_globals.lock);
262 return rc;
263}
264
265int tcp_received_msg(device_id_t device_id, packet_t *packet,
266 services_t receiver, services_t error)
267{
268 int rc;
269
270 if (receiver != SERVICE_TCP)
271 return EREFUSED;
272
273 fibril_rwlock_write_lock(&tcp_globals.lock);
274 rc = tcp_process_packet(device_id, packet, error);
275 if (rc != EOK)
276 fibril_rwlock_write_unlock(&tcp_globals.lock);
277
278 printf("receive %d \n", rc);
279
280 return rc;
281}
282
283int tcp_process_packet(device_id_t device_id, packet_t *packet, services_t error)
284{
285 size_t length;
286 size_t offset;
287 int result;
288 tcp_header_t *header;
289 socket_core_t *socket;
290 tcp_socket_data_t *socket_data;
291 packet_t *next_packet;
292 size_t total_length;
293 uint32_t checksum;
294 int fragments;
295 icmp_type_t type;
296 icmp_code_t code;
297 struct sockaddr *src;
298 struct sockaddr *dest;
299 size_t addrlen;
300 int rc;
301
302 switch (error) {
303 case SERVICE_NONE:
304 break;
305 case SERVICE_ICMP:
306 /* Process error */
307 result = icmp_client_process_packet(packet, &type, &code, NULL,
308 NULL);
309 if (result < 0)
310 return tcp_release_and_return(packet, result);
311
312 length = (size_t) result;
313 rc = packet_trim(packet, length, 0);
314 if (rc != EOK)
315 return tcp_release_and_return(packet, rc);
316 break;
317 default:
318 return tcp_release_and_return(packet, ENOTSUP);
319 }
320
321 /* TODO process received ipopts? */
322 result = ip_client_process_packet(packet, NULL, NULL, NULL, NULL, NULL);
323 if (result < 0)
324 return tcp_release_and_return(packet, result);
325
326 offset = (size_t) result;
327
328 length = packet_get_data_length(packet);
329 if (length <= 0)
330 return tcp_release_and_return(packet, EINVAL);
331
332 if (length < TCP_HEADER_SIZE + offset)
333 return tcp_release_and_return(packet, NO_DATA);
334
335 /* Trim all but TCP header */
336 rc = packet_trim(packet, offset, 0);
337 if (rc != EOK)
338 return tcp_release_and_return(packet, rc);
339
340 /* Get tcp header */
341 header = (tcp_header_t *) packet_get_data(packet);
342 if (!header)
343 return tcp_release_and_return(packet, NO_DATA);
344
345// printf("header len %d, port %d \n", TCP_HEADER_LENGTH(header),
346// ntohs(header->destination_port));
347
348 result = packet_get_addr(packet, (uint8_t **) &src, (uint8_t **) &dest);
349 if (result <= 0)
350 return tcp_release_and_return(packet, result);
351
352 addrlen = (size_t) result;
353
354 rc = tl_set_address_port(src, addrlen, ntohs(header->source_port));
355 if (rc != EOK)
356 return tcp_release_and_return(packet, rc);
357
358 /* Find the destination socket */
359 socket = socket_port_find(&tcp_globals.sockets,
360 ntohs(header->destination_port), (const char *) src, addrlen);
361 if (!socket) {
362 /* Find the listening destination socket */
363 socket = socket_port_find(&tcp_globals.sockets,
364 ntohs(header->destination_port), SOCKET_MAP_KEY_LISTENING,
365 0);
366 }
367
368 if (!socket) {
369 if (tl_prepare_icmp_packet(tcp_globals.net_phone,
370 tcp_globals.icmp_phone, packet, error) == EOK) {
371 icmp_destination_unreachable_msg(tcp_globals.icmp_phone,
372 ICMP_PORT_UNREACH, 0, packet);
373 }
374 return EADDRNOTAVAIL;
375 }
376
377 printf("socket id %d\n", socket->socket_id);
378 socket_data = (tcp_socket_data_t *) socket->specific_data;
379 assert(socket_data);
380
381 /* Some data received, clear the timeout counter */
382 socket_data->timeout_count = 0;
383
384 /* Count the received packet fragments */
385 next_packet = packet;
386 fragments = 0;
387 checksum = 0;
388 total_length = 0;
389 do {
390 fragments++;
391 length = packet_get_data_length(next_packet);
392 if (length <= 0)
393 return tcp_release_and_return(packet, NO_DATA);
394
395 total_length += length;
396
397 /* Add partial checksum if set */
398 if (!error) {
399 checksum = compute_checksum(checksum,
400 packet_get_data(packet),
401 packet_get_data_length(packet));
402 }
403
404 } while ((next_packet = pq_next(next_packet)));
405
406 fibril_rwlock_write_lock(socket_data->local_lock);
407
408 if (error)
409 goto has_error_service;
410
411 if (socket_data->state == TCP_SOCKET_LISTEN) {
412 if (socket_data->pseudo_header) {
413 free(socket_data->pseudo_header);
414 socket_data->pseudo_header = NULL;
415 socket_data->headerlen = 0;
416 }
417
418 rc = ip_client_get_pseudo_header(IPPROTO_TCP, src, addrlen,
419 dest, addrlen, total_length, &socket_data->pseudo_header,
420 &socket_data->headerlen);
421 if (rc != EOK) {
422 fibril_rwlock_write_unlock(socket_data->local_lock);
423 return tcp_release_and_return(packet, rc);
424 }
425 } else {
426 rc = ip_client_set_pseudo_header_data_length(
427 socket_data->pseudo_header, socket_data->headerlen,
428 total_length);
429 if (rc != EOK) {
430 fibril_rwlock_write_unlock(socket_data->local_lock);
431 return tcp_release_and_return(packet, rc);
432 }
433 }
434
435 checksum = compute_checksum(checksum, socket_data->pseudo_header,
436 socket_data->headerlen);
437 if (flip_checksum(compact_checksum(checksum)) != IP_CHECKSUM_ZERO) {
438 printf("checksum err %x -> %x\n", header->checksum,
439 flip_checksum(compact_checksum(checksum)));
440 fibril_rwlock_write_unlock(socket_data->local_lock);
441
442 rc = tl_prepare_icmp_packet(tcp_globals.net_phone,
443 tcp_globals.icmp_phone, packet, error);
444 if (rc == EOK) {
445 /* Checksum error ICMP */
446 icmp_parameter_problem_msg(tcp_globals.icmp_phone,
447 ICMP_PARAM_POINTER,
448 ((size_t) ((void *) &header->checksum)) -
449 ((size_t) ((void *) header)), packet);
450 }
451
452 return EINVAL;
453 }
454
455has_error_service:
456 fibril_rwlock_write_unlock(&tcp_globals.lock);
457
458 /* TODO error reporting/handling */
459 switch (socket_data->state) {
460 case TCP_SOCKET_LISTEN:
461 rc = tcp_process_listen(socket, socket_data, header, packet,
462 src, dest, addrlen);
463 break;
464 case TCP_SOCKET_SYN_RECEIVED:
465 rc = tcp_process_syn_received(socket, socket_data, header,
466 packet);
467 break;
468 case TCP_SOCKET_SYN_SENT:
469 rc = tcp_process_syn_sent(socket, socket_data, header, packet);
470 break;
471 case TCP_SOCKET_FIN_WAIT_1:
472 /* ack changing the state to FIN_WAIT_2 gets processed later */
473 case TCP_SOCKET_FIN_WAIT_2:
474 /* fin changing state to LAST_ACK gets processed later */
475 case TCP_SOCKET_LAST_ACK:
476 /* ack releasing the socket get processed later */
477 case TCP_SOCKET_CLOSING:
478 /* ack releasing the socket gets processed later */
479 case TCP_SOCKET_ESTABLISHED:
480 rc = tcp_process_established(socket, socket_data, header,
481 packet, fragments, total_length);
482 break;
483 default:
484 pq_release_remote(tcp_globals.net_phone, packet_get_id(packet));
485 }
486
487 if (rc != EOK) {
488 fibril_rwlock_write_unlock(socket_data->local_lock);
489 printf("process %d\n", rc);
490 }
491
492 return EOK;
493}
494
495int tcp_process_established(socket_core_t *socket, tcp_socket_data_t *
496 socket_data, tcp_header_t *header, packet_t *packet, int fragments,
497 size_t total_length)
498{
499 packet_t *next_packet;
500 packet_t *tmp_packet;
501 uint32_t old_incoming;
502 size_t order;
503 uint32_t sequence_number;
504 size_t length;
505 size_t offset;
506 uint32_t new_sequence_number;
507 bool forced_ack;
508 int rc;
509
510 assert(socket);
511 assert(socket_data);
512 assert(socket->specific_data == socket_data);
513 assert(header);
514 assert(packet);
515
516 forced_ack = false;
517
518 new_sequence_number = ntohl(header->sequence_number);
519 old_incoming = socket_data->next_incoming;
520
521 if (header->finalize) {
522 socket_data->fin_incoming = new_sequence_number +
523 total_length - TCP_HEADER_LENGTH(header);
524 }
525
526 /* Trim begining if containing expected data */
527 if (IS_IN_INTERVAL_OVERFLOW(new_sequence_number,
528 socket_data->next_incoming, new_sequence_number + total_length)) {
529
530 /* Get the acknowledged offset */
531 if (socket_data->next_incoming < new_sequence_number) {
532 offset = new_sequence_number -
533 socket_data->next_incoming;
534 } else {
535 offset = socket_data->next_incoming -
536 new_sequence_number;
537 }
538
539 new_sequence_number += offset;
540 total_length -= offset;
541 length = packet_get_data_length(packet);
542
543 /* Trim the acknowledged data */
544 while (length <= offset) {
545 /* Release the acknowledged packets */
546 next_packet = pq_next(packet);
547 pq_release_remote(tcp_globals.net_phone,
548 packet_get_id(packet));
549 packet = next_packet;
550 offset -= length;
551 length = packet_get_data_length(packet);
552 }
553
554 if (offset > 0) {
555 rc = packet_trim(packet, offset, 0);
556 if (rc != EOK)
557 return tcp_release_and_return(packet, rc);
558 }
559
560 assert(new_sequence_number == socket_data->next_incoming);
561 }
562
563 /* Release if overflowing the window */
564/*
565 if (IS_IN_INTERVAL_OVERFLOW(socket_data->next_incoming +
566 socket_data->window, new_sequence_number, new_sequence_number +
567 total_length)) {
568 return tcp_release_and_return(packet, EOVERFLOW);
569 }
570
571 // trim end if overflowing the window
572 if (IS_IN_INTERVAL_OVERFLOW(new_sequence_number,
573 socket_data->next_incoming + socket_data->window,
574 new_sequence_number + total_length)) {
575 // get the allowed data length
576 if (socket_data->next_incoming + socket_data->window <
577 new_sequence_number) {
578 offset = new_sequence_number -
579 socket_data->next_incoming + socket_data->window;
580 } else {
581 offset = socket_data->next_incoming +
582 socket_data->window - new_sequence_number;
583 }
584 next_packet = packet;
585 // trim the overflowing data
586 while (next_packet && (offset > 0)) {
587 length = packet_get_data_length(packet);
588 if (length <= offset)
589 next_packet = pq_next(next_packet);
590 else {
591 rc = packet_trim(next_packet, 0,
592 length - offset));
593 if (rc != EOK)
594 return tcp_release_and_return(packet,
595 rc);
596 }
597 offset -= length;
598 total_length -= length - offset;
599 }
600 // release the overflowing packets
601 next_packet = pq_next(next_packet);
602 if (next_packet) {
603 tmp_packet = next_packet;
604 next_packet = pq_next(next_packet);
605 pq_insert_after(tmp_packet, next_packet);
606 pq_release_remote(tcp_globals.net_phone,
607 packet_get_id(tmp_packet));
608 }
609 assert(new_sequence_number + total_length ==
610 socket_data->next_incoming + socket_data->window);
611 }
612*/
613 /* The expected one arrived? */
614 if (new_sequence_number == socket_data->next_incoming) {
615 printf("expected\n");
616 /* Process acknowledgement */
617 tcp_process_acknowledgement(socket, socket_data, header);
618
619 /* Remove the header */
620 total_length -= TCP_HEADER_LENGTH(header);
621 rc = packet_trim(packet, TCP_HEADER_LENGTH(header), 0);
622 if (rc != EOK)
623 return tcp_release_and_return(packet, rc);
624
625 if (total_length) {
626 rc = tcp_queue_received_packet(socket, socket_data,
627 packet, fragments, total_length);
628 if (rc != EOK)
629 return rc;
630 } else {
631 total_length = 1;
632 }
633
634 socket_data->next_incoming = old_incoming + total_length;
635 packet = socket_data->incoming;
636 while (packet) {
637 rc = pq_get_order(socket_data->incoming, &order, NULL);
638 if (rc != EOK) {
639 /* Remove the corrupted packet */
640 next_packet = pq_detach(packet);
641 if (packet == socket_data->incoming)
642 socket_data->incoming = next_packet;
643 pq_release_remote(tcp_globals.net_phone,
644 packet_get_id(packet));
645 packet = next_packet;
646 continue;
647 }
648
649 sequence_number = (uint32_t) order;
650 if (IS_IN_INTERVAL_OVERFLOW(sequence_number,
651 old_incoming, socket_data->next_incoming)) {
652 /* Move to the next */
653 packet = pq_next(packet);
654 /* Coninual data? */
655 } else if (IS_IN_INTERVAL_OVERFLOW(old_incoming,
656 sequence_number, socket_data->next_incoming)) {
657 /* Detach the packet */
658 next_packet = pq_detach(packet);
659 if (packet == socket_data->incoming)
660 socket_data->incoming = next_packet;
661 /* Get data length */
662 length = packet_get_data_length(packet);
663 new_sequence_number = sequence_number + length;
664 if (length <= 0) {
665 /* Remove the empty packet */
666 pq_release_remote(tcp_globals.net_phone,
667 packet_get_id(packet));
668 packet = next_packet;
669 continue;
670 }
671 /* Exactly following */
672 if (sequence_number ==
673 socket_data->next_incoming) {
674 /* Queue received data */
675 rc = tcp_queue_received_packet(socket,
676 socket_data, packet, 1,
677 packet_get_data_length(packet));
678 if (rc != EOK)
679 return rc;
680 socket_data->next_incoming =
681 new_sequence_number;
682 packet = next_packet;
683 continue;
684 /* At least partly following data? */
685 }
686 if (IS_IN_INTERVAL_OVERFLOW(sequence_number,
687 socket_data->next_incoming, new_sequence_number)) {
688 if (socket_data->next_incoming <
689 new_sequence_number) {
690 length = new_sequence_number -
691 socket_data->next_incoming;
692 } else {
693 length =
694 socket_data->next_incoming -
695 new_sequence_number;
696 }
697 rc = packet_trim(packet,length, 0);
698 if (rc == EOK) {
699 /* Queue received data */
700 rc = tcp_queue_received_packet(
701 socket, socket_data, packet,
702 1, packet_get_data_length(
703 packet));
704 if (rc != EOK)
705 return rc;
706 socket_data->next_incoming =
707 new_sequence_number;
708 packet = next_packet;
709 continue;
710 }
711 }
712 /* Remove the duplicit or corrupted packet */
713 pq_release_remote(tcp_globals.net_phone,
714 packet_get_id(packet));
715 packet = next_packet;
716 continue;
717 } else {
718 break;
719 }
720 }
721 } else if (IS_IN_INTERVAL(socket_data->next_incoming,
722 new_sequence_number,
723 socket_data->next_incoming + socket_data->window)) {
724 printf("in window\n");
725 /* Process acknowledgement */
726 tcp_process_acknowledgement(socket, socket_data, header);
727
728 /* Remove the header */
729 total_length -= TCP_HEADER_LENGTH(header);
730 rc = packet_trim(packet, TCP_HEADER_LENGTH(header), 0);
731 if (rc != EOK)
732 return tcp_release_and_return(packet, rc);
733
734 next_packet = pq_detach(packet);
735 length = packet_get_data_length(packet);
736 rc = pq_add(&socket_data->incoming, packet, new_sequence_number,
737 length);
738 if (rc != EOK) {
739 /* Remove the corrupted packets */
740 pq_release_remote(tcp_globals.net_phone,
741 packet_get_id(packet));
742 pq_release_remote(tcp_globals.net_phone,
743 packet_get_id(next_packet));
744 } else {
745 while (next_packet) {
746 new_sequence_number += length;
747 tmp_packet = pq_detach(next_packet);
748 length = packet_get_data_length(next_packet);
749
750 rc = pq_set_order(next_packet,
751 new_sequence_number, length);
752 if (rc != EOK) {
753 pq_release_remote(tcp_globals.net_phone,
754 packet_get_id(next_packet));
755 }
756 rc = pq_insert_after(packet, next_packet);
757 if (rc != EOK) {
758 pq_release_remote(tcp_globals.net_phone,
759 packet_get_id(next_packet));
760 }
761 next_packet = tmp_packet;
762 }
763 }
764 } else {
765 printf("unexpected\n");
766 /* Release duplicite or restricted */
767 pq_release_remote(tcp_globals.net_phone, packet_get_id(packet));
768 forced_ack = true;
769 }
770
771 if (header->finalize)
772 socket_data->next_incoming += 1;
773
774 /* If next in sequence is an incoming FIN */
775 if (socket_data->next_incoming == socket_data->fin_incoming) {
776 /* Advance sequence number */
777 socket_data->next_incoming += 1;
778
779 /* Handle FIN */
780 switch (socket_data->state) {
781 case TCP_SOCKET_FIN_WAIT_1:
782 case TCP_SOCKET_FIN_WAIT_2:
783 case TCP_SOCKET_CLOSING:
784 socket_data->state = TCP_SOCKET_CLOSING;
785 break;
786 case TCP_SOCKET_ESTABLISHED:
787 /* Queue end-of-data marker on the socket. */
788 tcp_queue_received_end_of_data(socket);
789 socket_data->state = TCP_SOCKET_CLOSE_WAIT;
790 break;
791 default:
792 socket_data->state = TCP_SOCKET_CLOSE_WAIT;
793 break;
794 }
795 }
796
797 packet = tcp_get_packets_to_send(socket, socket_data);
798 if (!packet && (socket_data->next_incoming != old_incoming || forced_ack)) {
799 /* Create the notification packet */
800 rc = tcp_create_notification_packet(&packet, socket,
801 socket_data, 0, 0);
802 if (rc != EOK)
803 return rc;
804 rc = tcp_queue_prepare_packet(socket, socket_data, packet, 1);
805 if (rc != EOK)
806 return rc;
807 packet = tcp_send_prepare_packet(socket, socket_data, packet, 1,
808 socket_data->last_outgoing + 1);
809 }
810
811 fibril_rwlock_write_unlock(socket_data->local_lock);
812
813 /* Send the packet */
814 tcp_send_packets(socket_data->device_id, packet);
815
816 return EOK;
817}
818
819int tcp_queue_received_packet(socket_core_t *socket,
820 tcp_socket_data_t *socket_data, packet_t *packet, int fragments,
821 size_t total_length)
822{
823 packet_dimension_t *packet_dimension;
824 int rc;
825
826 assert(socket);
827 assert(socket_data);
828 assert(socket->specific_data == socket_data);
829 assert(packet);
830 assert(fragments >= 1);
831 assert(socket_data->window > total_length);
832
833 /* Queue the received packet */
834 rc = dyn_fifo_push(&socket->received, packet_get_id(packet),
835 SOCKET_MAX_RECEIVED_SIZE);
836 if (rc != EOK)
837 return tcp_release_and_return(packet, rc);
838 rc = tl_get_ip_packet_dimension(tcp_globals.ip_phone,
839 &tcp_globals.dimensions, socket_data->device_id, &packet_dimension);
840 if (rc != EOK)
841 return tcp_release_and_return(packet, rc);
842
843 /* Decrease the window size */
844 socket_data->window -= total_length;
845
846 /* Notify the destination socket */
847 async_msg_5(socket->phone, NET_SOCKET_RECEIVED,
848 (sysarg_t) socket->socket_id,
849 ((packet_dimension->content < socket_data->data_fragment_size) ?
850 packet_dimension->content : socket_data->data_fragment_size), 0, 0,
851 (sysarg_t) fragments);
852
853 return EOK;
854}
855
856/** Queue end-of-data marker on the socket.
857 *
858 * Next element in the sequence space is FIN. Queue end-of-data marker
859 * on the socket.
860 *
861 * @param socket Socket
862 */
863static void tcp_queue_received_end_of_data(socket_core_t *socket)
864{
865 assert(socket != NULL);
866
867 /* Notify the destination socket */
868 async_msg_5(socket->phone, NET_SOCKET_RECEIVED,
869 (sysarg_t) socket->socket_id,
870 0, 0, 0,
871 (sysarg_t) 0 /* 0 fragments == no more data */);
872}
873
874int tcp_process_syn_sent(socket_core_t *socket, tcp_socket_data_t *
875 socket_data, tcp_header_t *header, packet_t *packet)
876{
877 packet_t *next_packet;
878 int rc;
879
880 assert(socket);
881 assert(socket_data);
882 assert(socket->specific_data == socket_data);
883 assert(header);
884 assert(packet);
885
886 if (!header->synchronize)
887 return tcp_release_and_return(packet, EINVAL);
888
889 /* Process acknowledgement */
890 tcp_process_acknowledgement(socket, socket_data, header);
891
892 socket_data->next_incoming = ntohl(header->sequence_number) + 1;
893
894 /* Release additional packets */
895 next_packet = pq_detach(packet);
896 if (next_packet) {
897 pq_release_remote(tcp_globals.net_phone,
898 packet_get_id(next_packet));
899 }
900
901 /* Trim if longer than the header */
902 if (packet_get_data_length(packet) > sizeof(*header)) {
903 rc = packet_trim(packet, 0,
904 packet_get_data_length(packet) - sizeof(*header));
905 if (rc != EOK)
906 return tcp_release_and_return(packet, rc);
907 }
908
909 tcp_prepare_operation_header(socket, socket_data, header, 0, 0);
910 fibril_mutex_lock(&socket_data->operation.mutex);
911 socket_data->operation.result = tcp_queue_packet(socket, socket_data,
912 packet, 1);
913
914 if (socket_data->operation.result == EOK) {
915 socket_data->state = TCP_SOCKET_ESTABLISHED;
916 packet = tcp_get_packets_to_send(socket, socket_data);
917 if (packet) {
918 fibril_rwlock_write_unlock( socket_data->local_lock);
919 /* Send the packet */
920 tcp_send_packets(socket_data->device_id, packet);
921 /* Signal the result */
922 fibril_condvar_signal( &socket_data->operation.condvar);
923 fibril_mutex_unlock( &socket_data->operation.mutex);
924 return EOK;
925 }
926 }
927
928 fibril_mutex_unlock(&socket_data->operation.mutex);
929 return tcp_release_and_return(packet, EINVAL);
930}
931
932int tcp_process_listen(socket_core_t *listening_socket,
933 tcp_socket_data_t *listening_socket_data, tcp_header_t *header,
934 packet_t *packet, struct sockaddr *src, struct sockaddr *dest,
935 size_t addrlen)
936{
937 packet_t *next_packet;
938 socket_core_t *socket;
939 tcp_socket_data_t *socket_data;
940 int socket_id;
941 int listening_socket_id = listening_socket->socket_id;
942 int listening_port = listening_socket->port;
943 int rc;
944
945 assert(listening_socket);
946 assert(listening_socket_data);
947 assert(listening_socket->specific_data == listening_socket_data);
948 assert(header);
949 assert(packet);
950
951 if (!header->synchronize)
952 return tcp_release_and_return(packet, EINVAL);
953
954 socket_data = (tcp_socket_data_t *) malloc(sizeof(*socket_data));
955 if (!socket_data)
956 return tcp_release_and_return(packet, ENOMEM);
957
958 tcp_initialize_socket_data(socket_data);
959 socket_data->local_lock = listening_socket_data->local_lock;
960 socket_data->local_sockets = listening_socket_data->local_sockets;
961 socket_data->listening_socket_id = listening_socket->socket_id;
962 socket_data->next_incoming = ntohl(header->sequence_number);
963 socket_data->treshold = socket_data->next_incoming +
964 ntohs(header->window);
965 socket_data->addrlen = addrlen;
966 socket_data->addr = malloc(socket_data->addrlen);
967 if (!socket_data->addr) {
968 free(socket_data);
969 return tcp_release_and_return(packet, ENOMEM);
970 }
971
972 memcpy(socket_data->addr, src, socket_data->addrlen);
973 socket_data->dest_port = ntohs(header->source_port);
974 rc = tl_set_address_port(socket_data->addr, socket_data->addrlen,
975 socket_data->dest_port);
976 if (rc != EOK) {
977 free(socket_data->addr);
978 free(socket_data);
979 return tcp_release_and_return(packet, rc);
980 }
981
982 /* Create a socket */
983 socket_id = -1;
984 rc = socket_create(socket_data->local_sockets, listening_socket->phone,
985 socket_data, &socket_id);
986 if (rc != EOK) {
987 free(socket_data->addr);
988 free(socket_data);
989 return tcp_release_and_return(packet, rc);
990 }
991
992 printf("new_sock %d\n", socket_id);
993 socket_data->pseudo_header = listening_socket_data->pseudo_header;
994 socket_data->headerlen = listening_socket_data->headerlen;
995 listening_socket_data->pseudo_header = NULL;
996 listening_socket_data->headerlen = 0;
997
998 fibril_rwlock_write_unlock(socket_data->local_lock);
999 fibril_rwlock_write_lock(&tcp_globals.lock);
1000
1001 /* Find the destination socket */
1002 listening_socket = socket_port_find(&tcp_globals.sockets,
1003 listening_port, SOCKET_MAP_KEY_LISTENING, 0);
1004 if (!listening_socket ||
1005 (listening_socket->socket_id != listening_socket_id)) {
1006 fibril_rwlock_write_unlock(&tcp_globals.lock);
1007 /* A shadow may remain until app hangs up */
1008 return tcp_release_and_return(packet, EOK /*ENOTSOCK*/);
1009 }
1010 listening_socket_data =
1011 (tcp_socket_data_t *) listening_socket->specific_data;
1012 assert(listening_socket_data);
1013
1014 fibril_rwlock_write_lock(listening_socket_data->local_lock);
1015
1016 socket = socket_cores_find(listening_socket_data->local_sockets,
1017 socket_id);
1018 if (!socket) {
1019 /* Where is the socket?!? */
1020 fibril_rwlock_write_unlock(&tcp_globals.lock);
1021 return ENOTSOCK;
1022 }
1023 socket_data = (tcp_socket_data_t *) socket->specific_data;
1024 assert(socket_data);
1025
1026 rc = socket_port_add(&tcp_globals.sockets, listening_port, socket,
1027 (const char *) socket_data->addr, socket_data->addrlen);
1028 assert(socket == socket_port_find(&tcp_globals.sockets, listening_port,
1029 (const char *) socket_data->addr, socket_data->addrlen));
1030
1031// rc = socket_bind_free_port(&tcp_globals.sockets, socket,
1032// TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
1033// tcp_globals.last_used_port);
1034// tcp_globals.last_used_port = socket->port;
1035 fibril_rwlock_write_unlock(&tcp_globals.lock);
1036 if (rc != EOK) {
1037 socket_destroy(tcp_globals.net_phone, socket->socket_id,
1038 socket_data->local_sockets, &tcp_globals.sockets,
1039 tcp_free_socket_data);
1040 return tcp_release_and_return(packet, rc);
1041 }
1042
1043 socket_data->state = TCP_SOCKET_LISTEN;
1044 socket_data->next_incoming = ntohl(header->sequence_number) + 1;
1045
1046 /* Release additional packets */
1047 next_packet = pq_detach(packet);
1048 if (next_packet) {
1049 pq_release_remote(tcp_globals.net_phone,
1050 packet_get_id(next_packet));
1051 }
1052
1053 /* Trim if longer than the header */
1054 if (packet_get_data_length(packet) > sizeof(*header)) {
1055 rc = packet_trim(packet, 0,
1056 packet_get_data_length(packet) - sizeof(*header));
1057 if (rc != EOK) {
1058 socket_destroy(tcp_globals.net_phone, socket->socket_id,
1059 socket_data->local_sockets, &tcp_globals.sockets,
1060 tcp_free_socket_data);
1061 return tcp_release_and_return(packet, rc);
1062 }
1063 }
1064
1065 tcp_prepare_operation_header(socket, socket_data, header, 1, 0);
1066
1067 rc = tcp_queue_packet(socket, socket_data, packet, 1);
1068 if (rc != EOK) {
1069 socket_destroy(tcp_globals.net_phone, socket->socket_id,
1070 socket_data->local_sockets, &tcp_globals.sockets,
1071 tcp_free_socket_data);
1072 return rc;
1073 }
1074
1075 packet = tcp_get_packets_to_send(socket, socket_data);
1076 if (!packet) {
1077 socket_destroy(tcp_globals.net_phone, socket->socket_id,
1078 socket_data->local_sockets, &tcp_globals.sockets,
1079 tcp_free_socket_data);
1080 return EINVAL;
1081 }
1082
1083 socket_data->state = TCP_SOCKET_SYN_RECEIVED;
1084 fibril_rwlock_write_unlock(socket_data->local_lock);
1085
1086 /* Send the packet */
1087 tcp_send_packets(socket_data->device_id, packet);
1088
1089 return EOK;
1090}
1091
1092int tcp_process_syn_received(socket_core_t *socket,
1093 tcp_socket_data_t *socket_data, tcp_header_t *header, packet_t *packet)
1094{
1095 socket_core_t *listening_socket;
1096 tcp_socket_data_t *listening_socket_data;
1097 int rc;
1098
1099 assert(socket);
1100 assert(socket_data);
1101 assert(socket->specific_data == socket_data);
1102 assert(header);
1103 assert(packet);
1104
1105 if (!header->acknowledge)
1106 return tcp_release_and_return(packet, EINVAL);
1107
1108 /* Process acknowledgement */
1109 tcp_process_acknowledgement(socket, socket_data, header);
1110
1111 socket_data->next_incoming = ntohl(header->sequence_number); // + 1;
1112 pq_release_remote(tcp_globals.net_phone, packet_get_id(packet));
1113 socket_data->state = TCP_SOCKET_ESTABLISHED;
1114 listening_socket = socket_cores_find(socket_data->local_sockets,
1115 socket_data->listening_socket_id);
1116 if (listening_socket) {
1117 listening_socket_data =
1118 (tcp_socket_data_t *) listening_socket->specific_data;
1119 assert(listening_socket_data);
1120
1121 /* Queue the received packet */
1122 rc = dyn_fifo_push(&listening_socket->accepted,
1123 (-1 * socket->socket_id), listening_socket_data->backlog);
1124 if (rc == EOK) {
1125 /* Notify the destination socket */
1126 async_msg_5(socket->phone, NET_SOCKET_ACCEPTED,
1127 (sysarg_t) listening_socket->socket_id,
1128 socket_data->data_fragment_size, TCP_HEADER_SIZE,
1129 0, (sysarg_t) socket->socket_id);
1130
1131 fibril_rwlock_write_unlock(socket_data->local_lock);
1132 return EOK;
1133 }
1134 }
1135 /* Send FIN */
1136 socket_data->state = TCP_SOCKET_FIN_WAIT_1;
1137
1138 /* Create the notification packet */
1139 rc = tcp_create_notification_packet(&packet, socket, socket_data, 0, 1);
1140 if (rc != EOK)
1141 return rc;
1142
1143 /* Send the packet */
1144 rc = tcp_queue_packet(socket, socket_data, packet, 1);
1145 if (rc != EOK)
1146 return rc;
1147
1148 /* Flush packets */
1149 packet = tcp_get_packets_to_send(socket, socket_data);
1150 fibril_rwlock_write_unlock(socket_data->local_lock);
1151 if (packet) {
1152 /* Send the packet */
1153 tcp_send_packets(socket_data->device_id, packet);
1154 }
1155
1156 return EOK;
1157}
1158
1159void tcp_process_acknowledgement(socket_core_t *socket,
1160 tcp_socket_data_t *socket_data, tcp_header_t *header)
1161{
1162 size_t number;
1163 size_t length;
1164 packet_t *packet;
1165 packet_t *next;
1166 packet_t *acknowledged = NULL;
1167 uint32_t old;
1168
1169 assert(socket);
1170 assert(socket_data);
1171 assert(socket->specific_data == socket_data);
1172 assert(header);
1173
1174 if (!header->acknowledge)
1175 return;
1176
1177 number = ntohl(header->acknowledgement_number);
1178
1179 /* If more data acknowledged */
1180 if (number != socket_data->expected) {
1181 old = socket_data->expected;
1182 if (IS_IN_INTERVAL_OVERFLOW(old, socket_data->fin_outgoing,
1183 number)) {
1184 switch (socket_data->state) {
1185 case TCP_SOCKET_FIN_WAIT_1:
1186 socket_data->state = TCP_SOCKET_FIN_WAIT_2;
1187 break;
1188 case TCP_SOCKET_LAST_ACK:
1189 case TCP_SOCKET_CLOSING:
1190 /*
1191 * FIN acknowledged - release the socket in
1192 * another fibril.
1193 */
1194 tcp_prepare_timeout(tcp_release_after_timeout,
1195 socket, socket_data, 0,
1196 TCP_SOCKET_TIME_WAIT,
1197 NET_DEFAULT_TCP_TIME_WAIT_TIMEOUT, true);
1198 break;
1199 default:
1200 break;
1201 }
1202 }
1203
1204 /* Update the treshold if higher than set */
1205 if (number + ntohs(header->window) >
1206 socket_data->expected + socket_data->treshold) {
1207 socket_data->treshold = number + ntohs(header->window) -
1208 socket_data->expected;
1209 }
1210
1211 /* Set new expected sequence number */
1212 socket_data->expected = number;
1213 socket_data->expected_count = 1;
1214 packet = socket_data->outgoing;
1215 while (pq_get_order(packet, &number, &length) == EOK) {
1216 if (IS_IN_INTERVAL_OVERFLOW((uint32_t) old,
1217 (uint32_t) (number + length),
1218 (uint32_t) socket_data->expected)) {
1219 next = pq_detach(packet);
1220 if (packet == socket_data->outgoing)
1221 socket_data->outgoing = next;
1222
1223 /* Add to acknowledged or release */
1224 if (pq_add(&acknowledged, packet, 0, 0) != EOK)
1225 pq_release_remote(tcp_globals.net_phone,
1226 packet_get_id(packet));
1227 packet = next;
1228 } else if (old < socket_data->expected)
1229 break;
1230 }
1231
1232 /* Release acknowledged */
1233 if (acknowledged) {
1234 pq_release_remote(tcp_globals.net_phone,
1235 packet_get_id(acknowledged));
1236 }
1237 return;
1238 /* If the same as the previous time */
1239 }
1240
1241 if (number == socket_data->expected) {
1242 /* Increase the counter */
1243 socket_data->expected_count++;
1244 if (socket_data->expected_count == TCP_FAST_RETRANSMIT_COUNT) {
1245 socket_data->expected_count = 1;
1246 /* TODO retransmit lock */
1247 //tcp_retransmit_packet(socket, socket_data, number);
1248 }
1249 }
1250}
1251
1252/** Processes the TCP message.
1253 *
1254 * @param[in] callid The message identifier.
1255 * @param[in] call The message parameters.
1256 * @param[out] answer The message answer parameters.
1257 * @param[out] answer_count The last parameter for the actual answer in the
1258 * answer parameter.
1259 * @return EOK on success.
1260 * @return ENOTSUP if the message is not known.
1261 *
1262 * @see tcp_interface.h
1263 * @see IS_NET_TCP_MESSAGE()
1264 */
1265int
1266tcp_message_standalone(ipc_callid_t callid, ipc_call_t *call,
1267 ipc_call_t *answer, int *answer_count)
1268{
1269 packet_t *packet;
1270 int rc;
1271
1272 assert(call);
1273 assert(answer);
1274 assert(answer_count);
1275
1276 *answer_count = 0;
1277 switch (IPC_GET_IMETHOD(*call)) {
1278 case NET_TL_RECEIVED:
1279// fibril_rwlock_read_lock(&tcp_globals.lock);
1280 rc = packet_translate_remote(tcp_globals.net_phone, &packet,
1281 IPC_GET_PACKET(call));
1282 if (rc != EOK) {
1283// fibril_rwlock_read_unlock(&tcp_globals.lock);
1284 return rc;
1285 }
1286 rc = tcp_received_msg(IPC_GET_DEVICE(call), packet, SERVICE_TCP,
1287 IPC_GET_ERROR(call));
1288// fibril_rwlock_read_unlock(&tcp_globals.lock);
1289 return rc;
1290 case IPC_M_CONNECT_TO_ME:
1291 return tcp_process_client_messages(callid, *call);
1292 }
1293
1294 return ENOTSUP;
1295}
1296
1297void tcp_refresh_socket_data(tcp_socket_data_t *socket_data)
1298{
1299 assert(socket_data);
1300
1301 bzero(socket_data, sizeof(*socket_data));
1302 socket_data->state = TCP_SOCKET_INITIAL;
1303 socket_data->device_id = DEVICE_INVALID_ID;
1304 socket_data->window = NET_DEFAULT_TCP_WINDOW;
1305 socket_data->treshold = socket_data->window;
1306 socket_data->last_outgoing = TCP_INITIAL_SEQUENCE_NUMBER;
1307 socket_data->timeout = NET_DEFAULT_TCP_INITIAL_TIMEOUT;
1308 socket_data->acknowledged = socket_data->last_outgoing;
1309 socket_data->next_outgoing = socket_data->last_outgoing + 1;
1310 socket_data->expected = socket_data->next_outgoing;
1311}
1312
1313void tcp_initialize_socket_data(tcp_socket_data_t *socket_data)
1314{
1315 assert(socket_data);
1316
1317 tcp_refresh_socket_data(socket_data);
1318 fibril_mutex_initialize(&socket_data->operation.mutex);
1319 fibril_condvar_initialize(&socket_data->operation.condvar);
1320 socket_data->data_fragment_size = MAX_TCP_FRAGMENT_SIZE;
1321}
1322
1323int tcp_process_client_messages(ipc_callid_t callid, ipc_call_t call)
1324{
1325 int res;
1326 bool keep_on_going = true;
1327 socket_cores_t local_sockets;
1328 int app_phone = IPC_GET_PHONE(&call);
1329 struct sockaddr *addr;
1330 int socket_id;
1331 size_t addrlen;
1332 size_t size;
1333 fibril_rwlock_t lock;
1334 ipc_call_t answer;
1335 int answer_count;
1336 tcp_socket_data_t *socket_data;
1337 socket_core_t *socket;
1338 packet_dimension_t *packet_dimension;
1339
1340 /*
1341 * Accept the connection
1342 * - Answer the first IPC_M_CONNECT_ME_TO call.
1343 */
1344 res = EOK;
1345 answer_count = 0;
1346
1347 socket_cores_initialize(&local_sockets);
1348 fibril_rwlock_initialize(&lock);
1349
1350 while (keep_on_going) {
1351
1352 /* Answer the call */
1353 answer_call(callid, res, &answer, answer_count);
1354 /* Refresh data */
1355 refresh_answer(&answer, &answer_count);
1356 /* Get the next call */
1357 callid = async_get_call(&call);
1358
1359 /* Process the call */
1360 switch (IPC_GET_IMETHOD(call)) {
1361 case IPC_M_PHONE_HUNGUP:
1362 keep_on_going = false;
1363 res = EHANGUP;
1364 break;
1365
1366 case NET_SOCKET:
1367 socket_data =
1368 (tcp_socket_data_t *) malloc(sizeof(*socket_data));
1369 if (!socket_data) {
1370 res = ENOMEM;
1371 break;
1372 }
1373
1374 tcp_initialize_socket_data(socket_data);
1375 socket_data->local_lock = &lock;
1376 socket_data->local_sockets = &local_sockets;
1377 fibril_rwlock_write_lock(&lock);
1378 socket_id = SOCKET_GET_SOCKET_ID(call);
1379 res = socket_create(&local_sockets, app_phone,
1380 socket_data, &socket_id);
1381 SOCKET_SET_SOCKET_ID(answer, socket_id);
1382 fibril_rwlock_write_unlock(&lock);
1383 if (res != EOK) {
1384 free(socket_data);
1385 break;
1386 }
1387 if (tl_get_ip_packet_dimension(tcp_globals.ip_phone,
1388 &tcp_globals.dimensions, DEVICE_INVALID_ID,
1389 &packet_dimension) == EOK) {
1390 SOCKET_SET_DATA_FRAGMENT_SIZE(answer,
1391 ((packet_dimension->content <
1392 socket_data->data_fragment_size) ?
1393 packet_dimension->content :
1394 socket_data->data_fragment_size));
1395 }
1396// SOCKET_SET_DATA_FRAGMENT_SIZE(answer, MAX_TCP_FRAGMENT_SIZE);
1397 SOCKET_SET_HEADER_SIZE(answer, TCP_HEADER_SIZE);
1398 answer_count = 3;
1399 break;
1400
1401 case NET_SOCKET_BIND:
1402 res = async_data_write_accept((void **) &addr, false,
1403 0, 0, 0, &addrlen);
1404 if (res != EOK)
1405 break;
1406 fibril_rwlock_write_lock(&tcp_globals.lock);
1407 fibril_rwlock_write_lock(&lock);
1408 res = socket_bind(&local_sockets, &tcp_globals.sockets,
1409 SOCKET_GET_SOCKET_ID(call), addr, addrlen,
1410 TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
1411 tcp_globals.last_used_port);
1412 if (res == EOK) {
1413 socket = socket_cores_find(&local_sockets,
1414 SOCKET_GET_SOCKET_ID(call));
1415 if (socket) {
1416 socket_data = (tcp_socket_data_t *)
1417 socket->specific_data;
1418 assert(socket_data);
1419 socket_data->state = TCP_SOCKET_LISTEN;
1420 }
1421 }
1422 fibril_rwlock_write_unlock(&lock);
1423 fibril_rwlock_write_unlock(&tcp_globals.lock);
1424 free(addr);
1425 break;
1426
1427 case NET_SOCKET_LISTEN:
1428 fibril_rwlock_read_lock(&tcp_globals.lock);
1429// fibril_rwlock_write_lock(&tcp_globals.lock);
1430 fibril_rwlock_write_lock(&lock);
1431 res = tcp_listen_message(&local_sockets,
1432 SOCKET_GET_SOCKET_ID(call),
1433 SOCKET_GET_BACKLOG(call));
1434 fibril_rwlock_write_unlock(&lock);
1435// fibril_rwlock_write_unlock(&tcp_globals.lock);
1436 fibril_rwlock_read_unlock(&tcp_globals.lock);
1437 break;
1438
1439 case NET_SOCKET_CONNECT:
1440 res = async_data_write_accept((void **) &addr, false,
1441 0, 0, 0, &addrlen);
1442 if (res != EOK)
1443 break;
1444 /*
1445 * The global lock may be released in the
1446 * tcp_connect_message() function.
1447 */
1448 fibril_rwlock_write_lock(&tcp_globals.lock);
1449 fibril_rwlock_write_lock(&lock);
1450 res = tcp_connect_message(&local_sockets,
1451 SOCKET_GET_SOCKET_ID(call), addr, addrlen);
1452 if (res != EOK) {
1453 fibril_rwlock_write_unlock(&lock);
1454 fibril_rwlock_write_unlock(&tcp_globals.lock);
1455 free(addr);
1456 }
1457 break;
1458
1459 case NET_SOCKET_ACCEPT:
1460 fibril_rwlock_read_lock(&tcp_globals.lock);
1461 fibril_rwlock_write_lock(&lock);
1462 res = tcp_accept_message(&local_sockets,
1463 SOCKET_GET_SOCKET_ID(call),
1464 SOCKET_GET_NEW_SOCKET_ID(call), &size, &addrlen);
1465 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, size);
1466 fibril_rwlock_write_unlock(&lock);
1467 fibril_rwlock_read_unlock(&tcp_globals.lock);
1468 if (res > 0) {
1469 SOCKET_SET_SOCKET_ID(answer, res);
1470 SOCKET_SET_ADDRESS_LENGTH(answer, addrlen);
1471 answer_count = 3;
1472 }
1473 break;
1474
1475 case NET_SOCKET_SEND:
1476 fibril_rwlock_read_lock(&tcp_globals.lock);
1477 fibril_rwlock_write_lock(&lock);
1478 res = tcp_send_message(&local_sockets,
1479 SOCKET_GET_SOCKET_ID(call),
1480 SOCKET_GET_DATA_FRAGMENTS(call), &size,
1481 SOCKET_GET_FLAGS(call));
1482 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, size);
1483 if (res != EOK) {
1484 fibril_rwlock_write_unlock(&lock);
1485 fibril_rwlock_read_unlock(&tcp_globals.lock);
1486 } else {
1487 answer_count = 2;
1488 }
1489 break;
1490
1491 case NET_SOCKET_SENDTO:
1492 res = async_data_write_accept((void **) &addr, false,
1493 0, 0, 0, &addrlen);
1494 if (res != EOK)
1495 break;
1496 fibril_rwlock_read_lock(&tcp_globals.lock);
1497 fibril_rwlock_write_lock(&lock);
1498 res = tcp_send_message(&local_sockets,
1499 SOCKET_GET_SOCKET_ID(call),
1500 SOCKET_GET_DATA_FRAGMENTS(call), &size,
1501 SOCKET_GET_FLAGS(call));
1502 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, size);
1503 if (res != EOK) {
1504 fibril_rwlock_write_unlock(&lock);
1505 fibril_rwlock_read_unlock(&tcp_globals.lock);
1506 } else {
1507 answer_count = 2;
1508 }
1509 free(addr);
1510 break;
1511
1512 case NET_SOCKET_RECV:
1513 fibril_rwlock_read_lock(&tcp_globals.lock);
1514 fibril_rwlock_write_lock(&lock);
1515 res = tcp_recvfrom_message(&local_sockets,
1516 SOCKET_GET_SOCKET_ID(call), SOCKET_GET_FLAGS(call),
1517 NULL);
1518 fibril_rwlock_write_unlock(&lock);
1519 fibril_rwlock_read_unlock(&tcp_globals.lock);
1520 if (res > 0) {
1521 SOCKET_SET_READ_DATA_LENGTH(answer, res);
1522 answer_count = 1;
1523 res = EOK;
1524 }
1525 break;
1526
1527 case NET_SOCKET_RECVFROM:
1528 fibril_rwlock_read_lock(&tcp_globals.lock);
1529 fibril_rwlock_write_lock(&lock);
1530 res = tcp_recvfrom_message(&local_sockets,
1531 SOCKET_GET_SOCKET_ID(call), SOCKET_GET_FLAGS(call),
1532 &addrlen);
1533 fibril_rwlock_write_unlock(&lock);
1534 fibril_rwlock_read_unlock(&tcp_globals.lock);
1535 if (res > 0) {
1536 SOCKET_SET_READ_DATA_LENGTH(answer, res);
1537 SOCKET_SET_ADDRESS_LENGTH(answer, addrlen);
1538 answer_count = 3;
1539 res = EOK;
1540 }
1541 break;
1542
1543 case NET_SOCKET_CLOSE:
1544 fibril_rwlock_write_lock(&tcp_globals.lock);
1545 fibril_rwlock_write_lock(&lock);
1546 res = tcp_close_message(&local_sockets,
1547 SOCKET_GET_SOCKET_ID(call));
1548 if (res != EOK) {
1549 fibril_rwlock_write_unlock(&lock);
1550 fibril_rwlock_write_unlock(&tcp_globals.lock);
1551 }
1552 break;
1553
1554 case NET_SOCKET_GETSOCKOPT:
1555 case NET_SOCKET_SETSOCKOPT:
1556 default:
1557 res = ENOTSUP;
1558 break;
1559 }
1560 }
1561
1562 /* Release the application phone */
1563 ipc_hangup(app_phone);
1564
1565 printf("release\n");
1566 /* Release all local sockets */
1567 socket_cores_release(tcp_globals.net_phone, &local_sockets,
1568 &tcp_globals.sockets, tcp_free_socket_data);
1569
1570 return EOK;
1571}
1572
1573int tcp_timeout(void *data)
1574{
1575 tcp_timeout_t *timeout = data;
1576 int keep_write_lock = false;
1577 socket_core_t *socket;
1578 tcp_socket_data_t *socket_data;
1579
1580 assert(timeout);
1581
1582 /* Sleep the given timeout */
1583 async_usleep(timeout->timeout);
1584 /* Lock the globals */
1585 if (timeout->globals_read_only)
1586 fibril_rwlock_read_lock(&tcp_globals.lock);
1587 else
1588 fibril_rwlock_write_lock(&tcp_globals.lock);
1589
1590 /* Find the pending operation socket */
1591 socket = socket_port_find(&tcp_globals.sockets, timeout->port,
1592 timeout->key, timeout->key_length);
1593 if (!socket || (socket->socket_id != timeout->socket_id))
1594 goto out;
1595
1596 socket_data = (tcp_socket_data_t *) socket->specific_data;
1597 assert(socket_data);
1598 if (socket_data->local_sockets != timeout->local_sockets)
1599 goto out;
1600
1601 fibril_rwlock_write_lock(socket_data->local_lock);
1602 if (timeout->sequence_number) {
1603 /* Increase the timeout counter */
1604 socket_data->timeout_count++;
1605 if (socket_data->timeout_count == TCP_MAX_TIMEOUTS) {
1606 /* TODO release as connection lost */
1607 //tcp_refresh_socket_data(socket_data);
1608 fibril_rwlock_write_unlock(socket_data->local_lock);
1609 } else {
1610 /* Retransmit */
1611// tcp_retransmit_packet(socket,
1612// socket_data, timeout->sequence_number);
1613 fibril_rwlock_write_unlock(socket_data->local_lock);
1614 }
1615 } else {
1616 fibril_mutex_lock(&socket_data->operation.mutex);
1617 /* Set the timeout operation result if state not changed */
1618 if (socket_data->state == timeout->state) {
1619 socket_data->operation.result = ETIMEOUT;
1620
1621 /* Notify the main fibril */
1622 fibril_condvar_signal(&socket_data->operation.condvar);
1623
1624 /* Keep the global write lock */
1625 keep_write_lock = true;
1626 } else {
1627 /*
1628 * Operation is ok, do nothing.
1629 * Unlocking from now on, so the unlocking
1630 * order does not matter.
1631 */
1632 fibril_rwlock_write_unlock(socket_data->local_lock);
1633 }
1634 fibril_mutex_unlock(&socket_data->operation.mutex);
1635 }
1636
1637out:
1638 /* Unlock only if no socket */
1639 if (timeout->globals_read_only)
1640 fibril_rwlock_read_unlock(&tcp_globals.lock);
1641 else if (!keep_write_lock)
1642 /* Release if not desired */
1643 fibril_rwlock_write_unlock(&tcp_globals.lock);
1644
1645 /* Release the timeout structure */
1646 free(timeout);
1647 return EOK;
1648}
1649
1650int tcp_release_after_timeout(void *data)
1651{
1652 tcp_timeout_t *timeout = data;
1653 socket_core_t *socket;
1654 tcp_socket_data_t *socket_data;
1655 fibril_rwlock_t *local_lock;
1656
1657 assert(timeout);
1658
1659 /* Sleep the given timeout */
1660 async_usleep(timeout->timeout);
1661
1662 /* Lock the globals */
1663 fibril_rwlock_write_lock(&tcp_globals.lock);
1664
1665 /* Find the pending operation socket */
1666 socket = socket_port_find(&tcp_globals.sockets, timeout->port,
1667 timeout->key, timeout->key_length);
1668
1669 if (socket && (socket->socket_id == timeout->socket_id)) {
1670 socket_data = (tcp_socket_data_t *) socket->specific_data;
1671 assert(socket_data);
1672 if (socket_data->local_sockets == timeout->local_sockets) {
1673 local_lock = socket_data->local_lock;
1674 fibril_rwlock_write_lock(local_lock);
1675 socket_destroy(tcp_globals.net_phone,
1676 timeout->socket_id, timeout->local_sockets,
1677 &tcp_globals.sockets, tcp_free_socket_data);
1678 fibril_rwlock_write_unlock(local_lock);
1679 }
1680 }
1681
1682 /* Unlock the globals */
1683 fibril_rwlock_write_unlock(&tcp_globals.lock);
1684
1685 /* Release the timeout structure */
1686 free(timeout);
1687
1688 return EOK;
1689}
1690
1691void tcp_retransmit_packet(socket_core_t *socket, tcp_socket_data_t *
1692 socket_data, size_t sequence_number)
1693{
1694 packet_t *packet;
1695 packet_t *copy;
1696 size_t data_length;
1697
1698 assert(socket);
1699 assert(socket_data);
1700 assert(socket->specific_data == socket_data);
1701
1702 /* Sent packet? */
1703 packet = pq_find(socket_data->outgoing, sequence_number);
1704 printf("retransmit %d\n", packet_get_id(packet));
1705 if (packet) {
1706 pq_get_order(packet, NULL, &data_length);
1707 copy = tcp_prepare_copy(socket, socket_data, packet,
1708 data_length, sequence_number);
1709 fibril_rwlock_write_unlock(socket_data->local_lock);
1710// printf("r send %d\n", packet_get_id(packet));
1711 if (copy)
1712 tcp_send_packets(socket_data->device_id, copy);
1713 } else {
1714 fibril_rwlock_write_unlock(socket_data->local_lock);
1715 }
1716}
1717
1718int tcp_listen_message(socket_cores_t *local_sockets, int socket_id,
1719 int backlog)
1720{
1721 socket_core_t *socket;
1722 tcp_socket_data_t *socket_data;
1723
1724 assert(local_sockets);
1725
1726 if (backlog < 0)
1727 return EINVAL;
1728
1729 /* Find the socket */
1730 socket = socket_cores_find(local_sockets, socket_id);
1731 if (!socket)
1732 return ENOTSOCK;
1733
1734 /* Get the socket specific data */
1735 socket_data = (tcp_socket_data_t *) socket->specific_data;
1736 assert(socket_data);
1737
1738 /* Set the backlog */
1739 socket_data->backlog = backlog;
1740
1741 return EOK;
1742}
1743
1744int tcp_connect_message(socket_cores_t *local_sockets, int socket_id,
1745 struct sockaddr *addr, socklen_t addrlen)
1746{
1747 socket_core_t *socket;
1748 int rc;
1749
1750 assert(local_sockets);
1751 assert(addr);
1752 assert(addrlen > 0);
1753
1754 /* Find the socket */
1755 socket = socket_cores_find(local_sockets, socket_id);
1756 if (!socket)
1757 return ENOTSOCK;
1758
1759 rc = tcp_connect_core(socket, local_sockets, addr, addrlen);
1760 if (rc != EOK) {
1761 tcp_free_socket_data(socket);
1762 /* Unbind if bound */
1763 if (socket->port > 0) {
1764 socket_ports_exclude(&tcp_globals.sockets,
1765 socket->port);
1766 socket->port = 0;
1767 }
1768 }
1769 return rc;
1770}
1771
1772int tcp_connect_core(socket_core_t *socket, socket_cores_t *local_sockets,
1773 struct sockaddr *addr, socklen_t addrlen)
1774{
1775 tcp_socket_data_t *socket_data;
1776 packet_t *packet;
1777 int rc;
1778
1779 assert(socket);
1780 assert(addr);
1781 assert(addrlen > 0);
1782
1783 /* Get the socket specific data */
1784 socket_data = (tcp_socket_data_t *) socket->specific_data;
1785 assert(socket_data);
1786 assert(socket->specific_data == socket_data);
1787 if ((socket_data->state != TCP_SOCKET_INITIAL) &&
1788 ((socket_data->state != TCP_SOCKET_LISTEN) ||
1789 (socket->port <= 0)))
1790 return EINVAL;
1791
1792 /* Get the destination port */
1793 rc = tl_get_address_port(addr, addrlen, &socket_data->dest_port);
1794 if (rc != EOK)
1795 return rc;
1796
1797 if (socket->port <= 0) {
1798 /* Try to find a free port */
1799 rc = socket_bind_free_port(&tcp_globals.sockets, socket,
1800 TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
1801 tcp_globals.last_used_port);
1802 if (rc != EOK)
1803 return rc;
1804 /* Set the next port as the search starting port number */
1805 tcp_globals.last_used_port = socket->port;
1806 }
1807
1808 rc = ip_get_route_req(tcp_globals.ip_phone, IPPROTO_TCP,
1809 addr, addrlen, &socket_data->device_id,
1810 &socket_data->pseudo_header, &socket_data->headerlen);
1811 if (rc != EOK)
1812 return rc;
1813
1814 /* Create the notification packet */
1815 rc = tcp_create_notification_packet(&packet, socket, socket_data, 1, 0);
1816 if (rc != EOK)
1817 return rc;
1818
1819 /* Unlock the globals and wait for an operation */
1820 fibril_rwlock_write_unlock(&tcp_globals.lock);
1821
1822 socket_data->addr = addr;
1823 socket_data->addrlen = addrlen;
1824
1825 /* Send the packet */
1826
1827 if (((rc = tcp_queue_packet(socket, socket_data, packet, 1)) != EOK) ||
1828 ((rc = tcp_prepare_timeout(tcp_timeout, socket, socket_data, 0,
1829 TCP_SOCKET_INITIAL, NET_DEFAULT_TCP_INITIAL_TIMEOUT, false)) !=
1830 EOK)) {
1831 socket_data->addr = NULL;
1832 socket_data->addrlen = 0;
1833 fibril_rwlock_write_lock(&tcp_globals.lock);
1834 } else {
1835 packet = tcp_get_packets_to_send(socket, socket_data);
1836 if (packet) {
1837 fibril_mutex_lock(&socket_data->operation.mutex);
1838 fibril_rwlock_write_unlock(socket_data->local_lock);
1839
1840 socket_data->state = TCP_SOCKET_SYN_SENT;
1841
1842 /* Send the packet */
1843 printf("connecting %d\n", packet_get_id(packet));
1844 tcp_send_packets(socket_data->device_id, packet);
1845
1846 /* Wait for a reply */
1847 fibril_condvar_wait(&socket_data->operation.condvar,
1848 &socket_data->operation.mutex);
1849 rc = socket_data->operation.result;
1850 if (rc != EOK) {
1851 socket_data->addr = NULL;
1852 socket_data->addrlen = 0;
1853 }
1854 } else {
1855 socket_data->addr = NULL;
1856 socket_data->addrlen = 0;
1857 rc = EINTR;
1858 }
1859 }
1860
1861 fibril_mutex_unlock(&socket_data->operation.mutex);
1862 return rc;
1863}
1864
1865int tcp_queue_prepare_packet(socket_core_t *socket,
1866 tcp_socket_data_t *socket_data, packet_t *packet, size_t data_length)
1867{
1868 tcp_header_t *header;
1869 int rc;
1870
1871 assert(socket);
1872 assert(socket_data);
1873 assert(socket->specific_data == socket_data);
1874
1875 /* Get TCP header */
1876 header = (tcp_header_t *) packet_get_data(packet);
1877 if (!header)
1878 return NO_DATA;
1879
1880 header->destination_port = htons(socket_data->dest_port);
1881 header->source_port = htons(socket->port);
1882 header->sequence_number = htonl(socket_data->next_outgoing);
1883
1884 rc = packet_set_addr(packet, NULL, (uint8_t *) socket_data->addr,
1885 socket_data->addrlen);
1886 if (rc != EOK)
1887 return tcp_release_and_return(packet, EINVAL);
1888
1889 /* Remember the outgoing FIN */
1890 if (header->finalize)
1891 socket_data->fin_outgoing = socket_data->next_outgoing;
1892
1893 return EOK;
1894}
1895
1896int tcp_queue_packet(socket_core_t *socket, tcp_socket_data_t *socket_data,
1897 packet_t *packet, size_t data_length)
1898{
1899 int rc;
1900
1901 assert(socket);
1902 assert(socket_data);
1903 assert(socket->specific_data == socket_data);
1904
1905 rc = tcp_queue_prepare_packet(socket, socket_data, packet, data_length);
1906 if (rc != EOK)
1907 return rc;
1908
1909 rc = pq_add(&socket_data->outgoing, packet, socket_data->next_outgoing,
1910 data_length);
1911 if (rc != EOK)
1912 return tcp_release_and_return(packet, rc);
1913
1914 socket_data->next_outgoing += data_length;
1915 return EOK;
1916}
1917
1918packet_t *tcp_get_packets_to_send(socket_core_t *socket, tcp_socket_data_t *
1919 socket_data)
1920{
1921 packet_t *packet;
1922 packet_t *copy;
1923 packet_t *sending = NULL;
1924 packet_t *previous = NULL;
1925 size_t data_length;
1926 int rc;
1927
1928 assert(socket);
1929 assert(socket_data);
1930 assert(socket->specific_data == socket_data);
1931
1932 packet = pq_find(socket_data->outgoing, socket_data->last_outgoing + 1);
1933 while (packet) {
1934 pq_get_order(packet, NULL, &data_length);
1935
1936 /*
1937 * Send only if fits into the window, respecting the possible
1938 * overflow.
1939 */
1940 if (!IS_IN_INTERVAL_OVERFLOW(
1941 (uint32_t) socket_data->last_outgoing,
1942 (uint32_t) (socket_data->last_outgoing + data_length),
1943 (uint32_t) (socket_data->expected + socket_data->treshold)))
1944 break;
1945
1946 copy = tcp_prepare_copy(socket, socket_data, packet,
1947 data_length, socket_data->last_outgoing + 1);
1948 if (!copy)
1949 return sending;
1950
1951 if (!sending) {
1952 sending = copy;
1953 } else {
1954 rc = pq_insert_after(previous, copy);
1955 if (rc != EOK) {
1956 pq_release_remote(tcp_globals.net_phone,
1957 packet_get_id(copy));
1958 return sending;
1959 }
1960 }
1961
1962 previous = copy;
1963 packet = pq_next(packet);
1964
1965 /* Overflow occurred? */
1966 if (!packet &&
1967 (socket_data->last_outgoing > socket_data->next_outgoing)) {
1968 printf("gpts overflow\n");
1969 /* Continue from the beginning */
1970 packet = socket_data->outgoing;
1971 }
1972 socket_data->last_outgoing += data_length;
1973 }
1974
1975 return sending;
1976}
1977
1978packet_t *tcp_send_prepare_packet(socket_core_t *socket, tcp_socket_data_t *
1979 socket_data, packet_t *packet, size_t data_length, size_t sequence_number)
1980{
1981 tcp_header_t *header;
1982 uint32_t checksum;
1983 int rc;
1984
1985 assert(socket);
1986 assert(socket_data);
1987 assert(socket->specific_data == socket_data);
1988
1989 /* Adjust the pseudo header */
1990 rc = ip_client_set_pseudo_header_data_length(socket_data->pseudo_header,
1991 socket_data->headerlen, packet_get_data_length(packet));
1992 if (rc != EOK) {
1993 pq_release_remote(tcp_globals.net_phone, packet_get_id(packet));
1994 return NULL;
1995 }
1996
1997 /* Get the header */
1998 header = (tcp_header_t *) packet_get_data(packet);
1999 if (!header) {
2000 pq_release_remote(tcp_globals.net_phone, packet_get_id(packet));
2001 return NULL;
2002 }
2003 assert(ntohl(header->sequence_number) == sequence_number);
2004
2005 /* Adjust the header */
2006 if (socket_data->next_incoming) {
2007 header->acknowledgement_number =
2008 htonl(socket_data->next_incoming);
2009 header->acknowledge = 1;
2010 }
2011 header->window = htons(socket_data->window);
2012
2013 /* Checksum */
2014 header->checksum = 0;
2015 checksum = compute_checksum(0, socket_data->pseudo_header,
2016 socket_data->headerlen);
2017 checksum = compute_checksum(checksum,
2018 (uint8_t *) packet_get_data(packet),
2019 packet_get_data_length(packet));
2020 header->checksum = htons(flip_checksum(compact_checksum(checksum)));
2021
2022 /* Prepare the packet */
2023 rc = ip_client_prepare_packet(packet, IPPROTO_TCP, 0, 0, 0, 0);
2024 if (rc != EOK) {
2025 pq_release_remote(tcp_globals.net_phone, packet_get_id(packet));
2026 return NULL;
2027 }
2028
2029 rc = tcp_prepare_timeout(tcp_timeout, socket, socket_data,
2030 sequence_number, socket_data->state, socket_data->timeout, true);
2031 if (rc != EOK) {
2032 pq_release_remote(tcp_globals.net_phone, packet_get_id(packet));
2033 return NULL;
2034 }
2035
2036 return packet;
2037}
2038
2039packet_t *tcp_prepare_copy(socket_core_t *socket, tcp_socket_data_t *
2040 socket_data, packet_t *packet, size_t data_length, size_t sequence_number)
2041{
2042 packet_t *copy;
2043
2044 assert(socket);
2045 assert(socket_data);
2046 assert(socket->specific_data == socket_data);
2047
2048 /* Make a copy of the packet */
2049 copy = packet_get_copy(tcp_globals.net_phone, packet);
2050 if (!copy)
2051 return NULL;
2052
2053 return tcp_send_prepare_packet(socket, socket_data, copy, data_length,
2054 sequence_number);
2055}
2056
2057void tcp_send_packets(device_id_t device_id, packet_t *packet)
2058{
2059 packet_t *next;
2060
2061 while (packet) {
2062 next = pq_detach(packet);
2063 ip_send_msg(tcp_globals.ip_phone, device_id, packet,
2064 SERVICE_TCP, 0);
2065 packet = next;
2066 }
2067}
2068
2069void tcp_prepare_operation_header(socket_core_t *socket,
2070 tcp_socket_data_t *socket_data, tcp_header_t *header, int synchronize,
2071 int finalize)
2072{
2073 assert(socket);
2074 assert(socket_data);
2075 assert(socket->specific_data == socket_data);
2076 assert(header);
2077
2078 bzero(header, sizeof(*header));
2079 header->source_port = htons(socket->port);
2080 header->source_port = htons(socket_data->dest_port);
2081 header->header_length = TCP_COMPUTE_HEADER_LENGTH(sizeof(*header));
2082 header->synchronize = synchronize;
2083 header->finalize = finalize;
2084}
2085
2086int tcp_prepare_timeout(int (*timeout_function)(void *tcp_timeout_t),
2087 socket_core_t *socket, tcp_socket_data_t *socket_data,
2088 size_t sequence_number, tcp_socket_state_t state, suseconds_t timeout,
2089 int globals_read_only)
2090{
2091 tcp_timeout_t *operation_timeout;
2092 fid_t fibril;
2093
2094 assert(socket);
2095 assert(socket_data);
2096 assert(socket->specific_data == socket_data);
2097
2098 /* Prepare the timeout with key bundle structure */
2099 operation_timeout = malloc(sizeof(*operation_timeout) +
2100 socket->key_length + 1);
2101 if (!operation_timeout)
2102 return ENOMEM;
2103
2104 bzero(operation_timeout, sizeof(*operation_timeout));
2105 operation_timeout->globals_read_only = globals_read_only;
2106 operation_timeout->port = socket->port;
2107 operation_timeout->local_sockets = socket_data->local_sockets;
2108 operation_timeout->socket_id = socket->socket_id;
2109 operation_timeout->timeout = timeout;
2110 operation_timeout->sequence_number = sequence_number;
2111 operation_timeout->state = state;
2112
2113 /* Copy the key */
2114 operation_timeout->key = ((char *) operation_timeout) +
2115 sizeof(*operation_timeout);
2116 operation_timeout->key_length = socket->key_length;
2117 memcpy(operation_timeout->key, socket->key, socket->key_length);
2118 operation_timeout->key[operation_timeout->key_length] = '\0';
2119
2120 /* Prepare the timeouting thread */
2121 fibril = fibril_create(timeout_function, operation_timeout);
2122 if (!fibril) {
2123 free(operation_timeout);
2124 return ENOMEM;
2125 }
2126
2127// fibril_mutex_lock(&socket_data->operation.mutex);
2128 /* Start the timeout fibril */
2129 fibril_add_ready(fibril);
2130 //socket_data->state = state;
2131 return EOK;
2132}
2133
2134int tcp_recvfrom_message(socket_cores_t *local_sockets, int socket_id,
2135 int flags, size_t *addrlen)
2136{
2137 socket_core_t *socket;
2138 tcp_socket_data_t *socket_data;
2139 int packet_id;
2140 packet_t *packet;
2141 size_t length;
2142 int rc;
2143
2144 assert(local_sockets);
2145
2146 /* Find the socket */
2147 socket = socket_cores_find(local_sockets, socket_id);
2148 if (!socket)
2149 return ENOTSOCK;
2150
2151 /* Get the socket specific data */
2152 if (!socket->specific_data)
2153 return NO_DATA;
2154
2155 socket_data = (tcp_socket_data_t *) socket->specific_data;
2156
2157 /* Check state */
2158 if ((socket_data->state != TCP_SOCKET_ESTABLISHED) &&
2159 (socket_data->state != TCP_SOCKET_CLOSE_WAIT))
2160 return ENOTCONN;
2161
2162 /* Send the source address if desired */
2163 if (addrlen) {
2164 rc = data_reply(socket_data->addr, socket_data->addrlen);
2165 if (rc != EOK)
2166 return rc;
2167 *addrlen = socket_data->addrlen;
2168 }
2169
2170 /* Get the next received packet */
2171 packet_id = dyn_fifo_value(&socket->received);
2172 if (packet_id < 0)
2173 return NO_DATA;
2174
2175 rc = packet_translate_remote(tcp_globals.net_phone, &packet, packet_id);
2176 if (rc != EOK)
2177 return rc;
2178
2179 /* Reply the packets */
2180 rc = socket_reply_packets(packet, &length);
2181 if (rc != EOK)
2182 return rc;
2183
2184 /* Release the packet */
2185 dyn_fifo_pop(&socket->received);
2186 pq_release_remote(tcp_globals.net_phone, packet_get_id(packet));
2187
2188 /* Return the total length */
2189 return (int) length;
2190}
2191
2192int tcp_send_message(socket_cores_t *local_sockets, int socket_id,
2193 int fragments, size_t *data_fragment_size, int flags)
2194{
2195 socket_core_t *socket;
2196 tcp_socket_data_t *socket_data;
2197 packet_dimension_t *packet_dimension;
2198 packet_t *packet;
2199 size_t total_length;
2200 tcp_header_t *header;
2201 int index;
2202 int result;
2203 int rc;
2204
2205 assert(local_sockets);
2206 assert(data_fragment_size);
2207
2208 /* Find the socket */
2209 socket = socket_cores_find(local_sockets, socket_id);
2210 if (!socket)
2211 return ENOTSOCK;
2212
2213 /* Get the socket specific data */
2214 if (!socket->specific_data)
2215 return NO_DATA;
2216
2217 socket_data = (tcp_socket_data_t *) socket->specific_data;
2218
2219 /* Check state */
2220 if ((socket_data->state != TCP_SOCKET_ESTABLISHED) &&
2221 (socket_data->state != TCP_SOCKET_CLOSE_WAIT))
2222 return ENOTCONN;
2223
2224 rc = tl_get_ip_packet_dimension(tcp_globals.ip_phone,
2225 &tcp_globals.dimensions, socket_data->device_id, &packet_dimension);
2226 if (rc != EOK)
2227 return rc;
2228
2229 *data_fragment_size =
2230 ((packet_dimension->content < socket_data->data_fragment_size) ?
2231 packet_dimension->content : socket_data->data_fragment_size);
2232
2233 for (index = 0; index < fragments; index++) {
2234 /* Read the data fragment */
2235 result = tl_socket_read_packet_data(tcp_globals.net_phone,
2236 &packet, TCP_HEADER_SIZE, packet_dimension,
2237 socket_data->addr, socket_data->addrlen);
2238 if (result < 0)
2239 return result;
2240
2241 total_length = (size_t) result;
2242
2243 /* Prefix the TCP header */
2244 header = PACKET_PREFIX(packet, tcp_header_t);
2245 if (!header)
2246 return tcp_release_and_return(packet, ENOMEM);
2247
2248 tcp_prepare_operation_header(socket, socket_data, header, 0, 0);
2249 rc = tcp_queue_packet(socket, socket_data, packet, 0);
2250 if (rc != EOK)
2251 return rc;
2252 }
2253
2254 /* Flush packets */
2255 packet = tcp_get_packets_to_send(socket, socket_data);
2256 fibril_rwlock_write_unlock(socket_data->local_lock);
2257 fibril_rwlock_read_unlock(&tcp_globals.lock);
2258
2259 if (packet) {
2260 /* Send the packet */
2261 tcp_send_packets(socket_data->device_id, packet);
2262 }
2263
2264 return EOK;
2265}
2266
2267int
2268tcp_close_message(socket_cores_t *local_sockets, int socket_id)
2269{
2270 socket_core_t *socket;
2271 tcp_socket_data_t *socket_data;
2272 packet_t *packet;
2273 int rc;
2274
2275 /* Find the socket */
2276 socket = socket_cores_find(local_sockets, socket_id);
2277 if (!socket)
2278 return ENOTSOCK;
2279
2280 /* Get the socket specific data */
2281 socket_data = (tcp_socket_data_t *) socket->specific_data;
2282 assert(socket_data);
2283
2284 /* Check state */
2285 switch (socket_data->state) {
2286 case TCP_SOCKET_ESTABLISHED:
2287 socket_data->state = TCP_SOCKET_FIN_WAIT_1;
2288 break;
2289
2290 case TCP_SOCKET_CLOSE_WAIT:
2291 socket_data->state = TCP_SOCKET_LAST_ACK;
2292 break;
2293
2294// case TCP_SOCKET_LISTEN:
2295
2296 default:
2297 /* Just destroy */
2298 rc = socket_destroy(tcp_globals.net_phone, socket_id,
2299 local_sockets, &tcp_globals.sockets,
2300 tcp_free_socket_data);
2301 if (rc == EOK) {
2302 fibril_rwlock_write_unlock(socket_data->local_lock);
2303 fibril_rwlock_write_unlock(&tcp_globals.lock);
2304 }
2305 return rc;
2306 }
2307
2308 /*
2309 * Send FIN.
2310 * TODO should I wait to complete?
2311 */
2312
2313 /* Create the notification packet */
2314 rc = tcp_create_notification_packet(&packet, socket, socket_data, 0, 1);
2315 if (rc != EOK)
2316 return rc;
2317
2318 /* Send the packet */
2319 rc = tcp_queue_packet(socket, socket_data, packet, 1);
2320 if (rc != EOK)
2321 return rc;
2322
2323 /* Flush packets */
2324 packet = tcp_get_packets_to_send(socket, socket_data);
2325 fibril_rwlock_write_unlock(socket_data->local_lock);
2326 fibril_rwlock_write_unlock(&tcp_globals.lock);
2327
2328 if (packet) {
2329 /* Send the packet */
2330 tcp_send_packets(socket_data->device_id, packet);
2331 }
2332
2333 return EOK;
2334}
2335
2336int tcp_create_notification_packet(packet_t **packet, socket_core_t *socket,
2337 tcp_socket_data_t *socket_data, int synchronize, int finalize)
2338{
2339 packet_dimension_t *packet_dimension;
2340 tcp_header_t *header;
2341 int rc;
2342
2343 assert(packet);
2344
2345 /* Get the device packet dimension */
2346 rc = tl_get_ip_packet_dimension(tcp_globals.ip_phone,
2347 &tcp_globals.dimensions, socket_data->device_id, &packet_dimension);
2348 if (rc != EOK)
2349 return rc;
2350
2351 /* Get a new packet */
2352 *packet = packet_get_4_remote(tcp_globals.net_phone, TCP_HEADER_SIZE,
2353 packet_dimension->addr_len, packet_dimension->prefix,
2354 packet_dimension->suffix);
2355
2356 if (!*packet)
2357 return ENOMEM;
2358
2359 /* Allocate space in the packet */
2360 header = PACKET_SUFFIX(*packet, tcp_header_t);
2361 if (!header)
2362 tcp_release_and_return(*packet, ENOMEM);
2363
2364 tcp_prepare_operation_header(socket, socket_data, header, synchronize,
2365 finalize);
2366
2367 return EOK;
2368}
2369
2370int tcp_accept_message(socket_cores_t *local_sockets, int socket_id,
2371 int new_socket_id, size_t *data_fragment_size, size_t *addrlen)
2372{
2373 socket_core_t *accepted;
2374 socket_core_t *socket;
2375 tcp_socket_data_t *socket_data;
2376 packet_dimension_t *packet_dimension;
2377 int rc;
2378
2379 assert(local_sockets);
2380 assert(data_fragment_size);
2381 assert(addrlen);
2382
2383 /* Find the socket */
2384 socket = socket_cores_find(local_sockets, socket_id);
2385 if (!socket)
2386 return ENOTSOCK;
2387
2388 /* Get the socket specific data */
2389 socket_data = (tcp_socket_data_t *) socket->specific_data;
2390 assert(socket_data);
2391
2392 /* Check state */
2393 if (socket_data->state != TCP_SOCKET_LISTEN)
2394 return EINVAL;
2395
2396 do {
2397 socket_id = dyn_fifo_value(&socket->accepted);
2398 if (socket_id < 0)
2399 return ENOTSOCK;
2400 socket_id *= -1;
2401
2402 accepted = socket_cores_find(local_sockets, socket_id);
2403 if (!accepted)
2404 return ENOTSOCK;
2405
2406 /* Get the socket specific data */
2407 socket_data = (tcp_socket_data_t *) accepted->specific_data;
2408 assert(socket_data);
2409 /* TODO can it be in another state? */
2410 if (socket_data->state == TCP_SOCKET_ESTABLISHED) {
2411 rc = data_reply(socket_data->addr,
2412 socket_data->addrlen);
2413 if (rc != EOK)
2414 return rc;
2415 rc = tl_get_ip_packet_dimension(tcp_globals.ip_phone,
2416 &tcp_globals.dimensions, socket_data->device_id,
2417 &packet_dimension);
2418 if (rc != EOK)
2419 return rc;
2420 *addrlen = socket_data->addrlen;
2421
2422 *data_fragment_size =
2423 ((packet_dimension->content <
2424 socket_data->data_fragment_size) ?
2425 packet_dimension->content :
2426 socket_data->data_fragment_size);
2427
2428 if (new_socket_id > 0) {
2429 rc = socket_cores_update(local_sockets,
2430 accepted->socket_id, new_socket_id);
2431 if (rc != EOK)
2432 return rc;
2433 accepted->socket_id = new_socket_id;
2434 }
2435 }
2436 dyn_fifo_pop(&socket->accepted);
2437 } while (socket_data->state != TCP_SOCKET_ESTABLISHED);
2438
2439 printf("ret accept %d\n", accepted->socket_id);
2440 return accepted->socket_id;
2441}
2442
2443void tcp_free_socket_data(socket_core_t *socket)
2444{
2445 tcp_socket_data_t *socket_data;
2446
2447 assert(socket);
2448
2449 printf("destroy_socket %d\n", socket->socket_id);
2450
2451 /* Get the socket specific data */
2452 socket_data = (tcp_socket_data_t *) socket->specific_data;
2453 assert(socket_data);
2454
2455 /* Free the pseudo header */
2456 if (socket_data->pseudo_header) {
2457 if (socket_data->headerlen) {
2458 printf("d pseudo\n");
2459 free(socket_data->pseudo_header);
2460 socket_data->headerlen = 0;
2461 }
2462 socket_data->pseudo_header = NULL;
2463 }
2464
2465 socket_data->headerlen = 0;
2466
2467 /* Free the address */
2468 if (socket_data->addr) {
2469 if (socket_data->addrlen) {
2470 printf("d addr\n");
2471 free(socket_data->addr);
2472 socket_data->addrlen = 0;
2473 }
2474 socket_data->addr = NULL;
2475 }
2476 socket_data->addrlen = 0;
2477}
2478
2479/** Releases the packet and returns the result.
2480 *
2481 * @param[in] packet The packet queue to be released.
2482 * @param[in] result The result to be returned.
2483 * @return The result parameter.
2484 */
2485int tcp_release_and_return(packet_t *packet, int result)
2486{
2487 pq_release_remote(tcp_globals.net_phone, packet_get_id(packet));
2488 return result;
2489}
2490
2491/** Default thread for new connections.
2492 *
2493 * @param[in] iid The initial message identifier.
2494 * @param[in] icall The initial message call structure.
2495 *
2496 */
2497static void tl_client_connection(ipc_callid_t iid, ipc_call_t * icall)
2498{
2499 /*
2500 * Accept the connection
2501 * - Answer the first IPC_M_CONNECT_ME_TO call.
2502 */
2503 ipc_answer_0(iid, EOK);
2504
2505 while (true) {
2506 ipc_call_t answer;
2507 int answer_count;
2508
2509 /* Clear the answer structure */
2510 refresh_answer(&answer, &answer_count);
2511
2512 /* Fetch the next message */
2513 ipc_call_t call;
2514 ipc_callid_t callid = async_get_call(&call);
2515
2516 /* Process the message */
2517 int res = tl_module_message_standalone(callid, &call, &answer,
2518 &answer_count);
2519
2520 /*
2521 * End if told to either by the message or the processing
2522 * result.
2523 */
2524 if ((IPC_GET_IMETHOD(call) == IPC_M_PHONE_HUNGUP) ||
2525 (res == EHANGUP))
2526 return;
2527
2528 /*
2529 * Answer the message
2530 */
2531 answer_call(callid, res, &answer, answer_count);
2532 }
2533}
2534
2535/** Starts the module.
2536 *
2537 * @return EOK on success.
2538 * @return Other error codes as defined for each specific module
2539 * start function.
2540 */
2541int
2542main(int argc, char *argv[])
2543{
2544 int rc;
2545
2546 rc = tl_module_start_standalone(tl_client_connection);
2547 return rc;
2548}
2549
2550/** @}
2551 */
Note: See TracBrowser for help on using the repository browser.