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

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

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

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