Sourcecode Fortschritt
-
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=0
blackjack 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.
-
version = "0.0.2.132 - Rev: 970" <--- Simulation mit qemu:
qemu gestartet mit TAP1/TAP2 unter Windows XP.Foto: http://www.henkessoft.de/OS_Dev/Bilder/rev.970_INTERNET_HTTP.PNG
strg+w baut die connection via router zum Internet auf Port 80 (HTTP) auf, strg+x fordert Daten mittels GET ... an.
DHCP läuft hierbei nicht sauber zum Ende durch (bleibt bei OFFER hängen, wobwi REQUEST gesendet wird, man muss mit TAP1 Aktivierung/Deaktivierung toggeln). Daher sind die HACKs wichtig.
So wie es aussieht, kann man TCP/IP damit trotz des DHCP-Problems testen.
qemu batch datei:
qemu.exe -fda FloppyImage.img -soundhw pcspk -net nic,model=rtl8139,addr=1A,macaddr=00:12:12:12:12:12 -net tap,ifname=TAP2 -net user -localtime
Die Emulation mit qemu funktioniert auch mit dem pcnet-Treiber.
pcnet anstelle rtl8139Noch besser: Da qemu und der HOST zusammen NAT spielen, werden die PrettyOS-Pakete unter der IP des HOST verschickt, sodass man in wireshark jedes Paket sieht: http://www.henkessoft.de/OS_Dev/Bilder/rev.970_INTERNET_HTTP_WIRESHARK.PNG
PrOS = PrettyOS, web = Website
Send Recv flags seq# ack# nextseq# window --------------------------------------------------------------------------- PrOS web SYN 0 - 65535 web PrOS SYN ACK 0 1 65535 PrOS web ACK 1 1 65535 PrOS web PSH ACK 1 1 82 65535 GET /OS_Dev/... web PrOS ACK 1 82 248 65535 1. Teil Header web PrOS ACK 248 82 755 65535 OK 2. Teil <!DOCTYPE ... PrOS web ACK 82 755 64781 web PrOS FIN ACK 755 82 65535 PrOS web ACK 82 756 64781
Anmerkung: beim ersten Datenpaket vom Webserver steht: TCP segment of a reassembled PDU
HTTP Protokollschicht:
GET /OS_Dev/PrettyOS.htm HTTP/1.1 Host: www.henkessoft.de Connection: close HTTP/1.1 200 OK Date: Mon, 20 Jun 2011 19:45:22 GMT Server: Apache/2.2.17 Last-Modified: Sun, 19 Jun 2011 16:32:48 GMT ETag: "1e07e25-1fb-4a6132b4e8c00" Accept-Ranges: bytes Content-Length: 507 Connection: close Content-Type: text/html <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta content="text/html;charset=ISO-8859-15" http-equiv="Content-Type"> <title>PrettyOS</title> </head> <body> <h1>Hallo, hier spricht PrettyOS. </h1> <h1>Ich wurde in C und Assembler erstellt. </h1> <h1>Es gibt eine Community, die mich hingebungsvoll pflegt und weiter entwickelt.<br> </h1> <h1><a href="http://www.c-plusplus.net/forum/f62">http://www.c-plusplus.net/forumf62</a></h1> <br> </body> </html>
-
version = "0.0.2.133 - Rev: 971"
- tcp etwas überarbeitet: mehr Ausgaben über connection (addr) und port
- bei strg+b und strg+w (gemischt) geht noch einiges durcheinander!
-
version = "0.0.2.134 - Rev: 972"
- strg+c: listet alle connections auf
- tcp kleine änderungen
-
Version 0.0.2.135:
- Keyboard-Treiber komplett neu geschrieben
-- Alle Tasten der Tastatur werden nun unterstützt (z.B. war früher der Num-Block unbenutzbar)
-- Bessere Unterstützung für US-International-Layout (fast vollständig)
-- Änderungen bei der Bedienung: Screenshots werden mit Print im Speicher angelegt. Drückt man unmittelbar danach f oder u, wird er auf Floppy bzw. USB-Stick gespeichert.
- Bessere ASCII -> CP437-Übersetzung: Mehr Zeichen darstellbar.
- Event-System
- getCursor nimmt nun position_t* (in den die Position geschrieben wird) und gibt void zurück. (Führte vorher zu #PF bei Verwendung als Syscall)
- Bugfix in list_Delete (führte ggf. zur Zerstörung der Listen)
- Keysound etwas verbessert: Tonhöhe hängt von gedrückter Taste ab, ESC beendet das Programm.Bekannte Probleme:
- Jedes zweite %-Zeichen wird von der Shell (genauer: printLine/kprintf) verschluckt (Problem existiert schon länger, ist erst jetzt aufgefallen)
- Unter Qemu 0.14.1 und 0.14.0 senden E0-Tasten kein 0xE0. Sie funktionieren daher nicht.
-
Version 0.0.2.135 - Rev: 974:
- events.h/c nachgeliefert
- Bugfix: Rebuild der Userprogramme geht wieder
-
Version 0.0.2.136 - Rev: 975
Experimenteller Zwischenstand mit arp_sendRequest und dem Versuch das Gateway einzutragen, klappt leider nicht (s. wireshark). Ursache unklar.
-
Version 0.0.2.137
- Berücksichtigung des Subnets beim Senden von Paketen. Problem: ARP-Requests funktionieren nicht
- Events mit mutex geschützt
- Für Tests die Funktion network_getFirstAdapter bereitgestellt
- Kleinigkeiten