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

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

Fix style of function headers and comments.

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