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.