void TCPConnection::SendIPv4Packet(uint8_t* packet, uint64_t length, uint8_t flags) { /* SYN: The active open is performed by the client sending a SYN to the server. The client sets the segment's sequence number to a random value A. SYN-ACK: In response, the server replies with a SYN-ACK. The acknowledgment number is set to one more than the received sequence number i.e. A+1, and the sequence number that the server chooses for the packet is another random number, B. ACK: Finally, the client sends an ACK back to the server. The sequence number is set to the received acknowledgement value i.e. A+1, and the acknowledgement number is set to one more than the received sequence number i.e. B+1. */ if(this->state == ConnectionState::Disconnected) { Log(1, "Error: cannot send packet through a disconnected socket."); return; } // setup a fake IPv4 header. IP::PseudoIPv4Header* pseudo = new IP::PseudoIPv4Header; pseudo->source = this->sourceip4; pseudo->dest = this->destip4; pseudo->zeroes = 0; pseudo->protocol = (uint8_t) IP::ProtocolType::TCP; pseudo->length = SwapEndian16(sizeof(TCPPacket) + (uint16_t) length); // calculate the pseudo header's checksum separately. uint16_t pseudocheck = IP::CalculateIPChecksum_Partial(0, pseudo, sizeof(IP::PseudoIPv4Header)); uint8_t* raw = new uint8_t[sizeof(TCPPacket) + length]; TCPPacket* tcp = (TCPPacket*) raw; tcp->clientport = SwapEndian16(this->clientport); tcp->serverport = SwapEndian16(this->serverport); tcp->sequence = SwapEndian32(this->localsequence + this->localcumlsequence); tcp->ackid = SwapEndian32(this->nextack); this->localcumlsequence += length; tcp->HeaderLength = 0x50; tcp->Flags = flags; // 32k tcp->WindowSize = SwapEndian16(TCP_MAXWINDOW); tcp->Checksum = 0; tcp->UrgentPointer = 0; Memory::Copy(raw + sizeof(TCPPacket), packet, length); uint16_t tcpcheck = IP::CalculateIPChecksum_Partial(pseudocheck, tcp, sizeof(TCPPacket) + length); tcp->Checksum = SwapEndian16(IP::CalculateIPChecksum_Finalise(tcpcheck)); // this->socket->WriteTCP(raw, sizeof(TCPPacket) + length); IP::SendIPv4Packet(this->socket->interface, raw, (uint16_t) (sizeof(TCPPacket) + length), 48131, this->destip4, IP::ProtocolType::TCP); this->AlreadyAcked = true; delete pseudo; delete tcp; }
/* * Class: org_openhome_net_device_DvInvocation * Method: DvInvocationGetAdapter * Signature: (J)I */ JNIEXPORT jint JNICALL Java_org_openhome_net_device_DvInvocation_DvInvocationGetAdapter (JNIEnv *aEnv, jclass aClass, jlong aInvocation) { DvInvocationC invocation = (DvInvocationC) (size_t)aInvocation; TIpAddress adapter; aEnv = aEnv; aClass = aClass; DvInvocationGetAdapter(invocation, &adapter); #ifdef DEFINE_LITTLE_ENDIAN return (jint) SwapEndian32(adapter); #elif defined DEFINE_BIG_ENDIAN return (jint) adapter; #else # error Endianness not defined #endif }
inline int String0::Compare(const String0& s) const { #ifdef FAST_STRING_COMPARE if((chr[KIND] | s.chr[KIND]) == 0) { #ifdef CPU_64 uint64 a64 = SwapEndian64(q[0]); uint64 b64 = SwapEndian64(s.q[0]); if(a64 != b64) return a64 < b64 ? -1 : 1; uint32 a32 = SwapEndian32(w[2]); uint32 b32 = SwapEndian32(s.w[2]); if(a32 != b32) return a32 < b32 ? -1 : 1; #else uint32 a32 = SwapEndian32(w[0]); uint32 b32 = SwapEndian32(s.w[0]); if(a32 != b32) return a32 < b32 ? -1 : 1; a32 = SwapEndian32(w[1]); b32 = SwapEndian32(s.w[1]); if(a32 != b32) return a32 < b32 ? -1 : 1; a32 = SwapEndian32(w[2]); b32 = SwapEndian32(s.w[2]); if(a32 != b32) return a32 < b32 ? -1 : 1; #endif uint16 a16 = SwapEndian16(v[6]); uint16 b16 = SwapEndian16(s.v[6]); if(a16 != b16) return a16 < b16 ? -1 : 1; return 0; } #endif return LCompare(s); }
inline int String0::Compare(const String0& s) const { #ifdef FAST_STRING_COMPARE if((chr[KIND] | s.chr[KIND]) == 0) { #ifdef CPU_64 uint64 a64 = q[0]; uint64 b64 = s.q[0]; if(a64 != b64) return SwapEndian64(a64) < SwapEndian64(b64) ? -1 : 1; uint32 a32 = w[2]; uint32 b32 = s.w[2]; if(a32 != b32) return SwapEndian32(a32) < SwapEndian32(b32) ? -1 : 1; #else uint32 a32 = w[0]; uint32 b32 = s.w[0]; if(a32 != b32) return SwapEndian32(a32) < SwapEndian32(b32) ? -1 : 1; a32 = w[1]; b32 = s.w[1]; if(a32 != b32) return SwapEndian32(a32) < SwapEndian32(b32) ? -1 : 1; a32 = w[2]; b32 = s.w[2]; if(a32 != b32) return SwapEndian32(a32) < SwapEndian32(b32) ? -1 : 1; #endif uint16 a16 = v[6]; uint16 b16 = s.v[6]; if(a16 != b16) return SwapEndian16(a16) < SwapEndian16(b16) ? -1 : 1; return 0; } #endif return LCompare(s); }
void TCPConnection::HandleIncoming(uint8_t* packet, uint64_t bytes, uint64_t HeaderSize) { // at this stage the checksum should be verified (and set to zero), so we can ignore that. TCPPacket* tcp = (TCPPacket*) packet; HeaderSize *= 4; // check if we got options. if(HeaderSize > sizeof(TCPPacket)) { uint64_t optsize = HeaderSize - sizeof(TCPPacket); uint64_t offset = sizeof(TCPPacket); while(offset < optsize) { switch(packet[offset]) { case 2: this->maxsegsize = SwapEndian16(*(packet + offset + 2)); offset += 4; break; } } } // check if ack. if(!(tcp->Flags & 0x10)) { Log("TCP ACK flag not set, discarding."); return; } uint64_t datalength = bytes - HeaderSize; this->lastpackettime = Time::Now(); this->nextack = SwapEndian32(tcp->sequence) + (uint32_t) datalength; this->servercumlsequence += __max(datalength, 1); this->PacketReceived = true; switch(this->state) { case ConnectionState::Disconnected: { Log(1, "TCP Stack error: Received packet from closed connection"); return; } case ConnectionState::WatingSYNReply: { // check if we're synchronising if(tcp->Flags & 0x2) { this->serversequence = SwapEndian32(tcp->sequence); this->servercumlsequence = 1; this->localcumlsequence = 1; this->nextack = 1; } break; } case ConnectionState::WaitingConnectionACK: { // handshake complete. Log("Established connection to %d.%d.%d.%d : %d; Relative local seq: %d, Relative server seq: %d", this->destip4.b1, this->destip4.b2, this->destip4.b3, this->destip4.b4, this->serverport, this->localcumlsequence, this->servercumlsequence); this->state = ConnectionState::Connected; break; } // disconnections: case ConnectionState::WaitingDisconnectACK: { // servers will either send an 'ACK', followed by a 'FIN, then ACK', or a 'FIN, ACK' directly. // handle both cases. if(tcp->Flags & 0x1 && tcp->Flags & 0x10) { // this is a FIN, ACK // don't respond. this->state = ConnectionState::Disconnected; return; } else if(tcp->Flags & 0x10) { // server sent an ACK, expect stuff later this->state = ConnectionState::WaitingDisconnectFINACK; return; } else { Log(1, "Invalid TCP response to FIN, ACK; state machine broken."); } break; } case ConnectionState::WaitingDisconnectFINACK: { // well we're expecting a FIN, ACK. if(tcp->Flags & 0x1 && tcp->Flags & 0x10) { this->nextack++; this->SendPacket(0, 0, 0x10); this->state = ConnectionState::Disconnected; Log("Disconnected from %d.%d.%d.%d : %d.", this->destip4.b1, this->destip4.b2, this->destip4.b3, this->destip4.b4, this->serverport); return; } else { Log(1, "Invalid TCP response to FIN, ACK; state machine broken."); } break; } case ConnectionState::Connected: { // first check if the server wants us to D/C if(tcp->Flags & 0x1) { // damn it, that f****r // send an ACK to that. this->nextack++; this->SendPacket(0, 0, 0x10); this->state = ConnectionState::WaitingDisconnectACK; return; } this->AlreadyAcked = false; // copy the packet data to the correct place. if(datalength > 0 && tcp->Flags & 0x8) { // push. // fine, bastard. uint64_t offset = SwapEndian32(tcp->sequence) - this->serversequence - 1; this->socket->recvbuffer.MoveWritePointer(offset); this->socket->recvbuffer.Write(packet + HeaderSize, datalength); Log("pushed %d bytes to offset %d", datalength, offset); } else if(datalength > 0 && (SwapEndian32(tcp->sequence) >= this->servercumlsequence) && (this->bufferfill + datalength) < TCP_MAXWINDOW) { uint64_t offset = SwapEndian32(tcp->sequence) - this->serversequence - 1; // uint64_t prp = this->packetbuffer->GetWritePointer(); Log("Copying %d bytes to offset %d", datalength, offset); this->socket->recvbuffer.MoveWritePointer(offset); this->socket->recvbuffer.Write(packet + HeaderSize, datalength); this->bufferfill += datalength; } else if((this->bufferfill + (bytes - HeaderSize)) >= TCP_MAXWINDOW) { // shit. // push data to application, // send collective ACK. HALT(""); // flush tcp to application. uint8_t* buf = new uint8_t[GLOBAL_MTU]; this->packetbuffer.Read(buf, GLOBAL_MTU); this->socket->recvbuffer.Write(buf, GLOBAL_MTU); delete[] buf; } break; } } }