File size: 26,100 Bytes
aaaaa79
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
"""
TCP Engine Module

Implements a complete TCP state machine in user-space:
- Full TCP state machine (SYN, SYN-ACK, ESTABLISHED, FIN, RST)
- Sequence and acknowledgment number tracking
- Sliding window implementation
- Retransmission and timeout handling
- Congestion control
"""

import time
import threading
import random
from typing import Dict, List, Optional, Tuple, Callable
from dataclasses import dataclass, field
from enum import Enum
from collections import deque

from .ip_parser import TCPHeader, IPv4Header, IPParser


class TCPState(Enum):
    CLOSED = "CLOSED"
    LISTEN = "LISTEN"
    SYN_SENT = "SYN_SENT"
    SYN_RECEIVED = "SYN_RECEIVED"
    ESTABLISHED = "ESTABLISHED"
    FIN_WAIT_1 = "FIN_WAIT_1"
    FIN_WAIT_2 = "FIN_WAIT_2"
    CLOSE_WAIT = "CLOSE_WAIT"
    CLOSING = "CLOSING"
    LAST_ACK = "LAST_ACK"
    TIME_WAIT = "TIME_WAIT"


@dataclass
class TCPSegment:
    """Represents a TCP segment"""
    seq_num: int
    ack_num: int
    flags: int
    window: int
    data: bytes
    timestamp: float = field(default_factory=time.time)
    retransmit_count: int = 0
    
    @property
    def data_length(self) -> int:
        """Get data length"""
        return len(self.data)
    
    @property
    def seq_end(self) -> int:
        """Get sequence number after this segment"""
        length = self.data_length
        # SYN and FIN consume one sequence number
        if self.flags & 0x02:  # SYN
            length += 1
        if self.flags & 0x01:  # FIN
            length += 1
        return self.seq_num + length


@dataclass
class TCPConnection:
    """Represents a TCP connection state"""
    # Connection identification
    local_ip: str
    local_port: int
    remote_ip: str
    remote_port: int
    
    # State
    state: TCPState = TCPState.CLOSED
    
    # Sequence numbers
    local_seq: int = 0
    local_ack: int = 0
    remote_seq: int = 0
    remote_ack: int = 0
    initial_seq: int = 0
    
    # Window management
    local_window: int = 65535
    remote_window: int = 65535
    window_scale: int = 0
    
    # Buffers
    send_buffer: deque = field(default_factory=deque)
    recv_buffer: deque = field(default_factory=deque)
    out_of_order_buffer: Dict[int, bytes] = field(default_factory=dict)
    
    # Retransmission
    unacked_segments: Dict[int, TCPSegment] = field(default_factory=dict)
    retransmit_timer: Optional[float] = None
    rto: float = 1.0  # Retransmission timeout
    srtt: float = 0.0  # Smoothed round-trip time
    rttvar: float = 0.0  # Round-trip time variation
    
    # Congestion control
    cwnd: int = 1  # Congestion window (in MSS units)
    ssthresh: int = 65535  # Slow start threshold
    mss: int = 1460  # Maximum segment size
    
    # Timers
    last_activity: float = field(default_factory=time.time)
    time_wait_start: Optional[float] = None
    
    # Callbacks
    on_data_received: Optional[Callable[[bytes], None]] = None
    on_connection_closed: Optional[Callable[[], None]] = None
    
    @property
    def connection_id(self) -> str:
        """Get unique connection identifier"""
        return f"{self.local_ip}:{self.local_port}-{self.remote_ip}:{self.remote_port}"
    
    @property
    def is_established(self) -> bool:
        """Check if connection is established"""
        return self.state == TCPState.ESTABLISHED
    
    @property
    def can_send_data(self) -> bool:
        """Check if connection can send data"""
        return self.state in [TCPState.ESTABLISHED, TCPState.CLOSE_WAIT]
    
    @property
    def effective_window(self) -> int:
        """Get effective send window"""
        return min(self.remote_window, self.cwnd * self.mss)


