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