void SendIcmpMessage(UInt32 destinationIPAddress, IcmpMessageType icmpMessageType, IcmpMessageCode icmpMessageCode, byte[] restOfHeader, byte[] data, Int64 timeoutInMachineTicks) { if (_isDisposed) { return; } lock (_icmpFrameBufferLock) { // configure ICMPv4 frame /* Type */ _icmpFrameBuffer[0] = (byte)icmpMessageType; /* Code (Subtype) */ _icmpFrameBuffer[1] = (byte)icmpMessageCode; /* checksum (clear this for now; we will calculate it shortly) */ Array.Clear(_icmpFrameBuffer, 2, 2); /* restOfHeader */ if (restOfHeader.Length < 4) { Array.Clear(_icmpFrameBuffer, 4, 4); } Array.Copy(restOfHeader, 0, _icmpFrameBuffer, 4, System.Math.Min(4, restOfHeader.Length)); UInt16 checksum; lock (_checksumLock) { // calculate checksum over entire ICMP frame including data _checksumBufferArray[0] = _icmpFrameBuffer; _checksumOffsetArray[0] = 0; _checksumCountArray[0] = ICMP_FRAME_BUFFER_LENGTH; _checksumBufferArray[1] = data; _checksumOffsetArray[1] = 0; _checksumCountArray[1] = data.Length; checksum = Utility.CalculateInternetChecksum(_checksumBufferArray, _checksumOffsetArray, _checksumCountArray, 2); } _icmpFrameBuffer[2] = (byte)((checksum >> 8) & 0xFF); _icmpFrameBuffer[3] = (byte)(checksum & 0xFF); _bufferArray[0] = _icmpFrameBuffer; _indexArray[0] = 0; _countArray[0] = ICMP_FRAME_BUFFER_LENGTH; _bufferArray[1] = data; _indexArray[1] = 0; _countArray[1] = data.Length; _ipv4Layer.Send(1 /* PROTOCOL for ICMP */, _ipv4Layer.IPAddress, destinationIPAddress, _bufferArray, _indexArray, _countArray, timeoutInMachineTicks); } }
internal void SendTcpSegment(UInt32 sourceIPAddress, UInt32 destinationIPAddress, UInt16 sourceIPPort, UInt16 destinationIPPort, UInt32 sequenceNumber, UInt32 acknowledgementNumber, UInt16 windowSize, bool sendAck, bool sendPsh, bool sendRst, bool sendSyn, bool sendFin, TcpOption[] tcpOptions, byte[] buffer, Int32 offset, Int32 count, Int64 timeoutInMachineTicks) { if (_isDisposed) { return; } lock (_tcpHeaderBufferLockObject) { Int32 tcpHeaderLength = TCP_HEADER_MIN_LENGTH + (sendSyn ? 4 : 0); // TCP basic header: 20 bytes _tcpHeaderBuffer[0] = (byte)((sourceIPPort >> 8) & 0xFF); _tcpHeaderBuffer[1] = (byte)(sourceIPPort & 0xFF); _tcpHeaderBuffer[2] = (byte)((destinationIPPort >> 8) & 0xFF); _tcpHeaderBuffer[3] = (byte)(destinationIPPort & 0xFF); // sequence number _tcpHeaderBuffer[4] = (byte)((sequenceNumber >> 24) & 0xFF); _tcpHeaderBuffer[5] = (byte)((sequenceNumber >> 16) & 0xFF); _tcpHeaderBuffer[6] = (byte)((sequenceNumber >> 8) & 0xFF); _tcpHeaderBuffer[7] = (byte)(sequenceNumber & 0xFF); // acknowledment number if (sendAck) { _tcpHeaderBuffer[8] = (byte)((acknowledgementNumber >> 24) & 0xFF); _tcpHeaderBuffer[9] = (byte)((acknowledgementNumber >> 16) & 0xFF); _tcpHeaderBuffer[10] = (byte)((acknowledgementNumber >> 8) & 0xFF); _tcpHeaderBuffer[11] = (byte)(acknowledgementNumber & 0xFF); } else { Array.Clear(_tcpHeaderBuffer, 8, 4); } // header length and flags _tcpHeaderBuffer[12] = (byte)((tcpHeaderLength / 4) << 4); // more flags _tcpHeaderBuffer[13] = (byte)( (sendFin ? 1 << 0 : 0) | (sendSyn ? 1 << 1 : 0) | (sendRst ? 1 << 2 : 0) | (sendPsh ? 1 << 3 : 0) | (sendAck ? 1 << 4 : 0) ); // window size (i.e. how much data we are willing to receive) _tcpHeaderBuffer[14] = (byte)((windowSize >> 8) & 0xFF); _tcpHeaderBuffer[15] = (byte)(windowSize & 0xFF); // tcp checksum Array.Clear(_tcpHeaderBuffer, 16, 2); // urgent pointer /* NOTE: bytes 18-19, never populated */ // TCP options: empty by default policy -- but zero-initialized under any circumstance Array.Clear(_tcpHeaderBuffer, TCP_HEADER_MIN_LENGTH, TCP_HEADER_MAX_LENGTH - TCP_HEADER_MIN_LENGTH); /* TCP options */ if (tcpOptions != null) { int headerPos = TCP_HEADER_MIN_LENGTH; for (int iOption = 0; iOption < tcpOptions.Length; iOption++) { _tcpHeaderBuffer[headerPos++] = tcpOptions[iOption].Kind; switch (tcpOptions[iOption].Kind) { case 0: /* EOL = End of Option List */ case 1: /* NOP = No OPeration; used for padding */ break; default: { if (tcpOptions[iOption].Data != null) { _tcpHeaderBuffer[headerPos++] = (byte)(tcpOptions[iOption].Data.Length + 2); Array.Copy(tcpOptions[iOption].Data, 0, _tcpHeaderBuffer, headerPos, tcpOptions[iOption].Data.Length); headerPos += tcpOptions[iOption].Data.Length; } else { _tcpHeaderBuffer[headerPos++] = 2; /* only 2 bytes--the kind and the length--with no data */ } } break; } } } UInt16 checksum; lock (_tcpPseudoHeaderBufferLockObject) { // create temporary pseudo header _tcpPseudoHeaderBuffer[0] = (byte)((sourceIPAddress >> 24) & 0xFF); _tcpPseudoHeaderBuffer[1] = (byte)((sourceIPAddress >> 16) & 0xFF); _tcpPseudoHeaderBuffer[2] = (byte)((sourceIPAddress >> 8) & 0xFF); _tcpPseudoHeaderBuffer[3] = (byte)(sourceIPAddress & 0xFF); _tcpPseudoHeaderBuffer[4] = (byte)((destinationIPAddress >> 24) & 0xFF); _tcpPseudoHeaderBuffer[5] = (byte)((destinationIPAddress >> 16) & 0xFF); _tcpPseudoHeaderBuffer[6] = (byte)((destinationIPAddress >> 8) & 0xFF); _tcpPseudoHeaderBuffer[7] = (byte)(destinationIPAddress & 0xFF); _tcpPseudoHeaderBuffer[8] = 0; // ZERO _tcpPseudoHeaderBuffer[9] = (byte)IPv4Layer.ProtocolType.Tcp; // Protocol Number UInt16 tcpLength = (UInt16)(tcpHeaderLength + count); _tcpPseudoHeaderBuffer[10] = (byte)((tcpLength >> 8) & 0xFF); _tcpPseudoHeaderBuffer[11] = (byte)(tcpLength & 0xFF); // calculate checksum over entire pseudo-header, UDP header and data _checksumBufferArray[0] = _tcpPseudoHeaderBuffer; _checksumOffsetArray[0] = 0; _checksumCountArray[0] = TCP_PSEUDO_HEADER_LENGTH; _checksumBufferArray[1] = _tcpHeaderBuffer; _checksumOffsetArray[1] = 0; _checksumCountArray[1] = tcpHeaderLength; _checksumBufferArray[2] = buffer; _checksumOffsetArray[2] = offset; _checksumCountArray[2] = count; checksum = Utility.CalculateInternetChecksum(_checksumBufferArray, _checksumOffsetArray, _checksumCountArray); /* NOTE: this function will append a pad byte if necessary for 16-bit alignment before calculation */ } // insert checksujm into UDP header _tcpHeaderBuffer[16] = (byte)((checksum >> 8) & 0xFF); _tcpHeaderBuffer[17] = (byte)(checksum & 0xFF); // queue up our buffer arrays _bufferArray[0] = _tcpHeaderBuffer; _indexArray[0] = 0; _countArray[0] = tcpHeaderLength; _bufferArray[1] = buffer; _indexArray[1] = offset; _countArray[1] = count; /* TODO: deal with our flags and timeout_ms; we shouldn't just be sending while blocking -- and ignoring the flags */ _ipv4Layer.Send((byte)IPv4Layer.ProtocolType.Tcp, sourceIPAddress, destinationIPAddress, _bufferArray, _indexArray, _countArray, timeoutInMachineTicks); } }
/* TODO: we can't lock permanently while waiting for another UDP packet to be sent; get rid of the _udpHeaderBufferLock "lock that could stay locked forever" */ public override Int32 SendTo(byte[] buffer, Int32 offset, Int32 count, Int32 flags, Int64 timeoutInMachineTicks, UInt32 ipAddress, UInt16 ipPort) { if (!_sourceIpAddressAndPortAssigned) { Bind(IP_ADDRESS_ANY, IP_PORT_ANY); } lock (_udpHeaderBufferLockObject) { // UDP header: 8 bytes _udpHeaderBuffer[0] = (byte)((_srcIPPort >> 8) & 0xFF); _udpHeaderBuffer[1] = (byte)(_srcIPPort & 0xFF); _udpHeaderBuffer[2] = (byte)((ipPort >> 8) & 0xFF); _udpHeaderBuffer[3] = (byte)(ipPort & 0xFF); UInt16 udpLength = (UInt16)(UDP_HEADER_LENGTH + count); _udpHeaderBuffer[4] = (byte)((udpLength >> 8) & 0xFF); _udpHeaderBuffer[5] = (byte)(udpLength & 0xFF); _udpHeaderBuffer[6] = 0; // for now, no checksum; we'll populate this when we calculate checksum over the pseudoheader + header + data + 16-bit-alignment-if-necessary-zero-pad-byte _udpHeaderBuffer[7] = 0; // checksum (continued) UInt16 checksum; lock (_udpPseudoHeaderBufferLockObject) { // create temporary pseudo header _udpPseudoHeaderBuffer[0] = (byte)((_srcIPAddress >> 24) & 0xFF); _udpPseudoHeaderBuffer[1] = (byte)((_srcIPAddress >> 16) & 0xFF); _udpPseudoHeaderBuffer[2] = (byte)((_srcIPAddress >> 8) & 0xFF); _udpPseudoHeaderBuffer[3] = (byte)(_srcIPAddress & 0xFF); _udpPseudoHeaderBuffer[4] = (byte)((ipAddress >> 24) & 0xFF); _udpPseudoHeaderBuffer[5] = (byte)((ipAddress >> 16) & 0xFF); _udpPseudoHeaderBuffer[6] = (byte)((ipAddress >> 8) & 0xFF); _udpPseudoHeaderBuffer[7] = (byte)(ipAddress & 0xFF); _udpPseudoHeaderBuffer[8] = 0; // ZERO _udpPseudoHeaderBuffer[9] = (byte)IPv4Layer.ProtocolType.Udp; // Protocol Number _udpPseudoHeaderBuffer[10] = (byte)((udpLength >> 8) & 0xFF); _udpPseudoHeaderBuffer[11] = (byte)(udpLength & 0xFF); // calculate checksum over entire pseudo-header, UDP header and data _checksumBufferArray[0] = _udpPseudoHeaderBuffer; _checksumOffsetArray[0] = 0; _checksumCountArray[0] = UDP_PSEUDO_HEADER_LENGTH; _checksumBufferArray[1] = _udpHeaderBuffer; _checksumOffsetArray[1] = 0; _checksumCountArray[1] = UDP_HEADER_LENGTH; _checksumBufferArray[2] = buffer; _checksumOffsetArray[2] = offset; _checksumCountArray[2] = count; checksum = Utility.CalculateInternetChecksum(_checksumBufferArray, _checksumOffsetArray, _checksumCountArray); /* NOTE: this function will append a pad byte if necessary for 16-bit alignment before calculation */ } // insert checksujm into UDP header _udpHeaderBuffer[6] = (byte)((checksum >> 8) & 0xFF); _udpHeaderBuffer[7] = (byte)(checksum & 0xFF); // queue up our buffer arrays _bufferArray[0] = _udpHeaderBuffer; _indexArray[0] = 0; _countArray[0] = UDP_HEADER_LENGTH; _bufferArray[1] = buffer; _indexArray[1] = offset; _countArray[1] = count; /* TODO: deal with our flags and timeout_ms; we shouldn't just be sending while blocking -- and ignoring the flags */ _ipv4Layer.Send((byte)IPv4Layer.ProtocolType.Udp, _srcIPAddress, ipAddress, _bufferArray, _indexArray, _countArray, timeoutInMachineTicks); } /* TODO: return actual # of bytes sent, if different; this may be caused by a limit on UDP datagram size, timeout while sending data, etc. */ return(count); }