bool handle_wait(pid_t pid, int status, int count, int *continued, int *terminated) { unsigned int alarm_remaining_sec = waitproc_flags_test(WAITPROC_FLAG_ALARMSET) ? alarm(0) : 0; if (pid != -1) { struct flagged_int *p = get_flagged_int(&waitproc_options.pids, pid); assert(p); if (WIFSTOPPED(status)) { long r = WSTOPSIG(status); assert(p->valid); switch (r) { case SIGSTOP: if (p->state == STATE_ATTACHED) { p->state = STATE_CONTINUED; r = 0; assert(*continued < count); if (++(*continued) == count) set_alarm(); } else { r = SIGCONT; } break; case SIGTSTP: r = SIGCONT; break; default: // forward the signal break; } if (r >= 0) { assert(p->state >= STATE_ATTACHED); r = ptrace(PTRACE_CONT, pid, 0, r); assert(r == 0); } } else if (WIFEXITED(status) || WIFSIGNALED(status)) { assert(p->valid && p->state < STATE_TERMINATED); p->state = STATE_TERMINATED; p->valid = false; print_terminated_process(pid); if (++(*terminated) == count) return false; } } else switch (errno) { case EINTR: if (waitproc_options.last_signal == SIGALRM) { waitproc_options.last_signal = SIGINVALID; if (DEBUG || !alarm_remaining_sec) return false; } else { fputs("Interrupted by unexpected signal\n", stderr); UNEXPECTED_STATE(); } break; case ECHILD: *terminated = count; return false; default: UNEXPECTED_STATE(); break; } assert(*terminated < count); if (alarm_remaining_sec) alarm(alarm_remaining_sec); return true; }
int CTCPConnection::Accept (CIPAddress *pForeignIP, u16 *pForeignPort) { switch (m_State) { case TCPStateSynSent: UNEXPECTED_STATE (); // fall through case TCPStateClosed: case TCPStateFinWait1: case TCPStateFinWait2: case TCPStateCloseWait: case TCPStateClosing: case TCPStateLastAck: case TCPStateTimeWait: return -1; case TCPStateListen: m_Event.Clear (); m_Event.Wait (); break; case TCPStateSynReceived: case TCPStateEstablished: break; } assert (pForeignIP != 0); pForeignIP->Set (m_ForeignIP); assert (pForeignPort != 0); *pForeignPort = m_nForeignPort; return 0; }
int CTCPConnection::Connect (void) { if (m_nErrno < 0) { return m_nErrno; } switch (m_State) { case TCPStateSynSent: case TCPStateSynReceived: m_Event.Clear (); m_Event.Wait (); break; case TCPStateEstablished: break; case TCPStateListen: case TCPStateFinWait1: case TCPStateFinWait2: case TCPStateCloseWait: case TCPStateClosing: case TCPStateLastAck: case TCPStateTimeWait: UNEXPECTED_STATE (); // fall through case TCPStateClosed: return -1; } return m_nErrno; }
bool send_signal(struct flagged_int *p, void *data_) { struct trace_data *data = (struct trace_data*) data_; const int *signal; int count = 0; if (inrange(p->state, STATE_ATTACHED, STATE_DETACHED)) { for (signal = data->d.signal; *signal != SIGINVALID; signal++) { if (kill((pid_t) p->i, *signal) == 0) { p->state = data->target_state; if (data->target_state == STATE_TERMINATED) p->valid = false; count++; } else { p->valid = false; switch (errno) { case ESRCH: p->state = STATE_TERMINATED; break; default: assert(errno != EINVAL); UNEXPECTED_STATE(); break; } break; } } } if (count) data->count++; return true; }
int CTCPConnection::PacketReceived (const void *pPacket, unsigned nLength, CIPAddress &rSenderIP, int nProtocol) { if (nProtocol != IPPROTO_TCP) { return 0; } if (nLength < sizeof (TTCPHeader)) { return -1; } assert (pPacket != 0); TTCPHeader *pHeader = (TTCPHeader *) pPacket; if (m_nOwnPort != be2le16 (pHeader->nDestPort)) { return 0; } if (m_State != TCPStateListen) { if ( m_ForeignIP != rSenderIP || m_nForeignPort != be2le16 (pHeader->nSourcePort)) { return 0; } } else { if (!(pHeader->nDataOffsetFlags & TCP_FLAG_SYN)) { return 0; } m_Checksum.SetDestinationAddress (rSenderIP); } if (m_Checksum.Calculate (pPacket, nLength) != CHECKSUM_OK) { return 0; } u16 nFlags = pHeader->nDataOffsetFlags; u32 nDataOffset = TCP_DATA_OFFSET (pHeader->nDataOffsetFlags)*4; u32 nDataLength = nLength-nDataOffset; // Current Segment Variables u32 nSEG_SEQ = be2le32 (pHeader->nSequenceNumber); u32 nSEG_ACK = be2le32 (pHeader->nAcknowledgmentNumber); u32 nSEG_LEN = nDataLength; if (nFlags & TCP_FLAG_SYN) { nSEG_LEN++; } if (nFlags & TCP_FLAG_FIN) { nSEG_LEN++; } u32 nSEG_WND = be2le16 (pHeader->nWindow); //u16 nSEG_UP = be2le16 (pHeader->nUrgentPointer); //u32 nSEG_PRC; // segment precedence value ScanOptions (pHeader); #ifdef TCP_DEBUG CLogger::Get ()->Write (FromTCP, LogDebug, "rx %c%c%c%c%c%c, seq %u, ack %u, win %u, len %u", nFlags & TCP_FLAG_URGENT ? 'U' : '-', nFlags & TCP_FLAG_ACK ? 'A' : '-', nFlags & TCP_FLAG_PUSH ? 'P' : '-', nFlags & TCP_FLAG_RESET ? 'R' : '-', nFlags & TCP_FLAG_SYN ? 'S' : '-', nFlags & TCP_FLAG_FIN ? 'F' : '-', nSEG_SEQ-m_nIRS, nFlags & TCP_FLAG_ACK ? nSEG_ACK-m_nISS : 0, nSEG_WND, nDataLength); DumpStatus (); #endif boolean bAcceptable = FALSE; // RFC 793 section 3.9 "SEGMENT ARRIVES" switch (m_State) { case TCPStateClosed: if (nFlags & TCP_FLAG_RESET) { // ignore } else if (!(nFlags & TCP_FLAG_ACK)) { m_ForeignIP.Set (rSenderIP); m_nForeignPort = be2le16 (pHeader->nSourcePort); m_Checksum.SetDestinationAddress (rSenderIP); SendSegment (TCP_FLAG_RESET | TCP_FLAG_ACK, 0, nSEG_SEQ+nSEG_LEN); } else { m_ForeignIP.Set (rSenderIP); m_nForeignPort = be2le16 (pHeader->nSourcePort); m_Checksum.SetDestinationAddress (rSenderIP); SendSegment (TCP_FLAG_RESET, nSEG_ACK); } break; case TCPStateListen: if (nFlags & TCP_FLAG_RESET) { // ignore } else if (nFlags & TCP_FLAG_ACK) { m_ForeignIP.Set (rSenderIP); m_nForeignPort = be2le16 (pHeader->nSourcePort); m_Checksum.SetDestinationAddress (rSenderIP); SendSegment (TCP_FLAG_RESET, nSEG_ACK); } else if (nFlags & TCP_FLAG_SYN) { m_nRCV_NXT = nSEG_SEQ+1; m_nIRS = nSEG_SEQ; m_nSND_WND = nSEG_WND; m_nSND_WL1 = nSEG_SEQ; m_nSND_WL2 = nSEG_ACK; assert (nSEG_LEN > 0); if (nDataLength > 0) { m_RxQueue.Enqueue ((u8 *) pPacket+nDataOffset, nDataLength); } m_nISS = CalculateISN (); m_RTOCalculator.Initialize (m_nISS); m_ForeignIP.Set (rSenderIP); m_nForeignPort = be2le16 (pHeader->nSourcePort); m_Checksum.SetDestinationAddress (rSenderIP); SendSegment (TCP_FLAG_SYN | TCP_FLAG_ACK, m_nISS, m_nRCV_NXT); m_RTOCalculator.SegmentSent (m_nISS); m_nSND_NXT = m_nISS+1; m_nSND_UNA = m_nISS; NEW_STATE (TCPStateSynReceived); m_Event.Set (); } break; case TCPStateSynSent: if (nFlags & TCP_FLAG_ACK) { if (!bwh (m_nISS, nSEG_ACK, m_nSND_NXT)) { if (!(nFlags & TCP_FLAG_RESET)) { SendSegment (TCP_FLAG_RESET, nSEG_ACK); } return 1; } else if (bwlh (m_nSND_UNA, nSEG_ACK, m_nSND_NXT)) { bAcceptable = TRUE; } } if (nFlags & TCP_FLAG_RESET) { if (bAcceptable) { NEW_STATE (TCPStateClosed); m_bSendSYN = FALSE; m_nErrno = -1; m_Event.Set (); } break; } if ( (nFlags & TCP_FLAG_ACK) && !bAcceptable) { break; } if (nFlags & TCP_FLAG_SYN) { m_nRCV_NXT = nSEG_SEQ+1; m_nIRS = nSEG_SEQ; if (nFlags & TCP_FLAG_ACK) { m_RTOCalculator.SegmentAcknowledged (nSEG_ACK); if (nSEG_ACK-m_nSND_UNA > 1) { m_RetransmissionQueue.Advance (nSEG_ACK-m_nSND_UNA-1); } m_nSND_UNA = nSEG_ACK; } if (gt (m_nSND_UNA, m_nISS)) { NEW_STATE (TCPStateEstablished); m_bSendSYN = FALSE; StopTimer (TCPTimerRetransmission); // next transmission starts with this count m_nRetransmissionCount = MAX_RETRANSMISSIONS; m_Event.Set (); // RFC 1122 section 4.2.2.20 (c) m_nSND_WND = nSEG_WND; m_nSND_WL1 = nSEG_SEQ; m_nSND_WL2 = nSEG_ACK; SendSegment (TCP_FLAG_ACK, m_nSND_NXT, m_nRCV_NXT); if ( (nFlags & TCP_FLAG_FIN) // other controls? || nDataLength > 0) { goto StepSix; } break; } else { NEW_STATE (TCPStateSynReceived); m_bSendSYN = FALSE; SendSegment (TCP_FLAG_SYN | TCP_FLAG_ACK, m_nISS, m_nRCV_NXT); m_RTOCalculator.SegmentSent (m_nISS); m_nRetransmissionCount = MAX_RETRANSMISSIONS; StartTimer (TCPTimerRetransmission, m_RTOCalculator.GetRTO ()); if ( (nFlags & TCP_FLAG_FIN) // other controls? || nDataLength > 0) { if (nFlags & TCP_FLAG_FIN) { SendSegment (TCP_FLAG_RESET, m_nSND_NXT); NEW_STATE (TCPStateClosed); } if (nDataLength > 0) { m_RxQueue.Enqueue ((u8 *) pPacket+nDataOffset, nDataLength); } break; } } } break; case TCPStateSynReceived: case TCPStateEstablished: case TCPStateFinWait1: case TCPStateFinWait2: case TCPStateCloseWait: case TCPStateClosing: case TCPStateLastAck: case TCPStateTimeWait: // step 1 ( check sequence number) if (m_nRCV_WND > 0) { if (nSEG_LEN == 0) { if (bwl (m_nRCV_NXT, nSEG_SEQ, m_nRCV_NXT+m_nRCV_WND)) { bAcceptable = TRUE; } } else { if ( bwl (m_nRCV_NXT, nSEG_SEQ, m_nRCV_NXT+m_nRCV_WND) || bwl (m_nRCV_NXT, nSEG_SEQ+nSEG_LEN-1, m_nRCV_NXT+m_nRCV_WND)) { bAcceptable = TRUE; } } } else { if (nSEG_LEN == 0) { if (nSEG_SEQ == m_nRCV_NXT) { bAcceptable = TRUE; } } } if ( !bAcceptable && m_State != TCPStateSynReceived) { SendSegment (TCP_FLAG_ACK, m_nSND_NXT, m_nRCV_NXT); break; } // step 2 (check RST bit) if (nFlags & TCP_FLAG_RESET) { switch (m_State) { case TCPStateSynReceived: m_RetransmissionQueue.Flush (); if (!m_bActiveOpen) { NEW_STATE (TCPStateListen); return 1; } else { m_nErrno = -1; NEW_STATE (TCPStateClosed); m_Event.Set (); return 1; } break; case TCPStateEstablished: case TCPStateFinWait1: case TCPStateFinWait2: case TCPStateCloseWait: m_nErrno = -1; m_RetransmissionQueue.Flush (); m_TxQueue.Flush (); m_RxQueue.Flush (); NEW_STATE (TCPStateClosed); m_Event.Set (); return 1; case TCPStateClosing: case TCPStateLastAck: case TCPStateTimeWait: NEW_STATE (TCPStateClosed); m_Event.Set (); return 1; default: UNEXPECTED_STATE (); return 1; } } // step 3 (check security and precedence, not supported) // step 4 (check SYN bit) if (nFlags & TCP_FLAG_SYN) { // RFC 1122 section 4.2.2.20 (e) if ( m_State == TCPStateSynReceived && !m_bActiveOpen) { NEW_STATE (TCPStateListen); return 1; } SendSegment (TCP_FLAG_RESET, m_nSND_NXT); m_nErrno = -1; m_RetransmissionQueue.Flush (); m_TxQueue.Flush (); m_RxQueue.Flush (); NEW_STATE (TCPStateClosed); m_Event.Set (); return 1; } // step 5 (check ACK field) if (!(nFlags & TCP_FLAG_ACK)) { return 1; } switch (m_State) { case TCPStateSynReceived: if (bwlh (m_nSND_UNA, nSEG_ACK, m_nSND_NXT)) { // RFC 1122 section 4.2.2.20 (f) m_nSND_WND = nSEG_WND; m_nSND_WL1 = nSEG_SEQ; m_nSND_WL2 = nSEG_ACK; m_nSND_UNA = nSEG_ACK; // got ACK for SYN m_RTOCalculator.SegmentAcknowledged (nSEG_ACK); NEW_STATE (TCPStateEstablished); // next transmission starts with this count m_nRetransmissionCount = MAX_RETRANSMISSIONS; } else { SendSegment (TCP_FLAG_RESET, nSEG_ACK); } break; case TCPStateEstablished: case TCPStateFinWait1: case TCPStateFinWait2: case TCPStateCloseWait: case TCPStateClosing: if (bwh (m_nSND_UNA, nSEG_ACK, m_nSND_NXT)) { m_RTOCalculator.SegmentAcknowledged (nSEG_ACK); unsigned nBytesAck = nSEG_ACK-m_nSND_UNA; m_nSND_UNA = nSEG_ACK; if (nSEG_ACK == m_nSND_NXT) // all segments are acknowledged { StopTimer (TCPTimerRetransmission); // next transmission starts with this count m_nRetransmissionCount = MAX_RETRANSMISSIONS; m_Event.Set (); } if ( m_State == TCPStateFinWait1 || m_State == TCPStateClosing) { nBytesAck--; // acknowledged FIN does not count m_bFINQueued = FALSE; } if ( m_State == TCPStateEstablished && nBytesAck == 1) { nBytesAck--; } if (nBytesAck > 0) { m_RetransmissionQueue.Advance (nBytesAck); } // update send window if ( lt (m_nSND_WL1, nSEG_SEQ) || ( m_nSND_WL1 == nSEG_SEQ && le (m_nSND_WL2, nSEG_ACK))) { m_nSND_WND = nSEG_WND; m_nSND_WL1 = nSEG_SEQ; m_nSND_WL2 = nSEG_ACK; } } else if (le (nSEG_ACK, m_nSND_UNA)) // RFC 1122 section 4.2.2.20 (g) { // ignore duplicate ACK ... // RFC 1122 section 4.2.2.20 (g) if (bwlh (m_nSND_UNA, nSEG_ACK, m_nSND_NXT)) { // ... but update send window if ( lt (m_nSND_WL1, nSEG_SEQ) || ( m_nSND_WL1 == nSEG_SEQ && le (m_nSND_WL2, nSEG_ACK))) { m_nSND_WND = nSEG_WND; m_nSND_WL1 = nSEG_SEQ; m_nSND_WL2 = nSEG_ACK; } } } else if (gt (nSEG_ACK, m_nSND_NXT)) { SendSegment (TCP_FLAG_ACK, m_nSND_NXT, m_nRCV_NXT); return 1; } switch (m_State) { case TCPStateEstablished: case TCPStateCloseWait: break; case TCPStateFinWait1: if (nSEG_ACK == m_nSND_NXT) // if our FIN is now acknowledged { m_RTOCalculator.SegmentAcknowledged (nSEG_ACK); m_bFINQueued = FALSE; StopTimer (TCPTimerRetransmission); NEW_STATE (TCPStateFinWait2); } else { break; } // fall through case TCPStateFinWait2: if (m_RetransmissionQueue.IsEmpty ()) { m_Event.Set (); } break; case TCPStateClosing: if (nSEG_ACK == m_nSND_NXT) // if our FIN is now acknowledged { m_RTOCalculator.SegmentAcknowledged (nSEG_ACK); m_bFINQueued = FALSE; StopTimer (TCPTimerRetransmission); NEW_STATE (TCPStateTimeWait); StartTimer (TCPTimerTimeWait, HZ_TIMEWAIT); } break; default: UNEXPECTED_STATE (); break; } break; case TCPStateLastAck: if (nSEG_ACK == m_nSND_NXT) // if our FIN is now acknowledged { m_bFINQueued = FALSE; NEW_STATE (TCPStateClosed); m_Event.Set (); return 1; } break; case TCPStateTimeWait: if (nSEG_ACK == m_nSND_NXT) // if our FIN is now acknowledged { m_bFINQueued = FALSE; SendSegment (TCP_FLAG_ACK, m_nSND_NXT, m_nRCV_NXT); StartTimer (TCPTimerTimeWait, HZ_TIMEWAIT); } break; default: UNEXPECTED_STATE (); break; } // step 6 (check URG bit, not supported) StepSix: // step 7 (process text segment) if (nSEG_LEN == 0) { return 1; } switch (m_State) { case TCPStateEstablished: case TCPStateFinWait1: case TCPStateFinWait2: if (nSEG_SEQ == m_nRCV_NXT) { if (nDataLength > 0) { m_RxQueue.Enqueue ((u8 *) pPacket+nDataOffset, nDataLength); m_nRCV_NXT += nDataLength; // m_nRCV_WND should be adjusted here (section 3.7) // following ACK could be piggybacked with data SendSegment (TCP_FLAG_ACK, m_nSND_NXT, m_nRCV_NXT); if (nFlags & TCP_FLAG_PUSH) { m_Event.Set (); } } } else { SendSegment (TCP_FLAG_ACK, m_nSND_NXT, m_nRCV_NXT); } break; case TCPStateCloseWait: case TCPStateClosing: case TCPStateLastAck: case TCPStateTimeWait: break; default: UNEXPECTED_STATE (); break; } // step 8 (check FIN bit) if ( m_State == TCPStateClosed || m_State == TCPStateListen || m_State == TCPStateSynSent) { return 1; } if (!(nFlags & TCP_FLAG_FIN)) { return 1; } // connection is closing m_nRCV_NXT++; SendSegment (TCP_FLAG_ACK, m_nSND_NXT, m_nRCV_NXT); switch (m_State) { case TCPStateSynReceived: case TCPStateEstablished: NEW_STATE (TCPStateCloseWait); m_Event.Set (); break; case TCPStateFinWait1: if (nSEG_ACK == m_nSND_NXT) // if our FIN is now acknowledged { m_bFINQueued = FALSE; StopTimer (TCPTimerRetransmission); StopTimer (TCPTimerUser); NEW_STATE (TCPStateTimeWait); StartTimer (TCPTimerTimeWait, HZ_TIMEWAIT); } else { NEW_STATE (TCPStateClosing); } break; case TCPStateFinWait2: StopTimer (TCPTimerRetransmission); StopTimer (TCPTimerUser); NEW_STATE (TCPStateTimeWait); StartTimer (TCPTimerTimeWait, HZ_TIMEWAIT); break; case TCPStateCloseWait: case TCPStateClosing: case TCPStateLastAck: break; case TCPStateTimeWait: StartTimer (TCPTimerTimeWait, HZ_TIMEWAIT); break; default: UNEXPECTED_STATE (); break; } break; } return 1; }