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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since eb221e5 was 228e490, checked in by Martin Decky <martin@…>, 15 years ago

initial modifications for supporting declarative IPC interfaces

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