Sourcecode Fortschritt
- 
					
					
					
					
 version = "0.0.2.114 - Rev: 953" Nun sind auch variable Längen des TCP-Datenpakets möglich. Wir reichen uns die Paketlänge von unten nach tcpReceive(network_adapter_t* adapter, tcpPacket_t* tcp, uint8_t transmittingIP[4], size_t length) durch. Codeausschnitt: if (adapter->TCP_CurrState == ESTABLISHED) // ESTABLISHED --> DATA TRANSFER { uint32_t tcpDataLength = -4 /* frame ? */ + length - (tcp->dataOffset << 2); printf("\ntcp packet data:"); for (uint16_t i=0; i<tcpDataLength; i++) { printf("%c", *(((uint8_t*)(tcp+1))+i) ); } tcpSend(adapter, 0, 0, htons(tcp->destPort), adapter->IP_address, htons(tcp->sourcePort), transmittingIP, ACK_FLAG, tcp->acknowledgmentNumber /*seqNumber*/, tcp->sequenceNumber+htonl(tcpDataLength) /*ackNumber*/); }telnet: open 192.168.1.97 sen ... sen ................ sen ....... closeanschließend bei PrettyOS wieder strg+c und erneut connection aufbauen, oder auch direkt open ... . Kann alles in wireshark und bei PrettyOS verfolgt werden.  
 
