/* * Copyright 2006-2008, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: * Axel Dörfler, axeld@pinc-software.de * Andrew Galante, haiku.galante@gmail.com * Hugo Santos, hugosantos@gmail.com */ #ifndef TCP_H #define TCP_H #include #include #include #include #include #include #include class EndpointManager; enum tcp_state { // establishing a connection CLOSED, LISTEN, SYNCHRONIZE_SENT, SYNCHRONIZE_RECEIVED, ESTABLISHED, // peer closes the connection FINISH_RECEIVED, WAIT_FOR_FINISH_ACKNOWLEDGE, // we close the connection FINISH_SENT, FINISH_ACKNOWLEDGED, CLOSING, TIME_WAIT }; struct tcp_header { uint16 source_port; uint16 destination_port; uint32 sequence; uint32 acknowledge; struct { #if B_HOST_IS_LENDIAN == 1 uint8 reserved : 4; uint8 header_length : 4; #else uint8 header_length : 4; uint8 reserved : 4; #endif }; uint8 flags; uint16 advertised_window; uint16 checksum; uint16 urgent_offset; uint32 HeaderLength() const { return (uint32)header_length << 2; } uint32 Sequence() const { return ntohl(sequence); } uint32 Acknowledge() const { return ntohl(acknowledge); } uint16 AdvertisedWindow() const { return ntohs(advertised_window); } uint16 Checksum() const { return ntohs(checksum); } uint16 UrgentOffset() const { return ntohs(urgent_offset); } } _PACKED; class tcp_sequence { public: inline tcp_sequence() {} inline tcp_sequence(uint32 sequence) : fNumber(sequence) { } inline uint32 Number() const { return fNumber; } inline tcp_sequence& operator=(tcp_sequence sequence) { fNumber = sequence.fNumber; return *this; } inline tcp_sequence& operator+=(tcp_sequence sequence) { fNumber += sequence.fNumber; return *this; } inline tcp_sequence& operator++() { fNumber++; return *this; } inline tcp_sequence operator++(int _) { fNumber++; return fNumber - 1; } // Conceptually private, but used in global operators. //private: uint32 fNumber; }; // Global tcp_sequence Operators inline bool operator>(tcp_sequence a, tcp_sequence b) { return (int32)(a.fNumber - b.fNumber) > 0; } inline bool operator>=(tcp_sequence a, tcp_sequence b) { return (int32)(a.fNumber - b.fNumber) >= 0; } inline bool operator<(tcp_sequence a, tcp_sequence b) { return (int32)(a.fNumber - b.fNumber) < 0; } inline bool operator<=(tcp_sequence a, tcp_sequence b) { return (int32)(a.fNumber - b.fNumber) <= 0; } inline tcp_sequence operator+(tcp_sequence a, tcp_sequence b) { return a.fNumber + b.fNumber; } inline tcp_sequence operator-(tcp_sequence a, tcp_sequence b) { return a.fNumber - b.fNumber; } inline bool operator!=(tcp_sequence a, tcp_sequence b) { return a.fNumber != b.fNumber; } inline bool operator==(tcp_sequence a, tcp_sequence b) { return a.fNumber == b.fNumber; } // TCP flag constants #define TCP_FLAG_FINISH 0x01 #define TCP_FLAG_SYNCHRONIZE 0x02 #define TCP_FLAG_RESET 0x04 #define TCP_FLAG_PUSH 0x08 #define TCP_FLAG_ACKNOWLEDGE 0x10 #define TCP_FLAG_URGENT 0x20 #define TCP_FLAG_CONGESTION_NOTIFICATION_ECHO 0x40 #define TCP_FLAG_CONGESTION_WINDOW_REDUCED 0x80 #define TCP_CONNECTION_TIMEOUT 75000000 // 75 secs #define TCP_DELAYED_ACKNOWLEDGE_TIMEOUT 100000 // 100 msecs #define TCP_DEFAULT_MAX_SEGMENT_SIZE 536 #define TCP_MAX_WINDOW 65535 #define TCP_MAX_SEGMENT_LIFETIME 60000000 // 60 secs struct tcp_sack { uint32 left_edge; uint32 right_edge; } _PACKED; struct tcp_option { uint8 kind; uint8 length; union { uint8 window_shift; uint16 max_segment_size; struct { uint32 value; uint32 reply; } timestamp; tcp_sack sack[0]; }; } _PACKED; enum tcp_option_kind { TCP_OPTION_END = 0, TCP_OPTION_NOP = 1, TCP_OPTION_MAX_SEGMENT_SIZE = 2, TCP_OPTION_WINDOW_SHIFT = 3, TCP_OPTION_SACK_PERMITTED = 4, TCP_OPTION_SACK = 5, TCP_OPTION_TIMESTAMP = 8, }; #define TCP_MAX_WINDOW_SHIFT 14 enum { TCP_HAS_WINDOW_SCALE = 1 << 0, TCP_HAS_TIMESTAMPS = 1 << 1, TCP_SACK_PERMITTED = 1 << 2, }; struct tcp_segment_header { tcp_segment_header(uint8 _flags) : flags(_flags), window_shift(0), max_segment_size(0), sack_count(0), options(0) {} uint32 sequence; uint32 acknowledge; uint16 advertised_window; uint16 urgent_offset; uint8 flags; uint8 window_shift; uint16 max_segment_size; uint32 timestamp_value; uint32 timestamp_reply; tcp_sack *sacks; int sack_count; uint32 options; bool AcknowledgeOnly() const { return (flags & (TCP_FLAG_SYNCHRONIZE | TCP_FLAG_FINISH | TCP_FLAG_RESET | TCP_FLAG_URGENT | TCP_FLAG_ACKNOWLEDGE)) == TCP_FLAG_ACKNOWLEDGE; } }; enum tcp_segment_action { KEEP = 0x00, DROP = 0x01, RESET = 0x02, ACKNOWLEDGE = 0x04, IMMEDIATE_ACKNOWLEDGE = 0x08, DELETE_ENDPOINT = 0x10, }; extern net_buffer_module_info* gBufferModule; extern net_datalink_module_info* gDatalinkModule; extern net_socket_module_info* gSocketModule; extern net_stack_module_info* gStackModule; EndpointManager* get_endpoint_manager(net_domain* domain); void put_endpoint_manager(EndpointManager* manager); status_t add_tcp_header(net_address_module_info* addressModule, tcp_segment_header& segment, net_buffer* buffer); size_t tcp_options_length(tcp_segment_header& segment); const char* name_for_state(tcp_state state); #endif // TCP_H