* Close the active socket - send FIN to remote, notify main thread
()
| 295 | * Close the active socket - send FIN to remote, notify main thread |
| 296 | */ |
| 297 | closeSocket() { |
| 298 | // Find the active TCP session (the one that's in FIN_WAIT or ESTABLISHED) |
| 299 | for (const [key, session] of this.natTable) { |
| 300 | if (session.state === 'ESTABLISHED' || session.state === 'FIN_WAIT') { |
| 301 | this.emit('debug', `[TCP] VM closing socket ${key}, state=${session.state}, sending FIN`); |
| 302 | |
| 303 | // If we already received FIN from remote (FIN_WAIT), just send ACK |
| 304 | // Otherwise send FIN to initiate close from our side |
| 305 | if (session.state === 'FIN_WAIT') { |
| 306 | // We already sent FIN-ACK when we received their FIN |
| 307 | // Now just clean up - notify main thread to close the socket |
| 308 | if (this.netPort) { |
| 309 | this.netPort.postMessage({ type: 'tcp-close', key }); |
| 310 | } |
| 311 | } else { |
| 312 | // ESTABLISHED - we're initiating close, send FIN |
| 313 | this.sendTCP(session.srcIP, session.srcPort, session.dstIP, session.dstPort, |
| 314 | session.mySeq, session.myAck, 0x11); // FIN | ACK |
| 315 | session.mySeq++; |
| 316 | |
| 317 | // Notify main thread to close the socket |
| 318 | if (this.netPort) { |
| 319 | this.netPort.postMessage({ type: 'tcp-close', key }); |
| 320 | } |
| 321 | } |
| 322 | // Delete the session to allow new connections |
| 323 | this.natTable.delete(key); |
| 324 | break; // Only close one socket (we only support one connection at a time currently) |
| 325 | } |
| 326 | } |
| 327 | |
| 328 | // Also clean up any stale closed sessions |
| 329 | for (const [key, session] of this.natTable) { |
| 330 | if (session.state === 'CLOSED_BY_REMOTE' || session.state === 'CLOSED' || session.state === 'FIN_SENT') { |
| 331 | this.emit('debug', `[TCP] Cleaning up stale session ${key}, state=${session.state}`); |
| 332 | this.natTable.delete(key); |
| 333 | } |
| 334 | } |
| 335 | } |
| 336 | |
| 337 | hasPendingData() { |
| 338 | return this.txBuffer.length > 0; |