- 
					
					
					
					
 version = "0.0.2.115 - Rev: 954" tcp.h weiter mit structs (DRAFT) gefüllt, um mit connections und dazu gehörigen sockets arbeiten zu können: typedef struct { uint32_t SND_UNA; // Send Unacknowledged uint32_t SND_NXT; // Send Next uint16_t SND_WND; // Send Window uint32_t SND_ISS; // Initial send sequence number uint32_t RCV_NXT; // Sequence number of next received set uint16_t RCV_WND; // Receive Window uint32_t RCV_IRS; // Initial receive sequence number } __attribute__((packed)) tcpTransmissionControlBlock_t; typedef struct { uint16_t port; uint8_t IP[4]; network_adapter_t* adapter; } __attribute__((packed)) tcpSocket_t; typedef struct { tcpSocket_t localSocket; tcpSocket_t remoteSocket; tcpTransmissionControlBlock_t tcb; TCP_state TCP_PrevState; TCP_state TCP_CurrState; } __attribute__((packed)) tcpConnection_t; typedef struct { uint32_t SEG_SEQ; // Sequence number uint32_t SEG_ACK; // Acknoledgement number uint32_t SEG_LEN; // segment length uint32_t SEG_WND; // segment windows tcpFlags SEG_CTL; // control bits } __attribute__((packed)) tcpSegment_t;
 
- 
					
					
					
					
 version = "0.0.2.116 - Rev: 955" TCP weiter ausgebaut. Die TCP States zu tcpConn umgehängt. In network.c das TCP Server "passive open" eingerichtet: // open TCP Server with State "LISTEN" adapter->tcpConn = malloc(sizeof(tcpConnection_t), 0, "tcp connection"); adapter->tcpConn->localSocket.port = getFreeSocket(); memcpy(adapter->tcpConn->localSocket.IP, adapter->IP_address, 4); adapter->tcpConn->TCP_PrevState = CLOSED; adapter->tcpConn->TCP_CurrState = LISTEN; // TODO: ...networktypes.h fehlt im Commit  
 
- 
					
					
					
					
 version = "0.0.2.117 - Rev: 956" nun auch mit networktypes.h Wichtige Links z.Z.: 
 http://www.tcpipguide.com/free/t_TCPConnectionPreparationTransmissionControlBlocksT-2.htm
 http://www.cs.northwestern.edu/~agupta/cs340/project2/TCPIP_State_Transition_Diagram.pdf
 
- 
					
					
					
					
 Version 0.0.2.118: - Ausgabe verbessert 
 - Mutexes verbessert
 - PCI nutzt nun eine Liste statt eines statischen Arrays
 - Aufgeräumt
 
- 
					
					
					
					
 Version 0.0.2.119: - TCP überarbeitet. (BUG: Datentransfer funktioniert nicht.) 
 
- 
					
					
					
					
 version = "0.0.2.120 - Rev: 959" Aktives öffnen und TCP ("SYN") senden (mit strg+w) klappt. 
 Problem: Internet Checksum ist falsch! (Ursache bisher unklar, da das Senden von SYN ACK oder FIN ACK als server bisher klappt)Ablauf: - PrettyOS bootet, holt sich per DHCP seine IP
- Man pingt PrettyOS von 192.168.1.23 an, damit der rechner in die ARP-Tabelle eingetragen wird (diese IP steht konkret in strg+w in keyboard.c drinnen, also ändern auf eigenen rechner)
- Man gibt strg+w ein bei PrettyOS um aktiv ein SYN zu senden
 Fazit: SYN senden klappt, aber checksum falsch
 TCP-Paket: 0402001700000000000000005002ffff88b00000 Checksum: 0x88b0 [incorrect, should be 0x2801 ...]Test mit dem Simulationsprogramm ergibt die korrekte Checksum, also stimmen die Eingangsdaten in die Berechnung für diese nicht. PS: der datentransfer in rev. 958 klappt (war offenbar ein TCP-Netzproblem) 
 
- 
					
					
					
					
 version = "0.0.2.121 - Rev: 960" Nun erfolgt die korrekte Berechnung der internet checksum. Fehler war im Pseudoheader. Dort fehlte noch die source IP. Erstes erfolgreiches "active open" mit Senden von SYN, das zum State SYN_SENT führt (wireshark): 8 22.328396 192.168.1.97 192.168.1.23 TCP 60 blackjack > telnet [SYN] Seq=0 Win=65535 Len=0blackjack steht für den gewählten Port mit der Nr. 1025. static uint16_t getFreeSocket() { static uint16_t srcPort = 1025; return srcPort++; }Um den kompletten Handshake zu sehen, gibt es einen einfachen Weg: - telnet dienst (server) in Windows starten
- firewall tcp port 23 öffnen
- strg+w (active open mit SYN)
 Resultat: 
 http://www.henkessoft.de/OS_Dev/Bilder/rev.960_TCP_TELNET_ACTIVE_OPEN.PNGSYN - SYN ACK - ACK  MrX hat auf die Schnelle einen kleinen TCP-Server geschrieben: #include <SFML/Network.hpp> #include <iostream> #include <string> #include <cstdint> sf::TcpSocket Socket; void Func() { while(true) { char buffer[512]; size_t size; if(Socket.Receive(buffer, 512, size) == sf::Socket::Disconnected) return; buffer[size] = 0; std::cout << buffer; } } sf::Thread Thr(&Func); int main() { sf::TcpListener Listener; Listener.SetBlocking(true); uint16_t port; std::cout << "Bitte Port eingeben: "; std::cin >> port; Listener.Listen(port); std::cout << "Server lauscht... "; Listener.Accept(Socket); std::cout << "Verbunden." << std::endl; Thr.Launch(); std::string str; std::cin >> str; while(str != "exit") { Socket.Send(str.c_str(), str.length()); std::cin >> str; } return(0); }Download der exe-Datei zusammen mit dem Sourcecode: http://www.henkessoft.de/OS_Dev/Downloads/TCPServer.zip (EXE etwas weiter entwickelt bezüglich Ausgaben) 
 
- 
					
					
					
					
 version = "0.0.2.122 - Rev: 960" - Beseitigung eines Fehlers, der nur ab und zu aufgetreten ist: versehentlich wurde mit bigEndian-Zahlen gerechnet, dabei verschiebt sich der Überlauf - falls vorhanden - nach rechts, da wir immer mit littleEndian-Zahlen "rechnen". Daher immer erst nach littleEndian umwandeln, dann rechnen, anschließend zurück nach bigEndian umwandeln: htonl(htonl(tcp->sequenceNumber)+1)<--- EDIT: das zweite htonl müsste ein ntohl sein, wurde inzwischen behoben. 
 - internetChecksumTest.cpp (von MrX, für code::blocks umgeschrieben) in /tools
 
- 
					
					
					
					
 version = "0.0.2.123 - Rev: 961" ntohs/ntohl und htons/htonl im Code aus Gründen der Dokumentation geordnet. vgl. http://beej.us/guide/bgnet/output/html/multipage/htonsman.html Die Inhalte der Macros sind für IA32 bei x86 zufällig gleich, aber es geht um den Weg (Netz <---> Host), der verschieden ist. // htonl = Host To Network Long // htons = Host To Network Short #define htons(v) ((((v) >> 8) & 0xFF) | (((v) & 0xFF) << 8)) #define htonl(v) ((((v) >> 24) & 0xFF) | (((v) >> 8) & 0xFF00) | (((v) & 0xFF00) << 8) | (((v) & 0xFF) << 24)) // ntohl = Network To Host Long // ntohs = Network To Host Short #define ntohs(v) htons(v) #define ntohl(v) htonl(v)Diese Macros machen den Code mehr portabel, denn wenn z.B. die CPU gemäß Big Endian arbeitet dann ist die Umsetzung eben einfach ein "no operation". Beispiel aus tpc.c: tcp_send(connection, 0, 0, ACK_FLAG, tcp->acknowledgmentNumber /*seqNumber*/, htonl(ntohl(tcp->sequenceNumber)+tcpDataLength) /*ackNumber*/); 
 
- 
					
					
					
					
 version = "0.0.2.124 - Rev: 962" Ausgaben bei networking etwas vereinfacht. 
 
- 
					
					
					
					
 version = "0.0.2.125 - Rev: 963" Kleine Veränderungen in networking Ausgabe 
 
- 
					
					
					
					
 Version 0.0.2.126: - netutils.c/h gebildet. Enthält ntohl (u.ä.) sowie checksum-Funktionen 
 - Syscall-Aufruf verwendet festgelegte Register (vermeidet Fehler mit -fomit-frame-pointer)
 - Code wird nun mit -fomit-frame-pointer gebaut
 - Kleinigkeiten
 
- 
					
					
					
					
 Version 0.0.2.127: - IPs und MACs jetzt mit memcmp verglichen 
 - IP_address und MAC_address in IP und MAC umbenannt
 
- 
					
					
					
					
 version = "0.0.2.128 - Rev: 966" (versehentlich zu hoch gedreht in ckernel.c) PrettyOS goes to INTERNET via routing (FIRST TEST) if(retchar == 'w') // Create & Bind connection { connection = tcp_createConnection(); // 94.142.241.111 auf Port 23 uint8_t destIP[4] ={94,142,241,111}; memcpy(connection->remoteSocket.IP, destIP, 4); connection->remoteSocket.port = 23; uint8_t sourceIP[4] ={IP_1,IP_2,IP_3,IP_4}; //HACK memcpy(connection->localSocket.IP, sourceIP, 4); network_adapter_t* adapter = network_getAdapter(sourceIP); printf("network adapter: %Xh\n", adapter); // check connection->adapter = adapter; if(adapter) { tcp_connect(connection); } return 0; }Da wird die Starwars Story erzählt von einem sehr geschwätzigen telnet server (IP: 94.142.241.111). Vielen Dank an Cuervo für diesen Bomben-Tipp! Foto: http://www.henkessoft.de/OS_Dev/Bilder/rev.966_INTERNET.PNG Wer dies nachstellen möchte, benötigt eine rtl8139 Netzwerkkarte, und bitte die router-mac (erhält man oft mit arp -a aus dem arp-cache) und die IP/RIP (gleich), die man von DHCP erhält, in network.h eintragen. Das muss alles noch automatisiert werden. Start ist z.Z. mit strg+w HTTP geht noch nicht (fehlt noch die ACH-Number aus dem SYN-ACK des handshake), kommt demnächst wenn der TCB in connection gefüttert wird.  
 
- 
					
					
					
					
 
 
- 
					
					
					
					
 version = "0.0.2.129 - Rev: 967" - Zuerst Senden (also erstes ACK nach handshake) auf www.henkessoft.de port 80 (HTTP) 
 - bei TIME_WAIT wird connection zerstört, damit man diese mit strg+w neu aufbauen kann.Anwendung: 
 strg+w (verb. aufbauen),
 strg+x (Daten werden geschickt: "GET / HTTP/1.0\r\nHost: www.henkessoft.de\r\n\r\n")(Die Homepage rast durch) Foto: http://www.henkessoft.de/OS_Dev/Bilder/rev.967_INTERNET_HTTP.PNG  
 
- 
					
					
					
					
 version = "0.0.2.130 - Rev: 968" - srand, rand eingebaut für Erzeugung von ISS in tcp.c 
 - Extra eine eigene Übungsseite gebaut: http://www.henkessoft.de/OS_Dev/PrettyOS.htmif(retchar == 'w') // Create & Bind connection { connection = tcp_createConnection(); // uint8_t destIP[4] ={94,142,241,111}; // 94.142.241.111 at Port 23, starwars story uint8_t destIP[4] = {82,100,220,68}; // www.henkessoft.de Port 80 memcpy(connection->remoteSocket.IP, destIP, 4); connection->remoteSocket.port = 80; uint8_t sourceIP[4] ={IP_1,IP_2,IP_3,IP_4}; //HACK memcpy(connection->localSocket.IP, sourceIP, 4); network_adapter_t* adapter = network_getAdapter(sourceIP); printf("network adapter: %Xh\n", adapter); // check connection->adapter = adapter; if(adapter) { tcp_connect(connection); } return 0; } if(retchar == 'x') // send data to the connection { tcp_send(connection, "GET /OS_Dev/PrettyOS.htm HTTP/1.1\r\nHost: www.henkessoft.de\r\nConnection: close\r\n\r\n", strlen("GET /OS_Dev/PrettyOS.htm HTTP/1.1\r\nHost: www.henkessoft.de\r\nConnection: close\r\n\r\n"), ACK_FLAG, connection->tcb.SND_NXT, connection->tcb.SND_UNA); return 0; }Klappt gut! HTTP hat natürlich im eigentlichen Kernel nichts verloren. Dies hier in keyboard ist sozusagen ein "Steckbrett". 
 
- 
					
					
					
					
 version = "0.0.2.131 - Rev: 969" - Gateway IP aus DHCP ACK gezogen und bei adpater->... eingehängt. 
 
- 
					
					
					
					
 version = "0.0.2.132 - Rev: 970" - Subnet Mask aus DHCP ACK gezogen und bei adpater->... eingehängt.