class TCPEngine:
    """TCP state machine implementation"""
    
    def __init__(self, config: Dict):
        self.config = config
        self.connections: Dict[str, TCPConnection] = {}
        self.listening_ports: Dict[int, Callable] = {}  # port -> accept callback
        self.lock = threading.Lock()
        self.running = False
        self.timer_thread = None
        
        # Default configuration
        self.default_mss = config.get('mss', 1460)
        self.default_window = config.get('initial_window', 65535)
        self.max_retries = config.get('max_retries', 3)
        self.connection_timeout = config.get('timeout', 300)
        self.time_wait_timeout = config.get('time_wait_timeout', 120)
    
    def _generate_isn(self) -> int:
        """Generate Initial Sequence Number"""
        return random.randint(0, 0xFFFFFFFF)
    
    def _get_connection_key(self, local_ip: str, local_port: int, remote_ip: str, remote_port: int) -> str:
        """Get connection key"""
        return f"{local_ip}:{local_port}-{remote_ip}:{remote_port}"
    
    def _create_tcp_segment(self, conn: TCPConnection, flags: int, data: bytes = b'') -> TCPSegment:
        """Create TCP segment"""
        segment = TCPSegment(
            seq_num=conn.local_seq,
            ack_num=conn.local_ack,
            flags=flags,
            window=conn.local_window,
            data=data
        )
        return segment
    
    def _build_tcp_packet(self, conn: TCPConnection, segment: TCPSegment) -> bytes:
        """Build complete TCP packet"""
        # Create IP header
        ip_header = IPv4Header(
            protocol=6,  # TCP
            source_ip=conn.local_ip,
            dest_ip=conn.remote_ip,
            ttl=64
        )
        
        # Create TCP header
        tcp_header = TCPHeader(
            source_port=conn.local_port,
            dest_port=conn.remote_port,
            seq_num=segment.seq_num,
            ack_num=segment.ack_num,
            flags=segment.flags,
            window_size=segment.window
        )
        
        # Build packet
        return IPParser.build_packet(ip_header, tcp_header, segment.data)
    
    def _update_rto(self, conn: TCPConnection, rtt: float):
        """Update retransmission timeout using RFC 6298"""
        if conn.srtt == 0:
            # First RTT measurement
            conn.srtt = rtt
            conn.rttvar = rtt / 2
        else:
            # Subsequent measurements
            alpha = 0.125
            beta = 0.25
            conn.rttvar = (1 - beta) * conn.rttvar + beta * abs(conn.srtt - rtt)
            conn.srtt = (1 - alpha) * conn.srtt + alpha * rtt
        
        # Calculate RTO
        conn.rto = max(1.0, conn.srtt + 4 * conn.rttvar)
        conn.rto = min(conn.rto, 60.0)  # Cap at 60 seconds
    
    def _update_congestion_window(self, conn: TCPConnection, acked_bytes: int):
        """Update congestion window (simplified congestion control)"""
        if conn.cwnd < conn.ssthresh:
            # Slow start
            conn.cwnd += 1
        else:
            # Congestion avoidance
            conn.cwnd += max(1, conn.mss * conn.mss // conn.cwnd)
    
    def _handle_retransmission(self, conn: TCPConnection):
        """Handle segment retransmission"""
        current_time = time.time()
        
        # Find segments that need retransmission
        to_retransmit = []
        for seq_num, segment in conn.unacked_segments.items():
            if current_time - segment.timestamp > conn.rto:
                if segment.retransmit_count < self.max_retries:
                    to_retransmit.append(segment)
                else:
                    # Max retries exceeded, close connection
                    self._close_connection(conn, reset=True)
                    return
        
        # Retransmit segments
        for segment in to_retransmit:
            segment.retransmit_count += 1
            segment.timestamp = current_time
            
            # Exponential backoff
            conn.rto = min(conn.rto * 2, 60.0)
            
            # Congestion control: reduce window
            conn.ssthresh = max(conn.cwnd // 2, 2)
            conn.cwnd = 1
            
            # Send retransmitted segment
            packet = self._build_tcp_packet(conn, segment)
            self._send_packet(packet)
    
    def _send_packet(self, packet: bytes):
        """Send packet (to be implemented by integration layer)"""
        # This will be connected to the packet bridge
        pass
    
    def _close_connection(self, conn: TCPConnection, reset: bool = False):
        """Close connection"""
        if reset:
            # Send RST
            segment = self._create_tcp_segment(conn, 0x04)  # RST flag
            packet = self._build_tcp_packet(conn, segment)
            self._send_packet(packet)
            conn.state = TCPState.CLOSED
        else:
            # Normal close
            if conn.state == TCPState.ESTABLISHED:
                # Send FIN
                segment = self._create_tcp_segment(conn, 0x01)  # FIN flag
                packet = self._build_tcp_packet(conn, segment)
                self._send_packet(packet)
                conn.local_seq += 1
                conn.state = TCPState.FIN_WAIT_1
        
        # Cleanup if closed
        if conn.state == TCPState.CLOSED:
            if conn.on_connection_closed:
                conn.on_connection_closed()
            
            with self.lock:
                if conn.connection_id in self.connections:
                    del self.connections[conn.connection_id]
    
    def listen(self, port: int, accept_callback: Callable):
        """Listen on port for incoming connections"""
        with self.lock:
            self.listening_ports[port] = accept_callback
    
    def connect(self, local_ip: str, local_port: int, remote_ip: str, remote_port: int) -> Optional[TCPConnection]:
        """Initiate outbound connection"""
        conn_key = self._get_connection_key(local_ip, local_port, remote_ip, remote_port)
        
        # Create connection
        conn = TCPConnection(
            local_ip=local_ip,
            local_port=local_port,
            remote_ip=remote_ip,
            remote_port=remote_port,
            state=TCPState.SYN_SENT,
            local_seq=self._generate_isn(),
            mss=self.default_mss,
            local_window=self.default_window
        )
        conn.initial_seq = conn.local_seq
        
        with self.lock:
            self.connections[conn_key] = conn
        
        # Send SYN
        segment = self._create_tcp_segment(conn, 0x02)  # SYN flag
        packet = self._build_tcp_packet(conn, segment)
        self._send_packet(packet)
        
        # Track unacked segment
        conn.unacked_segments[conn.local_seq] = segment
        conn.local_seq += 1
        conn.retransmit_timer = time.time()
        
        return conn
    
    def send_data(self, conn: TCPConnection, data: bytes) -> bool:
        """Send data on established connection"""
        if not conn.can_send_data:
            return False
        
        # Add to send buffer
        conn.send_buffer.append(data)
        
        # Try to send immediately
        self._try_send_data(conn)
        
        return True
    
    def _try_send_data(self, conn: TCPConnection):
        """Try to send buffered data"""
        while conn.send_buffer and len(conn.unacked_segments) * conn.mss < conn.effective_window:
            data = conn.send_buffer.popleft()
            
            # Split data if larger than MSS
            while data:
                chunk = data[:conn.mss]
                data = data[conn.mss:]
                
                # Create and send segment
                segment = self._create_tcp_segment(conn, 0x18, chunk)  # PSH+ACK flags
                packet = self._build_tcp_packet(conn, segment)
                self._send_packet(packet)
                
                # Track unacked segment
                conn.unacked_segments[conn.local_seq] = segment
                conn.local_seq += len(chunk)
                
                if not data:
                    break
    
    def process_packet(self, packet_data: bytes) -> bool:
        """Process incoming TCP packet"""
        try:
            # Parse packet
            parsed = IPParser.parse_packet(packet_data)
            if not isinstance(parsed.transport_header, TCPHeader):
                return False
            
            ip_header = parsed.ip_header
            tcp_header = parsed.transport_header
            payload = parsed.payload
            
            # Find or create connection
            conn_key = self._get_connection_key(
                ip_header.dest_ip, tcp_header.dest_port,
                ip_header.source_ip, tcp_header.source_port
            )
            
            with self.lock:
                conn = self.connections.get(conn_key)
                
                # Handle new connection (SYN to listening port)
                if not conn and tcp_header.syn and not tcp_header.ack:
                    if tcp_header.dest_port in self.listening_ports:
                        conn = self._handle_new_connection(ip_header, tcp_header)
                        if conn:
                            self.connections[conn_key] = conn
                
                if not conn:
                    # Send RST for unknown connection
                    self._send_rst(ip_header, tcp_header)
                    return False
            
            # Process segment
            return self._process_segment(conn, tcp_header, payload)
            
        except Exception as e:
            print(f"Error processing TCP packet: {e}")
            return False
    
    def _handle_new_connection(self, ip_header: IPv4Header, tcp_header: TCPHeader) -> Optional[TCPConnection]:
        """Handle new incoming connection"""
        accept_callback = self.listening_ports.get(tcp_header.dest_port)
        if not accept_callback:
            return None
        
        # Create connection
        conn = TCPConnection(
            local_ip=ip_header.dest_ip,
            local_port=tcp_header.dest_port,
            remote_ip=ip_header.source_ip,
            remote_port=tcp_header.source_port,
            state=TCPState.SYN_RECEIVED,
            local_seq=self._generate_isn(),
            remote_seq=tcp_header.seq_num,
            local_ack=tcp_header.seq_num + 1,
            mss=self.default_mss,
            local_window=self.default_window
        )
        conn.initial_seq = conn.local_seq
        
        # Send SYN-ACK
        segment = self._create_tcp_segment(conn, 0x12)  # SYN+ACK flags
        packet = self._build_tcp_packet(conn, segment)
        self._send_packet(packet)
        
        # Track unacked segment
        conn.unacked_segments[conn.local_seq] = segment
        conn.local_seq += 1
        conn.retransmit_timer = time.time()
        
        # Call accept callback
        accept_callback(conn)
        
        return conn
    
    def _process_segment(self, conn: TCPConnection, tcp_header: TCPHeader, payload: bytes) -> bool:
        """Process TCP segment based on connection state"""
        conn.last_activity = time.time()
        
        # Handle RST
        if tcp_header.rst:
            conn.state = TCPState.CLOSED
            self._close_connection(conn)
            return True
        
        # State machine
        if conn.state == TCPState.SYN_SENT:
            return self._handle_syn_sent(conn, tcp_header, payload)
        elif conn.state == TCPState.SYN_RECEIVED:
            return self._handle_syn_received(conn, tcp_header, payload)
        elif conn.state == TCPState.ESTABLISHED:
            return self._handle_established(conn, tcp_header, payload)
        elif conn.state == TCPState.FIN_WAIT_1:
            return self._handle_fin_wait_1(conn, tcp_header, payload)
        elif conn.state == TCPState.FIN_WAIT_2:
            return self._handle_fin_wait_2(conn, tcp_header, payload)
        elif conn.state == TCPState.CLOSE_WAIT:
            return self._handle_close_wait(conn, tcp_header, payload)
        elif conn.state == TCPState.CLOSING:
            return self._handle_closing(conn, tcp_header, payload)
        elif conn.state == TCPState.LAST_ACK:
            return self._handle_last_ack(conn, tcp_header, payload)
        elif conn.state == TCPState.TIME_WAIT:
            return self._handle_time_wait(conn, tcp_header, payload)
        
        return False
    
    def _handle_syn_sent(self, conn: TCPConnection, tcp_header: TCPHeader, payload: bytes) -> bool:
        """Handle segment in SYN_SENT state"""
        if tcp_header.syn and tcp_header.ack:
            # SYN-ACK received
            if tcp_header.ack_num == conn.local_seq:
                conn.remote_seq = tcp_header.seq_num
                conn.local_ack = tcp_header.seq_num + 1
                conn.remote_window = tcp_header.window_size
                
                # Remove SYN from unacked segments
                if conn.local_seq - 1 in conn.unacked_segments:
                    del conn.unacked_segments[conn.local_seq - 1]
                
                # Send ACK
                segment = self._create_tcp_segment(conn, 0x10)  # ACK flag
                packet = self._build_tcp_packet(conn, segment)
                self._send_packet(packet)
                
                conn.state = TCPState.ESTABLISHED
                return True
        
        return False
    
    def _handle_syn_received(self, conn: TCPConnection, tcp_header: TCPHeader, payload: bytes) -> bool:
        """Handle segment in SYN_RECEIVED state"""
        if tcp_header.ack and tcp_header.ack_num == conn.local_seq:
            # ACK for our SYN-ACK
            conn.remote_window = tcp_header.window_size
            
            # Remove SYN-ACK from unacked segments
            if conn.local_seq - 1 in conn.unacked_segments:
                del conn.unacked_segments[conn.local_seq - 1]
            
            conn.state = TCPState.ESTABLISHED
            return True
        
        return False
    
    def _handle_established(self, conn: TCPConnection, tcp_header: TCPHeader, payload: bytes) -> bool:
        """Handle segment in ESTABLISHED state"""
        # Handle ACK
        if tcp_header.ack:
            self._process_ack(conn, tcp_header.ack_num)
        
        # Handle data
        if payload and tcp_header.seq_num == conn.local_ack:
            conn.local_ack += len(payload)
            
            # Deliver data
            if conn.on_data_received:
                conn.on_data_received(payload)
            
            # Send ACK
            segment = self._create_tcp_segment(conn, 0x10)  # ACK flag
            packet = self._build_tcp_packet(conn, segment)
            self._send_packet(packet)
        
        # Handle FIN
        if tcp_header.fin:
            conn.local_ack += 1
            
            # Send ACK
            segment = self._create_tcp_segment(conn, 0x10)  # ACK flag
            packet = self._build_tcp_packet(conn, segment)
            self._send_packet(packet)
            
            conn.state = TCPState.CLOSE_WAIT
        
        return True
    
    def _handle_fin_wait_1(self, conn: TCPConnection, tcp_header: TCPHeader, payload: bytes) -> bool:
        """Handle segment in FIN_WAIT_1 state"""
        if tcp_header.ack:
            self._process_ack(conn, tcp_header.ack_num)
            if not conn.unacked_segments:  # Our FIN was ACKed
                conn.state = TCPState.FIN_WAIT_2
        
        if tcp_header.fin:
            conn.local_ack += 1
            
            # Send ACK
            segment = self._create_tcp_segment(conn, 0x10)  # ACK flag
            packet = self._build_tcp_packet(conn, segment)
            self._send_packet(packet)
            
            if conn.state == TCPState.FIN_WAIT_2:
                conn.state = TCPState.TIME_WAIT
                conn.time_wait_start = time.time()
            else:
                conn.state = TCPState.CLOSING
        
        return True
    
    def _handle_fin_wait_2(self, conn: TCPConnection, tcp_header: TCPHeader, payload: bytes) -> bool:
        """Handle segment in FIN_WAIT_2 state"""
        if tcp_header.fin:
            conn.local_ack += 1
            
            # Send ACK
            segment = self._create_tcp_segment(conn, 0x10)  # ACK flag
            packet = self._build_tcp_packet(conn, segment)
            self._send_packet(packet)
            
            conn.state = TCPState.TIME_WAIT
            conn.time_wait_start = time.time()
        
        return True
    
    def _handle_close_wait(self, conn: TCPConnection, tcp_header: TCPHeader, payload: bytes) -> bool:
        """Handle segment in CLOSE_WAIT state"""
        # Application should close the connection
        return True
    
    def _handle_closing(self, conn: TCPConnection, tcp_header: TCPHeader, payload: bytes) -> bool:
        """Handle segment in CLOSING state"""
        if tcp_header.ack:
            self._process_ack(conn, tcp_header.ack_num)
            if not conn.unacked_segments:  # Our FIN was ACKed
                conn.state = TCPState.TIME_WAIT
                conn.time_wait_start = time.time()
        
        return True
    
    def _handle_last_ack(self, conn: TCPConnection, tcp_header: TCPHeader, payload: bytes) -> bool:
        """Handle segment in LAST_ACK state"""
        if tcp_header.ack:
            self._process_ack(conn, tcp_header.ack_num)
            if not conn.unacked_segments:  # Our FIN was ACKed
                conn.state = TCPState.CLOSED
                self._close_connection(conn)
        
        return True
    
    def _handle_time_wait(self, conn: TCPConnection, tcp_header: TCPHeader, payload: bytes) -> bool:
        """Handle segment in TIME_WAIT state"""
        # Just acknowledge any segments
        if tcp_header.seq_num == conn.local_ack:
            segment = self._create_tcp_segment(conn, 0x10)  # ACK flag
            packet = self._build_tcp_packet(conn, segment)
            self._send_packet(packet)
        
        return True
    
    def _process_ack(self, conn: TCPConnection, ack_num: int):
        """Process ACK and remove acknowledged segments"""
        acked_segments = []
        acked_bytes = 0
        
        for seq_num, segment in list(conn.unacked_segments.items()):
            if seq_num < ack_num:
                acked_segments.append((seq_num, segment))
                acked_bytes += segment.data_length
                del conn.unacked_segments[seq_num]
        
        # Update RTT and congestion window
        if acked_segments:
            # Use first acked segment for RTT calculation
            rtt = time.time() - acked_segments[0][1].timestamp
            self._update_rto(conn, rtt)
            self._update_congestion_window(conn, acked_bytes)
            
            # Try to send more data
            self._try_send_data(conn)
    
    def _send_rst(self, ip_header: IPv4Header, tcp_header: TCPHeader):
        """Send RST for unknown connection"""
        # Create RST response
        rst_ip = IPv4Header(
            protocol=6,
            source_ip=ip_header.dest_ip,
            dest_ip=ip_header.source_ip,
            ttl=64
        )
        
        rst_tcp = TCPHeader(
            source_port=tcp_header.dest_port,
            dest_port=tcp_header.source_port,
            seq_num=tcp_header.ack_num if tcp_header.ack else 0,
            ack_num=tcp_header.seq_num + 1 if tcp_header.syn else tcp_header.seq_num,
            flags=0x14 if tcp_header.ack else 0x04  # RST+ACK or RST
        )
        
        packet = IPParser.build_packet(rst_ip, rst_tcp)
        self._send_packet(packet)
    
    def _timer_loop(self):
        """Timer loop for handling timeouts"""
        while self.running:
            current_time = time.time()
            
            with self.lock:
                connections_to_check = list(self.connections.values())
            
            for conn in connections_to_check:
                # Handle retransmissions
                if conn.unacked_segments:
                    self._handle_retransmission(conn)
                
                # Handle connection timeout
                if current_time - conn.last_activity > self.connection_timeout:
                    self._close_connection(conn, reset=True)
                
                # Handle TIME_WAIT timeout
                if (conn.state == TCPState.TIME_WAIT and 
                    conn.time_wait_start and 
                    current_time - conn.time_wait_start > self.time_wait_timeout):
                    conn.state = TCPState.CLOSED
                    self._close_connection(conn)
            
            time.sleep(1)  # Check every second
    
    def start(self):
        """Start TCP engine"""
        self.running = True
        self.timer_thread = threading.Thread(target=self._timer_loop, daemon=True)
        self.timer_thread.start()
        print("TCP engine started")
    
    def stop(self):
        """Stop TCP engine"""
        self.running = False
        if self.timer_thread:
            self.timer_thread.join()
        
        # Close all connections
        with self.lock:
            for conn in list(self.connections.values()):
                self._close_connection(conn, reset=True)
        
        print("TCP engine stopped")
    
    def get_connections(self) -> Dict[str, Dict]:
        """Get current connections"""
        with self.lock:
            return {
                conn_id: {
                    'local_ip': conn.local_ip,
                    'local_port': conn.local_port,
                    'remote_ip': conn.remote_ip,
                    'remote_port': conn.remote_port,
                    'state': conn.state.value,
                    'local_seq': conn.local_seq,
                    'local_ack': conn.local_ack,
                    'remote_seq': conn.remote_seq,
                    'remote_ack': conn.remote_ack,
                    'window_size': conn.local_window,
                    'cwnd': conn.cwnd,
                    'unacked_segments': len(conn.unacked_segments),
                    'last_activity': conn.last_activity
                }
                for conn_id, conn in self.connections.items()
            }