source: mainline/uspace/srv/net/tl/tcp/tcp.c@ 5fe7692

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5fe7692 was 5fe7692, checked in by Petr Koupy <petr.koupy@…>, 14 years ago

Removed side effects from map ADTs.

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